]>
Commit | Line | Data |
---|---|---|
1 | from .common import InfoExtractor | |
2 | from ..utils import ( | |
3 | int_or_none, | |
4 | smuggle_url, | |
5 | try_get, | |
6 | unified_timestamp, | |
7 | ) | |
8 | ||
9 | ||
10 | class TeleQuebecBaseIE(InfoExtractor): | |
11 | BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/%s/%s_default/index.html?videoId=%s' | |
12 | ||
13 | @staticmethod | |
14 | def _brightcove_result(brightcove_id, player_id, account_id='6150020952001'): | |
15 | return { | |
16 | '_type': 'url_transparent', | |
17 | 'url': smuggle_url(TeleQuebecBaseIE.BRIGHTCOVE_URL_TEMPLATE % (account_id, player_id, brightcove_id), {'geo_countries': ['CA']}), | |
18 | 'ie_key': 'BrightcoveNew', | |
19 | } | |
20 | ||
21 | ||
22 | class TeleQuebecIE(TeleQuebecBaseIE): | |
23 | _VALID_URL = r'''(?x) | |
24 | https?:// | |
25 | (?: | |
26 | zonevideo\.telequebec\.tv/media| | |
27 | coucou\.telequebec\.tv/videos | |
28 | )/(?P<id>\d+) | |
29 | ''' | |
30 | _TESTS = [{ | |
31 | # available till 01.01.2023 | |
32 | 'url': 'http://zonevideo.telequebec.tv/media/37578/un-petit-choc-et-puis-repart/un-chef-a-la-cabane', | |
33 | 'info_dict': { | |
34 | 'id': '6155972771001', | |
35 | 'ext': 'mp4', | |
36 | 'title': 'Un petit choc et puis repart!', | |
37 | 'description': 'md5:b04a7e6b3f74e32d7b294cffe8658374', | |
38 | 'timestamp': 1589262469, | |
39 | 'uploader_id': '6150020952001', | |
40 | 'upload_date': '20200512', | |
41 | }, | |
42 | 'add_ie': ['BrightcoveNew'], | |
43 | }, { | |
44 | 'url': 'https://zonevideo.telequebec.tv/media/55267/le-soleil/passe-partout', | |
45 | 'info_dict': { | |
46 | 'id': '6167180337001', | |
47 | 'ext': 'mp4', | |
48 | 'title': 'Le soleil', | |
49 | 'description': 'md5:64289c922a8de2abbe99c354daffde02', | |
50 | 'uploader_id': '6150020952001', | |
51 | 'upload_date': '20200625', | |
52 | 'timestamp': 1593090307, | |
53 | }, | |
54 | 'add_ie': ['BrightcoveNew'], | |
55 | }, { | |
56 | # no description | |
57 | 'url': 'http://zonevideo.telequebec.tv/media/30261', | |
58 | 'only_matching': True, | |
59 | }, { | |
60 | 'url': 'https://coucou.telequebec.tv/videos/41788/idee-de-genie/l-heure-du-bain', | |
61 | 'only_matching': True, | |
62 | }] | |
63 | ||
64 | def _real_extract(self, url): | |
65 | media_id = self._match_id(url) | |
66 | media = self._download_json( | |
67 | 'https://mnmedias.api.telequebec.tv/api/v3/media/' + media_id, | |
68 | media_id)['media'] | |
69 | source_id = next(source_info['sourceId'] for source_info in media['streamInfos'] if source_info.get('source') == 'Brightcove') | |
70 | info = self._brightcove_result(source_id, '22gPKdt7f') | |
71 | product = media.get('product') or {} | |
72 | season = product.get('season') or {} | |
73 | info.update({ | |
74 | 'description': try_get(media, lambda x: x['descriptions'][-1]['text'], str), | |
75 | 'series': try_get(season, lambda x: x['serie']['titre']), | |
76 | 'season': season.get('name'), | |
77 | 'season_number': int_or_none(season.get('seasonNo')), | |
78 | 'episode': product.get('titre'), | |
79 | 'episode_number': int_or_none(product.get('episodeNo')), | |
80 | }) | |
81 | return info | |
82 | ||
83 | ||
84 | class TeleQuebecSquatIE(InfoExtractor): | |
85 | _VALID_URL = r'https?://squat\.telequebec\.tv/videos/(?P<id>\d+)' | |
86 | _TESTS = [{ | |
87 | 'url': 'https://squat.telequebec.tv/videos/9314', | |
88 | 'info_dict': { | |
89 | 'id': 'd59ae78112d542e793d83cc9d3a5b530', | |
90 | 'ext': 'mp4', | |
91 | 'title': 'Poupeflekta', | |
92 | 'description': 'md5:2f0718f8d2f8fece1646ee25fb7bce75', | |
93 | 'duration': 1351, | |
94 | 'timestamp': 1569057600, | |
95 | 'upload_date': '20190921', | |
96 | 'series': 'Miraculous : Les Aventures de Ladybug et Chat Noir', | |
97 | 'season': 'Saison 3', | |
98 | 'season_number': 3, | |
99 | 'episode_number': 57, | |
100 | }, | |
101 | 'params': { | |
102 | 'skip_download': True, | |
103 | }, | |
104 | }] | |
105 | ||
106 | def _real_extract(self, url): | |
107 | video_id = self._match_id(url) | |
108 | ||
109 | video = self._download_json( | |
110 | f'https://squat.api.telequebec.tv/v1/videos/{video_id}', | |
111 | video_id) | |
112 | ||
113 | media_id = video['sourceId'] | |
114 | ||
115 | return { | |
116 | '_type': 'url_transparent', | |
117 | 'url': f'http://zonevideo.telequebec.tv/media/{media_id}', | |
118 | 'ie_key': TeleQuebecIE.ie_key(), | |
119 | 'id': media_id, | |
120 | 'title': video.get('titre'), | |
121 | 'description': video.get('description'), | |
122 | 'timestamp': unified_timestamp(video.get('datePublication')), | |
123 | 'series': video.get('container'), | |
124 | 'season': video.get('saison'), | |
125 | 'season_number': int_or_none(video.get('noSaison')), | |
126 | 'episode_number': int_or_none(video.get('episode')), | |
127 | } | |
128 | ||
129 | ||
130 | class TeleQuebecEmissionIE(InfoExtractor): | |
131 | _VALID_URL = r'''(?x) | |
132 | https?:// | |
133 | (?: | |
134 | [^/]+\.telequebec\.tv/emissions/| | |
135 | (?:www\.)?telequebec\.tv/ | |
136 | ) | |
137 | (?P<id>[^?#&]+) | |
138 | ''' | |
139 | _TESTS = [{ | |
140 | 'url': 'http://lindicemcsween.telequebec.tv/emissions/100430013/des-soins-esthetiques-a-377-d-interets-annuels-ca-vous-tente', | |
141 | 'info_dict': { | |
142 | 'id': '6154476028001', | |
143 | 'ext': 'mp4', | |
144 | 'title': 'Des soins esthétiques à 377 % d’intérêts annuels, ça vous tente?', | |
145 | 'description': 'md5:cb4d378e073fae6cce1f87c00f84ae9f', | |
146 | 'upload_date': '20200505', | |
147 | 'timestamp': 1588713424, | |
148 | 'uploader_id': '6150020952001', | |
149 | }, | |
150 | }, { | |
151 | 'url': 'http://bancpublic.telequebec.tv/emissions/emission-49/31986/jeunes-meres-sous-pression', | |
152 | 'only_matching': True, | |
153 | }, { | |
154 | 'url': 'http://www.telequebec.tv/masha-et-michka/epi059masha-et-michka-3-053-078', | |
155 | 'only_matching': True, | |
156 | }, { | |
157 | 'url': 'http://www.telequebec.tv/documentaire/bebes-sur-mesure/', | |
158 | 'only_matching': True, | |
159 | }] | |
160 | ||
161 | def _real_extract(self, url): | |
162 | display_id = self._match_id(url) | |
163 | ||
164 | webpage = self._download_webpage(url, display_id) | |
165 | ||
166 | media_id = self._search_regex( | |
167 | r'mediaId\s*:\s*(?P<id>\d+)', webpage, 'media id') | |
168 | ||
169 | return self.url_result( | |
170 | 'http://zonevideo.telequebec.tv/media/' + media_id, | |
171 | TeleQuebecIE.ie_key()) | |
172 | ||
173 | ||
174 | class TeleQuebecLiveIE(TeleQuebecBaseIE): | |
175 | _VALID_URL = r'https?://zonevideo\.telequebec\.tv/(?P<id>endirect)' | |
176 | _TEST = { | |
177 | 'url': 'http://zonevideo.telequebec.tv/endirect/', | |
178 | 'info_dict': { | |
179 | 'id': '6159095684001', | |
180 | 'ext': 'mp4', | |
181 | 'title': 're:^Télé-Québec [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$', | |
182 | 'is_live': True, | |
183 | 'description': 'Canal principal de Télé-Québec', | |
184 | 'uploader_id': '6150020952001', | |
185 | 'timestamp': 1590439901, | |
186 | 'upload_date': '20200525', | |
187 | }, | |
188 | 'params': { | |
189 | 'skip_download': True, | |
190 | }, | |
191 | } | |
192 | ||
193 | def _real_extract(self, url): | |
194 | return self._brightcove_result('6159095684001', 'skCsmi2Uw') | |
195 | ||
196 | ||
197 | class TeleQuebecVideoIE(TeleQuebecBaseIE): | |
198 | _VALID_URL = r'https?://video\.telequebec\.tv/player(?:-live)?/(?P<id>\d+)' | |
199 | _TESTS = [{ | |
200 | 'url': 'https://video.telequebec.tv/player/31110/stream', | |
201 | 'info_dict': { | |
202 | 'id': '6202570652001', | |
203 | 'ext': 'mp4', | |
204 | 'title': 'Le coût du véhicule le plus vendu au Canada / Tous les frais liés à la procréation assistée', | |
205 | 'description': 'md5:685a7e4c450ba777c60adb6e71e41526', | |
206 | 'upload_date': '20201019', | |
207 | 'timestamp': 1603115930, | |
208 | 'uploader_id': '6101674910001', | |
209 | }, | |
210 | }, { | |
211 | 'url': 'https://video.telequebec.tv/player-live/28527', | |
212 | 'only_matching': True, | |
213 | }] | |
214 | ||
215 | def _call_api(self, path, video_id): | |
216 | return self._download_json( | |
217 | 'http://beacon.playback.api.brightcove.com/telequebec/api/assets/' + path, | |
218 | video_id, query={'device_layout': 'web', 'device_type': 'web'})['data'] | |
219 | ||
220 | def _real_extract(self, url): | |
221 | asset_id = self._match_id(url) | |
222 | asset = self._call_api(asset_id, asset_id)['asset'] | |
223 | stream = self._call_api( | |
224 | asset_id + '/streams/' + asset['streams'][0]['id'], asset_id)['stream'] | |
225 | stream_url = stream['url'] | |
226 | account_id = try_get( | |
227 | stream, lambda x: x['video_provider_details']['account_id']) or '6101674910001' | |
228 | info = self._brightcove_result(stream_url, 'default', account_id) | |
229 | info.update({ | |
230 | 'description': asset.get('long_description') or asset.get('short_description'), | |
231 | 'series': asset.get('series_original_name'), | |
232 | 'season_number': int_or_none(asset.get('season_number')), | |
233 | 'episode': asset.get('original_name'), | |
234 | 'episode_number': int_or_none(asset.get('episode_number')), | |
235 | }) | |
236 | return info |