]> jfr.im git - yt-dlp.git/blob - yt_dlp/extractor/wimtv.py
[misc] Add `hatch`, `ruff`, `pre-commit` and improve dev docs (#7409)
[yt-dlp.git] / yt_dlp / extractor / wimtv.py
1 from .common import InfoExtractor
2 from ..utils import (
3 ExtractorError,
4 determine_ext,
5 parse_duration,
6 urlencode_postdata,
7 )
8
9
10 class WimTVIE(InfoExtractor):
11 _player = None
12 _UUID_RE = r'[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}'
13 _VALID_URL = r'''(?x:
14 https?://platform\.wim\.tv/
15 (?:
16 (?:embed/)?\?
17 |\#/webtv/.+?/
18 )
19 (?P<type>vod|live|cast)[=/]
20 (?P<id>%s).*?)''' % _UUID_RE
21 _EMBED_REGEX = [rf'<iframe[^>]+src=["\'](?P<url>{_VALID_URL})']
22 _TESTS = [{
23 # vod stream
24 'url': 'https://platform.wim.tv/embed/?vod=db29fb32-bade-47b6-a3a6-cb69fe80267a',
25 'md5': 'db29fb32-bade-47b6-a3a6-cb69fe80267a',
26 'info_dict': {
27 'id': 'db29fb32-bade-47b6-a3a6-cb69fe80267a',
28 'ext': 'mp4',
29 'title': 'AMA SUPERCROSS 2020 - R2 ST. LOUIS',
30 'duration': 6481,
31 'thumbnail': r're:https?://.+?/thumbnail/.+?/720$'
32 },
33 'params': {
34 'skip_download': True,
35 },
36 }, {
37 # live stream
38 'url': 'https://platform.wim.tv/embed/?live=28e22c22-49db-40f3-8c37-8cbb0ff44556&autostart=true',
39 'info_dict': {
40 'id': '28e22c22-49db-40f3-8c37-8cbb0ff44556',
41 'ext': 'mp4',
42 'title': 'Streaming MSmotorTV',
43 'is_live': True,
44 },
45 'params': {
46 'skip_download': True,
47 },
48 }, {
49 'url': 'https://platform.wim.tv/#/webtv/automotornews/vod/422492b6-539e-474d-9c6b-68c9d5893365',
50 'only_matching': True,
51 }, {
52 'url': 'https://platform.wim.tv/#/webtv/renzoarborechannel/cast/f47e0d15-5b45-455e-bf0d-dba8ffa96365',
53 'only_matching': True,
54 }]
55
56 def _real_initialize(self):
57 if not self._player:
58 self._get_player_data()
59
60 def _get_player_data(self):
61 msg_id = 'Player data'
62 self._player = {}
63
64 datas = [{
65 'url': 'https://platform.wim.tv/common/libs/player/wimtv/wim-rest.js',
66 'vars': [{
67 'regex': r'appAuth = "(.+?)"',
68 'variable': 'app_auth',
69 }]
70 }, {
71 'url': 'https://platform.wim.tv/common/config/endpointconfig.js',
72 'vars': [{
73 'regex': r'PRODUCTION_HOSTNAME_THUMB = "(.+?)"',
74 'variable': 'thumb_server',
75 }, {
76 'regex': r'PRODUCTION_HOSTNAME_THUMB\s*\+\s*"(.+?)"',
77 'variable': 'thumb_server_path',
78 }]
79 }]
80
81 for data in datas:
82 temp = self._download_webpage(data['url'], msg_id)
83 for var in data['vars']:
84 val = self._search_regex(var['regex'], temp, msg_id)
85 if not val:
86 raise ExtractorError('%s not found' % var['variable'])
87 self._player[var['variable']] = val
88
89 def _generate_token(self):
90 json = self._download_json(
91 'https://platform.wim.tv/wimtv-server/oauth/token', 'Token generation',
92 headers={'Authorization': 'Basic %s' % self._player['app_auth']},
93 data=urlencode_postdata({'grant_type': 'client_credentials'}))
94 token = json.get('access_token')
95 if not token:
96 raise ExtractorError('access token not generated')
97 return token
98
99 def _generate_thumbnail(self, thumb_id, width='720'):
100 if not thumb_id or not self._player.get('thumb_server'):
101 return None
102 if not self._player.get('thumb_server_path'):
103 self._player['thumb_server_path'] = ''
104 return '%s%s/asset/thumbnail/%s/%s' % (
105 self._player['thumb_server'],
106 self._player['thumb_server_path'],
107 thumb_id, width)
108
109 def _real_extract(self, url):
110 urlc = self._match_valid_url(url).groupdict()
111 video_id = urlc['id']
112 stream_type = is_live = None
113 if urlc['type'] in {'live', 'cast'}:
114 stream_type = urlc['type'] + '/channel'
115 is_live = True
116 else:
117 stream_type = 'vod'
118 is_live = False
119 token = self._generate_token()
120 json = self._download_json(
121 'https://platform.wim.tv/wimtv-server/api/public/%s/%s/play' % (
122 stream_type, video_id), video_id,
123 headers={'Authorization': 'Bearer %s' % token,
124 'Content-Type': 'application/json'},
125 data=bytes('{}', 'utf-8'))
126
127 formats = []
128 for src in json.get('srcs') or []:
129 if src.get('mimeType') == 'application/x-mpegurl':
130 formats.extend(
131 self._extract_m3u8_formats(
132 src.get('uniqueStreamer'), video_id, 'mp4'))
133 if src.get('mimeType') == 'video/flash':
134 formats.append({
135 'format_id': 'rtmp',
136 'url': src.get('uniqueStreamer'),
137 'ext': determine_ext(src.get('uniqueStreamer'), 'flv'),
138 'rtmp_live': is_live,
139 })
140 json = json.get('resource')
141 thumb = self._generate_thumbnail(json.get('thumbnailId'))
142
143 return {
144 'id': video_id,
145 'title': json.get('title') or json.get('name'),
146 'duration': parse_duration(json.get('duration')),
147 'formats': formats,
148 'thumbnail': thumb,
149 'is_live': is_live,
150 }