def _get_streams(self): api = self._create_api() match = _url_re.match(self.url) media_id = int(match.group("media_id")) try: info = api.get_info(media_id, fields=["media.stream_data"], schema=_media_schema) except CrunchyrollAPIError as err: raise PluginError(u"Media lookup error: {0}".format(err.msg)) if not info: return # The adaptive quality stream contains a superset of all the other streams listeed has_adaptive = any([s[u"quality"] == u"adaptive" for s in info[u"streams"]]) if has_adaptive: self.logger.debug(u"Loading streams from adaptive playlist") for stream in filter(lambda x: x[u"quality"] == u"adaptive", info[u"streams"]): return HLSStream.parse_variant_playlist(self.session, stream["url"]) else: streams = {} # If there is no adaptive quality stream then parse each individual result for stream in info[u"streams"]: # the video_encode_id indicates that the stream is not a variant playlist if u"video_encode_id" in stream: streams[stream[u"quality"]] = HLSStream(self.session, stream[u"url"]) else: # otherwise the stream url is actually a list of stream qualities streams.update(HLSStream.parse_variant_playlist(self.session, stream[u"url"])) return streams
def _get_streams(self): stream_type = self._url_re.match(self.url).group("type") hls_re = re.compile(r"""["'](?P<url>[^"']+\.m3u8[^"']*?)["']""") headers = { "Origin": "https://www.metube.id", "User-Agent": useragents.FIREFOX } res = self.session.http.get(self.url) match = hls_re.search(res.text) if not match: return stream_url = match.group("url") if stream_type == "live": return HLSStream.parse_variant_playlist(self.session, stream_url, headers=headers) else: streams = {} for quality, stream in HLSStream.parse_variant_playlist( self.session, stream_url, headers=headers).items(): name = self._VOD_STREAM_NAMES.get(quality, quality) streams[name] = stream return streams
def test_hls_stream(self): url = "http://test.se/stream.m3u8" stream = HLSStream(self.session, url, headers={"User-Agent": "Test"}) self.assertEqual( {"type": "hls", "url": url, "headers": { "User-Agent": "Test", "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", }}, stream.__json__() )
def _get_streams(self): if self.get_option("email") and self.get_option("password"): if not self.authenticate(self.get_option("email"), self.get_option("password")): self.logger.warning("Failed to login as {0}".format(self.get_option("email"))) # find the list of channels from the html in the page self.url = self.url.replace("https", "http") # https redirects to http res = http.get(self.url) if "enter your postcode" in res.text: self.logger.info("Setting your postcode to: {0}. " "This can be changed in the settings on tvplayer.com", self.dummy_postcode) res = http.post(self.update_url, data=dict(postcode=self.dummy_postcode), params=dict(return_url=self.url)) stream_attrs = self._get_stream_attrs(res) if stream_attrs: stream_data = self._get_stream_data(**stream_attrs) if stream_data: if stream_data.get("drmToken"): self.logger.error("This stream is protected by DRM can cannot be played") return else: return HLSStream.parse_variant_playlist(self.session, stream_data["stream"]) else: if "need to login" in res.text: self.logger.error( "You need to login using --tvplayer-email/--tvplayer-password to view this stream")
def _get_streams(self): match = _url_re.match(self.url) username = match.group("username") CSRFToken = str(uuid.uuid4().hex.upper()[0:32]) headers = { "Content-Type": "application/x-www-form-urlencoded", "X-CSRFToken": CSRFToken, "X-Requested-With": "XMLHttpRequest", "Referer": self.url, } cookies = { "csrftoken": CSRFToken, } post_data = "room_slug={0}&bandwidth=high".format(username) res = http.post(API_HLS, headers=headers, cookies=cookies, data=post_data) data = http.json(res, schema=_post_schema) if data["success"] is True and data["room_status"] == "public": for s in HLSStream.parse_variant_playlist(self.session, data["url"]).items(): yield s
def _get_streams(self): mdata = self._get_movie_data() if mdata: log.debug("Found video: {0} ({1})".format(mdata["title"], mdata["id"])) if mdata["media"]["url"]: for s in HLSStream.parse_variant_playlist(self.session, mdata["media"]["url"]).items(): yield s elif self.get_option("email") and self.get_option("password"): if self.login(self.get_option("email"), self.get_option("password")): details = self._get_details(mdata["id"]) if details: for item in details["items"]: for s in HLSStream.parse_variant_playlist(self.session, item["media"]["url"]).items(): yield s else: log.error("You must login to access this stream")
def _get_vod_stream(self): vod_url = self.url if vod_url.endswith('/'): vod_url = vod_url[:-1] json_url = '{0}.securevideo.json'.format(vod_url) res = http.get(json_url) match = _json_re.search(res.text) if not match: return data = parse_json(match.group(1)) res = http.get(API_VOD.format(data['clientid'], data['mzid'])) data = http.json(res, schema=_stream_schema) for d in data['targetUrls']: if d['type'] == 'HDS': hds_url = d['url'] for s in HDSStream.parse_manifest(self.session, hds_url).items(): yield s if d['type'] == 'HLS': hls_url = d['url'] for s in HLSStream.parse_variant_playlist(self.session, hls_url).items(): yield s
def _get_streams(self): match = _url_re.match(self.url) res = http.get(STREAM_INFO_URL, params=match.groupdict(), acceptable_status=STATUS_UNAVAILABLE) if res.status_code in STATUS_UNAVAILABLE: return data = http.json(res, schema=_stream_schema) if data.get("hls_url"): hls_url = data["hls_url"] hls_name = "live" elif data.get("replay_url"): self.logger.info("Live Stream ended, using replay instead") hls_url = data["replay_url"] hls_name = "replay" else: raise NoStreamsError(self.url) streams = HLSStream.parse_variant_playlist(self.session, hls_url) if not streams: return {hls_name: HLSStream(self.session, hls_url)} else: return streams
def _get_streams(self): match = _url_re.match(self.url) channel = match.group("channel") domain = match.group("domain") headers = { "Referer": self.url, "User-Agent": useragents.FIREFOX } if domain == "canlitv.plus": res = http.get(EMBED_URL_1.format(channel), headers=headers) elif domain == "ecanlitvizle.net": res = http.get(EMBED_URL_2.format(channel), headers=headers) else: res = http.get(self.url, headers=headers) url_match = _m3u8_re.search(res.text) if url_match: hls_url = url_match.group("url") if domain in ("canlitvlive.live", "canlitvlive.site"): hls_url = "http:" + hls_url self.logger.debug("Found URL: {0}".format(hls_url)) try: s = [] for s in HLSStream.parse_variant_playlist(self.session, hls_url).items(): yield s if not s: yield "live", HLSStream(self.session, hls_url) except IOError as err: self.logger.error("Failed to extract streams: {0}", err)
def mediaselector(self, vpid): urls = defaultdict(set) for platform in self.platforms: url = self.api_url.format(vpid=vpid, vpid_hash=self._hash_vpid(vpid), platform=platform) log.debug("Info API request: {0}", url) medias = self.session.http.get(url, schema=self.mediaselector_schema) for media in medias: for connection in media["connection"]: urls[connection.get("transferFormat")].add(connection["href"]) for stream_type, urls in urls.items(): log.debug("{0} {1} streams", len(urls), stream_type) for url in list(urls): try: if stream_type == "hds": for s in HDSStream.parse_manifest(self.session, url).items(): yield s if stream_type == "hls": for s in HLSStream.parse_variant_playlist(self.session, url).items(): yield s if stream_type == "dash": for s in DASHStream.parse_manifest(self.session, url).items(): yield s log.debug(" OK: {0}", url) except: log.debug(" FAIL: {0}", url)
def _get_streams(self): if self.is_live: self.logger.debug("Loading live stream for {0}...", self.channel) res = self.session.http.get(self.live_api_url, data={"r": random.randint(1, 100000)}) live_data = self.session.http.json(res) # all the streams are equal for each type, so pick a random one hls_streams = live_data.get("hls") if hls_streams: url = random.choice(hls_streams) url = url + '&' + urlencode(self.hls_session()) # TODO: use update_qsd for s in HLSStream.parse_variant_playlist(self.session, url, name_fmt="{pixels}_{bitrate}").items(): yield s mpd_streams = live_data.get("mpd") if mpd_streams: url = random.choice(mpd_streams) for s in DASHStream.parse_manifest(self.session, url).items(): yield s elif self.channel == "1tv": self.logger.debug("Attempting to find VOD stream...", self.channel) vod_data = self.vod_data() if vod_data: self.logger.info(u"Found VOD: {0}".format(vod_data[0]['title'])) for stream in vod_data[0]['mbr']: yield stream['name'], HTTPStream(self.session, update_scheme(self.url, stream['src']))
def _get_streams(self): match = _url_re.match(self.url) channel = match.group("channel") self.session.http.headers.update({'User-Agent': useragents.CHROME}) payload = '{"liveStreamID": "%s"}' % (channel) res = self.session.http.post(API_URL, data=payload) status = _status_re.search(res.text) if not status: self.logger.info("Stream currently unavailable.") return http_url = _rtmp_re.search(res.text).group(1) http_url = http_url.replace("http:", "https:") yield "live", HTTPStream(self.session, http_url) if 'pull-rtmp' in http_url: url = http_url.replace("https:", "rtmp:").replace(".flv", "") stream = RTMPStream(self.session, { "rtmp": url, "live": True }) yield "live", stream if 'wansu-' in http_url: url = http_url.replace(".flv", "/playlist.m3u8") for stream in HLSStream.parse_variant_playlist(self.session, url).items(): yield stream else: url = http_url.replace("live-hdl", "live-hls").replace(".flv", ".m3u8") yield "live", HLSStream(self.session, url)
def _get_streams(self): if "eltrecetv.com.ar/vivo" in self.url.lower(): try: http.headers = {'Referer': self.url, 'User-Agent': useragents.ANDROID} res = http.get('https://api.iamat.com/metadata/atcodes/eltrece') yt_id = parse_json(res.text)["atcodes"][0]["context"]["ahora"]["vivo"]["youtubeVideo"] yt_url = "https://www.youtube.com/watch?v={0}".format(yt_id) return self.session.streams(yt_url) except BaseException: self.logger.info("Live content is temporarily unavailable. Please try again later.") else: try: http.headers = {'Referer': self.url, 'User-Agent': useragents.CHROME} res = http.get(self.url) _player_re = re.compile(r'''data-kaltura="([^"]+)"''') match = _player_re.search(res.text) if not match: return entry_id = parse_json(match.group(1).replace(""", '"'))["entryId"] hls_url = "https://vodgc.com/p/111/sp/11100/playManifest/entryId/{0}/format/applehttp/protocol/https/a.m3u8".format(entry_id) return HLSStream.parse_variant_playlist(self.session, hls_url) except BaseException: self.logger.error("The requested VOD content is unavailable.")
def _get_vod_streams(self, params): manifest_url = params.get("autoURL") if not manifest_url: return res = http.get(manifest_url) if res.headers.get("Content-Type") == "application/f4m+xml": streams = HDSStream.parse_manifest(self.session, res.url) # TODO: Replace with "yield from" when dropping Python 2. for __ in streams.items(): yield __ elif res.headers.get("Content-Type") == "application/vnd.apple.mpegurl": streams = HLSStream.parse_variant_playlist(self.session, res.url) # TODO: Replace with "yield from" when dropping Python 2. for __ in streams.items(): yield __ else: manifest = http.json(res, schema=_vod_manifest_schema) for params in manifest["alternates"]: name = "{0}p".format(params["height"]) stream = self._create_flv_playlist(params["template"]) yield name, stream failovers = params.get("failover", []) for failover in failovers: stream = self._create_flv_playlist(failover) yield name, stream
def _get_streams(self): res = self.session.http.get(self.url) match = self._video_id_re.search(res.text) or self._video_id_alt_re.search(res.text) if match is None: return broadcaster_id = match.group('broadcaster_id') video_type = match.group('video_type') video_id = match.group('video_id') videos = self.session.http.get(self.DACAST_API_URL.format(broadcaster_id, video_type, video_id), schema=self._api_schema) token = self.session.http.get(self.DACAST_TOKEN_URL.format(broadcaster_id, video_type, video_id), schema=self._token_schema) parsed = [] for video_url in videos: video_url += token # Ignore duplicate video URLs if video_url in parsed: continue parsed.append(video_url) # Ignore HDS streams (broken) if '.m3u8' in video_url: for s in HLSStream.parse_variant_playlist(self.session, video_url).items(): yield s
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').replace('"', '"')) else: raise PluginError("Could not extract JSON metadata") streams = {} try: if mode == MODE_STREAM: sources = data['playlist']['videos'][0]['sources'] elif mode == MODE_VOD: sources = data['selected_video']['sources'] except (KeyError, IndexError): raise PluginError("Could not extract sources") for source in sources: try: if source['delivery'] != 'hls': continue url = source['src'].replace(r'\/', '/') except KeyError: continue stream = HLSStream.parse_variant_playlist(self.session, url) # work around broken HTTP connection persistence by acquiring a new connection http.close() streams.update(stream) return streams
def _get_streams(self): """ Finds the streams from tvcatchup.com. """ token = self.login(self.get_option("username"), self.get_option("password")) m = self._url_re.match(self.url) scode = m and m.group("scode") or self.get_option("station_code") res = http.get(self._guide_url) channels = {} for t in itertags(res.text, "a"): if t.attributes.get('cs'): channels[t.attributes.get('cs').lower()] = t.attributes.get('title').replace("Watch ", "") if not scode: self.logger.error("Station code not provided, use --ustvnow-station-code.") self.logger.error("Available stations are: {0}", ", ".join(channels.keys())) return if scode in channels: self.logger.debug("Finding streams for: {0}", channels.get(scode)) r = http.get(self._stream_url, params={"scode": scode, "token": token, "br_n": "Firefox", "br_v": "52", "br_d": "desktop"}, headers={"User-Agent": useragents.FIREFOX}) data = http.json(r) return HLSStream.parse_variant_playlist(self.session, data["stream"]) else: self.logger.error("Invalid station-code: {0}", scode)
def _get_streams(self): user = self.login(self.options.get("email"), self.options.get("password")) if user: self.logger.debug("Logged in to Schoolism as {0}", user) res = http.get(self.url, headers={"User-Agent": useragents.SAFARI_8}) lesson_playlist = self.playlist_schema.validate(res.text) part = self.options.get("part") self.logger.info("Attempting to play lesson Part {0}", part) found = False # make request to key-time api, to get key specific headers res = http.get(self.key_time_url, headers={"User-Agent": useragents.SAFARI_8}) for i, video in enumerate(lesson_playlist, 1): if video["sources"] and i == part: found = True for source in video["sources"]: for s in HLSStream.parse_variant_playlist(self.session, source["src"], headers={"User-Agent": useragents.SAFARI_8, "Referer": self.url}).items(): yield s if not found: self.logger.error("Could not find lesson Part {0}", part)
def _get_streams(self): res = self.session.http.get(self.url, headers={'User-Agent': useragents.CHROME}) video_search = res.text video_search = video_search[video_search.index('{"top":{"view":"PlayerContainer","model":{'):] video_search = video_search[: video_search.index('}]}}') + 4] + "}" video_url_found_hls = "" video_url_found_http = "" json_video_search = parse_json(video_search) json_video_search_sources = json_video_search["top"]["model"]["videos"][0]["sources"] self.logger.debug('Video ID found: {0}', json_video_search["top"]["model"]["id"]) for current_video_source in json_video_search_sources: if "HLS" in current_video_source["type"]: video_url_found_hls = "http://telefe.com" + current_video_source["url"] self.logger.debug("HLS content available") if "HTTP" in current_video_source["type"]: video_url_found_http = "http://telefe.com" + current_video_source["url"] self.logger.debug("HTTP content available") self.session.http.headers = {'Referer': self.url, 'User-Agent': useragents.CHROME, 'X-Requested-With': 'ShockwaveFlash/25.0.0.148'} if video_url_found_hls: hls_streams = HLSStream.parse_variant_playlist(self.session, video_url_found_hls) for s in hls_streams.items(): yield s if video_url_found_http: yield "http", HTTPStream(self.session, video_url_found_http)
def _get_streams(self): res = http.get(self.url) match = _info_re.search(res.text) if not match: return info = parse_json(match.group(1), schema=_schema) stream_name = info["mode"] mp4_url = info.get("mp4_url") ios_url = info.get("ios_url") swf_url = info.get("swf_url") if mp4_url: stream = HTTPStream(self.session, mp4_url) yield stream_name, stream if ios_url: if urlparse(ios_url).path.endswith(".m3u8"): streams = HLSStream.parse_variant_playlist(self.session, ios_url) # TODO: Replace with "yield from" when dropping Python 2. for stream in streams.items(): yield stream if swf_url: stream = self._get_rtmp_stream(swf_url) if stream: yield stream_name, stream
def _get_streams(self): http.headers.update({"User-Agent": useragents.CHROME, "Referer": self.referer}) fragment = dict(parse_qsl(urlparse(self.url).fragment)) link = fragment.get("link") if not link: link = self._get_tv_link() if not link: self.logger.error("Missing link fragment: stream unavailable") return player_url = self._api_url.format(link) self.logger.debug("Requesting player API: {0} (referer={1})", player_url, self.referer) res = http.get(player_url, params={"_": int(time.time() * 1000)}, headers={"X-Requested-With": "XMLHttpRequest"}) try: data = http.json(res, schema=self.api_schema) except PluginError as e: print(e) self.logger.error("Cannot play this stream type") else: if data["status"]: if data["file"].startswith("<"): self.logger.error("Cannot play embedded streams") else: return HLSStream.parse_variant_playlist(self.session, data["file"]) else: self.logger.error(data["text"])
def _get_streams(self): iframe_url = self._get_iframe_url(self.url) if iframe_url: log.debug("Found iframe URL={0}".format(iframe_url)) info_url = self._get_stream_info_url(iframe_url) if info_url: log.debug("Getting info from URL: {0}".format(info_url)) res = self.session.http.get(info_url, headers={"Referer": iframe_url}) data = self.session.http.json(res) if data['status'] == 200: for media in data['data']['playlist']['medialist']: if media['errors']: log.error(media['errors'].replace('\n', '').replace('\r', '')) for media_type in media.get('sources', []): if media_type == "m3u8": hls_url = media['sources'][media_type]['auto'] for s in HLSStream.parse_variant_playlist(self.session, hls_url).items(): yield s if media_type == "http": for pix, url in media['sources'][media_type].items(): yield "{0}p".format(pix), HTTPStream(self.session, url) else: log.error("An error occurred: {0}".format(data['errors'].replace('\n', '').replace('\r', ''))) else: log.error("Unable to get stream info URL") else: log.error("Could not find video iframe")
def _create_stream(self, stream, is_live): stream_name = "{0}p".format(stream["height"]) stream_type = stream["mediaType"] stream_url = stream["url"] if stream_type in ("hls", "mp4"): if urlparse(stream_url).path.endswith("m3u8"): try: streams = HLSStream.parse_variant_playlist(self.session, stream_url) # TODO: Replace with "yield from" when dropping Python 2. for stream in streams.items(): yield stream except IOError as err: self.logger.error("Failed to extract HLS streams: {0}", err) else: yield stream_name, HTTPStream(self.session, stream_url) elif stream_type == "rtmp": params = { "rtmp": stream["streamer"], "playpath": stream["url"], "swfVfy": SWF_URL, "pageUrl": self.url, } if is_live: params["live"] = True else: params["playpath"] = "mp4:{0}".format(params["playpath"]) stream = RTMPStream(self.session, params) yield stream_name, stream
def _get_video_streams(self): res = self.session.http.get(self.url) match = self._video_player_re.search(res.text) if match is None: return player_url = match.group('player_url') stream_data = self.session.http.get(player_url, schema=self._video_stream_schema) if stream_data is None: return # Check geolocation to prevent further errors when stream is parsed if not self.check_geolocation(stream_data['geoLocRestriction']): self.logger.error('Stream is geo-restricted') return # Check whether streams are DRM-protected if stream_data.get('drm', False): self.logger.error('Stream is DRM-protected') return now = datetime.datetime.now() try: if isinstance(stream_data['sources'], dict): urls = [] for profile, url in stream_data['sources'].items(): if not url or url in urls: continue match = self._stream_size_re.match(url) if match is not None: quality = match.group('size') else: quality = profile yield quality, HTTPStream(self.session, url) urls.append(url) hls_url = stream_data.get('urlHls') or stream_data.get('streamUrlHls') if hls_url: if stream_data.get('isLive', False): # Live streams require a token hls_url = self.tokenize_stream(hls_url) for stream in HLSStream.parse_variant_playlist(self.session, hls_url).items(): yield stream dash_url = stream_data.get('urlDash') or stream_data.get('streamUrlDash') if dash_url: if stream_data.get('isLive', False): # Live streams require a token dash_url = self.tokenize_stream(dash_url) for stream in DASHStream.parse_manifest(self.session, dash_url).items(): yield stream except IOError as err: if '403 Client Error' in str(err): # Check whether video is expired if 'startDate' in stream_data: if now < self.iso8601_to_epoch(stream_data['startDate']): self.logger.error('Stream is not yet available') elif 'endDate' in stream_data: if now > self.iso8601_to_epoch(stream_data['endDate']): self.logger.error('Stream has expired')
def _get_streams(self): match = self._url_re.match(self.url) channel = match.group('channel') res = self.session.http.get(self.FORMATS_URL.format(channel)) streams = self.session.http.json(res, schema=self._formats_schema)['streams'] if streams == []: self.logger.error('Channel may be geo-restricted, not directly provided by PlayTV or not freely available') return for language in streams: for protocol, bitrates in list(streams[language].items()): # - Ignore non-supported protocols (RTSP, DASH) # - Ignore deprecated Flash (RTMPE/HDS) streams (PlayTV doesn't provide anymore a Flash player) if protocol in ['rtsp', 'flash', 'dash', 'hds']: continue for bitrate in bitrates['bitrates']: if bitrate['value'] == 0: continue api_url = self.API_URL.format(channel, protocol, language, bitrate['value']) res = self.session.http.get(api_url) video_url = self.session.http.json(res, schema=self._api_schema)['url'] bs = '{0}k'.format(bitrate['value']) if protocol == 'hls': for _, stream in HLSStream.parse_variant_playlist(self.session, video_url).items(): yield bs, stream elif protocol == 'hds': for _, stream in HDSStream.parse_manifest(self.session, video_url).items(): yield bs, stream
def _get_streams(self): channel = self.url_re.match(self.url).group(1) res = http.get(self.api_url.format(channel)) data = http.json(res, schema=self.api_schema) return HLSStream.parse_variant_playlist(self.session, data["channel_stream_url"])
def _get_streams(self): match = _url_re.match(self.url) channel = match.group("channel") channel = channel.replace("_", "-") playlist_url = PLAYLIST_URL.format(channel) return HLSStream.parse_variant_playlist(self.session, playlist_url, check_streams=True)
def _get_streams(self): # get the HLS xml from the same sub domain as the main url, defaulting to www sdomain = _url_re.match(self.url).group(1) or "www" res = self.session.http.get(API_URL.format(sdomain)) stream_url = self.session.http.xml(res, schema=_schema) return HLSStream.parse_variant_playlist(self.session, stream_url)
def _get_hls_streams(self, type="live"): self._authenticate() if self._check_for_host() and self.options.get("disable_hosting"): self.logger.info("hosting was disabled by command line option") return {} else: self.logger.info("switching to {}", self.channel) sig, token = self._access_token(type) if type == "live": url = self.usher.channel(self.channel, sig=sig, token=token) elif type == "video": url = self.usher.video(self.video_id, nauthsig=sig, nauth=token) try: streams = HLSStream.parse_variant_playlist(self.session, url) except IOError as err: err = str(err) if "404 Client Error" in err or "Failed to parse playlist" in err: return else: raise PluginError(err) try: token = parse_json(token, schema=_token_schema) for name in token["restricted_bitrates"]: if name not in streams: self.logger.warning("The quality '{0}' is not available " "since it requires a subscription.", name) except PluginError: pass return streams
def _get_streams(self): email = self.get_option("email") password = self.get_option("password") if not self._authed and (not email and not password): self.logger.error("A login for WWE Network is required, use --wwenetwork-email/" "--wwenetwork-password to set them") return if not self._authed: if not self.login(email, password): self.logger.error("Failed to login, check your username/password") return content_id = self._get_content_id() if content_id: self.logger.debug("Found content ID: {0}", content_id) info = self._get_media_info(content_id) if info["status"]["code"] == 1: # update the session attributes self._update_session_attribute("fprt", info.get("fingerprint")) for attr in info["session_attributes"]: self._update_session_attribute(attr["name"], attr["value"]) if info.get("session_key"): self.session_key = info.get("session_key") for url in info["urls"]: for s in HLSStream.parse_variant_playlist(self.session, url, name_fmt="{pixels}_{bitrate}").items(): yield s else: raise PluginError("Could not load streams: {message} ({code})".format(**info["status"]))
def _get_video_streams(self): res = self.session.http.get(self.url) match = self._video_player_re.search(res.text) if match is None: return player_url = match.group('player_url') stream_data = self.session.http.get(player_url, schema=self._video_stream_schema) if stream_data is None: return # Check geolocation to prevent further errors when stream is parsed if not self.check_geolocation(stream_data['geoLocRestriction']): self.logger.error('Stream is geo-restricted') return # Check whether streams are DRM-protected if stream_data.get('drm', False): self.logger.error('Stream is DRM-protected') return now = datetime.datetime.now() try: if isinstance(stream_data['sources'], dict): urls = [] for profile, url in stream_data['sources'].items(): if not url or url in urls: continue match = self._stream_size_re.match(url) if match is not None: quality = match.group('size') else: quality = profile yield quality, HTTPStream(self.session, url) urls.append(url) hls_url = stream_data.get('urlHls') or stream_data.get( 'streamUrlHls') if hls_url: if stream_data.get('isLive', False): # Live streams require a token hls_url = self.tokenize_stream(hls_url) for stream in HLSStream.parse_variant_playlist( self.session, hls_url).items(): yield stream dash_url = stream_data.get('urlDash') or stream_data.get( 'streamUrlDash') if dash_url: if stream_data.get('isLive', False): # Live streams require a token dash_url = self.tokenize_stream(dash_url) for stream in DASHStream.parse_manifest( self.session, dash_url).items(): yield stream except IOError as err: if '403 Client Error' in str(err): # Check whether video is expired if 'startDate' in stream_data: if now < self.iso8601_to_epoch(stream_data['startDate']): self.logger.error('Stream is not yet available') elif 'endDate' in stream_data: if now > self.iso8601_to_epoch(stream_data['endDate']): self.logger.error('Stream has expired')
def _resolve_stream(self): res = self.session.http.get(self.url) for video in itertags(res.text, 'video'): stream_url = video.attributes.get("data-stream") log.debug("Stream data: {0}".format(stream_url)) return HLSStream.parse_variant_playlist(self.session, stream_url)
def _get_streams(self): """ Find the streams for vk.com :return: """ # If this is a 'videos' catalog URL with an video ID in the GET request, get that instead url = self.follow_vk_redirect(self.url) if url != self.url: self.logger.debug('Grabbing data from real video page at {}', url) headers = {} res = http.get(url, headers=headers) headers["Referer"] = url # Try and find an HLS source (livestream) stream_urls = self._livestream_sources_re.findall(res.text) if len(stream_urls): stream_url = stream_urls[0].replace('\/', '/') self.logger.debug("Found live stream at {}", stream_url) try: # try to parse the stream as a variant playlist variant = HLSStream.parse_variant_playlist(self.session, stream_url, headers=headers) if variant: for q, s in variant.items(): yield q, s else: # and if that fails, try it as a plain HLS stream yield 'live', HLSStream(self.session, stream_url, headers=headers) except IOError: self.logger.warning( "Could not open the stream, perhaps the channel is offline" ) return # Try and find a set of MP4 sources (VOD) vod_urls = self._vod_sources_re.findall(res.text) if len(vod_urls): vod_urls = [v.replace('\/', '/') for v in vod_urls] # Try to get quality from URL qualities = {} for s in vod_urls: q = self._vod_quality_re.findall(s) if not len(q): break qualities[s] = q[0] try: if len(qualities) == len(vod_urls): for s in vod_urls: yield qualities[s] + 'p', HTTPStream(self.session, s) else: # Fall back to numerical ranking for q, s in enumerate(vod_urls): yield str(q), HTTPStream(self.session, s) except IOError: self.logger.warning( "Could not open the stream, perhaps the channel is offline" )
def _get_streams(self): info = self._get_stream_info(self.url) if not info: return 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 adaptive_streams = {} best_audio_itag = None # Extract audio streams from the DASH format list for stream_info in info.get("adaptive_fmts", []): if stream_info.get("s"): protected = True continue stream_params = dict(parse_qsl(stream_info["url"])) if "itag" not in stream_params: continue itag = int(stream_params["itag"]) # extract any high quality streams only available in adaptive formats adaptive_streams[itag] = stream_info["url"] stream_type, stream_format = stream_info["type"] if stream_type == "audio": stream = HTTPStream(self.session, stream_info["url"]) name = "audio_{0}".format(stream_format) streams[name] = stream # find the best quality audio stream m4a, opus or vorbis if best_audio_itag is None or self.adp_audio[itag] > self.adp_audio[best_audio_itag]: best_audio_itag = itag if best_audio_itag and adaptive_streams and MuxedStream.is_usable(self.session): aurl = adaptive_streams[best_audio_itag] for itag, name in self.adp_video.items(): if itag in adaptive_streams: vurl = adaptive_streams[itag] streams[name] = MuxedStream(self.session, HTTPStream(self.session, vurl), HTTPStream(self.session, aurl)) hls_playlist = info.get("hlsvp") if hls_playlist: try: hls_streams = HLSStream.parse_variant_playlist( self.session, hls_playlist, headers=HLS_HEADERS, namekey="pixels" ) streams.update(hls_streams) except IOError as err: self.logger.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_streams(self): page = http.get(self.url, schema=_schema) if not page: return pubkey_pem = get_public_key(self.cache, urljoin(self.url, page["clientlibs"])) if not pubkey_pem: raise PluginError("Unable to get public key") flashvars = page["flashvars"] params = { "cashPath": int(time.time() * 1000) } res = http.get(urljoin(self.url, flashvars["country"]), params=params) if not res: return language = http.xml(res, schema=_language_schema) api_params = {} for key in ("ss_id", "mv_id", "device_cd", "ss1_prm", "ss2_prm", "ss3_prm"): if flashvars.get(key, ""): api_params[key] = flashvars[key] aeskey = number.long_to_bytes(random.getrandbits(8 * 32), 32) params = { "s": flashvars["s"], "c": language, "e": self.url, "d": aes_encrypt(aeskey, json.dumps(api_params)), "a": rsa_encrypt(pubkey_pem, aeskey) } res = http.get(urljoin(self.url, flashvars["init"]), params=params) if not res: return rtn = http.json(res, schema=_init_schema) if not rtn: return init_data = parse_json(aes_decrypt(aeskey, rtn)) parsed = urlparse(init_data["play_url"]) if parsed.scheme != "https" or not parsed.path.startswith("/i/") or not parsed.path.endswith("/master.m3u8"): return hlsstream_url = init_data["play_url"] streams = HLSStream.parse_variant_playlist(self.session, hlsstream_url) if "caption_url" in init_data: if self.get_option("mux_subtitles") and FFMPEGMuxer.is_usable(self.session): res = http.get(init_data["caption_url"]) srt = http.xml(res, ignore_ns=True, schema=_xml_to_srt_schema) subfiles = [] metadata = {} for i, lang, srt in ((i, s[0], s[1]) for i, s in enumerate(srt)): subfile = tempfile.TemporaryFile() subfile.write(srt.encode("utf8")) subfile.seek(0) subfiles.append(FileStream(self.session, fileobj=subfile)) metadata["s:s:{0}".format(i)] = ["language={0}".format(lang)] for n, s in streams.items(): yield n, MuxedStream(self.session, s, *subfiles, maps=list(range(0, len(metadata) + 1)), metadata=metadata) return else: self.logger.info("Subtitles: {0}".format(init_data["caption_url"])) for s in streams.items(): yield s
def _get_streams(self): match = _url_re.match(self.url) subdomain = match.group("subdomain") http.verify = False http.mount('https://', HTTPAdapter(max_retries=99)) if subdomain == 'v': vid = match.group("vid") headers = { "User-Agent": useragents.ANDROID, "X-Requested-With": "XMLHttpRequest" } res = http.get(VAPI_URL.format(vid), headers=headers) room = http.json(res, schema=_vapi_schema) yield "source", HLSStream(self.session, room["video_url"]) return channel = match.group("channel") try: channel = int(channel) except ValueError: channel = http.get(self.url, schema=_room_id_schema) if channel is None: channel = http.get(self.url, schema=_room_id_alt_schema) http.headers.update({'User-Agent': useragents.WINDOWS_PHONE_8}) cdns = ["ws", "tct", "ws2", "dl"] ts = int(time.time()) suffix = "room/{0}?aid=wp&cdn={1}&client_sys=wp&time={2}".format( channel, cdns[0], ts) sign = hashlib.md5((suffix + API_SECRET).encode()).hexdigest() res = http.get(API_URL.format(suffix, sign)) room = http.json(res, schema=_room_schema) if not room: self.logger.info("Not a valid room url.") return if room["show_status"] != SHOW_STATUS_ONLINE: self.logger.info("Stream currently unavailable.") return url = room["hls_url"] yield "source", HLSStream(self.session, url) url = "{room[rtmp_url]}/{room[rtmp_live]}".format(room=room) if 'rtmp:' in url: stream = RTMPStream(self.session, {"rtmp": url, "live": True}) yield "source", stream else: yield "source", HTTPStream(self.session, url) multi_streams = {"middle": "low", "middle2": "medium"} for name, url in room["rtmp_multi_bitrate"].items(): url = "{room[rtmp_url]}/{url}".format(room=room, url=url) name = multi_streams[name] if 'rtmp:' in url: stream = RTMPStream(self.session, {"rtmp": url, "live": True}) yield name, stream else: yield name, HTTPStream(self.session, url)
def _get_streams(self): http.headers = {"User-Agent": useragents.CHROME} res = http.get(self.url) rlanguage = self.get_option("language") id_m = self.experience_id_re.search(res.text) experience_id = id_m and int(id_m.group(1)) if experience_id: self.logger.debug("Found experience ID: {0}", experience_id) exp = Experience(experience_id) self.logger.debug("Found episode: {0}", exp.episode_info["episodeTitle"]) self.logger.debug(" has languages: {0}", ", ".join(exp.episode_info["languages"].keys())) self.logger.debug(" requested language: {0}", rlanguage) self.logger.debug(" current language: {0}", exp.language) if rlanguage != exp.language: self.logger.debug("switching language to: {0}", rlanguage) exp.set_language(rlanguage) if exp.language != rlanguage: self.logger.warning( "Requested language {0} is not available, continuing with {1}", rlanguage, exp.language) else: self.logger.debug("New experience ID: {0}", exp.experience_id) subtitles = None stream_metadata = {} disposition = {} for subtitle in exp.subtitles(): self.logger.info("Subtitles: {0}", subtitle["src"]) if subtitle["src"].endswith( ".vtt") or subtitle["src"].endswith(".srt"): sub_lang = {"en": "eng", "ja": "jpn"}[subtitle["language"]] # pick the first suitable subtitle stream subtitles = subtitles or HTTPStream( self.session, subtitle["src"]) stream_metadata["s:s:0"] = [ "language={0}".format(sub_lang) ] stream_metadata["s:a:0"] = [ "language={0}".format(exp.language_code) ] for item in exp.sources()["items"]: url = item["src"] if ".m3u8" in url: for q, s in HLSStream.parse_variant_playlist( self.session, url).items(): if self.get_option("mux_subtitles") and subtitles: yield q, MuxedStream(self.session, s, subtitles, metadata=stream_metadata, disposition=disposition) else: yield q, s elif ".mp4" in url: # TODO: fix quality s = HTTPStream(self.session, url) if self.get_option("mux_subtitles") and subtitles: yield self.mp4_quality, MuxedStream( self.session, s, subtitles, metadata=stream_metadata, disposition=disposition) else: yield self.mp4_quality, s else: self.logger.error("Could not find experience ID?!")
def test_hls_stream(self): expected = "http://test.se/stream.m3u8" stream = HLSStream(self.session, expected) self.assertEqual(expected, stream_to_url(stream)) self.assertEqual(expected, stream.to_url())
def _get_streams(self): res = http.get(self.url, headers={'User-Agent': useragents.ANDROID}) match = self._video_data_re.search(res.text) if match is None: print(colored("\n => Performer is OFFLINE <=", "yellow", "on_red")) print(colored("\n => END <= ", 'yellow', 'on_blue')) time.sleep(6) sys.exit() if match: try: hls_streams = HLSStream.parse_variant_playlist( self.session, match.group('hls_url'), headers={'Referer': self.url}) print( colored("\n => HLS STREAMS => {} <=", "yellow", "on_blue")).format(hls_streams) for s in hls_streams.items(): rtmp_video = self._flash_data_schema.validate( match.group('flash_data')) swf = rtmp_video['playerUrl'] flashvars = rtmp_video['flashVars'] rtmp_stream = RTMPStream( self.session, { 'rtmp': rtmp_video['flashVars']['videoAppUrl'], 'playpath': rtmp_video['flashVars']['videoPlayUrl'], 'swfUrl': rtmp_video['playerUrl'] }) vpu = flashvars['videoPlayUrl'] rname = vpu.split('-')[0] wcdn = vpu.split('-')[1] print( colored("\n => PLAY URL => {} <=\n", "yellow", "on_blue")).format(vpu) vau = flashvars['videoAppUrl'] print( colored(" => APP URL => {} <=\n", "yellow", "on_blue")).format(vau) hlsurl = 'https://cam4-hls.xcdnpro.com/{}/cam4-origin-live/{}_aac/playlist.m3u8'.format( wcdn, vpu) print(colored(" => HLS URL => {} <=", "yellow", "on_blue")).format(hlsurl) while True: try: print mode = int( raw_input( colored( " => MODE => EXIT(5) => YTDL(4) => SL(3) => FFMPEG(2) => FFPLAY(1) => RTMP(0) => ", "yellow", "on_blue"))) break except ValueError: print( colored("\n => Input must be a number <=", "yellow", "on_red")) if mode == 0: mod = 'RTMP' if mode == 1: mod = 'FFPLAY' if mode == 2: mod = 'FFMPEG' if mode == 3: mod = 'SL' if mode == 4: mod = 'YTDL' if mode == 5: mod = 'EXIT' timestamp = str(time.strftime("%d%m%Y-%H%M%S")) stime = str(time.strftime("%H:%M:%S")) path = config.get('folders', 'output_folder_C4') fn = rname + '_C4_' + timestamp fn1 = rname + '_C4_' + timestamp + '.flv' fn2 = rname + '_C4_' + timestamp + '.mp4' fn3 = rname + '_C4_' + timestamp + '.ts' pf1 = (path + fn1) pf2 = (path + fn2) pf3 = (path + fn3) rtmp = config.get('files', 'rtmpdump') ffmpeg = config.get('files', 'ffmpeg') ffplay = config.get('files', 'ffplay') streamlink = config.get('files', 'streamlink') youtube = config.get('files', 'youtube') if mod == 'RTMP': print print( colored(' => RTMP-REC => {} <=', 'yellow', 'on_red')).format(fn1) print command = '{} -r"{}" -a"cam4-edge-live" -W"{}" --live -q -y"{}" -o"{}"'.format( rtmp, vau, swf, vpu, pf1) os.system(command) print(colored(" => END <=", 'yellow', 'on_blue')) if mod == 'FFPLAY': print( colored("\n => FFPLAY => {} <=", "yellow", "on_magenta")).format(fn) command = ( '{} -hide_banner -loglevel panic -i {} -infbuf -autoexit -window_title "{} * {}"' .format(ffplay, hlsurl, rname, stime)) os.system(command) print(colored(" => END <= ", "yellow", "on_blue")) if mod == 'FFMPEG': print( colored("\n => FFMPEG-REC => {} <=", "yellow", "on_red")).format(fn1) print command = ( '{} -hide_banner -loglevel panic -i {} -c:v copy -c:a aac -b:a 160k {}' .format(ffmpeg, hlsurl, pf1)) os.system(command) print(colored(" => END <= ", "yellow", "on_blue")) if mod == 'SL': print( colored('\n => SL-REC >>> {} <<<', 'yellow', 'on_red')).format(fn2) print command = ('{} hls://"{}" best -Q -o "{}"'.format( streamlink, hlsurl, pf2)) os.system(command) print(colored(" => END <= ", 'yellow', 'on_blue')) if mod == 'YTDL': print( colored('\n => YTDL-REC => {} <=', 'yellow', 'on_red')).format(fn3) command = ( '{} --hls-use-mpegts --no-part -q {} -o {}'.format( youtube, hlsurl, pf3)) os.system(command) print(colored("\n => END <= ", 'yellow', 'on_blue')) if mod == 'EXIT': print(colored("\n => END <= ", 'yellow', 'on_blue')) time.sleep(3) sys.exit() except Exception as e: if '404' in str(e): print( colored("\n => Performer is AWAY or PRIVATE <=", "yellow", "on_red")) print(colored("\n => END <= ", 'yellow', 'on_blue')) time.sleep(6) sys.exit()
def _get_streams(self): res = self.session.http.get(self.url) match = self.playervars_re.search(res.text) if match: stream_url = match.group(1) return HLSStream.parse_variant_playlist(self.session, stream_url)
def _get_streams(self): self.session.http.headers.update({"User-Agent": useragents.CHROME, "Referer": self.url}) hls_url = self.session.http.get(self.url, schema=self._schema_hls) if hls_url: return HLSStream.parse_variant_playlist(self.session, hls_url)
def _get_streams(self): hls_url = self._get_data() if not hls_url: return log.debug('URL={0}'.format(hls_url)) return HLSStream.parse_variant_playlist(self.session, hls_url)
def _get_streams(self): stream_url = self.stream_schema.validate(http.get(self.url).text) if stream_url: return HLSStream.parse_variant_playlist(self.session, stream_url)
def _get_streams(self): self.session.http.headers.update({'User-Agent': useragents.IPAD}) self.session.http.verify = False log.warning('SSL certificate verification is disabled.') # fetch requested url and find playlist info response = self.session.http.get(self.url) info = self._find_playlist_info(response) if not info: # do next try with new API def _fallback_api(*args, **kwargs): self.api2 = CeskatelevizeAPI2(self.session, self.url, *args, **kwargs) return self.api2._get_streams() # playlist info not found, let's try to find player url player_url = self._find_player_url(response) if not player_url: log.debug( 'Cannot find playlist info or player url, do next try with new API' ) return _fallback_api(res=response) # get player url and try to find playlist info in it response = self.session.http.get(player_url) info = self._find_playlist_info(response) if not info: log.debug( 'Cannot find playlist info in the player url, do next try with new API' ) return _fallback_api() log.trace('{0!r}'.format(info)) data = { 'playlist[0][type]': info['type'], 'playlist[0][id]': info['id'], 'requestUrl': '/ivysilani/embed/iFramePlayer.php', 'requestSource': 'iVysilani', 'type': 'html' } headers = { 'x-addr': '127.0.0.1', } # fetch playlist url response = self.session.http.post(self.ajax_url, data=data, headers=headers) json_data = self.session.http.json(response, schema=self._playlist_url_schema) log.trace('{0!r}'.format(json_data)) if json_data['url'] in ['Error', 'error_region']: log.error('This stream is not available') return # fetch playlist response = self.session.http.post(json_data['url']) json_data = self.session.http.json(response, schema=self._playlist_schema) log.trace('{0!r}'.format(json_data)) playlist = json_data['playlist'][0]['streamUrls']['main'] return HLSStream.parse_variant_playlist(self.session, playlist)
def _get_streams_for_feed(self, feed, audio_only=False): """Get HLS streams for the specified broadcast feed.""" event_id = feed.get("eventId") content_id = feed.get("mediaPlaybackId") feed_type = feed.get("mediaFeedType") streams = {} if not self._session_key: self._get_session_key(event_id) url = "{}/stream".format(_MEDIA_API_URL) if audio_only: scenario = "HTTP_CLOUD_AUDIO" else: scenario = "HTTP_CLOUD_WIRED_60_ADS" params = { "contentId": content_id, "playbackScenario": scenario, "sessionKey": self._session_key, "auth": "response", "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() if json.get("status_code") != 1: log.debug("Could not get streams for {}/{}: {}".format( event_id, content_id, json.get("status_message"))) return streams for attr in json.get("session_info", {}).get("sessionAttributes", []): name = attr.get("attributeName") if name == "mediaAuth_v2": auth = attr.get("attributeValue", "") if self._media_auth != auth: cookie = requests.cookies.create_cookie(name, auth, domain=".nhl.com") self.session.http.cookies.set_cookie(cookie) for event in json.get("user_verified_event", []): for content in event.get("user_verified_content", []): for media in content.get("user_verified_media_item", {}): if media.get("auth_status") != "SuccessStatus": msg = ( "Your account is not authorized to view this content." " Accounts without an active NHL.tv subscription can only view" " designated free games. Please refer to NHL.com to see a schedule" " of upcoming free games.") raise PluginError(msg) if (media.get("blackout_status", {}).get("status") != "SuccessStatus"): msg = ( "This content is unavailable in your region due to NHL blackout restrictions." " For more information visit: https://www.nhl.com/info/nhltv-blackout-detector" ) raise PluginError(msg) url = media.get("url") if url: prefix = "{}_".format(feed_type.lower()) if audio_only: name_fmt = "audio" else: name_fmt = None parsed = HLSStream.parse_variant_playlist( self.session, url, name_fmt=name_fmt, name_prefix=prefix) for name, stream in parsed.items(): if name.endswith("_alt"): # 720p_alt is actually 720p60, not an alternate url name = "{}60".format(name[:-4]) streams[name] = stream return streams
def _get_streams(self): self.session.http.headers = {"User-Agent": useragents.CHROME} res = self.session.http.get(self.url) # remap en to english, and ja to japanese rlanguage = { "en": "english", "ja": "japanese" }.get( self.get_option("language").lower(), self.get_option("language").lower()) if "_Incapsula_Resource" in res.text: log.error("This page is protected by Incapsula, please see " "https://github.com/streamlink/streamlink/issues/2088" " for a workaround.") return if "Out of Territory" in res.text: log.error( "The content requested is not available in your territory.") return id_m = self.experience_id_re.search(res.text) experience_id = id_m and int(id_m.group(1)) if experience_id: log.debug("Found experience ID: {0}", experience_id) exp = Experience(self.session, experience_id) if self.get_option("email") and self.get_option("password"): if exp.login(self.get_option("email"), self.get_option("password")): log.info("Logged in to Funimation as {0}", self.get_option("email")) else: log.warning("Failed to login") if exp.episode_info: log.debug("Found episode: {0}", exp.episode_info["episodeTitle"]) log.debug(" has languages: {0}", ", ".join(exp.episode_info["languages"].keys())) log.debug(" requested language: {0}", rlanguage) log.debug(" current language: {0}", exp.language) if rlanguage != exp.language: log.debug("switching language to: {0}", rlanguage) exp.set_language(rlanguage) if exp.language != rlanguage: log.warning( "Requested language {0} is not available, continuing with {1}", rlanguage, exp.language) else: log.debug("New experience ID: {0}", exp.experience_id) subtitles = None stream_metadata = {} disposition = {} for subtitle in exp.subtitles(): log.debug("Subtitles: {0}", subtitle["src"]) if subtitle["src"].endswith( ".vtt") or subtitle["src"].endswith(".srt"): sub_lang = { "en": "eng", "ja": "jpn" }[subtitle["language"]] # pick the first suitable subtitle stream subtitles = subtitles or HTTPStream( self.session, subtitle["src"]) stream_metadata["s:s:0"] = [ "language={0}".format(sub_lang) ] stream_metadata["s:a:0"] = [ "language={0}".format(exp.language_code) ] sources = exp.sources() if 'errors' in sources: for error in sources['errors']: log.error("{0} : {1}".format(error['title'], error['detail'])) return for item in sources["items"]: url = item["src"] if ".m3u8" in url: for q, s in HLSStream.parse_variant_playlist( self.session, url).items(): if self.get_option("mux_subtitles") and subtitles: yield q, MuxedStream(self.session, s, subtitles, metadata=stream_metadata, disposition=disposition) else: yield q, s elif ".mp4" in url: # TODO: fix quality s = HTTPStream(self.session, url) if self.get_option("mux_subtitles") and subtitles: yield self.mp4_quality, MuxedStream( self.session, s, subtitles, metadata=stream_metadata, disposition=disposition) else: yield self.mp4_quality, s else: log.error("Could not find experience ID?!")
def _get_streams(self): res = self.session.http.get(self.url) m = self.cam_name_re.search(res.text) cam_name = m and m.group("name") json_base = self.cam_data_schema.validate(res.text) cam_data = json_base["cam"][cam_name] log.debug("Found cam for {0} - {1}".format(cam_data["group"], cam_data["title"])) is_live = (cam_data["liveon"] == "true" and cam_data["defaulttab"] == "live") # HLS data hls_domain = cam_data["html5_streamingdomain"] hls_playpath = cam_data["html5_streampath"] # RTMP data rtmp_playpath = "" if is_live: n = "live" rtmp_domain = cam_data["streamingdomain"] rtmp_path = cam_data["livestreamingpath"] rtmp_live = cam_data["liveon"] if rtmp_path: match = self.playpath_re.search(rtmp_path) rtmp_playpath = match.group("file") rtmp_url = rtmp_domain + match.group("folder") else: n = "vod" rtmp_domain = cam_data["archivedomain"] rtmp_path = cam_data["archivepath"] rtmp_live = cam_data["archiveon"] if rtmp_path: rtmp_playpath = rtmp_path rtmp_url = rtmp_domain # RTMP stream if rtmp_playpath: log.debug("RTMP URL: {0}{1}".format(rtmp_url, rtmp_playpath)) params = { "rtmp": rtmp_url, "playpath": rtmp_playpath, "pageUrl": self.url, "swfUrl": self.swf_url, "live": rtmp_live } yield n, RTMPStream(self.session, params) # HLS stream if hls_playpath and is_live: hls_url = hls_domain + hls_playpath hls_url = update_scheme(self.url, hls_url) log.debug("HLS URL: {0}".format(hls_url)) for s in HLSStream.parse_variant_playlist(self.session, hls_url).items(): yield s if not (rtmp_playpath or hls_playpath): log.error("This cam stream appears to be in offline or " "snapshot mode and not live stream can be played.") return
def _get_streams(self): # Retrieve geolocation data res = http.get(self.GEO_URL) geo = http.json(res, schema=self._geo_schema) country_code = geo['reponse']['geo_info']['country_code'] # Retrieve URL page and search for video ID res = http.get(self.url) if 'france.tv' in self.url: match = self._pluzz_video_id_re.search(res.text) elif 'ludo.fr' in self.url or 'zouzous.fr' in self.url: match = self._jeunesse_video_id_re.search(res.text) elif 'france3-regions.francetvinfo.fr' in self.url: match = self._f3_regions_video_id_re.search(res.text) elif 'sport.francetvinfo.fr' in self.url: match = self._sport_video_id_re.search(res.text) if match is None: return video_id = match.group('video_id') # Retrieve SWF player URL swf_url = None res = http.get(self.PLAYER_GENERATOR_URL) player_url = update_scheme(self.url, http.json(res, schema=self._player_schema)['result']) res = http.get(player_url) match = self._swf_re.search(res.text) if match is not None: swf_url = update_scheme(self.url, match.group(0)) res = http.get(self.API_URL.format(video_id)) videos = http.json(res, schema=self._api_schema) now = time.time() offline = False geolocked = False drm = False expired = False streams = [] for video in videos['videos']: video_url = video['url'] # Check whether video format is available if video['statut'] != 'ONLINE': offline = offline or True continue # Check whether video format is geo-locked if video['geoblocage'] is not None and country_code not in video['geoblocage']: geolocked = geolocked or True continue # Check whether video is DRM-protected if video['drm']: drm = drm or True continue # Check whether video format is expired available = False for interval in video['plages_ouverture']: available = (interval['debut'] or 0) <= now <= (interval['fin'] or sys.maxsize) if available: break if not available: expired = expired or True continue # TODO: add DASH streams once supported if '.mpd' in video_url: continue if '.f4m' in video_url or 'france.tv' in self.url: res = http.get(self.TOKEN_URL.format(video_url)) video_url = res.text if '.f4m' in video_url and swf_url is not None: for bitrate, stream in HDSStream.parse_manifest(self.session, video_url, is_akamai=True, pvswf=swf_url).items(): # HDS videos with data in their manifest fragment token # doesn't seem to be supported by HDSStream. Ignore such # stream (but HDS stream having only the hdntl parameter in # their manifest token will be provided) pvtoken = stream.request_params['params'].get('pvtoken', '') match = self._hds_pv_data_re.search(pvtoken) if match is None: streams.append((bitrate, stream)) elif '.m3u8' in video_url: for stream in HLSStream.parse_variant_playlist(self.session, video_url).items(): streams.append(stream) # HBB TV streams are not provided anymore by France Televisions elif '.mp4' in video_url and '/hbbtv/' not in video_url: match = self._mp4_bitrate_re.match(video_url) if match is not None: bitrate = match.group('bitrate') else: # Fallback bitrate (seems all France Televisions MP4 videos # seem have such bitrate) bitrate = '1500k' streams.append((bitrate, HTTPStream(self.session, video_url))) if self.get_option("mux_subtitles") and videos['subtitles'] != []: substreams = {} for subtitle in videos['subtitles']: # TTML subtitles are available but not supported by FFmpeg if subtitle['format'] == 'ttml': continue substreams[subtitle['type']] = HTTPStream(self.session, subtitle['url']) for quality, stream in streams: yield quality, MuxedStream(self.session, stream, subtitles=substreams) else: for stream in streams: yield stream if offline: self.logger.error('Failed to access stream, may be due to offline content') if geolocked: self.logger.error('Failed to access stream, may be due to geo-restricted content') if drm: self.logger.error('Failed to access stream, may be due to DRM-protected content') if expired: self.logger.error('Failed to access stream, may be due to expired content')
def _resolve_playlist(self, playlist_all): playlist_referer = self.get_option('playlist_referer') or self.url self.session.http.headers.update({'Referer': playlist_referer}) playlist_max = self.get_option('playlist_max') or 5 count_playlist = { 'dash': 0, 'hds': 0, 'hls': 0, 'http': 0, } o = urlparse(self.url) origin_tuple = ( '.cloudfront.net', '.metube.id', ) for url in playlist_all: parsed_url = urlparse(url) if parsed_url.netloc.endswith(origin_tuple): self.session.http.headers.update({ 'Origin': '{0}://{1}'.format(o.scheme, o.netloc), }) if (parsed_url.path.endswith(('.m3u8')) or parsed_url.query.endswith(('.m3u8'))): if count_playlist['hls'] >= playlist_max: log.debug('Skip - {0}'.format(url)) continue try: streams = HLSStream.parse_variant_playlist(self.session, url).items() if not streams: yield 'live', HLSStream(self.session, url) for s in streams: yield s log.debug('HLS URL - {0}'.format(url)) count_playlist['hls'] += 1 except Exception as e: log.error('Skip HLS with error {0}'.format(str(e))) elif (parsed_url.path.endswith(('.f4m')) or parsed_url.query.endswith(('.f4m'))): if count_playlist['hds'] >= playlist_max: log.debug('Skip - {0}'.format(url)) continue try: for s in HDSStream.parse_manifest(self.session, url).items(): yield s log.debug('HDS URL - {0}'.format(url)) count_playlist['hds'] += 1 except Exception as e: log.error('Skip HDS with error {0}'.format(str(e))) elif (parsed_url.path.endswith(('.mp3', '.mp4')) or parsed_url.query.endswith(('.mp3', '.mp4'))): if count_playlist['http'] >= playlist_max: log.debug('Skip - {0}'.format(url)) continue try: name = 'vod' m = self._httpstream_bitrate_re.search(url) if m: bitrate = m.group('bitrate') resolution = m.group('resolution') if bitrate: name = '{0}k'.format(m.group('bitrate')) elif resolution: name = resolution yield name, HTTPStream(self.session, url) log.debug('HTTP URL - {0}'.format(url)) count_playlist['http'] += 1 except Exception as e: log.error('Skip HTTP with error {0}'.format(str(e))) elif (parsed_url.path.endswith(('.mpd')) or parsed_url.query.endswith(('.mpd'))): if count_playlist['dash'] >= playlist_max: log.debug('Skip - {0}'.format(url)) continue try: for s in DASHStream.parse_manifest(self.session, url).items(): yield s log.debug('DASH URL - {0}'.format(url)) count_playlist['dash'] += 1 except Exception as e: log.error('Skip DASH with error {0}'.format(str(e))) else: log.error('parsed URL - {0}'.format(url))
def _get_streams(self): match = _url_re.match(self.url) prefix = match.group("prefix") channel = match.group("channel") res = self.session.http.get(self.url) if prefix == 'xingyan.': roominfo = _roominfo_re.search(res.text).group(1) roominfo = json.loads(roominfo) videoinfo = roominfo['videoinfo'] if videoinfo['hlsurl']: yield 'source', HLSStream(self.session, videoinfo['hlsurl']) # wangsu cdn prior to others, wangsu = 0, alicloud = 1, qcloud = videoinfo['streamurl'] _cdn = 0 if videoinfo['zl'][_cdn]['streamurl']: yield 'source', HTTPStream(self.session, videoinfo['zl'][_cdn]['streamurl']) if videoinfo['zl'][_cdn]['streamtrans']['mid']: yield 'medium', HTTPStream(self.session, videoinfo['zl'][_cdn]['streamtrans']['mid']) if videoinfo['zl'][_cdn]['streamtrans']['small']: yield 'low', HTTPStream(self.session, videoinfo['zl'][_cdn]['streamtrans']['small']) return try: channel = int(channel) except ValueError: channel = _room_id_re.search(res.text).group(1) ts = int(time.time()) url = ROOM_API_V2.format(channel, ts) res = self.session.http.get(url) try: status = _status_re.search(res.text).group(1) room_key = _room_key_re.search(res.text).group(1) hostid = _hostid_re.search(res.text).group(1) param = _param_re.search(res.text).group(1) tt = _time_re.search(res.text).group(1) sign = _sign_re.search(res.text).group(1) sd = _sd_re.search(res.text).group(1) hd = _hd_re.search(res.text).group(1) od = _od_re.search(res.text).group(1) except AttributeError: self.logger.info("Not a valid room url.") return if status != '2': self.logger.info("Stream currently unavailable.") return ts = int(time.time()) param = param.replace("\\", "") param = quote(param) url = ROOM_API.format(hostid, channel, room_key, ts, param, tt, sign) room = self.session.http.get(url) data = self.session.http.json(room, schema=_room_schema) if not isinstance(data, dict): self.logger.info("Please Check PandaTV Room API") return videoinfo = data.get('videoinfo') plflag_list = videoinfo.get('plflag_list') if not videoinfo or not plflag_list: self.logger.info("Please Check PandaTV Room API") return plflag = videoinfo.get('plflag') if not plflag or '_' not in plflag: self.logger.info("Please Check PandaTV Room API") return plflag_list = json.loads(plflag_list) backup = plflag_list["backup"] rid = plflag_list["auth"]["rid"] sign = plflag_list["auth"]["sign"] ts = plflag_list["auth"]["time"] backup.append(plflag) plflag0 = backup plflag0 = [i.split('_')[1] for i in plflag0] # let wangsu cdn priority, flag can see here in "H5PLAYER_CDN_LINES": # https://www.panda.tv/cmstatic/global-config.js lines = ["3", "4"] try: plflag1 = [i for i in plflag0 if i in lines][0] except IndexError: plflag1 = plflag0[0] if sd == '1': yield 'source', HTTPStream(self.session, SD_URL_PATTERN.format(plflag1, room_key, sign, ts, rid)) if hd == '1': yield 'medium', HTTPStream(self.session, HD_URL_PATTERN.format(plflag1, room_key, sign, ts, rid)) if od == '1': yield 'low', HTTPStream(self.session, OD_URL_PATTERN.format(plflag1, room_key, sign, ts, rid)) return
def _get_streams(self): match = _url_re.match(self.url) subdomain = match.group("subdomain") http.verify = False http.mount('https://', HTTPAdapter(max_retries=99)) http.headers.update({ 'User-Agent': useragents.CHROME, 'Referer': self.url }) dir = os.path.dirname(os.path.abspath(__file__)) node_modules = os.path.join(dir, 'douyutv') os.environ['NODE_PATH'] = node_modules did = uuid.uuid4().hex env = os.environ.copy() self.logger.debug(env['PATH']) try: Popen(['node', '-v'], stdout=PIPE, stderr=PIPE, env=env).communicate() except (OSError, IOError) as err: self.logger.info( str(err) + "\n" "Please install Node.js first.\n" "If you have installed Node.js but still show this message,\n" "please reboot computer.") if is_win32: self.logger.info( "If you are using windows portable version,\n" "you can copy node.exe to the same folder as streamlink.exe." ) return if subdomain == 'v': vid = match.group("vid") tt = int(time.time()) process = Popen([ 'node', node_modules + '/douyutv_vsigner.js', str(vid), str(tt), did ], stdout=PIPE, stderr=PIPE, env=env) res = process.communicate()[0].decode() sign = _sign_re.search(res).group(1) data = {"vid": vid, "did": did, "tt": tt, "sign": sign} if args.http_cookie: res = http.post(VAPI_URL, data=data) else: cookie = dict(acf_auth='') res = http.post(VAPI_URL, data=data, cookies=cookie) if _supern_re.search(res.text): self.logger.info( "This video has source quality, but need logged-in cookie.\n" "Copy acf_auth value in cookie with option '--http-cookie acf_auth=value'." ) if is_win32: self.logger.info( "If you are using windows version,\n" "The percent symbol '%' in cookie must be modified to '%%' in command-line and batch file." ) if _super_re.search(res.text): room = http.json(res, schema=_vapi_schema) yield "source", HLSStream(self.session, room["thumb_video"]["super"]["url"]) yield "medium", HLSStream(self.session, room["thumb_video"]["high"]["url"]) yield "low", HLSStream(self.session, room["thumb_video"]["normal"]["url"]) else: room = http.json(res, schema=_vapin_schema) try: yield "medium", HLSStream( self.session, room["thumb_video"]["high"]["url"]) except: pass yield "low", HLSStream(self.session, room["thumb_video"]["normal"]["url"]) return channel = match.group("channel") try: channel = int(channel) except ValueError: res = http.get(self.url) try: channel = _room_id_re.search(res.text).group(1) except AttributeError: room_list = _room_id_alt_re.findall(res.text) try: ops = _index_re.search(self.url).group(1) channel = room_list[int(ops)] except AttributeError: try: self.logger.info( "Available sub-channels: {0}".format(room_list)) ops = _channel_re.search(self.url).group(1) channel = room_list[int(ops) - 1] except AttributeError: self.logger.info( "You can add '?ch=number' after url to choose channel,\n" "if no query string, default use '?ch=1' for first channel in list." ) channel = room_list[0] ts = int(time.time() / 60) sign = hashlib.md5(("{0}{1}{2}".format(channel, API_SECRET, ts)).encode()).hexdigest() res = http.get(API_URL.format(channel, ts, sign)) room = http.json(res, schema=_room_schema) if not room: self.logger.info("Not a valid room url.") return if room["show_status"] != SHOW_STATUS_ONLINE: self.logger.info("Stream currently unavailable.") return cdns = room["cdns"] try: self.logger.info("Available cdns: {0}".format(cdns)) cdn = _cdn_re.search(self.url).group(1) except AttributeError: self.logger.info( "You can add '?cdn=CDN_name' after url to choose CDN,\n" "if no query string, default use '?cdn=ws' for ws CDN.") cdn = "ws" h5js = http.get(H5JS_URL) ver = _h5ver_re.search(h5js.text).group(1) tt = int(time.time() / 60) process = Popen([ 'node', node_modules + '/douyutv1_signer.js', str(channel), str(tt), did ], stdout=PIPE, stderr=PIPE, env=env) res = process.communicate()[0].decode() sign = _sign_re.search(res).group(1) cptl = _sign_re.search(res).group(2) self.logger.info("Now channel: {0}, CDN: {1}".format(channel, cdn)) rate = [0, 4, 2, 1] quality = ["source", "high", "medium", "low"] for i in range(0, 4, 1): room = self._get_room_json(channel, cdn, rate[i], ver, tt, did, sign, cptl) url = "{room[rtmp_url]}/{room[rtmp_live]}".format(room=room) if 'rtmp:' in url: stream = RTMPStream(self.session, {"rtmp": url, "live": True}) yield quality[i], stream else: yield quality[i], HTTPStream(self.session, url) if room["is_mixed"]: url = "{room[mixed_url]}/{room[mixed_live]}".format(room=room) yield "mix", HTTPStream(self.session, url)
def _get_streams(self): match = url_re.match(self.url) stream_page_scheme = 'https' stream_page_domain = match.group(4) stream_page_path = match.group(5) country_code = CONST_DEFAULT_COUNTRY_CODE # create http session and set headers http_session = http http_session.headers.update(CONST_HEADERS) # get cookies r = http_session.get( urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', ''))) # redirect to profile page means stream is offline if '/profile/' in r.url: print(colored('\n => Performer is OFFLINE <=', 'yellow', 'on_red')) print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(6) sys.exit() if not r.ok: self.logger.debug('Status code for {0}: {1}', r.url, r.status_code) raise NoStreamsError(self.url) if len(http_session.cookies) == 0: raise PluginError("Can't get a cookies") if urlparse(r.url).netloc != stream_page_domain: # then redirected to regional subdomain country_code = urlparse(r.url).netloc.split('.')[0].lower() # time to set variables baseurl = urlunparse( (stream_page_scheme, urlparse(r.url).netloc, '', '', '', '')) amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION) stream_page_url = urljoin(baseurl, stream_page_path) headers = { 'User-Agent': useragents.CHROME, 'Referer': stream_page_url, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format( stream_page_path) self.logger.debug('DATA: {0}'.format(str(data))) # send request and close http-session r = http_session.post(url=amf_gateway_url, headers=headers, params={CONST_AMF_GATEWAY_PARAM: country_code}, data=data) http_session.close() if r.status_code != 200: raise PluginError('unexpected status code for {0}: {1}', r.url, r.status_code) stream_source_info = amf_msg_schema.validate(json.loads(r.text)) self.logger.debug('source stream info:\n{0}', stream_source_info) if not stream_source_info: return performer = stream_source_info['performerData']['username'] real_name = stream_source_info['performerData']['displayName'] performer_id = stream_source_info['performerData']['userId'] print(colored('\n => Performer => {} <=', 'yellow', 'on_blue')).format(real_name) print(colored('\n => Performer ID => {} <=', 'yellow', 'on_blue')).format(performer_id) urlnoproto = stream_source_info['localData']['videoServerUrl'] urlnoproto = update_scheme('https://', urlnoproto) hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format( urlnoproto, performer) server = re.sub('https://', '', urlnoproto) print(colored('\n => Server => {} <=', 'yellow', 'on_blue')).format(server) if hls_url: try: for s in HLSStream.parse_variant_playlist( self.session, hls_url, headers=headers).items(): timestamp = str(time.strftime('%d%m%Y-%H%M%S')) path = config.get('folders', 'output_folder_BC') fn = real_name + '_BC_' + timestamp + '.mp4' pf = (path + fn) streamlink = config.get('files', 'streamlink') print( colored('\n => SL-24/7-REC => {} <=', 'yellow', 'on_red')).format(fn) print command = ('{} hls://"{}" best -Q -o "{}"'.format( streamlink, hls_url, pf)) os.system(command) print(colored(' => END <= ', 'yellow', 'on_blue')) sys.exit() except Exception as e: if '404' in str(e): print( colored('\n => Performer is AWAY or PRIVATE <=', 'yellow', 'on_red')) print(colored('\n => END <= ', 'yellow', 'on_blue')) time.sleep(6) sys.exit()
def _make_stream(self, url): if url and url.endswith("flv"): return HTTPStream(self.session, url) elif url and url.endswith("m3u8"): return HLSStream(self.session, url)
def _get_streams(self): # Get video ID and channel from URL match = self._url_re.match(self.url) channel = match.group('channel') if channel is None: # Replay website channel = match.group('replay_channel') video_id = match.group('replay_video_id') else: video_id = match.group('video_id') if video_id is None: # Retrieve URL page and search for video ID res = http.get(self.url) match = self._video_id_re.search(res.text) if match is None: return video_id = match.group('video_id') res = http.get(self.API_URL.format(self.CHANNEL_MAP[channel], video_id)) videos = http.json(res, schema=self._api_schema) parsed = [] headers = {'User-Agent': self._user_agent} for quality, video_url in list(videos['MEDIA']['VIDEOS'].items()): # Ignore empty URLs if video_url == '': continue # Ignore duplicate video URLs if video_url in parsed: continue parsed.append(video_url) try: if '.f4m' in video_url: for stream in HDSStream.parse_manifest( self.session, video_url, params={ 'hdcore': self.HDCORE_VERSION }, headers=headers).items(): yield stream elif '.m3u8' in video_url: for stream in HLSStream.parse_variant_playlist( self.session, video_url, headers=headers).items(): yield stream elif '.mp4' in video_url: # Get bitrate from video filename match = self._mp4_bitrate_re.match(video_url) if match is not None: bitrate = match.group('bitrate') else: bitrate = quality yield bitrate, HTTPStream(self.session, video_url, params={'secret': self.SECRET}, headers=headers) except PluginError: self.logger.error( 'Failed to access stream, may be due to geo-restriction') raise
def _get_vod_stream(self, page): data = self.data_schema.validate(page.text) if data: return HLSStream.parse_variant_playlist(self.session, data["vod"])
def _get_streams(self): stream_url, params = self.get_stream_url(self.get_event_id(self.url)) return HLSStream.parse_variant_playlist(self.session, stream_url, params=params)
def _get_streams(self): return HLSStream.parse_variant_playlist(self.session, self.session.http.get(self.api_url, schema=self.api_schema))
def _get_streams(self): match = url_re.match(self.url) stream_page_scheme = 'https' stream_page_domain = match.group(4) stream_page_path = match.group(5) country_code = CONST_DEFAULT_COUNTRY_CODE # create http session and set headers http_session = http http_session.headers.update(CONST_HEADERS) # get cookies r = http_session.get( urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', ''))) # redirect to profile page means stream is offline if '/profile/' in r.url: raise NoStreamsError(self.url) if not r.ok: self.logger.debug("Status code for {0}: {1}", r.url, r.status_code) raise NoStreamsError(self.url) if len(http_session.cookies) == 0: raise PluginError("Can't get a cookies") if urlparse(r.url).netloc != stream_page_domain: # then redirected to regional subdomain country_code = urlparse(r.url).netloc.split('.')[0].lower() # time to set variables baseurl = urlunparse( (stream_page_scheme, urlparse(r.url).netloc, '', '', '', '')) amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION) stream_page_url = urljoin(baseurl, stream_page_path) headers = { 'User-Agent': useragents.CHROME, 'Referer': stream_page_url, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format( stream_page_path) self.logger.debug('DATA: {0}'.format(str(data))) # send request and close http-session r = http_session.post(url=amf_gateway_url, headers=headers, params={CONST_AMF_GATEWAY_PARAM: country_code}, data=data) http_session.close() if r.status_code != 200: raise PluginError("unexpected status code for {0}: {1}", r.url, r.status_code) stream_source_info = amf_msg_schema.validate(json.loads(r.text)) self.logger.debug("source stream info:\n{0}", stream_source_info) if not stream_source_info: return urlnoproto = stream_source_info['localData']['videoServerUrl'] urlnoproto = update_scheme('https://', urlnoproto) performer = stream_source_info['performerData']['username'] hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format( urlnoproto, performer) if hls_url: self.logger.debug('HLS URL: {0}'.format(hls_url)) try: for s in HLSStream.parse_variant_playlist( self.session, hls_url, headers=headers).items(): yield s except Exception as e: if '404' in str(e): self.logger.error('Stream is currently offline or private') else: self.logger.error(str(e)) return