telequebec.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. from .common import InfoExtractor
  4. from ..compat import compat_str
  5. from ..utils import (
  6. int_or_none,
  7. smuggle_url,
  8. try_get,
  9. unified_timestamp,
  10. )
  11. class TeleQuebecBaseIE(InfoExtractor):
  12. @staticmethod
  13. def _result(url, ie_key):
  14. return {
  15. '_type': 'url_transparent',
  16. 'url': smuggle_url(url, {'geo_countries': ['CA']}),
  17. 'ie_key': ie_key,
  18. }
  19. @staticmethod
  20. def _limelight_result(media_id):
  21. return TeleQuebecBaseIE._result(
  22. 'limelight:media:' + media_id, 'LimelightMedia')
  23. @staticmethod
  24. def _brightcove_result(brightcove_id):
  25. return TeleQuebecBaseIE._result(
  26. 'http://players.brightcove.net/6150020952001/default_default/index.html?videoId=%s'
  27. % brightcove_id, 'BrightcoveNew')
  28. class TeleQuebecIE(TeleQuebecBaseIE):
  29. _VALID_URL = r'''(?x)
  30. https?://
  31. (?:
  32. zonevideo\.telequebec\.tv/media|
  33. coucou\.telequebec\.tv/videos
  34. )/(?P<id>\d+)
  35. '''
  36. _TESTS = [{
  37. # available till 01.01.2023
  38. 'url': 'http://zonevideo.telequebec.tv/media/37578/un-petit-choc-et-puis-repart/un-chef-a-la-cabane',
  39. 'info_dict': {
  40. 'id': '577116881b4b439084e6b1cf4ef8b1b3',
  41. 'ext': 'mp4',
  42. 'title': 'Un petit choc et puis repart!',
  43. 'description': 'md5:067bc84bd6afecad85e69d1000730907',
  44. },
  45. 'params': {
  46. 'skip_download': True,
  47. },
  48. }, {
  49. 'url': 'https://zonevideo.telequebec.tv/media/55267/le-soleil/passe-partout',
  50. 'info_dict': {
  51. 'id': '6167180337001',
  52. 'ext': 'mp4',
  53. 'title': 'Le soleil',
  54. 'description': 'md5:64289c922a8de2abbe99c354daffde02',
  55. 'uploader_id': '6150020952001',
  56. 'upload_date': '20200625',
  57. 'timestamp': 1593090307,
  58. },
  59. 'params': {
  60. 'format': 'bestvideo',
  61. 'skip_download': True,
  62. },
  63. 'add_ie': ['BrightcoveNew'],
  64. }, {
  65. # no description
  66. 'url': 'http://zonevideo.telequebec.tv/media/30261',
  67. 'only_matching': True,
  68. }, {
  69. 'url': 'https://coucou.telequebec.tv/videos/41788/idee-de-genie/l-heure-du-bain',
  70. 'only_matching': True,
  71. }]
  72. def _real_extract(self, url):
  73. media_id = self._match_id(url)
  74. media_data = self._download_json(
  75. 'https://mnmedias.api.telequebec.tv/api/v2/media/' + media_id,
  76. media_id)['media']
  77. source_id = media_data['streamInfo']['sourceId']
  78. source = (try_get(
  79. media_data, lambda x: x['streamInfo']['source'],
  80. compat_str) or 'limelight').lower()
  81. if source == 'brightcove':
  82. info = self._brightcove_result(source_id)
  83. else:
  84. info = self._limelight_result(source_id)
  85. info.update({
  86. 'title': media_data.get('title'),
  87. 'description': try_get(
  88. media_data, lambda x: x['descriptions'][0]['text'], compat_str),
  89. 'duration': int_or_none(
  90. media_data.get('durationInMilliseconds'), 1000),
  91. })
  92. return info
  93. class TeleQuebecSquatIE(InfoExtractor):
  94. _VALID_URL = r'https://squat\.telequebec\.tv/videos/(?P<id>\d+)'
  95. _TESTS = [{
  96. 'url': 'https://squat.telequebec.tv/videos/9314',
  97. 'info_dict': {
  98. 'id': 'd59ae78112d542e793d83cc9d3a5b530',
  99. 'ext': 'mp4',
  100. 'title': 'Poupeflekta',
  101. 'description': 'md5:2f0718f8d2f8fece1646ee25fb7bce75',
  102. 'duration': 1351,
  103. 'timestamp': 1569057600,
  104. 'upload_date': '20190921',
  105. 'series': 'Miraculous : Les Aventures de Ladybug et Chat Noir',
  106. 'season': 'Saison 3',
  107. 'season_number': 3,
  108. 'episode_number': 57,
  109. },
  110. 'params': {
  111. 'skip_download': True,
  112. },
  113. }]
  114. def _real_extract(self, url):
  115. video_id = self._match_id(url)
  116. video = self._download_json(
  117. 'https://squat.api.telequebec.tv/v1/videos/%s' % video_id,
  118. video_id)
  119. media_id = video['sourceId']
  120. return {
  121. '_type': 'url_transparent',
  122. 'url': 'http://zonevideo.telequebec.tv/media/%s' % media_id,
  123. 'ie_key': TeleQuebecIE.ie_key(),
  124. 'id': media_id,
  125. 'title': video.get('titre'),
  126. 'description': video.get('description'),
  127. 'timestamp': unified_timestamp(video.get('datePublication')),
  128. 'series': video.get('container'),
  129. 'season': video.get('saison'),
  130. 'season_number': int_or_none(video.get('noSaison')),
  131. 'episode_number': int_or_none(video.get('episode')),
  132. }
  133. class TeleQuebecEmissionIE(TeleQuebecBaseIE):
  134. _VALID_URL = r'''(?x)
  135. https?://
  136. (?:
  137. [^/]+\.telequebec\.tv/emissions/|
  138. (?:www\.)?telequebec\.tv/
  139. )
  140. (?P<id>[^?#&]+)
  141. '''
  142. _TESTS = [{
  143. 'url': 'http://lindicemcsween.telequebec.tv/emissions/100430013/des-soins-esthetiques-a-377-d-interets-annuels-ca-vous-tente',
  144. 'info_dict': {
  145. 'id': '66648a6aef914fe3badda25e81a4d50a',
  146. 'ext': 'mp4',
  147. 'title': "Des soins esthétiques à 377 % d'intérêts annuels, ça vous tente?",
  148. 'description': 'md5:369e0d55d0083f1fc9b71ffb640ea014',
  149. 'upload_date': '20171024',
  150. 'timestamp': 1508862118,
  151. },
  152. 'params': {
  153. 'skip_download': True,
  154. },
  155. }, {
  156. 'url': 'http://bancpublic.telequebec.tv/emissions/emission-49/31986/jeunes-meres-sous-pression',
  157. 'only_matching': True,
  158. }, {
  159. 'url': 'http://www.telequebec.tv/masha-et-michka/epi059masha-et-michka-3-053-078',
  160. 'only_matching': True,
  161. }, {
  162. 'url': 'http://www.telequebec.tv/documentaire/bebes-sur-mesure/',
  163. 'only_matching': True,
  164. }]
  165. def _real_extract(self, url):
  166. display_id = self._match_id(url)
  167. webpage = self._download_webpage(url, display_id)
  168. media_id = self._search_regex(
  169. r'mediaUID\s*:\s*["\'][Ll]imelight_(?P<id>[a-z0-9]{32})', webpage,
  170. 'limelight id')
  171. info = self._limelight_result(media_id)
  172. info.update({
  173. 'title': self._og_search_title(webpage, default=None),
  174. 'description': self._og_search_description(webpage, default=None),
  175. })
  176. return info
  177. class TeleQuebecLiveIE(InfoExtractor):
  178. _VALID_URL = r'https?://zonevideo\.telequebec\.tv/(?P<id>endirect)'
  179. _TEST = {
  180. 'url': 'http://zonevideo.telequebec.tv/endirect/',
  181. 'info_dict': {
  182. 'id': 'endirect',
  183. 'ext': 'mp4',
  184. 'title': 're:^Télé-Québec - En direct [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$',
  185. 'is_live': True,
  186. },
  187. 'params': {
  188. 'skip_download': True,
  189. },
  190. }
  191. def _real_extract(self, url):
  192. video_id = self._match_id(url)
  193. m3u8_url = None
  194. webpage = self._download_webpage(
  195. 'https://player.telequebec.tv/Tq_VideoPlayer.js', video_id,
  196. fatal=False)
  197. if webpage:
  198. m3u8_url = self._search_regex(
  199. r'm3U8Url\s*:\s*(["\'])(?P<url>(?:(?!\1).)+)\1', webpage,
  200. 'm3u8 url', default=None, group='url')
  201. if not m3u8_url:
  202. m3u8_url = 'https://teleqmmd.mmdlive.lldns.net/teleqmmd/f386e3b206814e1f8c8c1c71c0f8e748/manifest.m3u8'
  203. formats = self._extract_m3u8_formats(
  204. m3u8_url, video_id, 'mp4', m3u8_id='hls')
  205. self._sort_formats(formats)
  206. return {
  207. 'id': video_id,
  208. 'title': self._live_title('Télé-Québec - En direct'),
  209. 'is_live': True,
  210. 'formats': formats,
  211. }