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