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.

134 lines
5.1 KiB

  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. from .common import InfoExtractor
  5. from ..compat import compat_HTTPError
  6. from ..utils import (
  7. dict_get,
  8. ExtractorError,
  9. int_or_none,
  10. js_to_json,
  11. parse_iso8601,
  12. )
  13. class ZypeIE(InfoExtractor):
  14. _ID_RE = r'[\da-fA-F]+'
  15. _COMMON_RE = r'//player\.zype\.com/embed/%s\.(?:js|json|html)\?.*?(?:access_token|(?:ap[ip]|player)_key)='
  16. _VALID_URL = r'https?:%s[^&]+' % (_COMMON_RE % ('(?P<id>%s)' % _ID_RE))
  17. _TEST = {
  18. 'url': 'https://player.zype.com/embed/5b400b834b32992a310622b9.js?api_key=jZ9GUhRmxcPvX7M3SlfejB6Hle9jyHTdk2jVxG7wOHPLODgncEKVdPYBhuz9iWXQ&autoplay=false&controls=true&da=false',
  19. 'md5': 'eaee31d474c76a955bdaba02a505c595',
  20. 'info_dict': {
  21. 'id': '5b400b834b32992a310622b9',
  22. 'ext': 'mp4',
  23. 'title': 'Smoky Barbecue Favorites',
  24. 'thumbnail': r're:^https?://.*\.jpe?g',
  25. 'description': 'md5:5ff01e76316bd8d46508af26dc86023b',
  26. 'timestamp': 1504915200,
  27. 'upload_date': '20170909',
  28. },
  29. }
  30. @staticmethod
  31. def _extract_urls(webpage):
  32. return [
  33. mobj.group('url')
  34. for mobj in re.finditer(
  35. r'<script[^>]+\bsrc=(["\'])(?P<url>(?:https?:)?%s.+?)\1' % (ZypeIE._COMMON_RE % ZypeIE._ID_RE),
  36. webpage)]
  37. def _real_extract(self, url):
  38. video_id = self._match_id(url)
  39. try:
  40. response = self._download_json(re.sub(
  41. r'\.(?:js|html)\?', '.json?', url), video_id)['response']
  42. except ExtractorError as e:
  43. if isinstance(e.cause, compat_HTTPError) and e.cause.code in (400, 401, 403):
  44. raise ExtractorError(self._parse_json(
  45. e.cause.read().decode(), video_id)['message'], expected=True)
  46. raise
  47. body = response['body']
  48. video = response['video']
  49. title = video['title']
  50. if isinstance(body, dict):
  51. formats = []
  52. for output in body.get('outputs', []):
  53. output_url = output.get('url')
  54. if not output_url:
  55. continue
  56. name = output.get('name')
  57. if name == 'm3u8':
  58. formats = self._extract_m3u8_formats(
  59. output_url, video_id, 'mp4',
  60. 'm3u8_native', m3u8_id='hls', fatal=False)
  61. else:
  62. f = {
  63. 'format_id': name,
  64. 'tbr': int_or_none(output.get('bitrate')),
  65. 'url': output_url,
  66. }
  67. if name in ('m4a', 'mp3'):
  68. f['vcodec'] = 'none'
  69. else:
  70. f.update({
  71. 'height': int_or_none(output.get('height')),
  72. 'width': int_or_none(output.get('width')),
  73. })
  74. formats.append(f)
  75. text_tracks = body.get('subtitles') or []
  76. else:
  77. m3u8_url = self._search_regex(
  78. r'(["\'])(?P<url>(?:(?!\1).)+\.m3u8(?:(?!\1).)*)\1',
  79. body, 'm3u8 url', group='url')
  80. formats = self._extract_m3u8_formats(
  81. m3u8_url, video_id, 'mp4', 'm3u8_native', m3u8_id='hls')
  82. text_tracks = self._search_regex(
  83. r'textTracks\s*:\s*(\[[^]]+\])',
  84. body, 'text tracks', default=None)
  85. if text_tracks:
  86. text_tracks = self._parse_json(
  87. text_tracks, video_id, js_to_json, False)
  88. self._sort_formats(formats)
  89. subtitles = {}
  90. if text_tracks:
  91. for text_track in text_tracks:
  92. tt_url = dict_get(text_track, ('file', 'src'))
  93. if not tt_url:
  94. continue
  95. subtitles.setdefault(text_track.get('label') or 'English', []).append({
  96. 'url': tt_url,
  97. })
  98. thumbnails = []
  99. for thumbnail in video.get('thumbnails', []):
  100. thumbnail_url = thumbnail.get('url')
  101. if not thumbnail_url:
  102. continue
  103. thumbnails.append({
  104. 'url': thumbnail_url,
  105. 'width': int_or_none(thumbnail.get('width')),
  106. 'height': int_or_none(thumbnail.get('height')),
  107. })
  108. return {
  109. 'id': video_id,
  110. 'display_id': video.get('friendly_title'),
  111. 'title': title,
  112. 'thumbnails': thumbnails,
  113. 'description': dict_get(video, ('description', 'ott_description', 'short_description')),
  114. 'timestamp': parse_iso8601(video.get('published_at')),
  115. 'duration': int_or_none(video.get('duration')),
  116. 'view_count': int_or_none(video.get('request_count')),
  117. 'average_rating': int_or_none(video.get('rating')),
  118. 'season_number': int_or_none(video.get('season')),
  119. 'episode_number': int_or_none(video.get('episode')),
  120. 'formats': formats,
  121. 'subtitles': subtitles,
  122. }