You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
5.8 KiB

12 years ago
  1. import re
  2. import json
  3. import xml.etree.ElementTree
  4. from .common import InfoExtractor
  5. from ..utils import (
  6. ExtractorError,
  7. unified_strdate,
  8. )
  9. class ArteTvIE(InfoExtractor):
  10. """
  11. There are two sources of video in arte.tv: videos.arte.tv and
  12. www.arte.tv/guide, the extraction process is different for each one.
  13. The videos expire in 7 days, so we can't add tests.
  14. """
  15. _EMISSION_URL = r'(?:http://)?www\.arte.tv/guide/(?P<lang>fr|de)/(?:(?:sendungen|emissions)/)?(?P<id>.*?)/(?P<name>.*?)(\?.*)?'
  16. _VIDEOS_URL = r'(?:http://)?videos.arte.tv/(?P<lang>fr|de)/.*-(?P<id>.*?).html'
  17. _LIVE_URL = r'index-[0-9]+\.html$'
  18. IE_NAME = u'arte.tv'
  19. @classmethod
  20. def suitable(cls, url):
  21. return any(re.match(regex, url) for regex in (cls._EMISSION_URL, cls._VIDEOS_URL))
  22. # TODO implement Live Stream
  23. # from ..utils import compat_urllib_parse
  24. # def extractLiveStream(self, url):
  25. # video_lang = url.split('/')[-4]
  26. # info = self.grep_webpage(
  27. # url,
  28. # r'src="(.*?/videothek_js.*?\.js)',
  29. # 0,
  30. # [
  31. # (1, 'url', u'Invalid URL: %s' % url)
  32. # ]
  33. # )
  34. # http_host = url.split('/')[2]
  35. # next_url = 'http://%s%s' % (http_host, compat_urllib_parse.unquote(info.get('url')))
  36. # info = self.grep_webpage(
  37. # next_url,
  38. # r'(s_artestras_scst_geoFRDE_' + video_lang + '.*?)\'.*?' +
  39. # '(http://.*?\.swf).*?' +
  40. # '(rtmp://.*?)\'',
  41. # re.DOTALL,
  42. # [
  43. # (1, 'path', u'could not extract video path: %s' % url),
  44. # (2, 'player', u'could not extract video player: %s' % url),
  45. # (3, 'url', u'could not extract video url: %s' % url)
  46. # ]
  47. # )
  48. # video_url = u'%s/%s' % (info.get('url'), info.get('path'))
  49. def _real_extract(self, url):
  50. mobj = re.match(self._EMISSION_URL, url)
  51. if mobj is not None:
  52. lang = mobj.group('lang')
  53. # This is not a real id, it can be for example AJT for the news
  54. # http://www.arte.tv/guide/fr/emissions/AJT/arte-journal
  55. video_id = mobj.group('id')
  56. return self._extract_emission(url, video_id, lang)
  57. mobj = re.match(self._VIDEOS_URL, url)
  58. if mobj is not None:
  59. id = mobj.group('id')
  60. lang = mobj.group('lang')
  61. return self._extract_video(url, id, lang)
  62. if re.search(self._LIVE_URL, video_id) is not None:
  63. raise ExtractorError(u'Arte live streams are not yet supported, sorry')
  64. # self.extractLiveStream(url)
  65. # return
  66. def _extract_emission(self, url, video_id, lang):
  67. """Extract from www.arte.tv/guide"""
  68. webpage = self._download_webpage(url, video_id)
  69. json_url = self._html_search_regex(r'arte_vp_url="(.*?)"', webpage, 'json url')
  70. json_info = self._download_webpage(json_url, video_id, 'Downloading info json')
  71. self.report_extraction(video_id)
  72. info = json.loads(json_info)
  73. player_info = info['videoJsonPlayer']
  74. info_dict = {'id': player_info['VID'],
  75. 'title': player_info['VTI'],
  76. 'description': player_info['VDE'],
  77. 'upload_date': unified_strdate(player_info['VDA'].split(' ')[0]),
  78. 'thumbnail': player_info['programImage'],
  79. 'ext': 'flv',
  80. }
  81. formats = player_info['VSR'].values()
  82. def _match_lang(f):
  83. # Return true if that format is in the language of the url
  84. if lang == 'fr':
  85. l = 'F'
  86. elif lang == 'de':
  87. l = 'A'
  88. regexes = [r'VO?%s' % l, r'V%s-ST.' % l]
  89. return any(re.match(r, f['versionCode']) for r in regexes)
  90. # Some formats may not be in the same language as the url
  91. formats = filter(_match_lang, formats)
  92. # We order the formats by quality
  93. formats = sorted(formats, key=lambda f: int(f['height']))
  94. # Pick the best quality
  95. format_info = formats[-1]
  96. if format_info['mediaType'] == u'rtmp':
  97. info_dict['url'] = format_info['streamer']
  98. info_dict['play_path'] = 'mp4:' + format_info['url']
  99. else:
  100. info_dict['url'] = format_info['url']
  101. return info_dict
  102. def _extract_video(self, url, video_id, lang):
  103. """Extract from videos.arte.tv"""
  104. ref_xml_url = url.replace('/videos/', '/do_delegate/videos/')
  105. ref_xml_url = ref_xml_url.replace('.html', ',view,asPlayerXml.xml')
  106. ref_xml = self._download_webpage(ref_xml_url, video_id, note=u'Downloading metadata')
  107. ref_xml_doc = xml.etree.ElementTree.fromstring(ref_xml)
  108. config_node = ref_xml_doc.find('.//video[@lang="%s"]' % lang)
  109. config_xml_url = config_node.attrib['ref']
  110. config_xml = self._download_webpage(config_xml_url, video_id, note=u'Downloading configuration')
  111. video_urls = list(re.finditer(r'<url quality="(?P<quality>.*?)">(?P<url>.*?)</url>', config_xml))
  112. def _key(m):
  113. quality = m.group('quality')
  114. if quality == 'hd':
  115. return 2
  116. else:
  117. return 1
  118. # We pick the best quality
  119. video_urls = sorted(video_urls, key=_key)
  120. video_url = list(video_urls)[-1].group('url')
  121. title = self._html_search_regex(r'<name>(.*?)</name>', config_xml, 'title')
  122. thumbnail = self._html_search_regex(r'<firstThumbnailUrl>(.*?)</firstThumbnailUrl>',
  123. config_xml, 'thumbnail')
  124. return {'id': video_id,
  125. 'title': title,
  126. 'thumbnail': thumbnail,
  127. 'url': video_url,
  128. 'ext': 'flv',
  129. }