hitbox.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. import re
  4. from .common import InfoExtractor
  5. from ..utils import (
  6. clean_html,
  7. parse_iso8601,
  8. float_or_none,
  9. int_or_none,
  10. compat_str,
  11. determine_ext,
  12. )
  13. class HitboxIE(InfoExtractor):
  14. IE_NAME = 'hitbox'
  15. _VALID_URL = r'https?://(?:www\.)?hitbox\.tv/video/(?P<id>[0-9]+)'
  16. _TEST = {
  17. 'url': 'http://www.hitbox.tv/video/203213',
  18. 'info_dict': {
  19. 'id': '203213',
  20. 'title': 'hitbox @ gamescom, Sub Button Hype extended, Giveaway - hitbox News Update with Oxy',
  21. 'alt_title': 'hitboxlive - Aug 9th #6',
  22. 'description': '',
  23. 'ext': 'mp4',
  24. 'thumbnail': 're:^https?://.*\.jpg$',
  25. 'duration': 215.1666,
  26. 'resolution': 'HD 720p',
  27. 'uploader': 'hitboxlive',
  28. 'view_count': int,
  29. 'timestamp': 1407576133,
  30. 'upload_date': '20140809',
  31. 'categories': ['Live Show'],
  32. },
  33. 'params': {
  34. # m3u8 download
  35. 'skip_download': True,
  36. },
  37. }
  38. def _extract_metadata(self, url, video_id):
  39. thumb_base = 'https://edge.sf.hitbox.tv'
  40. metadata = self._download_json(
  41. '%s/%s' % (url, video_id), video_id)
  42. date = 'media_live_since'
  43. media_type = 'livestream'
  44. if metadata.get('media_type') == 'video':
  45. media_type = 'video'
  46. date = 'media_date_added'
  47. video_meta = metadata.get(media_type, [])[0]
  48. title = video_meta.get('media_status')
  49. alt_title = video_meta.get('media_title')
  50. description = clean_html(
  51. video_meta.get('media_description') or
  52. video_meta.get('media_description_md'))
  53. duration = float_or_none(video_meta.get('media_duration'))
  54. uploader = video_meta.get('media_user_name')
  55. views = int_or_none(video_meta.get('media_views'))
  56. timestamp = parse_iso8601(video_meta.get(date), ' ')
  57. categories = [video_meta.get('category_name')]
  58. thumbs = [
  59. {'url': thumb_base + video_meta.get('media_thumbnail'),
  60. 'width': 320,
  61. 'height': 180},
  62. {'url': thumb_base + video_meta.get('media_thumbnail_large'),
  63. 'width': 768,
  64. 'height': 432},
  65. ]
  66. return {
  67. 'id': video_id,
  68. 'title': title,
  69. 'alt_title': alt_title,
  70. 'description': description,
  71. 'ext': 'mp4',
  72. 'thumbnails': thumbs,
  73. 'duration': duration,
  74. 'uploader': uploader,
  75. 'view_count': views,
  76. 'timestamp': timestamp,
  77. 'categories': categories,
  78. }
  79. def _real_extract(self, url):
  80. video_id = self._match_id(url)
  81. metadata = self._extract_metadata(
  82. 'https://www.hitbox.tv/api/media/video',
  83. video_id)
  84. player_config = self._download_json(
  85. 'https://www.hitbox.tv/api/player/config/video/%s' % video_id,
  86. video_id)
  87. formats = []
  88. for video in player_config['clip']['bitrates']:
  89. label = video.get('label')
  90. if label == 'Auto':
  91. continue
  92. video_url = video.get('url')
  93. if not video_url:
  94. continue
  95. bitrate = int_or_none(video.get('bitrate'))
  96. if determine_ext(video_url) == 'm3u8':
  97. if not video_url.startswith('http'):
  98. continue
  99. formats.append({
  100. 'url': video_url,
  101. 'ext': 'mp4',
  102. 'tbr': bitrate,
  103. 'format_note': label,
  104. 'protocol': 'm3u8_native',
  105. })
  106. else:
  107. formats.append({
  108. 'url': video_url,
  109. 'tbr': bitrate,
  110. 'format_note': label,
  111. })
  112. metadata['formats'] = formats
  113. return metadata
  114. class HitboxLiveIE(HitboxIE):
  115. IE_NAME = 'hitbox:live'
  116. _VALID_URL = r'https?://(?:www\.)?hitbox\.tv/(?!video)(?P<id>.+)'
  117. _TEST = {
  118. 'url': 'http://www.hitbox.tv/dimak',
  119. 'info_dict': {
  120. 'id': 'dimak',
  121. 'ext': 'mp4',
  122. 'description': 'md5:c9f80fa4410bc588d7faa40003fc7d0e',
  123. 'timestamp': int,
  124. 'upload_date': compat_str,
  125. 'title': compat_str,
  126. 'uploader': 'Dimak',
  127. },
  128. 'params': {
  129. # live
  130. 'skip_download': True,
  131. },
  132. }
  133. def _real_extract(self, url):
  134. video_id = self._match_id(url)
  135. metadata = self._extract_metadata(
  136. 'https://www.hitbox.tv/api/media/live',
  137. video_id)
  138. player_config = self._download_json(
  139. 'https://www.hitbox.tv/api/player/config/live/%s' % video_id,
  140. video_id)
  141. formats = []
  142. cdns = player_config.get('cdns')
  143. servers = []
  144. for cdn in cdns:
  145. base_url = cdn.get('netConnectionUrl')
  146. host = re.search('.+\.([^\.]+\.[^\./]+)/.+', base_url).group(1)
  147. if base_url not in servers:
  148. servers.append(base_url)
  149. for stream in cdn.get('bitrates'):
  150. label = stream.get('label')
  151. if label == 'Auto':
  152. continue
  153. stream_url = stream.get('url')
  154. if not stream_url:
  155. continue
  156. bitrate = int_or_none(stream.get('bitrate'))
  157. if stream.get('provider') == 'hls' or determine_ext(stream_url) == 'm3u8':
  158. if not stream_url.startswith('http'):
  159. continue
  160. formats.append({
  161. 'url': stream_url,
  162. 'ext': 'mp4',
  163. 'tbr': bitrate,
  164. 'format_note': label,
  165. 'rtmp_live': True,
  166. })
  167. else:
  168. formats.append({
  169. 'url': '%s/%s' % (base_url, stream_url),
  170. 'ext': 'mp4',
  171. 'tbr': bitrate,
  172. 'rtmp_live': True,
  173. 'format_note': host,
  174. 'page_url': url,
  175. 'player_url': 'http://www.hitbox.tv/static/player/flowplayer/flowplayer.commercial-3.2.16.swf',
  176. })
  177. self._sort_formats(formats)
  178. metadata['formats'] = formats
  179. metadata['is_live'] = True
  180. metadata['title'] = self._live_title(metadata.get('title'))
  181. return metadata