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.

146 lines
5.8 KiB

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