示例#1
0
class Streamable(Plugin):
    url_re = re.compile(r"https?://(?:www\.)?streamable\.com/(.+)")
    meta_re = re.compile(r'''var\s*videoObject\s*=\s*({.*});''')
    config_schema = validate.Schema(
        validate.transform(meta_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1), validate.transform(parse_json), {
                    "files": {
                        validate.text: {
                            "url": validate.url(),
                            "width": int,
                            "height": int,
                            "bitrate": int
                        }
                    }
                })))

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def _get_streams(self):
        data = http.get(self.url, schema=self.config_schema)

        for info in data["files"].values():
            stream_url = update_scheme(self.url, info["url"])
            # pick the smaller of the two dimensions, for landscape v. portrait videos
            res = min(info["width"], info["height"])
            yield "{0}p".format(res), HTTPStream(self.session, stream_url)
示例#2
0
class CDNBG(Plugin):
    url_re = re.compile(
        r"""
        https?://(?:www\.)?(?:
            tv\.bnt\.bg/\w+(?:/\w+)?|
            bitelevision\.com/live|
            nova\.bg/live|
            kanal3\.bg/live|
            bgonair\.bg/tvonline|
            tvevropa\.com/na-zhivo|
            bloombergtv.bg/video
        )/?
    """, re.VERBOSE)
    iframe_re = re.compile(
        r"iframe .*?src=\"((?:https?:)?//(?:\w+\.)?cdn.bg/live[^\"]+)\"",
        re.DOTALL)
    sdata_re = re.compile(
        r"sdata\.src.*?=.*?(?P<q>[\"'])(?P<url>http.*?)(?P=q)")
    hls_file_re = re.compile(
        r"(src|file): (?P<q>[\"'])(?P<url>(https?:)?//.+?m3u8.*?)(?P=q)")
    hls_src_re = re.compile(r"video src=(?P<url>http[^ ]+m3u8[^ ]*)")

    stream_schema = validate.Schema(
        validate.any(
            validate.all(validate.transform(sdata_re.search),
                         validate.get("url")),
            validate.all(validate.transform(hls_file_re.search),
                         validate.get("url")),
            validate.all(validate.transform(hls_src_re.search),
                         validate.get("url")),
        ))

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def find_iframe(self, res):
        p = urlparse(self.url)
        for url in self.iframe_re.findall(res.text):
            if "googletagmanager" not in url:
                if url.startswith("//"):
                    return "{0}:{1}".format(p.scheme, url)
                else:
                    return url

    def _get_streams(self):
        http.headers = {"User-Agent": useragents.CHROME}
        res = http.get(self.url)
        iframe_url = self.find_iframe(res)

        if iframe_url:
            self.logger.debug("Found iframe: {0}", iframe_url)
            res = http.get(iframe_url, headers={"Referer": self.url})
            stream_url = update_scheme(self.url,
                                       self.stream_schema.validate(res.text))
            return HLSStream.parse_variant_playlist(
                self.session,
                stream_url,
                headers={"User-Agent": useragents.CHROME})
 def test_dict_keys(self):
     assert validate({text: int}, {"a": 1, "b": 2}) == {"a": 1, "b": 2}
     assert validate({transform(text): transform(int)}, {
                          1: 3.14,
                          3.14: 1
                      }) == {
                          "1": 3,
                          "3.14": 1
                      }
    def test_basic(self):
        assert validate(1, 1) == 1

        assert validate(int, 1) == 1

        assert validate(transform(int), "1") == 1

        assert validate(text, "abc") == "abc"
        assert validate(text, u"日本語") == u"日本語"
        assert validate(transform(text), 1) == "1"

        assert validate(list, ["a", 1]) == ["a", 1]
        assert validate(dict, {"a": 1}) == {"a": 1}

        assert validate(lambda n: 0 < n < 5, 3) == 3
示例#5
0
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)
示例#6
0
class RaiPlay(Plugin):
    url_re = re.compile(r"https?://(?:www\.)?raiplay\.it/dirette/(\w+)/?")
    stream_re = re.compile(r"data-video-url.*?=.*?\"([^\"]+)\"")
    stream_schema = validate.Schema(
        validate.all(
            validate.transform(stream_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):
        http.headers.update({"User-Agent": useragents.FIREFOX})
        channel = self.url_re.match(self.url).group(1)
        self.logger.debug("Found channel: {0}", channel)
        stream_url = http.get(self.url, schema=self.stream_schema)
        if stream_url:
            try:
                return HLSStream.parse_variant_playlist(
                    self.session, stream_url)
            except Exception as e:
                if "Missing #EXTM3U header" in str(e):
                    raise PluginError(
                        "The streaming of this content is available in Italy only."
                    )
                raise e
示例#7
0
class Filmon(Plugin):
    url_re = re.compile(
        r"""https?://(?:\w+\.)?filmon.(?:tv|com)/
        (?:
            (tv|channel)/(?P<channel>[^/]+)|
            vod/view/(?P<vod_id>\d+)-|
            group/
        )
    """, re.VERBOSE)

    _channel_id_re = re.compile(r'''channel_id\s*?=\s*["']?(\d+)["']''')
    _channel_id_schema = validate.Schema(
        validate.transform(_channel_id_re.search),
        validate.any(None, validate.get(1)))

    quality_weights = {"high": 720, "low": 480}

    def __init__(self, url):
        super(Filmon, self).__init__(url)
        self.api = FilmOnAPI()

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    @classmethod
    def stream_weight(cls, key):
        weight = cls.quality_weights.get(key)
        if weight:
            return weight, "filmon"

        return Plugin.stream_weight(key)

    def _get_streams(self):
        url_m = self.url_re.match(self.url)

        vod_id = url_m and url_m.group("vod_id")

        if vod_id:
            self.logger.debug("vod_id: {0}".format(vod_id))
            data = self.api.vod(vod_id)
            for _, stream in data["streams"].items():
                yield stream["quality"], FilmOnHLS(self.session,
                                                   vod_id=vod_id,
                                                   quality=stream["quality"])

        else:
            channel = http.get(self.url, schema=self._channel_id_schema)
            if channel:
                self.logger.debug("channel_id: {0}".format(channel))
            else:
                channel = url_m and url_m.group("channel")
                self.logger.debug("channel: {0}".format(channel))

            data = self.api.channel(channel)
            for stream in data["streams"]:
                yield stream["quality"], FilmOnHLS(self.session,
                                                   channel=channel,
                                                   quality=stream["quality"])
示例#8
0
class RadioNet(Plugin):
    _url_re = re.compile(r"https?://(\w+)\.radio\.(net|at|de|dk|es|fr|it|pl|pt|se)")
    _stream_data_re = re.compile(r'\bstation\s*:\s*(\{.+\}),?\s*')

    _stream_schema = validate.Schema(
        validate.transform(_stream_data_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1),
                validate.transform(parse_json),
                {
                    'stationType': validate.text,
                    'streamUrls': validate.all([{
                        'bitRate': int,
                        'streamUrl': validate.url()
                    }])
                },
            )
        )
    )

    @classmethod
    def can_handle_url(cls, url):
        return cls._url_re.match(url)

    def _get_streams(self):
        streams = http.get(self.url, schema=self._stream_schema)
        if streams is None:
            return

        # Ignore non-radio streams (podcasts...)
        if streams['stationType'] != 'radio_station':
            return

        stream_urls = []
        for stream in streams['streamUrls']:
            if stream['streamUrl'] in stream_urls:
                continue

            if stream['bitRate'] > 0:
                bitrate = '{}k'.format(stream['bitRate'])
            else:
                bitrate = 'live'
            yield bitrate, HTTPStream(self.session, stream['streamUrl'])
            stream_urls.append(stream['streamUrl'])
示例#9
0
class TVRBy(Plugin):
    url_re = re.compile(r"""https?://(?:www\.)?tvr.by/televidenie/belarus""")
    file_re = re.compile(
        r"""(?P<q1>["']?)file(?P=q1)\s*:\s*(?P<q2>["'])(?P<url>(?:http.+?m3u8.*?|rtmp://.*?))(?P=q2)"""
    )

    stream_schema = validate.Schema(
        validate.all(validate.transform(file_re.finditer),
                     validate.transform(list), [validate.get("url")]), )

    def __init__(self, url):
        # ensure the URL ends with a /
        if not url.endswith("/"):
            url += "/"
        super(TVRBy, self).__init__(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_urls = self.stream_schema.validate(res.text)
        self.logger.debug("Found {0} stream URL{1}", len(stream_urls),
                          "" if len(stream_urls) == 1 else "s")

        for stream_url in stream_urls:
            if "m3u8" in stream_url:
                for _, s in HLSStream.parse_variant_playlist(
                        self.session, stream_url).items():
                    yield "live", s
            if stream_url.startswith("rtmp://"):
                a = stream_url.split("///")
                s = RTMPStream(
                    self.session, {
                        "rtmp": a[0],
                        "playpath": "live",
                        "swfVfy": "http://www.tvr.by/plugines/uppod/uppod.swf",
                        "pageUrl": self.url
                    })
                yield "live", s
示例#10
0
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'''jwConfig\s*=\s*(\{.*\});''', 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: {0}", 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: {0}", 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"])
示例#11
0
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("&quot;", '"')),
                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)
示例#12
0
class ovvaTV(Plugin):
    url_re = re.compile(
        r"https?://(?:www\.)?ovva.tv/(?:ua/)?tvguide/.*?/online")
    iframe_re = re.compile(
        r"iframe .*?src=\"((?:https?:)?//(?:\w+\.)?ovva.tv/[^\"]+)\"",
        re.DOTALL)
    data_re = re.compile(r"ovva\(\'(.*?)\'\);")
    ovva_data_schema = validate.Schema({"url": validate.url()},
                                       validate.get("url"))
    ovva_redirect_schema = validate.Schema(
        validate.all(validate.transform(lambda x: x.split("=")),
                     ['302', validate.url()], validate.get(1)))

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def find_iframe(self, res):
        for url in self.iframe_re.findall(res.text):
            if url.startswith("//"):
                p = urlparse(self.url)
                return "{0}:{1}".format(p.scheme, url)
            else:
                return url

    def _get_streams(self):
        http.headers = {"User-Agent": useragents.ANDROID}
        res = http.get(self.url)
        iframe_url = self.find_iframe(res)

        if iframe_url:
            self.logger.debug("Found iframe: {0}", iframe_url)
            res = http.get(iframe_url, headers={"Referer": self.url})
            data = self.data_re.search(res.text)
            if data:
                try:
                    ovva_url = parse_json(b64decode(
                        data.group(1)).decode("utf8"),
                                          schema=self.ovva_data_schema)
                    stream_url = http.get(ovva_url,
                                          schema=self.ovva_redirect_schema)
                except PluginError as e:
                    self.logger.error("Could not find stream URL: {0}", e)
                else:
                    return HLSStream.parse_variant_playlist(
                        self.session, stream_url)
            else:
                self.logger.error("Could not find player data.")
示例#13
0
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)
示例#14
0
class Cam4(Plugin):
    _url_re = re.compile(r'https?://([a-z]+\.)?cam4.com/.+')
    _video_data_re = re.compile(
        r"flashData: (?P<flash_data>{.*}), hlsUrl: '(?P<hls_url>.+?)'")

    _flash_data_schema = validate.Schema(
        validate.all(
            validate.transform(parse_json),
            validate.Schema({
                'playerUrl':
                validate.url(),
                'flashVars':
                validate.Schema({
                    'videoPlayUrl': validate.text,
                    'videoAppUrl': validate.url(scheme='rtmp')
                })
            })))

    @classmethod
    def can_handle_url(cls, url):
        return Cam4._url_re.match(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:
            return

        hls_streams = HLSStream.parse_variant_playlist(
            self.session,
            match.group('hls_url'),
            headers={'Referer': self.url})
        for s in hls_streams.items():
            yield s

        rtmp_video = self._flash_data_schema.validate(
            match.group('flash_data'))
        rtmp_stream = RTMPStream(
            self.session, {
                'rtmp': rtmp_video['flashVars']['videoAppUrl'],
                'playpath': rtmp_video['flashVars']['videoPlayUrl'],
                'swfUrl': rtmp_video['playerUrl']
            })
        yield 'live', rtmp_stream
示例#15
0
class TVRPlus(Plugin):
    url_re = re.compile(r"https?://(?:www\.)tvrplus.ro/live-")
    hls_file_re = re.compile(
        r"""src:\s?(?P<q>["'])(?P<url>http.+?m3u8.*?)(?P=q)""")

    stream_schema = validate.Schema(
        validate.all(validate.transform(hls_file_re.search),
                     validate.any(None, validate.get("url"))), )

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def _get_streams(self):
        stream_url = self.stream_schema.validate(http.get(self.url).text)
        if stream_url:
            headers = {"Referer": self.url}
            return HLSStream.parse_variant_playlist(self.session,
                                                    stream_url,
                                                    headers=headers)
示例#16
0
class RaiPlay(Plugin):
    url_re = re.compile(r"https?://(?:www\.)?raiplay\.it/dirette/(\w+)/?")
    stream_re = re.compile(r"data-video-url.*?=.*?\"([^\"]+)\"")
    stream_schema = validate.Schema(
        validate.all(
            validate.transform(stream_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):
        channel = self.url_re.match(self.url).group(1)
        self.logger.debug("Found channel: {0}", channel)
        stream_url = http.get(self.url, schema=self.stream_schema)
        if stream_url:
            return HLSStream.parse_variant_playlist(self.session, stream_url)
示例#17
0
class ovvaTV(Plugin):
    url_re = re.compile(r"https?://(?:www\.)?1plus1\.video/tvguide/embed/[^/]")
    data_re = re.compile(r"""ovva-player["'],["'](.*?)["']\)};""")
    next_date_re = re.compile(
        r"""<div\sclass=["']o-message-timer['"]\sdata-timer=["'](\d+)["']""")
    ovva_data_schema = validate.Schema({"balancer": validate.url()},
                                       validate.get("balancer"))
    ovva_redirect_schema = validate.Schema(
        validate.all(validate.transform(lambda x: x.split("=")),
                     ['302', validate.url()], validate.get(1)))

    @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_re.search(res.text)
        next_date = self.next_date_re.search(res.text)
        if data:
            try:
                ovva_url = parse_json(b64decode(data.group(1)).decode("utf8"),
                                      schema=self.ovva_data_schema)
                stream_url = http.get(ovva_url,
                                      schema=self.ovva_redirect_schema)
            except PluginError as e:
                self.logger.error("Could not find stream URL: {0}", e)
            else:
                return HLSStream.parse_variant_playlist(
                    self.session, stream_url)
        elif next_date:
            self.logger.info("The broadcast will be available at {0}".format(
                datetime.fromtimestamp(int(
                    next_date.group(1))).strftime('%Y-%m-%d %H:%M:%S')))
        else:
            self.logger.error("Could not find player data.")
示例#18
0
def parse_fmt_list(formatsmap):
    formats = {}
    if not formatsmap:
        return formats

    for format in formatsmap.split(","):
        s = format.split("/")
        (w, h) = s[1].split("x")
        formats[int(s[0])] = "{0}p".format(h)

    return formats


_config_schema = validate.Schema({
    validate.optional("fmt_list"):
    validate.all(validate.text, validate.transform(parse_fmt_list)),
    validate.optional("url_encoded_fmt_stream_map"):
    validate.all(validate.text, validate.transform(parse_stream_map), [{
        "itag":
        validate.all(validate.text, validate.transform(int)),
        "quality":
        validate.text,
        "url":
        validate.url(scheme="http"),
        validate.optional("s"):
        validate.text,
        validate.optional("stereo3d"):
        validate.all(validate.text, validate.transform(int),
                     validate.transform(bool)),
    }]),
    validate.optional("adaptive_fmts"):
    def test_all(self):
        assert validate(all(int, lambda n: 0 < n < 5), 3) == 3

        assert validate(all(transform(int), lambda n: 0 < n < 5), 3.33) == 3
示例#20
0
    if not formatsmap:
        return formats

    for format in formatsmap.split(","):
        s = format.split("/")
        (w, h) = s[1].split("x")
        formats[int(s[0])] = "{0}p".format(h)

    return formats


_config_schema = validate.Schema(
    {
        validate.optional("fmt_list"): validate.all(
            validate.text,
            validate.transform(parse_fmt_list)
        ),
        validate.optional("url_encoded_fmt_stream_map"): validate.all(
            validate.text,
            validate.transform(parse_stream_map),
            [{
                "itag": validate.all(
                    validate.text,
                    validate.transform(int)
                ),
                "quality": validate.text,
                "url": validate.url(scheme="http"),
                validate.optional("s"): validate.text,
                validate.optional("stereo3d"): validate.all(
                    validate.text,
                    validate.transform(int),
示例#21
0
class Looch(Plugin):
    url_re = re.compile(
        r"https?://(?:www\.)?looch\.tv/channel/(?P<name>[^/]+)(/videos/(?P<video_id>\d+))?"
    )

    api_base = "https://api.looch.tv"
    channel_api = api_base + "/channels/{name}"
    video_api = api_base + "/videos/{id}"

    playback_schema = validate.Schema({"weight": int, "uri": validate.url()})
    data_schema = validate.Schema({
        "type": validate.text,
        "attributes": {
            validate.optional("playback"): [playback_schema],
            validate.optional("resolution"): {
                "width": int,
                "height": int
            }
        }
    })
    channel_schema = validate.Schema(
        validate.transform(parse_json), {
            "included":
            validate.all(
                [data_schema],
                validate.filter(lambda x: x["type"] == "active_streams"),
                validate.map(lambda x: x["attributes"].get("playback")),
                validate.transform(lambda x: list(itertools.chain(*x)))),
        }, validate.get("included"))
    video_schema = validate.Schema(validate.transform(parse_json),
                                   {"data": data_schema}, validate.get("data"),
                                   validate.get("attributes"))

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def _get_live_stream(self, channel):
        url = self.channel_api.format(name=channel)
        self.logger.debug("Channel API call: {0}", url)
        data = http.get(url, schema=self.channel_schema)
        self.logger.debug("Got {0} channel playback items", len(data))
        for playback in data:
            for s in HLSStream.parse_variant_playlist(self.session,
                                                      playback["uri"]).items():
                yield s

    def _get_video_stream(self, video_id):
        url = self.video_api.format(id=video_id)
        self.logger.debug("Video API call: {0}", url)
        data = http.get(url, schema=self.video_schema)
        self.logger.debug("Got video {0} playback items",
                          len(data["playback"]))
        res = data["resolution"]["height"]
        for playback in data["playback"]:
            yield "{0}p".format(res), HTTPStream(self.session, playback["uri"])

    def _get_streams(self):
        match = self.url_re.match(self.url)
        self.logger.debug("Matched URL: name={name}, video_id={video_id}",
                          **match.groupdict())

        if match.group("video_id"):
            return self._get_video_stream(match.group("video_id"))
        elif match.group("name"):
            return self._get_live_stream(match.group("name"))
示例#22
0
class WebTV(Plugin):
    _url_re = re.compile(r"http(?:s)?://(\w+)\.web.tv/?")
    _sources_re = re.compile(r'"sources": (\[.*?\]),', re.DOTALL)
    _sources_schema = validate.Schema([{
        u"src":
        validate.any(
            validate.contains("m3u8"),
            validate.all(
                validate.text,
                validate.transform(lambda x: WebTV.decrypt_stream_url(x)),
                validate.contains("m3u8"))),
        u"type":
        validate.text,
        u"label":
        validate.text
    }])

    @classmethod
    def can_handle_url(cls, url):
        return cls._url_re.match(url) is not None

    @staticmethod
    def decrypt_stream_url(encoded_url):
        data = base64.b64decode(encoded_url)
        cipher_text = binascii.unhexlify(data[96:])

        decryptor = crypto_AES.new(binascii.unhexlify(data[32:96]),
                                   crypto_AES.MODE_CBC,
                                   binascii.unhexlify(data[:32]))

        return unpad_pkcs5(decryptor.decrypt(cipher_text)).decode("utf8")

    def _get_streams(self):
        """
        Find the streams for web.tv
        :return:
        """
        headers = {}
        res = http.get(self.url, headers=headers)
        headers["Referer"] = self.url

        sources = self._sources_re.findall(res.text)
        if len(sources):
            sdata = parse_json(sources[0], schema=self._sources_schema)
            for source in sdata:
                self.logger.debug("Found stream of type: {}", source[u'type'])
                if source[u'type'] == u"application/vnd.apple.mpegurl":
                    url = update_scheme(self.url, source[u"src"])

                    try:
                        # try to parse the stream as a variant playlist
                        variant = HLSStream.parse_variant_playlist(
                            self.session, 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,
                                                    url,
                                                    headers=headers)
                    except IOError:
                        self.logger.warning(
                            "Could not open the stream, perhaps the channel is offline"
                        )
示例#23
0
                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},
                                  validate.get("session_id"))


class CrunchyrollAPIError(Exception):
    """Exception thrown by the Crunchyroll API when an error occurs"""
    def __init__(self, msg, code):
        Exception.__init__(self, msg)
        self.msg = msg
        self.code = code
示例#24
0
__livecli_docs__ = {
    "domains": [
        "openrec.tv",
    ],
    "geo_blocked": [],
    "notes": "",
    "live": True,
    "vod": True,
    "last_update": "2017-02-09",
}

_url_re = re.compile(r"https?://(?:www\.)?openrec.tv/(live|movie)/")
_playlist_url_re = re.compile(r"data-(source)?file=\"(?P<url>[^\"]+)\"")
_movie_data_re = re.compile(r'''<script type="application/ld\+json">(.*?)</script>''', re.DOTALL | re.M)
_live_schema = validate.Schema(
    validate.transform(_playlist_url_re.findall),
    [
        validate.union({
            "isSource": validate.all(validate.get(0), validate.transform(lambda s: s == "source")),
            "url": validate.all(validate.get(1), validate.url(scheme="http",
                                                              path=validate.endswith(".m3u8")))
        })
    ]
)
_movie_schema = validate.Schema(
    validate.transform(_movie_data_re.search),
    validate.any(
        None,
        validate.all(
            validate.get(1),
            validate.transform(parse_json),
示例#25
0
class IDF1(Plugin):
    DACAST_API_URL = 'https://json.dacast.com/b/{}/{}/{}'
    DACAST_TOKEN_URL = 'https://services.dacast.com/token/i/b/{}/{}/{}'

    _url_re = re.compile(
        r'http://www\.idf1\.fr/(videos/[^/]+/[^/]+\.html|live\b)')
    _video_id_re = re.compile(
        r"dacast\('(?P<broadcaster_id>\d+)_(?P<video_type>[a-z]+)_(?P<video_id>\d+)', 'replay_content', data\);"
    )
    _video_id_alt_re = re.compile(
        r'<script src="//player.dacast.com/js/player.js" id="(?P<broadcaster_id>\d+)_(?P<video_type>[cf])_(?P<video_id>\d+)"'
    )
    _player_url = 'http://ssl.p.jwpcdn.com/player/v/7.12.6/jwplayer.flash.swf'

    _api_schema = validate.Schema(
        validate.transform(parse_json), {
            validate.optional('html5'): validate.all([
                {
                    'src': validate.url()
                },
            ], ),
            'hls': validate.url(),
            'hds': validate.url()
        },
        validate.transform(
            lambda x: [update_scheme(IDF1.DACAST_API_URL, x['hls']), x['hds']
                       ] + [y['src'] for y in x.get('html5', [])]))

    _token_schema = validate.Schema(validate.transform(parse_json),
                                    {'token': validate.text},
                                    validate.get('token'))

    _user_agent = useragents.IE_11

    @classmethod
    def can_handle_url(cls, url):
        return IDF1._url_re.match(url)

    def _get_streams(self):
        res = 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 = http.get(self.DACAST_API_URL.format(broadcaster_id,
                                                     video_type, video_id),
                          schema=self._api_schema)
        token = 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
示例#26
0
class Rtve(Plugin):
    secret_key = base64.b64decode("eWVMJmRhRDM=")
    content_id_re = re.compile(r'data-id\s*=\s*"(\d+)"')
    url_re = re.compile(
        r"""
        https?://(?:www\.)?rtve\.es/(?:directo|noticias|television|deportes|alacarta|drmn)/.*?/?
    """, re.VERBOSE)
    cdn_schema = validate.Schema(
        validate.transform(partial(parse_xml, invalid_char_entities=True)),
        validate.xml_findall(".//preset"), [
            validate.union({
                "quality":
                validate.all(validate.getattr("attrib"), validate.get("type")),
                "urls":
                validate.all(validate.xml_findall(".//url"),
                             [validate.getattr("text")])
            })
        ])
    subtitles_api = "http://www.rtve.es/api/videos/{id}/subtitulos.json"
    subtitles_schema = validate.Schema(
        {"page": {
            "items": [{
                "src": validate.url(),
                "lang": validate.text
            }]
        }}, validate.get("page"), validate.get("items"))
    video_api = "http://www.rtve.es/api/videos/{id}.json"
    video_schema = validate.Schema(
        {
            "page": {
                "items": [{
                    "qualities": [{
                        "preset": validate.text,
                        "height": int
                    }]
                }]
            }
        }, validate.get("page"), validate.get("items"), validate.get(0))
    options = PluginOptions({"mux_subtitles": False})

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def __init__(self, url):
        Plugin.__init__(self, url)
        self.zclient = ZTNRClient(self.secret_key)
        http.headers = {"User-Agent": useragents.SAFARI_8}

    def _get_content_id(self):
        res = http.get(self.url)
        m = self.content_id_re.search(res.text)
        return m and int(m.group(1))

    def _get_subtitles(self, content_id):
        res = http.get(self.subtitles_api.format(id=content_id))
        return http.json(res, schema=self.subtitles_schema)

    def _get_quality_map(self, content_id):
        res = http.get(self.video_api.format(id=content_id))
        data = http.json(res, schema=self.video_schema)
        qmap = {}
        for item in data["qualities"]:
            qname = {
                "MED": "Media",
                "HIGH": "Alta",
                "ORIGINAL": "Original"
            }.get(item["preset"], item["preset"])
            qmap[qname] = u"{0}p".format(item["height"])
        return qmap

    def _get_streams(self):
        streams = []
        content_id = self._get_content_id()
        if content_id:
            self.logger.debug("Found content with id: {0}", content_id)
            stream_data = self.zclient.get_cdn_list(content_id,
                                                    schema=self.cdn_schema)
            quality_map = None

            for stream in stream_data:
                for url in stream["urls"]:
                    if url.endswith("m3u8"):
                        try:
                            streams.extend(
                                HLSStream.parse_variant_playlist(
                                    self.session, url).items())
                        except (IOError, OSError):
                            self.logger.debug("Failed to load m3u8 url: {0}",
                                              url)
                    elif ((url.endswith("mp4") or url.endswith("mov")
                           or url.endswith("avi"))
                          and http.head(
                              url, raise_for_status=False).status_code == 200):
                        if quality_map is None:  # only make the request when it is necessary
                            quality_map = self._get_quality_map(content_id)
                        # rename the HTTP sources to match the HLS sources
                        quality = quality_map.get(stream["quality"],
                                                  stream["quality"])
                        streams.append((quality, HTTPStream(self.session,
                                                            url)))

            subtitles = None
            if self.get_option("mux_subtitles"):
                subtitles = self._get_subtitles(content_id)
            if subtitles:
                substreams = {}
                for i, subtitle in enumerate(subtitles):
                    substreams[subtitle["lang"]] = HTTPStream(
                        self.session, subtitle["src"])

                for q, s in streams:
                    yield q, MuxedStream(self.session, s, subtitles=substreams)
            else:
                for s in streams:
                    yield s
示例#27
0
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
HUAJIAO_URL = "http://www.huajiao.com/l/{}"
LAPI_URL = "http://g2.live.360.cn/liveplay?stype=flv&channel={}&bid=huajiao&sn={}&sid={}&_rate=xd&ts={}&r={}&_ostype=flash&_delay=0&_sign=null&_ver=13"

_url_re = re.compile(
    r"""
        http(s)?://(www\.)?huajiao.com
        /l/(?P<channel>[^/]+)
""", re.VERBOSE)

_feed_json_re = re.compile(r'^\s*var\s*feed\s*=\s*(?P<feed>{.*})\s*;',
                           re.MULTILINE)

_feed_json_schema = validate.Schema(
    validate.all(
        validate.transform(_feed_json_re.search),
        validate.any(
            None,
            validate.all(validate.get('feed'),
                         validate.transform(json.loads)))))


class Huajiao(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")
示例#28
0
class SRGSSR(Plugin):
    url_re = re.compile(
        r"""https?://(?:www\.)?
            (srf|rts|rsi|rtr)\.ch/
            (?:
                play/tv|
                livestream/player|
                live-streaming|
                sport/direct/(\d+)-
            )""", re.VERBOSE)
    api_url = "http://il.srgssr.ch/integrationlayer/1.0/ue/{site}/video/play/{id}.json"
    token_url = "http://tp.srgssr.ch/akahd/token"
    video_id_re = re.compile(
        r'urn(?:%3A|:)(srf|rts|rsi|rtr)(?:%3A|:)(?:ais(?:%3A|:))?video(?:%3A|:)([^&"]+)'
    )
    video_id_schema = validate.Schema(validate.transform(video_id_re.search))
    api_schema = validate.Schema(
        {
            "Video": {
                "Playlists": {
                    "Playlist": [{
                        "@protocol":
                        validate.text,
                        "url": [{
                            "@quality": validate.text,
                            "text": validate.url()
                        }]
                    }]
                }
            }
        }, validate.get("Video"), validate.get("Playlists"),
        validate.get("Playlist"))
    token_schema = validate.Schema({"token": {
        "authparams": validate.text
    }}, validate.get("token"), validate.get("authparams"))

    @classmethod
    def can_handle_url(cls, url):
        return cls.url_re.match(url) is not None

    def get_video_id(self):
        parsed = urlparse(self.url)
        qinfo = dict(parse_qsl(parsed.query or parsed.fragment.lstrip("?")))

        site, video_id = None, None
        url_m = self.url_re.match(self.url)

        # look for the video id in the URL, otherwise find it in the page
        if "tvLiveId" in qinfo:
            video_id = qinfo["tvLiveId"]
            site = url_m.group(1)
        elif url_m.group(2):
            site, video_id = url_m.group(1), url_m.group(2)
        else:
            video_id_m = http.get(self.url, schema=self.video_id_schema)
            if video_id_m:
                site, video_id = video_id_m.groups()

        return site, video_id

    def auth_url(self, url):
        parsed = urlparse(url)
        path, _ = parsed.path.rsplit("/", 1)
        token_res = http.get(self.token_url, params=dict(acl=path + "/*"))
        authparams = http.json(token_res, schema=self.token_schema)

        existing = dict(parse_qsl(parsed.query))
        existing.update(dict(parse_qsl(authparams)))

        return urlunparse(parsed._replace(query=urlencode(existing)))

    def _get_streams(self):
        site, video_id = self.get_video_id()

        if video_id and site:
            self.logger.debug("Found {0} video ID {1}", site, video_id)

            try:
                res = http.get(self.api_url.format(site=site, id=video_id))
            except PluginError:
                return

            for stream_info in http.json(res, schema=self.api_schema):
                for url in stream_info["url"]:
                    if stream_info["@protocol"] == "HTTP-HLS":
                        for s in HLSStream.parse_variant_playlist(
                                self.session,
                                self.auth_url(url["text"])).items():
                            yield s
示例#29
0
    "live": True,
    "vod": False,
    "last_update": "",
    "broken": True,
}

BALANCER_URL = "http://www.mips.tv:1935/loadbalancer"
PLAYER_URL = "http://mips.tv/embedplayer/{0}/1/500/400"
SWF_URL = "http://mips.tv/content/scripts/eplayer.swf"

_url_re = re.compile(r"http(s)?://(\w+.)?mips.tv/(?P<channel>[^/&?]+)")
_flashvars_re = re.compile(r"'FlashVars', '([^']+)'")
_rtmp_re = re.compile(r"redirect=(.+)")

_schema = validate.Schema(
    validate.transform(_flashvars_re.search),
    validate.any(
        None,
        validate.all(validate.get(1), validate.transform(parse_query), {
            "id": validate.transform(int),
            validate.optional("s"): validate.text
        })))
_rtmp_schema = validate.Schema(
    validate.transform(_rtmp_re.search),
    validate.get(1),
)


class Mips(Plugin):
    @classmethod
    def can_handle_url(self, url):
示例#30
0
    "vod": True,
    "last_update": "2017-03-26",
}

_url_re = re.compile(
    r"""
    https?://(\w+\.)?aliez.\w+/
    (?:live/[^/]+|video/\d+/[^/]+)
""", re.VERBOSE)
_file_re = re.compile(r"\"?file\"?:\s+['\"]([^'\"]+)['\"]")
_swf_url_re = re.compile(r"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