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.

151 lines
5.4 KiB

  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. from .common import InfoExtractor
  5. from ..compat import compat_str
  6. from ..utils import (
  7. int_or_none,
  8. js_to_json,
  9. strip_or_none,
  10. try_get,
  11. unified_timestamp,
  12. )
  13. class WatchBoxIE(InfoExtractor):
  14. _VALID_URL = r'https?://(?:www\.)?watchbox\.de/(?P<kind>serien|filme)/(?:[^/]+/)*[^/]+-(?P<id>\d+)'
  15. _TESTS = [{
  16. # film
  17. 'url': 'https://www.watchbox.de/filme/free-jimmy-12325.html',
  18. 'info_dict': {
  19. 'id': '341368',
  20. 'ext': 'mp4',
  21. 'title': 'Free Jimmy',
  22. 'description': 'md5:bcd8bafbbf9dc0ef98063d344d7cc5f6',
  23. 'thumbnail': r're:^https?://.*\.jpg$',
  24. 'duration': 4890,
  25. 'age_limit': 16,
  26. 'release_year': 2009,
  27. },
  28. 'params': {
  29. 'format': 'bestvideo',
  30. 'skip_download': True,
  31. },
  32. 'expected_warnings': ['Failed to download m3u8 information'],
  33. }, {
  34. # episode
  35. 'url': 'https://www.watchbox.de/serien/ugly-americans-12231/staffel-1/date-in-der-hoelle-328286.html',
  36. 'info_dict': {
  37. 'id': '328286',
  38. 'ext': 'mp4',
  39. 'title': 'S01 E01 - Date in der Hölle',
  40. 'description': 'md5:2f31c74a8186899f33cb5114491dae2b',
  41. 'thumbnail': r're:^https?://.*\.jpg$',
  42. 'duration': 1291,
  43. 'age_limit': 12,
  44. 'release_year': 2010,
  45. 'series': 'Ugly Americans',
  46. 'season_number': 1,
  47. 'episode': 'Date in der Hölle',
  48. 'episode_number': 1,
  49. },
  50. 'params': {
  51. 'format': 'bestvideo',
  52. 'skip_download': True,
  53. },
  54. 'expected_warnings': ['Failed to download m3u8 information'],
  55. }, {
  56. 'url': 'https://www.watchbox.de/serien/ugly-americans-12231/staffel-2/der-ring-des-powers-328270',
  57. 'only_matching': True,
  58. }]
  59. def _real_extract(self, url):
  60. mobj = re.match(self._VALID_URL, url)
  61. kind, video_id = mobj.group('kind', 'id')
  62. webpage = self._download_webpage(url, video_id)
  63. source = self._parse_json(
  64. self._search_regex(
  65. r'(?s)source\s*:\s*({.+?})\s*,\s*\n', webpage, 'source',
  66. default='{}'),
  67. video_id, transform_source=js_to_json, fatal=False) or {}
  68. video_id = compat_str(source.get('videoId') or video_id)
  69. devapi = self._download_json(
  70. 'http://api.watchbox.de/devapi/id/%s' % video_id, video_id, query={
  71. 'format': 'json',
  72. 'apikey': 'hbbtv',
  73. }, fatal=False)
  74. item = try_get(devapi, lambda x: x['items'][0], dict) or {}
  75. title = item.get('title') or try_get(
  76. item, lambda x: x['movie']['headline_movie'],
  77. compat_str) or source['title']
  78. formats = []
  79. hls_url = item.get('media_videourl_hls') or source.get('hls')
  80. if hls_url:
  81. formats.extend(self._extract_m3u8_formats(
  82. hls_url, video_id, 'mp4', entry_protocol='m3u8_native',
  83. m3u8_id='hls', fatal=False))
  84. dash_url = item.get('media_videourl_wv') or source.get('dash')
  85. if dash_url:
  86. formats.extend(self._extract_mpd_formats(
  87. dash_url, video_id, mpd_id='dash', fatal=False))
  88. mp4_url = item.get('media_videourl')
  89. if mp4_url:
  90. formats.append({
  91. 'url': mp4_url,
  92. 'format_id': 'mp4',
  93. 'width': int_or_none(item.get('width')),
  94. 'height': int_or_none(item.get('height')),
  95. 'tbr': int_or_none(item.get('bitrate')),
  96. })
  97. self._sort_formats(formats)
  98. description = strip_or_none(item.get('descr'))
  99. thumbnail = item.get('media_content_thumbnail_large') or source.get('poster') or item.get('media_thumbnail')
  100. duration = int_or_none(item.get('media_length') or source.get('length'))
  101. timestamp = unified_timestamp(item.get('pubDate'))
  102. view_count = int_or_none(item.get('media_views'))
  103. age_limit = int_or_none(try_get(item, lambda x: x['movie']['fsk']))
  104. release_year = int_or_none(try_get(item, lambda x: x['movie']['rel_year']))
  105. info = {
  106. 'id': video_id,
  107. 'title': title,
  108. 'description': description,
  109. 'thumbnail': thumbnail,
  110. 'duration': duration,
  111. 'timestamp': timestamp,
  112. 'view_count': view_count,
  113. 'age_limit': age_limit,
  114. 'release_year': release_year,
  115. 'formats': formats,
  116. }
  117. if kind.lower() == 'serien':
  118. series = try_get(
  119. item, lambda x: x['special']['title'],
  120. compat_str) or source.get('format')
  121. season_number = int_or_none(self._search_regex(
  122. r'^S(\d{1,2})\s*E\d{1,2}', title, 'season number',
  123. default=None) or self._search_regex(
  124. r'/staffel-(\d+)/', url, 'season number', default=None))
  125. episode = source.get('title')
  126. episode_number = int_or_none(self._search_regex(
  127. r'^S\d{1,2}\s*E(\d{1,2})', title, 'episode number',
  128. default=None))
  129. info.update({
  130. 'series': series,
  131. 'season_number': season_number,
  132. 'episode': episode,
  133. 'episode_number': episode_number,
  134. })
  135. return info