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