watchbox.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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'playerConf\s*=\s*({.+?})\s*;', webpage, 'player config',
  66. default='{}'),
  67. video_id, transform_source=js_to_json,
  68. fatal=False) or {}).get('source') or {}
  69. video_id = compat_str(source.get('videoId') or video_id)
  70. devapi = self._download_json(
  71. 'http://api.watchbox.de/devapi/id/%s' % video_id, video_id, query={
  72. 'format': 'json',
  73. 'apikey': 'hbbtv',
  74. }, fatal=False)
  75. item = try_get(devapi, lambda x: x['items'][0], dict) or {}
  76. title = item.get('title') or try_get(
  77. item, lambda x: x['movie']['headline_movie'],
  78. compat_str) or source['title']
  79. formats = []
  80. hls_url = item.get('media_videourl_hls') or source.get('hls')
  81. if hls_url:
  82. formats.extend(self._extract_m3u8_formats(
  83. hls_url, video_id, 'mp4', entry_protocol='m3u8_native',
  84. m3u8_id='hls', fatal=False))
  85. dash_url = item.get('media_videourl_wv') or source.get('dash')
  86. if dash_url:
  87. formats.extend(self._extract_mpd_formats(
  88. dash_url, video_id, mpd_id='dash', fatal=False))
  89. mp4_url = item.get('media_videourl')
  90. if mp4_url:
  91. formats.append({
  92. 'url': mp4_url,
  93. 'format_id': 'mp4',
  94. 'width': int_or_none(item.get('width')),
  95. 'height': int_or_none(item.get('height')),
  96. 'tbr': int_or_none(item.get('bitrate')),
  97. })
  98. self._sort_formats(formats)
  99. description = strip_or_none(item.get('descr'))
  100. thumbnail = item.get('media_content_thumbnail_large') or source.get('poster') or item.get('media_thumbnail')
  101. duration = int_or_none(item.get('media_length') or source.get('length'))
  102. timestamp = unified_timestamp(item.get('pubDate'))
  103. view_count = int_or_none(item.get('media_views'))
  104. age_limit = int_or_none(try_get(item, lambda x: x['movie']['fsk']))
  105. release_year = int_or_none(try_get(item, lambda x: x['movie']['rel_year']))
  106. info = {
  107. 'id': video_id,
  108. 'title': title,
  109. 'description': description,
  110. 'thumbnail': thumbnail,
  111. 'duration': duration,
  112. 'timestamp': timestamp,
  113. 'view_count': view_count,
  114. 'age_limit': age_limit,
  115. 'release_year': release_year,
  116. 'formats': formats,
  117. }
  118. if kind.lower() == 'serien':
  119. series = try_get(
  120. item, lambda x: x['special']['title'],
  121. compat_str) or source.get('format')
  122. season_number = int_or_none(self._search_regex(
  123. r'^S(\d{1,2})\s*E\d{1,2}', title, 'season number',
  124. default=None) or self._search_regex(
  125. r'/staffel-(\d+)/', url, 'season number', default=None))
  126. episode = source.get('title')
  127. episode_number = int_or_none(self._search_regex(
  128. r'^S\d{1,2}\s*E(\d{1,2})', title, 'episode number',
  129. default=None))
  130. info.update({
  131. 'series': series,
  132. 'season_number': season_number,
  133. 'episode': episode,
  134. 'episode_number': episode_number,
  135. })
  136. return info