class TV360(Plugin): url_re = re.compile(r"https?://(?:www.)?tv360.com.tr/CanliYayin") data_re = re.compile(r'''div.*?data-tp=(?P<q>["'])(?P<data>.*?)(?P=q)''', re.DOTALL) _js_to_json = partial(re.compile(r"""(\w+):(["']|\d+,|true|false)""").sub, r'"\1":\2') data_schema = validate.Schema( validate.transform(data_re.search), validate.any( None, validate.all( validate.get("data"), validate.transform(_js_to_json), validate.transform(lambda x: x.replace("'", '"')), validate.transform(parse_json), { "tp_type": "hls4", "tp_file": validate.url(), } ) ) ) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): res = http.get(self.url) data = self.data_schema.validate(res.text) if data: return HLSStream.parse_variant_playlist(self.session, data["tp_file"])
class TV8(Plugin): """ Support for the live stream on www.tv8.com.tr """ url_re = re.compile(r"https?://www.tv8.com.tr/canli-yayin") player_config_re = re.compile( r""" configPlayer.source.media.push[ ]*\( [ ]*\{[ ]*'src':[ ]*"(.*?)", [ ]*type:[ ]*"application/x-mpegURL"[ ]*}[ ]*\); """, re.VERBOSE) player_config_schema = validate.Schema( validate.transform(player_config_re.search), validate.any(None, validate.all(validate.get(1), validate.url()))) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): res = http.get(self.url) stream_url = self.player_config_schema.validate(res.text) if stream_url: return HLSStream.parse_variant_playlist(self.session, stream_url)
class INE(Plugin): url_re = re.compile(r"""https://streaming.ine.com/play\#?/ ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/? (.+)?""", re.VERBOSE) play_url = "https://streaming.ine.com/play/{vid}/watch" js_re = re.compile(r'''script type="text/javascript" src="(https://content.jwplatform.com/players/.*?)"''') jwplayer_re = re.compile(r'''jwplayer\(".*?"\).setup\((\{.*\})\);''', re.DOTALL) setup_schema = validate.Schema( validate.transform(jwplayer_re.search), validate.any( None, validate.all( validate.get(1), validate.transform(json.loads), {"playlist": [ {"sources": [{"file": validate.text, "type": validate.text}]} ]} ) ) ) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): vid = self.url_re.match(self.url).group(1) self.logger.debug("Found video ID: {}", vid) page = http.get(self.play_url.format(vid=vid)) js_url_m = self.js_re.search(page.text) if js_url_m: js_url = js_url_m.group(1) self.logger.debug("Loading player JS: {}", js_url) res = http.get(js_url) data = self.setup_schema.validate(res.text) for source in data["playlist"][0]["sources"]: if source["type"] == "hls": return HLSStream.parse_variant_playlist(self.session, "https:" + source["file"])
class LiveMe(Plugin): url_re = re.compile(r"https?://(www.)?liveme.com/media/play/(.*)") api_url = "http://live.ksmobile.net/live/queryinfo?userid=1&videoid={id}" api_schema = validate.Schema( validate.all( { "status": "200", "data": { "video_info": { "videosource": validate.any('', validate.url()), "hlsvideosource": validate.any('', validate.url()), } } }, validate.get("data"))) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None 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): url_params = dict(parse_qsl(urlparse(self.url).query)) video_id = url_params.get("videoid") if video_id: self.logger.debug("Found Video ID: {}", video_id) res = http.get(self.api_url.format(id=video_id)) data = http.json(res, schema=self.api_schema) hls = self._make_stream(data["video_info"]["hlsvideosource"]) video = self._make_stream(data["video_info"]["videosource"]) if hls: yield "live", hls if video: yield "live", video
class Turkuvaz(Plugin): """ Plugin to support ATV/A2TV Live streams from www.atv.com.tr and www.a2tv.com.tr """ _url_re = re.compile( r"""https?://(?:www.)? (?: (atv|a2tv|ahaber|aspor|minikago|minikacocuk).com.tr/webtv/canli-yayin| (atvavrupa).tv/webtv/videoizle/atv_avrupa/canli_yayin )""", re.VERBOSE) _hls_url = "http://trkvz-live.ercdn.net/{channel}/{channel}.m3u8" _token_url = "http://videotoken.tmgrup.com.tr/webtv/secure" _token_schema = validate.Schema( validate.all({ "Success": True, "Url": validate.url(), }, validate.get("Url"))) @classmethod def can_handle_url(cls, url): return cls._url_re.match(url) is not None def _get_streams(self): url_m = self._url_re.match(self.url) domain = url_m.group(1) or url_m.group(2) # remap the domain to channel channel = { "atv": "atvhd", "ahaber": "ahaberhd", "aspor": "asporhd" }.get(domain, domain) hls_url = self._hls_url.format(channel=channel) # get the secure HLS URL res = http.get(self._token_url, params={"url": hls_url}) secure_hls_url = http.json(res, schema=self._token_schema) return HLSStream.parse_variant_playlist(self.session, secure_hls_url)
class CinerGroup(Plugin): """ Support for the live stream on www.showtv.com.tr """ url_re = re.compile( r"""https?://(?:www.)? (?: showtv.com.tr/canli-yayin/showtv| haberturk.com/canliyayin| showmax.com.tr/canliyayin| showturk.com.tr/canli-yayin/showturk| bloomberght.com/tv| haberturk.tv/canliyayin )/?""", re.VERBOSE) stream_re = re.compile( r"""div .*? data-ht=(?P<quote>["'])(?P<data>.*?)(?P=quote)""", re.DOTALL) stream_data_schema = validate.Schema( validate.transform(stream_re.search), validate.any( None, validate.all( validate.get("data"), validate.transform(unquote), validate.transform(lambda x: x.replace(""", '"')), validate.transform(json.loads), {"ht_stream_m3u8": validate.url()}, validate.get("ht_stream_m3u8")))) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): res = http.get(self.url) stream_url = self.stream_data_schema.validate(res.text) if stream_url: return HLSStream.parse_variant_playlist(self.session, stream_url)
class PowerApp(Plugin): url_re = re.compile(r"https?://(?:www.)?powerapp.com.tr/tv/(\w+)") api_url = "http://api.powergroup.com.tr/Channels/{}/?appRef=iPowerWeb&apiVersion=11" api_schema = validate.Schema( validate.all( { "errorCode": 0, "response": { "channel_stream_url": validate.url() } }, validate.get("response"))) @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None 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"])
_url_re = re.compile( """ http(s)?://(\w+\.)?cybergame.tv (?: /videos/(?P<video_id>\d+) )? (?: /(?P<channel>[^/&?]+) )? """, re.VERBOSE) _playlist_schema = validate.Schema( validate.union({ "base": validate.all(validate.xml_find("./head/meta"), validate.get("base"), validate.url(scheme="rtmp")), "videos": validate.all(validate.xml_findall(".//video"), [ validate.union({ "src": validate.all(validate.get("src"), validate.text), "height": validate.all(validate.get("height"), validate.text, validate.transform(int)) }) ]) })) class Cybergame(Plugin): @classmethod
_url_re = re.compile("http(s)?://(\w+\.)?ssh101\.com/") _live_re = re.compile(""" \s*jwplayer\(\"player\"\)\.setup\({.*? \s*primary:\s+"([^"]+)".*? \s*file:\s+"([^"]+)" """, re.DOTALL) _live_schema = validate.Schema( validate.transform(_live_re.search), validate.any( None, validate.union({ "type": validate.get(1), "url": validate.all( validate.get(2), validate.url(scheme="http"), ), }) ) ) class SSH101(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url) def _get_streams(self): res = http.get(self.url, schema=_live_schema) if not res: return
(?: tv4play.se/program/[^\?/]+| fotbollskanalen.se/video ) .+(video_id|videoid)=(?P<video_id>\d+) """, re.VERBOSE) _asset_schema = validate.Schema( validate.xml_findall("items/item"), [ validate.all( validate.xml_findall("*"), validate.map(lambda e: (e.tag, e.text)), validate.transform(dict), { "base": validate.text, "bitrate": validate.all( validate.text, validate.transform(int) ), "url": validate.text } ) ] ) class TV4Play(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) def _get_streams(self):
""", re.VERBOSE) _channels_schema = validate.Schema( { "Data": [{ "Slug": validate.text, "StreamingServers": validate.all([{ "LinkType": validate.text, "Qualities": [ validate.all( { "Streams": validate.all([ validate.all({"Stream": validate.text}, validate.get("Stream")) ], validate.get(0)) }, validate.get("Streams")) ], "Server": validate.text }], validate.filter(lambda s: s["LinkType"] in STREAMING_TYPES)) }] }, validate.get("Data", {})) _video_schema = validate.Schema( { "Data": [{ "Assets": validate.all([{
_media_schema = validate.Schema({ "_mediaArray": [{ "_mediaStreamArray": [{ validate.optional("_server"): validate.text, "_stream": validate.any(validate.text, [validate.text]), "_quality": validate.any(int, validate.text) }] }] }) _smil_schema = validate.Schema( validate.union({ "base": validate.all(validate.xml_find("head/meta"), validate.get("base"), validate.url(scheme="http")), "videos": validate.all(validate.xml_findall("body/seq/video"), [validate.get("src")]) })) class ard_mediathek(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) def _get_http_streams(self, info): name = QUALITY_MAP.get(info["_quality"], "vod") urls = info["_stream"] if not isinstance(info["_stream"], list):
_embed_re = re.compile("<iframe src=\"(http://tv.aftonbladet.se[^\"]+)\"") _aptoma_id_re = re.compile("<div id=\"drvideo\".+data-aptomaId=\"([^\"]+)\"") _live_re = re.compile("data-isLive=\"true\"") _url_re = re.compile("http(s)?://(\w+.)?.aftonbladet.se") _video_schema = validate.Schema({ "formats": validate.all( { validate.text: { validate.text: validate.all( dict, validate.filter(lambda k, v: k in STREAM_FORMATS), { validate.text: [{ "address": validate.text, "filename": validate.text, "path": validate.text }] }, ) } }, validate.filter(lambda k, v: k in STREAM_TYPES)) }) class Aftonbladet(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url)
_schema = validate.Schema( validate.transform(_js_var_re.findall), validate.transform(dict), { "a": validate.transform(int), "b": validate.transform(int), "c": validate.transform(int), "d": validate.transform(int), "f": validate.transform(int), "v_part": validate.text, }, validate.union({ "server_ip": validate.transform(_parse_server_ip), "path": validate.all(validate.get("v_part"), validate.transform(_rtmp_re.findall), validate.get(0)) })) class LetOnTV(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url) def _get_streams(self): match = _url_re.match(self.url) info = http.get(PLAYER_URL, params=match.groupdict(), schema=_schema) if not info["path"]: return app, playpath = info["path"]
""" http(s)?://(\w+\.)?aliez.tv (?: /live/[^/]+ )? (?: /video/\d+/[^/]+ )? """, re.VERBOSE) _file_re = re.compile("\"?file\"?:\s+['\"]([^'\"]+)['\"]") _swf_url_re = re.compile("swfobject.embedSWF\(\"([^\"]+)\",") _schema = validate.Schema( validate.union({ "urls": validate.all(validate.transform(_file_re.findall), validate.map(unquote), [validate.url()]), "swf": validate.all( validate.transform(_swf_url_re.search), validate.any( None, validate.all( validate.get(1), validate.url(scheme="http", path=validate.endswith("swf"))))) })) class Aliez(Plugin): @classmethod def can_handle_url(self, url):
import re from ACEStream.PluginsContainer.livestreamer.plugin import Plugin from ACEStream.PluginsContainer.livestreamer.plugin.api import http, validate from ACEStream.PluginsContainer.livestreamer.stream import HLSStream _url_re = re.compile("http(s)?://(www\.)?openrec.tv/(live|movie)/[^/?&]+") _playlist_url_re = re.compile("data-file=\"(?P<url>[^\"]+)\"") _schema = validate.Schema( validate.transform(_playlist_url_re.search), validate.any( None, validate.all( validate.get("url"), validate.url( scheme="http", path=validate.endswith(".m3u8") ) ) ) ) class OPENRECtv(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url) def _get_streams(self): playlist_url = http.get(self.url, schema=_schema) if not playlist_url: return
BLOCK_TYPE_NO_SLOTS = 11 _url_re = re.compile( "http(s)?://(\w+\.)?weeb.tv/(channel|online)/(?P<channel>[^/&?]+)") _schema = validate.Schema( dict, validate.map(lambda k, v: (PARAMS_KEY_MAP.get(k, k), v)), validate.any( { "status": validate.transform(int), "rtmp": validate.url(scheme="rtmp"), "playpath": validate.text, "multibitrate": validate.all(validate.transform(int), validate.transform(bool)), "block_type": validate.transform(int), validate.optional("token"): validate.text, validate.optional("block_time"): validate.text, validate.optional("reconnect_time"): validate.text, }, { "status": validate.transform(int), }, ))
from ACEStream.PluginsContainer.livestreamer.plugin import Plugin from ACEStream.PluginsContainer.livestreamer.plugin.api import http, validate from ACEStream.PluginsContainer.livestreamer.stream import HLSStream COOKIE_PARAMS = ("devicetype=desktop&" "preferred-player-odm=hlslink&" "preferred-player-live=hlslink") _id_re = re.compile("/(?:program|direkte|serie/[^/]+)/([^/]+)") _url_re = re.compile("https?://(tv|radio).nrk.no/") _api_baseurl_re = re.compile('apiBaseUrl:\s*"(?P<baseurl>[^"]+)"') _schema = validate.Schema( validate.transform(_api_baseurl_re.search), validate.any( None, validate.all(validate.get("baseurl"), validate.url(scheme="http")))) _mediaelement_schema = validate.Schema( {"mediaUrl": validate.url(scheme="http", path=validate.endswith(".m3u8"))}) class NRK(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url) def _get_streams(self): # Get the stream type from the url (tv/radio). stream_type = _url_re.match(self.url).group(1).upper() cookie = {"NRK_PLAYER_SETTINGS_{0}".format(stream_type): COOKIE_PARAMS}
scheme="http", path=validate.endswith(".m3u8") ), }, None) }, validate.optional("playerUri"): validate.text, validate.optional("viewerPlusSwfUrl"): validate.url(scheme="http"), validate.optional("lsPlayerSwfUrl"): validate.text, validate.optional("hdPlayerSwfUrl"): validate.text }) _smil_schema = validate.Schema(validate.union({ "http_base": validate.all( validate.xml_find("{http://www.w3.org/2001/SMIL20/Language}head/" "{http://www.w3.org/2001/SMIL20/Language}meta" "[@name='httpBase']"), validate.xml_element(attrib={ "content": validate.text }), validate.get("content") ), "videos": validate.all( validate.xml_findall("{http://www.w3.org/2001/SMIL20/Language}body/" "{http://www.w3.org/2001/SMIL20/Language}switch/" "{http://www.w3.org/2001/SMIL20/Language}video"), [ validate.all( validate.xml_element(attrib={ "src": validate.text, "system-bitrate": validate.all( validate.text, validate.transform(int)
LOGIN_PAGE_URL = "http://www.livestation.com/en/users/new" LOGIN_POST_URL = "http://www.livestation.com/en/sessions.json" _csrf_token_re = re.compile("<meta content=\"([^\"]+)\" name=\"csrf-token\"") _hls_playlist_re = re.compile( "<meta content=\"([^\"]+.m3u8)\" property=\"og:video\" />") _url_re = re.compile("http(s)?://(\w+\.)?livestation.com") _csrf_token_schema = validate.Schema(validate.transform(_csrf_token_re.search), validate.any(None, validate.get(1))) _hls_playlist_schema = validate.Schema( validate.transform(_hls_playlist_re.search), validate.any( None, validate.all( validate.get(1), validate.url(scheme="http", path=validate.endswith(".m3u8"))))) _login_schema = validate.Schema({ "email": validate.text, validate.optional("errors"): validate.all( {"base": [validate.text]}, validate.get("base"), ) }) class Livestation(Plugin): options = PluginOptions({"email": "", "password": ""})
_video_flashvars_re = re.compile( "<embed width=\"486\" height=\"326\" flashvars=\"([^\"]+)\"") _live_schema = validate.Schema({ "streams": [{ "name": validate.text, "quality": validate.text, "url": validate.url(scheme="rtmp") }] }) _schema = validate.Schema( validate.union({ "export_url": validate.all(validate.transform(_live_export_re.search), validate.any( None, validate.get(1), )), "video_flashvars": validate.all( validate.transform(_video_flashvars_re.search), validate.any( None, validate.all( validate.get(1), validate.transform(parse_query), { "_111pix_serverURL": validate.url(scheme="rtmp"), "en_flash_providerName": validate.text }))), "history_video": validate.all( validate.transform(_history_re.search),
_url_re = re.compile( """ http(s)?://(\w+\.)? (?P<domain>vaughnlive|breakers|instagib|vapers).tv (/embed/video)? /(?P<channel>[^/&?]+) """, re.VERBOSE) _swf_player_re = re.compile( 'swfobject.embedSWF\("(/\d+/swf/[0-9A-Za-z]+\.swf)"') _schema = validate.Schema( validate.transform(lambda s: s.split(";")), validate.length(3), validate.union({ "server": validate.all(validate.get(0), validate.text), "token": validate.all(validate.get(1), validate.text, validate.startswith(":mvnkey-"), validate.transform(lambda s: s[len(":mvnkey-"):])), "ingest": validate.all(validate.get(2), validate.text) })) class VaughnLive(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) def _get_streams(self):
(?: (?P<seconds>\d+)s )? """, re.VERBOSE) _access_token_schema = validate.Schema( { "token": validate.text, "sig": validate.text }, validate.union((validate.get("sig"), validate.get("token")))) _token_schema = validate.Schema( { "chansub": { "restricted_bitrates": validate.all([validate.text], validate.filter(lambda n: not re.match( r"(.+_)?archives|live|chunked", n))) } }, validate.get("chansub")) _user_schema = validate.Schema( {validate.optional("display_name"): validate.text}, validate.get("display_name")) _video_schema = validate.Schema({ "chunks": { validate.text: [{ "length": int, "url": validate.any(None, validate.url(scheme="http")), "upkeep": validate.any("pass", "fail", None) }] }, "restrictions": {
_api_schema = validate.Schema({ "error": bool, validate.optional("code"): validate.text, validate.optional("message"): validate.text, validate.optional("data"): object, }) _media_schema = validate.Schema( { "stream_data": validate.any( None, { "streams": validate.all( [{ "quality": validate.any(validate.text, None), "url": validate.url( scheme="http", path=validate.endswith(".m3u8") ), validate.optional("video_encode_id"): validate.text }] ) } ) }, validate.get("stream_data") ) _login_schema = validate.Schema({ "auth": validate.text, "expires": validate.all( validate.text, validate.transform(parse_timestamp) ),
QQ_STREAM_INFO_URL = "http://info.zb.qq.com/?cnlid=%d&cmd=2&stream=%d&system=1&sdtfrom=113" PLU_STREAM_INFO_URL = "http://star.api.plu.cn/live/GetLiveUrl?roomId=%d" _quality_re = re.compile("\d+x(\d+)$") _url_re = re.compile( "http://star\.longzhu\.(?:tv|com)/(m\/)?(?P<domain>[a-z0-9]+)") _channel_schema = validate.Schema( { "data": validate.any( None, { "channel": validate.any( None, { "id": validate.all(validate.text, validate.transform(int)), "vid": int }) }) }, validate.get("data")) _plu_schema = validate.Schema({ "urls": [{ "securityUrl": validate.url(scheme=validate.any("rtmp", "http")), "resolution": validate.text, "ext": validate.text }] }) _qq_schema = validate.Schema( {validate.optional("playurl"): validate.url(scheme="http")},
play.tv3 | juicyplay | viafree ) \. (?: dk|ee|lt|lv|no|se|com ) (/.+?/|/embed\?id=) (?P<stream_id>\d+) """, re.VERBOSE) _stream_schema = validate.Schema( { "streams": validate.all( {validate.text: validate.any(validate.text, int, None)}, validate.filter(lambda k, v: isinstance(v, validate.text)) ) }, validate.get("streams") ) class Viasat(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) def _get_swf_url(self): res = http.get(self.url) match = _swf_url_re.search(res.text) if not match:
SHOW_STATUS_ONLINE = 1 SHOW_STATUS_OFFLINE = 2 STREAM_WEIGHTS = {"low": 540, "middle": 720, "source": 1080} _url_re = re.compile( """ http(s)?://(www\.)?douyu.com /(?P<channel>[^/]+) """, re.VERBOSE) _room_id_re = re.compile(r'"room_id"\s*:\s*(\d+),') _room_id_alt_re = re.compile(r'data-room_id="(\d+)"') _room_id_schema = validate.Schema( validate.all( validate.transform(_room_id_re.search), validate.any(None, validate.all(validate.get(1), validate.transform(int))))) _room_id_alt_schema = validate.Schema( validate.all( validate.transform(_room_id_alt_re.search), validate.any(None, validate.all(validate.get(1), validate.transform(int))))) _room_schema = validate.Schema( { "data": validate.any(None, { "show_status": validate.all(validate.text, validate.transform(int)) })
svtflow | oppetarkiv ) .se """, re.VERBOSE) # Regex to match video ID _id_re = re.compile(r"""data-video-id=['"](?P<id>[^'"]+)['"]""") _old_id_re = re.compile(r"/(?:video|klipp)/(?P<id>[0-9]+)/") # New video schema used with API call _video_schema = validate.Schema( { "videoReferences": validate.all([{ "url": validate.text, "format": validate.text }], ), }, validate.get("videoReferences")) # Old video schema _old_video_schema = validate.Schema( { "video": { "videoReferences": validate.all([{ "url": validate.text, "playerType": validate.text }], ), } }, validate.get("video"), validate.get("videoReferences"))
_url_re = re.compile( """ http(s)?://(\w+\.)? dailymotion.com (/embed)?/(video|live) /(?P<media_id>[^_?/]+) """, re.VERBOSE) _media_inner_schema = validate.Schema([{ "layerList": [{ "name": validate.text, validate.optional("sequenceList"): [{ "layerList": validate.all([{ "name": validate.text, validate.optional("param"): dict }], validate.filter(lambda l: l["name"] in ("video", "reporting"))) }] }] }]) _media_schema = validate.Schema( validate.any( _media_inner_schema, validate.all({"sequence": _media_inner_schema}, validate.get("sequence")))) _vod_playlist_schema = validate.Schema({ "duration": float, "fragments": [[int, float]], "template": validate.text }) _vod_manifest_schema = validate.Schema({
return parser.unescape(s) _url_re = re.compile(r"https?://(?:www\.)?vidio\.com/(?P<type>live|watch)/(?P<id>\d+)-(?P<name>[^/?#&]+)") _clipdata_re = re.compile(r"""data-json-clips\s*=\s*(['"])(.*?)\1""") _schema = validate.Schema( validate.transform(_clipdata_re.search), validate.any( None, validate.all( validate.get(2), validate.transform(html_unescape), validate.transform(parse_json), [{ "sources": [{ "file": validate.url( scheme="http", path=validate.endswith(".m3u8") ) }] }] ) ) ) class Vidio(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) def _get_streams(self):