telequebec.py 8.7 KB

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