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.

178 lines
5.9 KiB

  1. # coding: utf-8
  2. from __future__ import unicode_literals
  3. from .common import InfoExtractor
  4. from ..compat import (
  5. compat_str,
  6. compat_HTTPError,
  7. )
  8. from ..utils import (
  9. qualities,
  10. strip_or_none,
  11. int_or_none,
  12. ExtractorError,
  13. )
  14. class FilmOnIE(InfoExtractor):
  15. IE_NAME = 'filmon'
  16. _VALID_URL = r'(?:https?://(?:www\.)?filmon\.com/vod/view/|filmon:)(?P<id>\d+)'
  17. _TESTS = [{
  18. 'url': 'https://www.filmon.com/vod/view/24869-0-plan-9-from-outer-space',
  19. 'info_dict': {
  20. 'id': '24869',
  21. 'ext': 'mp4',
  22. 'title': 'Plan 9 From Outer Space',
  23. 'description': 'Dead human, zombies and vampires',
  24. },
  25. }, {
  26. 'url': 'https://www.filmon.com/vod/view/2825-1-popeye-series-1',
  27. 'info_dict': {
  28. 'id': '2825',
  29. 'title': 'Popeye Series 1',
  30. 'description': 'The original series of Popeye.',
  31. },
  32. 'playlist_mincount': 8,
  33. }]
  34. def _real_extract(self, url):
  35. video_id = self._match_id(url)
  36. try:
  37. response = self._download_json(
  38. 'https://www.filmon.com/api/vod/movie?id=%s' % video_id,
  39. video_id)['response']
  40. except ExtractorError as e:
  41. if isinstance(e.cause, compat_HTTPError):
  42. errmsg = self._parse_json(e.cause.read().decode(), video_id)['reason']
  43. raise ExtractorError('%s said: %s' % (self.IE_NAME, errmsg), expected=True)
  44. raise
  45. title = response['title']
  46. description = strip_or_none(response.get('description'))
  47. if response.get('type_id') == 1:
  48. entries = [self.url_result('filmon:' + episode_id) for episode_id in response.get('episodes', [])]
  49. return self.playlist_result(entries, video_id, title, description)
  50. QUALITY = qualities(('low', 'high'))
  51. formats = []
  52. for format_id, stream in response.get('streams', {}).items():
  53. stream_url = stream.get('url')
  54. if not stream_url:
  55. continue
  56. formats.append({
  57. 'format_id': format_id,
  58. 'url': stream_url,
  59. 'ext': 'mp4',
  60. 'quality': QUALITY(stream.get('quality')),
  61. 'protocol': 'm3u8_native',
  62. })
  63. self._sort_formats(formats)
  64. thumbnails = []
  65. poster = response.get('poster', {})
  66. thumbs = poster.get('thumbs', {})
  67. thumbs['poster'] = poster
  68. for thumb_id, thumb in thumbs.items():
  69. thumb_url = thumb.get('url')
  70. if not thumb_url:
  71. continue
  72. thumbnails.append({
  73. 'id': thumb_id,
  74. 'url': thumb_url,
  75. 'width': int_or_none(thumb.get('width')),
  76. 'height': int_or_none(thumb.get('height')),
  77. })
  78. return {
  79. 'id': video_id,
  80. 'title': title,
  81. 'formats': formats,
  82. 'description': description,
  83. 'thumbnails': thumbnails,
  84. }
  85. class FilmOnChannelIE(InfoExtractor):
  86. IE_NAME = 'filmon:channel'
  87. _VALID_URL = r'https?://(?:www\.)?filmon\.com/(?:tv|channel)/(?P<id>[a-z0-9-]+)'
  88. _TESTS = [{
  89. # VOD
  90. 'url': 'http://www.filmon.com/tv/sports-haters',
  91. 'info_dict': {
  92. 'id': '4190',
  93. 'ext': 'mp4',
  94. 'title': 'Sports Haters',
  95. 'description': 'md5:dabcb4c1d9cfc77085612f1a85f8275d',
  96. },
  97. }, {
  98. # LIVE
  99. 'url': 'https://www.filmon.com/channel/filmon-sports',
  100. 'only_matching': True,
  101. }, {
  102. 'url': 'https://www.filmon.com/tv/2894',
  103. 'only_matching': True,
  104. }]
  105. _THUMBNAIL_RES = [
  106. ('logo', 56, 28),
  107. ('big_logo', 106, 106),
  108. ('extra_big_logo', 300, 300),
  109. ]
  110. def _real_extract(self, url):
  111. channel_id = self._match_id(url)
  112. try:
  113. channel_data = self._download_json(
  114. 'http://www.filmon.com/api-v2/channel/' + channel_id, channel_id)['data']
  115. except ExtractorError as e:
  116. if isinstance(e.cause, compat_HTTPError):
  117. errmsg = self._parse_json(e.cause.read().decode(), channel_id)['message']
  118. raise ExtractorError('%s said: %s' % (self.IE_NAME, errmsg), expected=True)
  119. raise
  120. channel_id = compat_str(channel_data['id'])
  121. is_live = not channel_data.get('is_vod') and not channel_data.get('is_vox')
  122. title = channel_data['title']
  123. QUALITY = qualities(('low', 'high'))
  124. formats = []
  125. for stream in channel_data.get('streams', []):
  126. stream_url = stream.get('url')
  127. if not stream_url:
  128. continue
  129. if not is_live:
  130. formats.extend(self._extract_wowza_formats(
  131. stream_url, channel_id, skip_protocols=['dash', 'rtmp', 'rtsp']))
  132. continue
  133. quality = stream.get('quality')
  134. formats.append({
  135. 'format_id': quality,
  136. # this is an m3u8 stream, but we are deliberately not using _extract_m3u8_formats
  137. # because it doesn't have bitrate variants anyway
  138. 'url': stream_url,
  139. 'ext': 'mp4',
  140. 'quality': QUALITY(quality),
  141. })
  142. self._sort_formats(formats)
  143. thumbnails = []
  144. for name, width, height in self._THUMBNAIL_RES:
  145. thumbnails.append({
  146. 'id': name,
  147. 'url': 'http://static.filmon.com/assets/channels/%s/%s.png' % (channel_id, name),
  148. 'width': width,
  149. 'height': height,
  150. })
  151. return {
  152. 'id': channel_id,
  153. 'display_id': channel_data.get('alias'),
  154. 'title': self._live_title(title) if is_live else title,
  155. 'description': channel_data.get('description'),
  156. 'thumbnails': thumbnails,
  157. 'formats': formats,
  158. 'is_live': is_live,
  159. }