hidive.py (4113B)
1 # coding: utf-8 2 from __future__ import unicode_literals 3 4 import re 5 6 from .common import InfoExtractor 7 from ..compat import compat_str 8 from ..utils import ( 9 ExtractorError, 10 int_or_none, 11 url_or_none, 12 urlencode_postdata, 13 ) 14 15 16 class HiDiveIE(InfoExtractor): 17 _VALID_URL = r'https?://(?:www\.)?hidive\.com/stream/(?P<title>[^/]+)/(?P<key>[^/?#&]+)' 18 # Using X-Forwarded-For results in 403 HTTP error for HLS fragments, 19 # so disabling geo bypass completely 20 _GEO_BYPASS = False 21 _NETRC_MACHINE = 'hidive' 22 _LOGIN_URL = 'https://www.hidive.com/account/login' 23 24 _TESTS = [{ 25 'url': 'https://www.hidive.com/stream/the-comic-artist-and-his-assistants/s01e001', 26 'info_dict': { 27 'id': 'the-comic-artist-and-his-assistants/s01e001', 28 'ext': 'mp4', 29 'title': 'the-comic-artist-and-his-assistants/s01e001', 30 'series': 'the-comic-artist-and-his-assistants', 31 'season_number': 1, 32 'episode_number': 1, 33 }, 34 'params': { 35 'skip_download': True, 36 }, 37 'skip': 'Requires Authentication', 38 }] 39 40 def _real_initialize(self): 41 email, password = self._get_login_info() 42 if email is None: 43 return 44 45 webpage = self._download_webpage(self._LOGIN_URL, None) 46 form = self._search_regex( 47 r'(?s)<form[^>]+action="/account/login"[^>]*>(.+?)</form>', 48 webpage, 'login form') 49 data = self._hidden_inputs(form) 50 data.update({ 51 'Email': email, 52 'Password': password, 53 }) 54 self._download_webpage( 55 self._LOGIN_URL, None, 'Logging in', data=urlencode_postdata(data)) 56 57 def _real_extract(self, url): 58 mobj = re.match(self._VALID_URL, url) 59 title, key = mobj.group('title', 'key') 60 video_id = '%s/%s' % (title, key) 61 62 settings = self._download_json( 63 'https://www.hidive.com/play/settings', video_id, 64 data=urlencode_postdata({ 65 'Title': title, 66 'Key': key, 67 'PlayerId': 'f4f895ce1ca713ba263b91caeb1daa2d08904783', 68 })) 69 70 restriction = settings.get('restrictionReason') 71 if restriction == 'RegionRestricted': 72 self.raise_geo_restricted() 73 74 if restriction and restriction != 'None': 75 raise ExtractorError( 76 '%s said: %s' % (self.IE_NAME, restriction), expected=True) 77 78 formats = [] 79 subtitles = {} 80 for rendition_id, rendition in settings['renditions'].items(): 81 bitrates = rendition.get('bitrates') 82 if not isinstance(bitrates, dict): 83 continue 84 m3u8_url = url_or_none(bitrates.get('hls')) 85 if not m3u8_url: 86 continue 87 formats.extend(self._extract_m3u8_formats( 88 m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native', 89 m3u8_id='%s-hls' % rendition_id, fatal=False)) 90 cc_files = rendition.get('ccFiles') 91 if not isinstance(cc_files, list): 92 continue 93 for cc_file in cc_files: 94 if not isinstance(cc_file, list) or len(cc_file) < 3: 95 continue 96 cc_lang = cc_file[0] 97 cc_url = url_or_none(cc_file[2]) 98 if not isinstance(cc_lang, compat_str) or not cc_url: 99 continue 100 subtitles.setdefault(cc_lang, []).append({ 101 'url': cc_url, 102 }) 103 self._sort_formats(formats) 104 105 season_number = int_or_none(self._search_regex( 106 r's(\d+)', key, 'season number', default=None)) 107 episode_number = int_or_none(self._search_regex( 108 r'e(\d+)', key, 'episode number', default=None)) 109 110 return { 111 'id': video_id, 112 'title': video_id, 113 'subtitles': subtitles, 114 'formats': formats, 115 'series': title, 116 'season_number': season_number, 117 'episode_number': episode_number, 118 }