class DingitTV(Plugin): """ Plugin that supports playing streams from DingIt.tv """ # regex to match the site urls url_re = re.compile(r""" http://www.dingit.tv/( highlight/(?P<highlight_id>\d+)| channel/(?P<broadcaster>\w+)/(?P<channel_id>\d+) )""", re.VERBOSE) # flashvars API url and schema flashvars_url = "http://www.dingit.tv/api/get_player_flashvars" flashvars_schema = validate.Schema({ u"status": 0, u"data": [{ validate.optional("stream"): validate.text, validate.optional("akaurl"): validate.text, validate.optional("pereakaurl"): validate.text, }] }, validate.get("data"), validate.length(1), validate.get(0) ) pereakaurl = "http://dingitmedia-vh.akamaihd.net/i/{}/master.m3u8" akaurl = "https://dingmedia1-a.akamaihd.net/processed/delivery/{}70f8b7bc-5ed4-336d-609a-2d2cd86288c6.m3u8" @classmethod def can_handle_url(cls, url): return cls.url_re.match(url) is not None def _get_streams(self): match = self.url_re.match(self.url) res = http.post(self.flashvars_url, data=dict( broadcaster=match.group("broadcaster") or "Verm", stream_id=match.group("channel_id") or match.group("highlight_id"))) flashvars = http.json(res, schema=self.flashvars_schema) if flashvars.get("pereakaurl"): url = self.pereakaurl.format(flashvars.get("pereakaurl").strip("/")) return HLSStream.parse_variant_playlist(self.session, url) elif flashvars.get("akaurl"): url = self.akaurl.format(flashvars.get("akaurl").strip("/")) return HLSStream.parse_variant_playlist(self.session, url) elif flashvars.get("stream"): self.logger.error("OctoStreams are not currently supported")
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 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 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 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 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"])
_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([{ validate.optional("Links"):
validate.any( validate.text, dict, { "videoinfo": validate.any( validate.text, { "room_key": validate.text, "plflag": validate.text, "status": validate.text, "stream_addr": { "HD": validate.text, "OD": validate.text, "SD": validate.text } }) }) }, validate.get("data")) class pandatv(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url) def _get_streams(self): match = _url_re.match(self.url) channel = match.group("channel") url = ROOM_API + channel res = http.get(url) data = http.json(res, schema=_room_schema) if not isinstance(data, dict):
_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"]
(?: (?P<hours>\d+)h )? (?: (?P<minutes>\d+)m )? (?: (?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: [{
_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):
_url_re = re.compile( """ http(s)?://(\w+\.)?gaminglive\.tv /(?P<type>channels|videos)/(?P<name>[^/]+) """, re.VERBOSE) _quality_re = re.compile("[^/]+-(?P<quality>[^/]+)") _channel_schema = validate.Schema( { validate.optional("state"): { "stream": { "qualities": [validate.text], "rootUrl": validate.url(scheme="rtmp") } } }, validate.get("state")) _vod_schema = validate.Schema( { "name": validate.text, "channel_slug": validate.text, "title": validate.text, "created_at": validate.transform(int) }, ) class GamingLive(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url)
.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")) class SVTPlay(Plugin):
\. (?: 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: raise PluginError("Unable to find SWF URL in the HTML") return match.group(1)
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) ), "user": { "username": validate.any(validate.text, None), "email": validate.text } }) _session_schema = validate.Schema( { "session_id": validate.text
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}
}, 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) ) }), validate.transform(
from ACEStream.PluginsContainer.livestreamer.stream import HLSStream, HTTPStream _url_re = re.compile("http(s)?://(\w+\.)?seemeplay.ru/") _player_re = re.compile( """ SMP.(channel|video).player.init\({ \s+file:\s+"([^"]+)" """, re.VERBOSE) _schema = validate.Schema( validate.transform(_player_re.search), validate.any( None, validate.union({ "type": validate.get(1), "url": validate.all( validate.get(2), validate.url(scheme="http"), ), }))) class SeeMePlay(Plugin): @classmethod def can_handle_url(cls, url): return _url_re.match(url) def _get_streams(self): res = http.get(self.url, schema=_schema)
from ACEStream.PluginsContainer.livestreamer.stream import HLSStream _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)
CHANNEL_RESULT_OK = 1 _url_re = re.compile( "http(s)?://(\w+\.)?afreeca(tv)?.com/(?P<username>\w+)(/\d+)?") _channel_schema = validate.Schema( { "CHANNEL": { "RESULT": validate.transform(int), "BROAD_INFOS": [{ "list": [{ "nBroadNo": validate.text }] }] } }, validate.get("CHANNEL")) _stream_schema = validate.Schema({ validate.optional("view_url"): validate.url(scheme=validate.any("rtmp", "http")) }) class AfreecaTV(Plugin): @classmethod def can_handle_url(self, url): return _url_re.match(url) def _get_channel_info(self, username): headers = {"Referer": self.url} params = {"uid": username} res = http.get(CHANNEL_INFO_URL, params=params, headers=headers)
#-plugin-sig:ndEiyRW3P8MfPorpHFFSH2O2CRPRvepIW9hNPMAUB94OXs//5NgB2pw9lVxgHr4o2YUj7M3wtnAG9Ws7KEVRVq6vd+cjAJyWDaKmOAA/VdVbPGrLRTwJaTucHPGogJ0xcNDm/huGb+6ExZ71IN5zAFcI9Ko03xU9mgd/gp5fKTWS3I00ESjXkEkCs05tkqk4IzhfZbIZIrRpM28XOycKQxgc9Ot4Kq2npHByj4E0XGn+X9QoOdc/5uqQ0VrJUSVdxq47V+Zc2pI1FBK87Z1hktEKAx8bESXzKTvFnJUcNLuJHUxutXrwNH4MKVroxpap7wZUc7a/YplEOQXPRRpdJA== 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:
""", 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): return _url_re.match(url) def _get_streams(self): res = http.get(self.url, schema=_schema) streams = {} for url in res["urls"]: parsed = urlparse(url)
"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")}, validate.get("playurl")) STREAM_WEIGHTS = {"middle": 540, "source": 1080}
_embed_url_re = re.compile( '<meta itemprop="embedURL" content="http://www.viagame.com/embed/video/([^"]+)"' ) _store_data_re = re.compile("window.fluxData\s*=\s*JSON.parse\(\"(.+)\"\);") _url_re = re.compile("http(s)?://(www\.)?viagame.com/channels/.+") _store_schema = validate.Schema( { "initialStoresData": [{ "instanceName": validate.text, "storeName": validate.text, "initialData": validate.any(dict, list) }] }, validate.get("initialStoresData") ) _match_store_schema = validate.Schema( { "match": { "id": validate.text, "type": validate.text, "videos": [{ "id": validate.text, "play_id": validate.text, }] } }, validate.get("match") )
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)) }) }, validate.get("data"))
"<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), validate.any(
"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({ "alternates": [{ "height": int, "template": validate.text, validate.optional("failover"): [validate.text] }] }) class DailyMotion(Plugin):
except ImportError: from html.parser import HTMLParser def html_unescape(s): parser = HTMLParser() 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):