def _get_streams(self): res = self.session.http.get(self.url) m = self._playback_re.search(res.text) if m: hls_url = m.group(0) if is_py3: hls_url = bytes(unquote_plus(hls_url), "utf-8").decode("unicode_escape") else: hls_url = unquote_plus(hls_url).decode("unicode_escape") else: if self._livestream_re.search(res.text) is not None: raise PluginError('Stream is offline') m = self._username_re.search(res.text) if m: hls_url = "https://live.prd.dlive.tv/hls/live/{}.m3u8".format( m.group(0)) else: raise PluginError('Could not find username') return HLSStream.parse_variant_playlist(self.session, hls_url)
def _get_streams(self): stream_info = self._get_stream_info() log.debug("Live stream info: {}".format(stream_info)) if not stream_info["movie"]["live"]: raise PluginError("The live stream is offline") # Keys are already validated by schema above proto = stream_info["fmp4"]["proto"] host = stream_info["fmp4"]["host"] movie_id = stream_info["movie"]["id"] if stream_info["fmp4"]["source"]: mode = "main" # High quality elif stream_info["fmp4"]["mobilesource"]: mode = "mobilesource" # Medium quality else: mode = "base" # Low quality if (proto == '') or (host == '') or (not movie_id): raise PluginError("No stream available for user {}".format( self.channel)) real_stream_url = self._STREAM_REAL_URL.format(proto=proto, host=host, movie_id=movie_id, mode=mode) log.debug("Real stream url: {}".format(real_stream_url)) return { mode: TwitCastingStream(session=self.session, url=real_stream_url) }
def _get_token(self, path): res = self.session.http.get(self.url) m = self.app_id_js_url_re.search(res.text) app_id_js_url = m and m.group(1) if not app_id_js_url: raise PluginError("Could not determine app_id_js_url") log.debug("app_id_js_url={0}".format(app_id_js_url)) res = self.session.http.get(app_id_js_url) m = self.app_id_re.search(res.text) app_id = m and m.group(1) if not app_id: raise PluginError("Could not determine app_id") log.debug("app_id={0}".format(app_id)) res = self.session.http.get(self.token_url, params=dict( format='json', appId=app_id, path=path, )) token_data = self.session.http.json(res, schema=self._token_schema) if 'error' in token_data: raise PluginError(token_data['error']['message']) return token_data['token']
def _get_streams(self): url_type = self.match.group(1) log.debug("URL type={0}".format(url_type)) res = self.session.http.get(self.url) if url_type != "live": m = self.video_name_re.search(res.text) video_name = m and m.group(1) if not video_name: raise PluginError('Could not determine video_name') log.debug("Video name={0}".format(video_name)) m = self.main_js_url_re.search(res.text) main_js_path = m and m.group(1) if not main_js_path: raise PluginError('Could not determine main_js_path') log.debug("Main JS path={0}".format(main_js_path)) res = self.session.http.get(urljoin(self.url, main_js_path)) m = self.user_id_re.search(res.text) user_id = m and m.group(1) if not user_id: raise PluginError('Could not determine user_id') log.debug("User ID={0}".format(user_id)) if url_type == "live": return self._get_live(user_id) else: return self._get_vod(user_id, video_name)
def _get_vod(self, user_id, video_name): res = self.session.http.get(urljoin(self.api_url, "getVideoByFileName"), params=dict(userId=user_id, videoName=video_name, serverType="web", callback="x")) vod_data = self.session.http.json(res, schema=self.vod_schema) if video_name == vod_data['ShowTitle']: host, base_path = self.server_addr_re.search( vod_data['ServerAddress']).groups() if not host or not base_path: raise PluginError("Could not split 'ServerAddress' components") base_file, file_ext = self.media_file_re.search( vod_data['MediaFile']).groups() if not base_file or not file_ext: raise PluginError("Could not split 'MediaFile' components") media_path = "{0}{1}{2}{3}{4}{5}".format( base_path, vod_data['MediaRoot'], base_file, vod_data['Bitrates'], file_ext, vod_data['StreamingType']) log.debug("Media path={0}".format(media_path)) vod_url = urlunparse((vod_data['ProtocolType'], host, media_path, '', vod_data['Token'], '')) log.debug("URL={0}".format(vod_url)) return HLSStream.parse_variant_playlist(self.session, vod_url)
def _get_streams(self): if _stream_url_re.match(self.url): mode = MODE_STREAM else: mode = MODE_VOD res = http.get(self.url) match = _json_re.search(res.text) if match: data = json.loads(_json_re.search(res.text).group('json')) else: raise PluginError("Could not extract JSON metadata") streams = {} try: if mode == MODE_STREAM: sources = data['values']['episode'][ 'livestream_playlist_data']['videos'][0]['sources'] elif mode == MODE_VOD: sources = data['values']['segment']['playlist_item_array'][ 'sources'] except (KeyError, IndexError): raise PluginError("Could not extract sources") for source in sources: try: if source['delivery'] != 'hls': continue url = source['src'].replace('\/', '/') except KeyError: continue stream = HLSStream.parse_variant_playlist(self.session, url) streams.update(stream) return streams
def _authenticate(self, email, password): csrf_token = http.get(LOGIN_PAGE_URL, schema=_csrf_token_schema) if not csrf_token: raise PluginError("Unable to find CSRF token") data = { "authenticity_token": csrf_token, "channel_id": "", "commit": "Login", "plan_id": "", "session[email]": email, "session[password]": password, "utf8": "\xE2\x9C\x93", # Check Mark Character } res = http.post(LOGIN_POST_URL, data=data, acceptable_status=(200, 422)) result = http.json(res, schema=_login_schema) errors = result.get("errors") if errors: errors = ", ".join(errors) raise PluginError("Unable to authenticate: {0}".format(errors)) self.logger.info("Successfully logged in as {0}", result["email"])
def _get_streams(self): url_type, show_name, episode_name = self.match.groups() if url_type == 'streams' and not show_name: url_type = 'live-stream' elif not show_name: raise PluginError("Missing show_name for url_type: {0}".format( url_type, )) log.debug("URL type={0}".format(url_type)) if url_type == 'live-stream': video_id = self._get_stream_data(url_type) elif url_type == 'streams': video_id = self._get_stream_data(show_name) elif url_type == 'videos': if show_name is None or episode_name is None: raise PluginError( "Missing show_name or episode_name for url_type: {0}".format( url_type, ) ) video_id = self._get_video_data(episode_name) else: raise PluginError("Unrecognised url_type: {0}".format(url_type)) if video_id is None: raise PluginError("Could not find video_id") log.debug("Video ID={0}".format(video_id)) res = self.session.http.get(self.video_data_url.format(video_id)) url_data = self.session.http.json(res, schema=self._api_schema) if 'unprotected' in url_data: url = url_data['unprotected']['url'] elif 'bulkaes' in url_data: url_parsed = urlparse(url_data['bulkaes']['url']) token = self._get_token(url_parsed.path) url = urlunparse(( url_parsed.scheme, url_parsed.netloc, url_parsed.path, url_parsed.params, "{0}={1}".format('hdnts', token), url_parsed.fragment, )) else: raise PluginError("Could not find a usable URL in url_data") log.debug("URL={0}".format(url)) return HLSStream.parse_variant_playlist(self.session, url)
def _get_streams(self): match = _url_re.match(self.url) channel_name = match.group("channel") form = { "cid": channel_name, "watchTime": 0, "firstConnect": 1, "ip": "NaN" } res = http.post(API_URL, data=form, headers=HEADERS) params = parse_query(res.text, schema=_schema) if params["status"] <= 0: return if params["block_type"] != 0: if params["block_type"] == BLOCK_TYPE_VIEWING_LIMIT: msg = BLOCKED_MSG_FORMAT.format( params.get("block_time", "UNKNOWN"), params.get("reconnect_time", "UNKNOWN")) raise PluginError(msg) elif params["block_type"] == BLOCK_TYPE_NO_SLOTS: raise PluginError("No free slots available") else: raise PluginError("Blocked for unknown reasons") if "token" not in params: raise PluginError("Server seems busy, retry again later") streams = {} stream_names = ["sd"] if params["multibitrate"]: stream_names += ["hd"] for stream_name in stream_names: playpath = params["playpath"] if stream_name == "hd": playpath += "HI" stream = RTMPStream( self.session, { "rtmp": "{0}/{1}".format(params["rtmp"], playpath), "pageUrl": self.url, "swfVfy": SWF_URL, "weeb": params["token"], "live": True }) streams[stream_name] = stream return streams
def _get_streams(self): self.session.http.headers.update({ 'Referer': 'http://www.abweb.com/BIS-TV-Online/bistvo-tele-universal.aspx' }) login_username = self.get_option('username') login_password = self.get_option('password') if self.options.get('purge_credentials'): self.clear_cookies() self._authed = False log.info('All credentials were successfully removed.') if self._authed: log.info('Attempting to authenticate using cached cookies') elif not self._authed and not (login_username and login_password): log.error( 'A login for ABweb is required, use --abweb-username USERNAME --abweb-password PASSWORD' ) return elif not self._authed and not self._login(login_username, login_password): return log.debug('get iframe_url') res = self.session.http.get(self.url) for iframe in itertags(res.text, 'iframe'): iframe_url = iframe.attributes.get('src') if iframe_url.startswith('/'): iframe_url = url_concat('https://www.abweb.com', iframe_url) else: iframe_url = update_scheme('https://', iframe_url) log.debug(f'iframe_url={iframe_url}') break else: raise PluginError('No iframe_url found.') self.session.http.headers.update({'Referer': iframe_url}) res = self.session.http.get(iframe_url) m = self._hls_re.search(res.text) if not m: raise PluginError('No hls_url found.') hls_url = update_scheme('https://', m.group('url')) streams = HLSStream.parse_variant_playlist(self.session, hls_url) if streams: yield from streams.items() else: yield 'live', HLSStream(self.session, hls_url)
def _find_video_id(self, url): m = _url_re.match(url) if m.group("video_id"): log.debug("Video ID from URL") return m.group("video_id") res = self.session.http.get(url) datam = _ytdata_re.search(res.text) if datam: data = parse_json(datam.group(1)) # find the videoRenderer object, where there is a LVE NOW badge for vid_ep in search_dict(data, 'currentVideoEndpoint'): video_id = vid_ep.get("watchEndpoint", {}).get("videoId") if video_id: log.debug("Video ID from currentVideoEndpoint") return video_id for x in search_dict(data, 'videoRenderer'): for bstyle in search_dict(x.get("badges", {}), "style"): if bstyle == "BADGE_STYLE_TYPE_LIVE_NOW": if x.get("videoId"): log.debug("Video ID from videoRenderer (live)") return x["videoId"] raise PluginError("Could not find a video on this page")
def _get_streams(self): if not self.login(self.get_option("email"), self.get_option("password")): raise PluginError("Login failed") try: start_point = int( float( dict(parse_qsl(urlparse(self.url).query)).get( "startPoint", 0.0))) if start_point > 0: log.info("Stream will start at {0}".format( seconds_to_hhmmss(start_point))) except ValueError: start_point = 0 content_id = self._get_video_id() if content_id: log.debug("Found content ID: {0}".format(content_id)) info = self._get_media_info(content_id) if info.get("hlsUrl"): yield from HLSStream.parse_variant_playlist( self.session, info["hlsUrl"], start_offset=start_point).items() else: log.error("Could not find the HLS URL")
def _get_stream_info(self, video_id, pl_id): info = None log.debug("Starting YoutubeDL process") try: ytdl = YoutubeDL(self.ytdl_options) url = "https://www.youtube.com/watch?v=%s" % video_id info = ytdl.extract_info(url, ie_key="Youtube", download=False, process=True) ua = info["formats"][-1]["http_headers"]["User-Agent"] self.session.http.headers.update({"User-Agent": ua}) pl_path = self.get_option("playlist-dir") if pl_id and pl_path: if not os.path.isdir(pl_path): os.makedirs(pl_path) log.debug( "Playlist directory '{0}' created".format(pl_path)) url = "https://www.youtube.com/playlist?list=%s" % pl_id _info = ytdl.extract_info(url, ie_key="YoutubePlaylist", download=False, process=True) self._save2M3U(pl_path, _info, ua) except Exception as e: raise PluginError(e) return info
def get_token(self): """ Get the token for USTVNow :return: a valid token """ if not self._token: log.debug("Getting new session token") res = self.session.http.get(self._token_url, params={ "tenant_code": self.TENANT_CODE, "box_id": self.box_id, "product": self.TENANT_CODE, "device_id": 5, "display_lang_code": "ENG", "device_sub_type": "", "timezone": "UTC" }) data = res.json() if data['status']: self._token = data['response']['sessionId'] log.debug("New token: {}".format(self._token)) else: log.error( "Token acquisition failed: {details} ({detail})".format( **data['error'])) raise PluginError("could not obtain token") return self._token
def _login(self, username, password): log.debug('Attempting to login.') data = {} for i in itertags(self.session.http.get(self.url_l).text, 'input'): data[i.attributes.get('name')] = i.attributes.get('value', '') if not data: raise PluginError('Missing input data on login website.') data.update({ 'ctl00$ContentPlaceHolder1$Login1$UserName': username, 'ctl00$ContentPlaceHolder1$Login1$Password': password, 'ctl00$ContentPlaceHolder1$Login1$LoginButton.x': '0', 'ctl00$ContentPlaceHolder1$Login1$LoginButton.y': '0', 'ctl00$ContentPlaceHolder1$Login1$RememberMe': 'on', }) self.session.http.post(self.url_l, data=data) if (self.session.http.cookies.get('ASP.NET_SessionId') and self.session.http.cookies.get('.abportail1')): for cookie in self.session.http.cookies: # remove www from cookie domain cookie.domain = '.abweb.com' self.save_cookies(default_expires=3600 * 24) return True else: log.error('Failed to login, check your username/password') return False
def _get_vod_streams(self, vod_id): res = self.session.http.get(self.vod_url.format(vod_id)) m = self.vod_data_re.search(res.text) vod_json = m and m.group(1) if vod_json is None: raise PluginError("Failed to get VOD data") vod_data = parse_json(vod_json, schema=self._vod_data_schema) self.author = vod_data['username'] self.category = 'VOD' self.title = vod_data['title'] vod_data = vod_data['vaddress'] streams = {} for stream in vod_data: video_res = stream['vheight'] if 'p' not in str(video_res): video_res = "{0}p".format(video_res) if video_res in streams: video_res = "{0}_alt".format(video_res) streams[video_res] = HLSStream(self.session, stream['url']) return streams
def _get_streams(self): self.session.http.headers.update({ 'User-Agent': useragents.FIREFOX, 'Referer': self.url }) match = _url_re.match(self.url) channel = match.group("channel") res_room_id = self.session.http.get( self.options.get("apihost") + ROOM_API.format(channel)) log.debug(res_room_id.json()) _room_id_json = res_room_id.json() try: room_id_json = self.session.http.json(res_room_id, schema=_room_id_schema) except: log.info("Error during processing json: %s", _room_id_json) raise self.room_id = room_id_json['room_id'] if room_id_json['live_status'] != SHOW_STATUS_ONLINE: log.error("This video is not a live. (abort)") raise PluginError("This video is not a live. (abort)") return '''params = { 'cid': room_id, 'quality': '4', 'platform': 'web', }''' name = "source" for url in self.update_playlist(): #stream = BilibiliHLSStream.parse_variant_playlist(self.session, url) stream = BilibiliHLSStream(self.session, url) stream.plugin = self #for c in stream: # stream[c].plugin = self yield name, stream
def _get_streams(self): nickname = self.match.group('nickname') res = self.session.http.get(f'https://wasd.tv/api/channels/nicknames/{nickname}') channel_id = self.session.http.json(res, schema=self._api_nicknames_schema) res = self.session.http.get( 'https://wasd.tv/api/v2/media-containers', params={ 'media_container_status': 'RUNNING', 'limit': '1', 'offset': '0', 'channel_id': channel_id, 'media_container_type': 'SINGLE,COOP', } ) json_res = self.session.http.json(res, schema=self._api_schema) log.trace('{0!r}'.format(json_res)) if not json_res: raise PluginError('No data returned from URL={0}'.format(res.url)) for stream in json_res['media_container_streams']: log.debug('media_container_status: {0}, media_container_online_status: {1}'.format( json_res['media_container_status'], json_res['media_container_online_status'])) for stream in stream['stream_media']: if stream['media_status'] == 'STOPPED': hls_url = stream['media_meta']['media_archive_url'] elif stream['media_status'] == 'RUNNING': hls_url = stream['media_meta']['media_url'] yield from HLSStream.parse_variant_playlist(self.session, hls_url).items()
def _get_session_key(self, event_id): url = "{}/stream".format(_MEDIA_API_URL) params = { "eventId": event_id, "format": "json", "platform": "WEB_MEDIAPLAYER", "subject": "NHLTV", "_": now_ms(), } headers = { "Accept": "application/json", "Authorization": self._auth_token, } json = self.session.http.get(url, params=params, headers=headers).json() session_key = json.get("session_key") if not session_key: status = json.get("status_code") if status == -3500: log.debug( "Plugin is being rate-limited for making too many session key requests." ) raise PluginError("Could not obtain session key: {}".format( json.get("status_message"))) # This session key is normally supposed to last for a single browser session. # If we repeatedly request new session keys we will get rate limited by the NHL.tv backend, # so we cache session keys for 2.5 hours (roughly the length of an NHL hockey game) to # aproximate normal behavior. self.cache.set("session_key", session_key, 9000)
def _get_streams(self): is_live = False self.video_id = self._find_video_id(self.url) log.debug(f"Using video ID: {self.video_id}") info = self._get_stream_info(self.video_id) if info and info.get("status") == "fail": log.error("Could not get video info: {0}".format( info.get("reason"))) return elif not info: log.error("Could not get video info") return if info.get("player_response", {}).get("videoDetails", {}).get("isLive"): log.debug("This video is live.") is_live = True streams = {} protected = False if (info.get("player_response", {}).get("streamingData", {}).get( "adaptiveFormats", [{}])[0].get("cipher") or info.get( "player_response", {}).get("streamingData", {}).get( "adaptiveFormats", [{}])[0].get("signatureCipher") or info.get("player_response", {}).get("streamingData", {}).get( "formats", [{}])[0].get("cipher")): protected = True log.debug("This video may be protected.") for stream_info in info.get("player_response", {}).get("streamingData", {}).get("formats", []): if "url" not in stream_info: continue stream = HTTPStream(self.session, stream_info["url"]) name = stream_info["qualityLabel"] streams[name] = stream if not is_live: streams = self._create_adaptive_streams(info, streams) hls_manifest = info.get("player_response", {}).get("streamingData", {}).get("hlsManifestUrl") if hls_manifest: try: hls_streams = HLSStream.parse_variant_playlist( self.session, hls_manifest, namekey="pixels") streams.update(hls_streams) except IOError as err: log.warning(f"Failed to extract HLS streams: {err}") if not streams and protected: raise PluginError("This plugin does not support protected videos, " "try youtube-dl instead") return streams
def _get_streams(self): streams = {} # streaming.media.ccc.de match = _url_streaming_media_re.match(self.url) if match: query_url = API_URL_STREAMING_MEDIA live_streams = parse_streaming_media_json(get_json(query_url),\ match.group('room')) for stream_name, stream_url in live_streams.items(): if re.search(r"m3u8", live_streams[stream_name]): streams[stream_name] = HLSStream(self.session,\ stream_url) else: streams[stream_name] = HTTPStream(self.session,\ stream_url) # media.ccc.de elif _url_media_re.search(self.url): event_id = get_event_id(self.url) query_url = "%s/public/events/%i" % (API_URL_MEDIA, event_id) recordings = parse_media_json(get_json(query_url)) for name, stream_url in recordings.items(): streams[name] = HTTPStream(self.session, stream_url) if not streams: raise PluginError("This plugin does not support your " "selected video.") return streams
def _find_video_id(self, url): m = _url_re.match(url) if m.group("video_id"): log.debug("Video ID from URL") return m.group("video_id") res = self.session.http.get(url) datam = _ytdata_re.search(res.text) if datam: data = parse_json(datam.group(1)) # find the videoRenderer object, where there is a LVE NOW badge for vid_ep in search_dict(data, 'currentVideoEndpoint'): video_id = vid_ep.get("watchEndpoint", {}).get("videoId") if video_id: log.debug("Video ID from currentVideoEndpoint") return video_id for x in search_dict(data, 'videoRenderer'): for bstyle in search_dict(x.get("badges", {}), "style"): if bstyle == "BADGE_STYLE_TYPE_LIVE_NOW": if x.get("videoId"): log.debug("Video ID from videoRenderer (live)") return x["videoId"] if "/embed/live_stream" in url: for link in itertags(res.text, "link"): if link.attributes.get("rel") == "canonical": canon_link = link.attributes.get("href") if canon_link != url: log.debug("Re-directing to canonical URL: {0}".format(canon_link)) return self._find_video_id(canon_link) raise PluginError("Could not find a video on this page")
def _get_swf_url(self): res = self.session.http.get(self.url) match = _swf_url_re.search(res.text) if not match: raise PluginError("Unable to find SWF URL in the HTML") return match.group(1)
def _create_api(self): """Creates a new CrunchyrollAPI object, initiates it's session and tries to authenticate it either by using saved credentials or the user's username and password. """ if self.options.get("purge_credentials"): self.cache.set("session_id", None, 0) self.cache.set("auth", None, 0) self.cache.set("session_id", None, 0) current_time = datetime.datetime.utcnow() device_id = self._get_device_id() # use the crunchyroll locale as an override, for backwards compatibility locale = self.get_option("locale") or self.session.localization.language_code api = CrunchyrollAPI( self.options.get("session_id") or self.cache.get("session_id"), self.cache.get("auth"), locale ) self.logger.debug("Creating session with locale: {0}", locale) try: api.session_id = api.start_session(device_id, schema=_session_schema) except CrunchyrollAPIError as err: if err.code == "bad_session": self.logger.debug("Current session has expired, creating a new one") api = CrunchyrollAPI(locale=locale) api.session_id = api.start_session(device_id, schema=_session_schema) else: raise err # Save session and hope it lasts for a few hours self.cache.set("session_id", api.session_id, 4 * 60 * 60) self.logger.debug("Session created") if api.auth: self.logger.debug("Using saved credentials") elif self.options.get("username"): try: self.logger.info("Attempting to login using username and password") login = api.login( self.options.get("username"), self.options.get("password"), schema=_login_schema ) api.auth = login["auth"] self.logger.info("Successfully logged in as '{0}'", login["user"]["username"] or login["user"]["email"]) expires = (login["expires"] - current_time).total_seconds() self.cache.set("auth", login["auth"], expires) except CrunchyrollAPIError as err: raise PluginError(u"Authentication error: {0}".format(err.msg)) else: self.logger.warning( "No authentication provided, you won't be able to access " "premium restricted content" ) return api
def _get_streams(self): res = self._get_res(self.url) if self.match.group( "channel") and not self.match.group("channel_live"): initial = self._get_data_from_regex(res, self._re_ytInitialData, "initial data") video_id = self._data_video_id(initial) if video_id is None: log.error("Could not find videoId on channel page") return self.url = self._url_canonical.format(video_id=video_id) res = self._get_res(self.url) data = self._get_data_from_regex(res, self._re_ytInitialPlayerResponse, "initial player response") if not self._data_status(data): data = self._get_data_from_api(res) if not self._data_status(data, True): return self.id, self.author, self.category, self.title, is_live = self._schema_videodetails( data) log.debug(f"Using video ID: {self.id}") if is_live: log.debug("This video is live.") streams = {} hls_manifest, formats, adaptive_formats = self._schema_streamingdata( data) protected = next( (True for url, *_ in formats + adaptive_formats if url is None), False) if protected: log.debug("This video may be protected.") for url, label in formats: if url is None: continue streams[label] = HTTPStream(self.session, url) if not is_live: streams.update(self._create_adaptive_streams(adaptive_formats)) if hls_manifest: streams.update( HLSStream.parse_variant_playlist(self.session, hls_manifest, name_key="pixels")) if not streams and protected: raise PluginError( "This plugin does not support protected videos, try youtube-dl instead" ) return streams
def _get_streams(self): http.headers.update({'User-Agent': useragents.CHROME}) is_live = False video_id = self._find_video_id(self.url) if not video_id: log.error("Could not find a video on this page") return log.debug("Using video ID: {0}", video_id) info = self._get_stream_info(video_id) if info and info.get("status") == "fail": log.error("Could not get video info: {0}".format( info.get("reason"))) return elif not info: log.error("Could not get video info") return if info.get("livestream") == '1' or info.get("live_playback") == '1': log.debug("This video is live.") is_live = True formats = info.get("fmt_list") streams = {} protected = False for stream_info in info.get("url_encoded_fmt_stream_map", []): if stream_info.get("s"): protected = True continue stream = HTTPStream(self.session, stream_info["url"]) name = formats.get(stream_info["itag"]) or stream_info["quality"] if stream_info.get("stereo3d"): name += "_3d" streams[name] = stream if not is_live: streams, protected = self._create_adaptive_streams( info, streams, protected) hls_playlist = info.get("hlsvp") if hls_playlist: try: hls_streams = HLSStream.parse_variant_playlist( self.session, hls_playlist, namekey="pixels") streams.update(hls_streams) except IOError as err: log.warning("Failed to extract HLS streams: {0}", err) if not streams and protected: raise PluginError("This plugin does not support protected videos, " "try youtube-dl instead") return streams
def _get_video_data(self, slug): m = self.truncate_url_re.search(self.url) if m and m.group(1): log.debug("Truncated URL={0}".format(m.group(1))) else: raise PluginError("Failed to truncate URL") res = self.session.http.get(m.group(1)) m = self.json_data_re.search(res.text) if m and m.group(1): videos = parse_json(m.group(1), schema=self._video_data_schema) else: raise PluginError("Failed to get json_data") for video in videos: if 'slug' in videos[video]: if slug == videos[video]['slug'] and 'id' in videos[video]: return videos[video]['id']
def policy_key(self, video_id): # Get the embedded player page res = self.session.http.get(self.player_url(video_id)) policy_key_m = self.policy_key_re.search(res.text) policy_key = policy_key_m and policy_key_m.group("key") if not policy_key: raise PluginError("Could not find Brightcove policy key") return policy_key
def _get_streams(self): api = self._create_api() media_id = int(self.match.group("media_id")) try: # the media.stream_data field is required, no stream data is returned otherwise info = api.get_info(media_id, fields=[ "media.name", "media.series_name", "media.media_type", "media.stream_data" ], schema=_media_schema) except CrunchyrollAPIError as err: raise PluginError(f"Media lookup error: {err.msg}") if not info: return streams = {} self.title = info.get("name") self.author = info.get("series_name") self.category = info.get("media_type") info = info["stream_data"] # The adaptive quality stream sometimes a subset of all the other streams listed, ultra is no included has_adaptive = any( [s["quality"] == "adaptive" for s in info["streams"]]) if has_adaptive: log.debug("Loading streams from adaptive playlist") for stream in filter(lambda x: x["quality"] == "adaptive", info["streams"]): for q, s in HLSStream.parse_variant_playlist( self.session, stream["url"]).items(): # rename the bitrates to low, mid, or high. ultra doesn't seem to appear in the adaptive streams name = STREAM_NAMES.get(q, q) streams[name] = s # If there is no adaptive quality stream then parse each individual result for stream in info["streams"]: if stream["quality"] != "adaptive": # the video_encode_id indicates that the stream is not a variant playlist if "video_encode_id" in stream: streams[stream["quality"]] = HLSStream( self.session, stream["url"]) else: # otherwise the stream url is actually a list of stream qualities for q, s in HLSStream.parse_variant_playlist( self.session, stream["url"]).items(): # rename the bitrates to low, mid, or high. ultra doesn't seem to appear in the adaptive streams name = STREAM_NAMES.get(q, q) streams[name] = s return streams
def get_streams(self, video_id): log.debug(f"Finding streams for video: {video_id}") player_url = self.URL_PLAYER.format( account_id=self.account_id, player_id=self.player_id, video_id=video_id ) policy_key = self.session.http.get( player_url, params={"videoId": video_id}, schema=validate.Schema( validate.transform(re.compile(r"""policyKey\s*:\s*(?P<q>['"])(?P<key>[\w-]+)(?P=q)""").search), validate.any(None, validate.get("key")) ) ) if not policy_key: raise PluginError("Could not find Brightcove policy key") log.debug(f"Found policy key: {policy_key}") self.session.http.headers.update({"Referer": player_url}) sources, self.title = self.session.http.get( self.URL_API.format(account_id=self.account_id, video_id=video_id), headers={"Accept": f"application/json;pk={policy_key}"}, schema=validate.Schema( validate.parse_json(), { "sources": [{ "src": validate.url(), validate.optional("type"): str, validate.optional("container"): str, validate.optional("height"): int, validate.optional("avg_bitrate"): int, }], validate.optional("name"): str, }, validate.union_get("sources", "name") ) ) for source in sources: if source.get("type") in ("application/vnd.apple.mpegurl", "application/x-mpegURL"): yield from HLSStream.parse_variant_playlist(self.session, source.get("src")).items() elif source.get("container") == "MP4": # determine quality name if source.get("height"): q = f"{source.get('height')}p" elif source.get("avg_bitrate"): q = f"{source.get('avg_bitrate') // 1000}k" else: q = "live" yield q, HTTPStream(self.session, source.get("src"))