class ard_live(Plugin): swf_url = "http://live.daserste.de/lib/br-player/swf/main.swf" _url_re = re.compile(r"https?://(www.)?daserste.de/", re.I) _player_re = re.compile(r'''dataURL\s*:\s*(?P<q>['"])(?P<url>.*?)(?P=q)''') _player_url_schema = validate.Schema( validate.transform(_player_re.search), validate.any(None, validate.all(validate.get("url"), validate.text))) _livestream_schema = validate.Schema( validate.xml_findall(".//assets"), validate.filter(lambda x: x.attrib.get("type") != "subtitles"), validate.get(0), validate.xml_findall(".//asset"), [ validate.union({ "url": validate.xml_findtext("./fileName"), "bitrate": validate.xml_findtext("./bitrateVideo") }) ]) @classmethod def can_handle_url(cls, url): return cls._url_re.match(url) is not None def _get_streams(self): data_url = http.get(self.url, schema=self._player_url_schema) if data_url: res = http.get(urljoin(self.url, data_url)) stream_info = http.xml(res, schema=self._livestream_schema) for stream in stream_info: url = stream["url"] try: if ".m3u8" in url: for s in HLSStream.parse_variant_playlist( self.session, url, name_key="bitrate").items(): yield s elif ".f4m" in url: for s in HDSStream.parse_manifest( self.session, url, pvswf=self.swf_url, is_akamai=True).items(): yield s elif ".mp4" in url: yield "{0}k".format(stream["bitrate"]), HTTPStream( self.session, url) except IOError as err: self.logger.warning("Error parsing stream: {0}", err)
def test_xml_findtext(self): el = Element("foo") el.text = "bar" assert validate(xml_findtext("."), el) == "bar"
class Neulion(Plugin): """Livecli Plugin for websites based on Neulion Example urls can be found in tests/test_plugin_neulion.py """ url_re = re.compile( r"""https?:// (?P<domain> www\.(?: ufc\.tv | elevensports\.(?:be|lu|pl|sg|tw) | tennischanneleverywhere\.com ) | watch\.(?: nba\.com | rugbypass\.com ) | fanpass\.co\.nz ) /(?P<vtype>channel|game|video)/.+""", re.VERBOSE) video_info_re = re.compile(r"""program\s*=\s*(\{.*?});""", re.DOTALL) channel_info_re = re.compile(r"""g_channel\s*=\s(\{.*?});""", re.DOTALL) current_video_re = re.compile( r"""(?:currentVideo|video)\s*=\s*(\{[^;]+});""", re.DOTALL) info_fallback_re = re.compile( r""" var\s? (?: currentGameId | programId ) \s?=\s?["']?(?P<id>\d+)["']?; """, re.VERBOSE) stream_api_url = "https://{0}/service/publishpoint" auth_url = "https://{0}/secure/authenticate" auth_schema = validate.Schema(validate.xml_findtext("code")) options = PluginOptions({"username": None, "password": None}) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None @property def _domain(self): match = self.url_re.match(self.url) return match.group("domain") @property def _vtype(self): match = self.url_re.match(self.url) return match.group("vtype") def _get_stream_url(self, video_id, vtype): try: res = http.post(self.stream_api_url.format(self._domain), data={ "id": video_id, "type": vtype, "format": "json" }, headers={"User-Agent": useragents.IPHONE_6}) except Exception as e: if "400 Client Error" in str(e): self.logger.error("Login required") return else: raise e data = http.json(res) return data.get("path") def _get_info(self, text): # try to find video info first m = self.video_info_re.search(text) if not m: m = self.current_video_re.search(text) if not m: # and channel info if that fails m = self.channel_info_re.search(text) if m: js_data = m.group(1) try: return_data = js_to_json(js_data) self.logger.debug("js_to_json") except Exception: self.logger.debug("js_to_json_regex_fallback") return_data = js_to_json_regex_fallback(js_data) finally: return return_data def _get_info_fallback(self, text): info_id = self.info_fallback_re.search(text) if info_id: self.logger.debug("Found id from _get_info_fallback") return {"id": info_id.group("id")} def _login(self, username, password): res = http.post(self.auth_url.format(self._domain), data={ "username": username, "password": password, "cookielink": False }) login_status = http.xml(res, schema=self.auth_schema) self.logger.debug("Login status for {0}: {1}", username, login_status) if login_status == "loginlocked": self.logger.error( "The account {0} has been locked, the password needs to be reset" ) return login_status == "loginsuccess" def _get_streams(self): login_username = self.get_option("username") login_password = self.get_option("password") if login_username and login_password: self.logger.debug("Attempting login as {0}", login_username) if self._login(login_username, login_password): self.logger.info("Successfully logged in as {0}", login_username) else: self.logger.info("Failed to login as {0}", login_username) res = http.get(self.url) video = self._get_info(res.text) if not video: video = self._get_info_fallback(res.text) if video: self.logger.debug("Found {type}: {name}".format( type=video.get("type", self._vtype), name=video.get("name", "???"))) surl = self._get_stream_url(video["id"], video.get("type", self._vtype)) if surl: surl = surl.replace("_iphone", "") return HLSStream.parse_variant_playlist(self.session, surl) else: self.logger.error( "Could not get stream URL for video: {name} ({id})".format( id=video.get("id", "???"), name=video.get("name", "???"), )) else: self.logger.error("Could not find any video info on the page")
__livecli_docs__ = { "domains": [ "nhk.or.jp", ], "geo_blocked": [], "notes": "", "live": True, "vod": False, "last_update": "2016-11-24", } API_URL = "http://{}.nhk.or.jp/nhkworld/app/tv/hlslive_web.xml" _url_re = re.compile(r"http(?:s)?://(?:(\w+)\.)?nhk.or.jp/nhkworld") _schema = validate.Schema(validate.xml_findtext("./main_url/wstrm")) class NHKWorld(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) is not None 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 = http.get(API_URL.format(sdomain)) stream_url = http.xml(res, schema=_schema) return HLSStream.parse_variant_playlist(self.session, stream_url)
], "geo_blocked": [], "notes": "rtmpdump K-S-V", "live": True, "vod": False, "last_update": "2014-07-13", } SWF_URL = "http://play.streamingvideoprovider.com/player2.swf" API_URL = "http://player.webvideocore.net/index.php" _url_re = re.compile( r"http(s)?://(\w+\.)?streamingvideoprovider.co.uk/(?P<channel>[^/&?]+)") _hls_re = re.compile(r"'(http://.+\.m3u8)'") _rtmp_schema = validate.Schema(validate.xml_findtext("./info/url"), validate.url(scheme="rtmp")) _hls_schema = validate.Schema( validate.transform(_hls_re.search), validate.any( None, validate.all( validate.get(1), validate.url(scheme="http", path=validate.endswith("m3u8"))))) class Streamingvideoprovider(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url)
validate.optional("device_cd"): validate.text, validate.optional("ss1_prm"): validate.text, validate.optional("ss2_prm"): validate.text, validate.optional("ss3_prm"): validate.text } ), "clientlibs": validate.all( validate.transform(_clientlibs_re.search), validate.get(2), validate.text ) }) ) _language_schema = validate.Schema( validate.xml_findtext("./country_code") ) _xml_to_srt_schema = validate.Schema( validate.xml_findall(".//body/div"), [ validate.union([validate.all( validate.getattr("attrib"), validate.get("{http://www.w3.org/XML/1998/namespace}lang") ), validate.all( validate.xml_findall("./p"), validate.transform(lambda x: list(enumerate(x, 1))), [ validate.all( validate.union({
class WWENetwork(Plugin): url_re = re.compile(r"https?://network.wwe.com") content_id_re = re.compile(r'''"content_id" : "(\d+)"''') playback_scenario = "HTTP_CLOUD_WIRED" login_url = "https://secure.net.wwe.com/workflow.do" login_page_url = "https://secure.net.wwe.com/enterworkflow.do?flowId=account.login&forwardUrl=http%3A%2F%2Fnetwork.wwe.com" api_url = "https://ws.media.net.wwe.com/ws/media/mf/op-findUserVerifiedEvent/v-2.3" _info_schema = validate.Schema( validate.union({ "status": validate.union({ "code": validate.all(validate.xml_findtext(".//status-code"), validate.transform(int)), "message": validate.xml_findtext(".//status-message"), }), "urls": validate.all( validate.xml_findall(".//url"), [validate.getattr("text")] ), validate.optional("fingerprint"): validate.xml_findtext(".//updated-fingerprint"), validate.optional("session_key"): validate.xml_findtext(".//session-key"), "session_attributes": validate.all( validate.xml_findall(".//session-attribute"), [validate.getattr("attrib"), validate.union({ "name": validate.get("name"), "value": validate.get("value") })] ) }) ) options = PluginOptions({ "email": None, "password": None, }) def __init__(self, url): super(WWENetwork, self).__init__(url) http.headers.update({"User-Agent": useragents.CHROME}) self._session_attributes = Cache(filename="plugin-cache.json", key_prefix="wwenetwork:attributes") self._session_key = self.cache.get("session_key") self._authed = self._session_attributes.get("ipid") and self._session_attributes.get("fprt") @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def login(self, email, password): self.logger.debug("Attempting login as {0}", email) # sets some required cookies to login http.get(self.login_page_url) # login res = http.post(self.login_url, data=dict(registrationAction='identify', emailAddress=email, password=password, submitButton=""), headers={"Referer": self.login_page_url}, allow_redirects=False) self._authed = "Authentication Error" not in res.text if self._authed: self._session_attributes.set("ipid", res.cookies.get("ipid"), expires=3600 * 1.5) self._session_attributes.set("fprt", res.cookies.get("fprt"), expires=3600 * 1.5) return self._authed def _update_session_attribute(self, key, value): if value: self._session_attributes.set(key, value, expires=3600 * 1.5) # 1h30m expiry http.cookies.set(key, value) @property def session_key(self): return self._session_key @session_key.setter def session_key(self, value): self.cache.set("session_key", value) self._session_key = value def _get_media_info(self, content_id): """ Get the info about the content, based on the ID :param content_id: :return: """ params = {"identityPointId": self._session_attributes.get("ipid"), "fingerprint": self._session_attributes.get("fprt"), "contentId": content_id, "playbackScenario": self.playback_scenario, "platform": "WEB_MEDIAPLAYER_5", "subject": "LIVE_EVENT_COVERAGE", "frameworkURL": "https://ws.media.net.wwe.com", "_": int(time.time())} if self.session_key: params["sessionKey"] = self.session_key url = self.api_url.format(id=content_id) res = http.get(url, params=params) return http.xml(res, ignore_ns=True, schema=self._info_schema) def _get_content_id(self): # check the page to find the contentId res = http.get(self.url) m = self.content_id_re.search(res.text) if m: return m.group(1) 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"]))