ninecninemedia.py (3772B)
1 # coding: utf-8 2 from __future__ import unicode_literals 3 4 import re 5 6 from .common import InfoExtractor 7 from ..utils import ( 8 ExtractorError, 9 float_or_none, 10 int_or_none, 11 parse_iso8601, 12 try_get, 13 ) 14 15 16 class NineCNineMediaIE(InfoExtractor): 17 IE_NAME = '9c9media' 18 _GEO_COUNTRIES = ['CA'] 19 _VALID_URL = r'9c9media:(?P<destination_code>[^:]+):(?P<id>\d+)' 20 _API_BASE_TEMPLATE = 'http://capi.9c9media.com/destinations/%s/platforms/desktop/contents/%s/' 21 22 def _real_extract(self, url): 23 destination_code, content_id = re.match(self._VALID_URL, url).groups() 24 api_base_url = self._API_BASE_TEMPLATE % (destination_code, content_id) 25 content = self._download_json(api_base_url, content_id, query={ 26 '$include': '[Media.Name,Season,ContentPackages.Duration,ContentPackages.Id]', 27 }) 28 title = content['Name'] 29 content_package = content['ContentPackages'][0] 30 package_id = content_package['Id'] 31 content_package_url = api_base_url + 'contentpackages/%s/' % package_id 32 content_package = self._download_json( 33 content_package_url, content_id, query={ 34 '$include': '[HasClosedCaptions]', 35 }) 36 37 if try_get(content_package, lambda x: x['Constraints']['Security']['Type']): 38 raise ExtractorError('This video is DRM protected.', expected=True) 39 40 manifest_base_url = content_package_url + 'manifest.' 41 formats = [] 42 formats.extend(self._extract_m3u8_formats( 43 manifest_base_url + 'm3u8', content_id, 'mp4', 44 'm3u8_native', m3u8_id='hls', fatal=False)) 45 formats.extend(self._extract_f4m_formats( 46 manifest_base_url + 'f4m', content_id, 47 f4m_id='hds', fatal=False)) 48 formats.extend(self._extract_mpd_formats( 49 manifest_base_url + 'mpd', content_id, 50 mpd_id='dash', fatal=False)) 51 self._sort_formats(formats) 52 53 thumbnails = [] 54 for image in (content.get('Images') or []): 55 image_url = image.get('Url') 56 if not image_url: 57 continue 58 thumbnails.append({ 59 'url': image_url, 60 'width': int_or_none(image.get('Width')), 61 'height': int_or_none(image.get('Height')), 62 }) 63 64 tags, categories = [], [] 65 for source_name, container in (('Tags', tags), ('Genres', categories)): 66 for e in content.get(source_name, []): 67 e_name = e.get('Name') 68 if not e_name: 69 continue 70 container.append(e_name) 71 72 season = content.get('Season') or {} 73 74 info = { 75 'id': content_id, 76 'title': title, 77 'description': content.get('Desc') or content.get('ShortDesc'), 78 'timestamp': parse_iso8601(content.get('BroadcastDateTime')), 79 'episode_number': int_or_none(content.get('Episode')), 80 'season': season.get('Name'), 81 'season_number': int_or_none(season.get('Number')), 82 'season_id': season.get('Id'), 83 'series': try_get(content, lambda x: x['Media']['Name']), 84 'tags': tags, 85 'categories': categories, 86 'duration': float_or_none(content_package.get('Duration')), 87 'formats': formats, 88 'thumbnails': thumbnails, 89 } 90 91 if content_package.get('HasClosedCaptions'): 92 info['subtitles'] = { 93 'en': [{ 94 'url': manifest_base_url + 'vtt', 95 'ext': 'vtt', 96 }, { 97 'url': manifest_base_url + 'srt', 98 'ext': 'srt', 99 }] 100 } 101 102 return info