Example #1
0
class QQ(Plugin):
    """Livecli Plugin for live.qq.com"""

    _data_schema = validate.Schema({"data": {
        "hls_url": validate.text
    }}, validate.get("data", {}), validate.get("hls_url"))

    api_url = "http://live.qq.com/api/h5/room?room_id={0}"

    _data_re = re.compile(r"""(?P<data>{.+})""")
    _url_re = re.compile(r"""https?://(m\.)?live\.qq\.com/(?P<room_id>\d+)""")

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

    def _get_streams(self):
        match = self._url_re.match(self.url)
        if not match:
            return

        room_id = match.group("room_id")
        res = http.get(self.api_url.format(room_id))

        data = self._data_re.search(res.text)
        if not data:
            return

        try:
            hls_url = parse_json(data.group("data"), schema=self._data_schema)
        except Exception:
            raise NoStreamsError(self.url)

        self.logger.debug("URL={0}".format(hls_url))
        return {"live": HLSStream(self.session, hls_url)}
Example #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})
Example #3
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.")
Example #4
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)
Example #5
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
Example #6
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)
Example #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"])
Example #8
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)
Example #9
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)
Example #10
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.")
Example #11
0
class LiveMe(Plugin):
    url_re = re.compile(r"https?://(www.)?liveme\.com/live\.html\?videoid=(\d+)")
    api_url = "https://live.ksmobile.net/live/queryinfo"
    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 _random_t(self, t):
        return "".join(random.choice("ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678") for _ in range(t))

    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:
            vali = '{0}l{1}m{2}'.format(self._random_t(4), self._random_t(4), self._random_t(5))
            data = {
                'userid': 1,
                'videoid': video_id,
                'area': '',
                'h5': 1,
                'vali': vali
            }
            self.logger.debug("Found Video ID: {0}".format(video_id))
            res = http.post(self.api_url, data=data)
            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
Example #12
0
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.)?
                             (?:(atvavrupa).tv|
                                (atv|a2tv|ahaber|aspor|minikago|minikacocuk|anews).com.tr)
                                /webtv/(live-broadcast|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",
            "anews": "anewshd",
            "minikacocuk": "minikagococuk"
        }.get(domain, domain)
        hls_url = self._hls_url.format(channel=channel)
        # get the secure HLS URL
        res = http.get(self._token_url,
                       params="url={0}".format(hls_url),
                       headers={
                           "Referer": self.url,
                           "User-Agent": useragents.CHROME
                       })

        secure_hls_url = http.json(res, schema=self._token_schema)

        self.logger.debug("Found HLS URL: {0}".format(secure_hls_url))
        return HLSStream.parse_variant_playlist(self.session, secure_hls_url)
Example #13
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'])
Example #14
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)
Example #15
0
class RTBF(Plugin):
    """Livecli Plugin for RTBF"""

    _url_re = re.compile(r"""https?://(?:www\.)rtbf\.be/auvio/""")

    api_live_url = "https://www.rtbf.be/embed/d/ajax/refresh?id={0}"

    _live_schema = validate.Schema(
        {
            "data": validate.any(
                None,
                [],
                {
                    "streamUrlHls": validate.text,
                },
            ),
        },
        validate.get("data"),
    )

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

    def _get_live_stream(self, live_id):
        res = http.get(self.api_live_url.format(live_id))
        live_data = http.json(res, schema=self._live_schema)
        if not live_data:
            self.logger.debug("No data found.")
            return

        for s in HLSStream.parse_variant_playlist(
                self.session, live_data["streamUrlHls"]).items():
            yield s

    def _get_streams(self):
        params = dict(parse_qsl(urlparse(self.url).query))
        live_id = params.get("lid")

        if live_id:
            return self._get_live_stream(live_id)
Example #16
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"])
Example #17
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
Example #18
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)
Example #19
0
class FilmOnAPI(object):
    channel_url = "http://www.filmon.com/api-v2/channel/{0}?protocol=hls"
    vod_url = "http://www.filmon.com/vod/info/{0}"

    stream_schema = {
        "quality": validate.text,
        "url": validate.url(),
        "watch-timeout": int
    }
    api_schema = validate.Schema(
        {
            "data": {
                "streams":
                validate.any({validate.text: stream_schema}, [stream_schema])
            }
        }, validate.get("data"))

    def channel(self, channel):
        res = http.get(self.channel_url.format(channel))
        return http.json(res, schema=self.api_schema)

    def vod(self, vod_id):
        res = http.get(self.vod_url.format(vod_id))
        return http.json(res, schema=self.api_schema)
Example #20
0
class PowerApp(Plugin):
    url_re = re.compile(r"https?://(?:www.)?powerapp.com.tr/tv/(\w+)")
    api_url = "http://api.powergroup.com.tr/Channels/{0}/?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"])
Example #21
0
class Zattoo(Plugin):
    API_HELLO = '{0}/zapi/session/hello'
    API_LOGIN = '******'
    API_CHANNELS = '{0}/zapi/v2/cached/channels/{1}?details=False'
    API_WATCH = '{0}/zapi/watch'
    API_WATCH_REC = '{0}/zapi/watch/recording/{1}'
    API_WATCH_VOD = '{0}/zapi/avod/videos/{1}/watch'

    _url_re = re.compile(r'''
        https?://
        (?P<base_url>
        zattoo\.com
        |
        tvonline\.ewe\.de
        |
        nettv\.netcologne\.de
        )/
        (?:
            (?:ondemand/)?(?:watch/(?:[^/\s]+)(?:/[^/]+/(?P<recording_id>\d+)))
            |
            watch/(?P<channel>[^/\s]+)
            |
            ondemand/watch/(?P<vod_id>[^-]+)-
        )
        ''', re.VERBOSE)

    _app_token_re = re.compile(r"""window\.appToken\s+=\s+'([^']+)'""")

    _channels_schema = validate.Schema({
        'success': int,
        'channel_groups': [{
            'channels': [
                {
                    'display_alias': validate.text,
                    'cid': validate.text
                },
            ]
        }]},
        validate.get('channel_groups'),
    )

    options = PluginOptions({
        'email': None,
        'password': None,
        'purge_credentials': None
    })

    def __init__(self, url):
        super(Zattoo, self).__init__(url)
        self._session_attributes = Cache(filename='plugin-cache.json', key_prefix='zattoo:attributes')
        self._authed = self._session_attributes.get('beaker.session.id') and self._session_attributes.get('pzuid') and self._session_attributes.get('power_guide_hash')
        self._uuid = self._session_attributes.get('uuid')
        self._expires = self._session_attributes.get('expires', 946684800)

        self.base_url = 'https://{0}'.format(Zattoo._url_re.match(url).group('base_url'))
        self.headers = {
            'User-Agent': useragents.CHROME,
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': self.base_url
        }

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

    def _hello(self):
        self.logger.debug('_hello ...')
        headers = {
            'User-Agent': useragents.CHROME,
            'Referer': self.base_url
        }
        res = requests.get("{0}/login".format(self.base_url), headers=headers)
        match = self._app_token_re.search(res.text)

        app_token = match.group(1)
        hello_url = self.API_HELLO.format(self.base_url)

        if self._uuid:
            __uuid = self._uuid
        else:
            __uuid = str(uuid.uuid4())
            self._session_attributes.set('uuid', __uuid, expires=3600 * 24)

        params = {
            'client_app_token': app_token,
            'uuid': __uuid,
            'lang': 'en',
            'format': 'json'
        }
        res = http.post(hello_url, headers=self.headers, data=params)
        return res

    def _login(self, email, password, _hello):
        self.logger.debug('_login ... Attempting login as {0}'.format(email))

        login_url = self.API_LOGIN.format(self.base_url)

        params = {
            'login': email,
            'password': password,
            'remember': 'true'
        }

        res = http.post(login_url, headers=self.headers, data=params, cookies=_hello.cookies)
        data = http.json(res)

        self._authed = data['success']
        if self._authed:
            self.logger.debug('New Session Data')
            self._session_attributes.set('beaker.session.id', res.cookies.get('beaker.session.id'), expires=3600 * 24)
            self._session_attributes.set('pzuid', res.cookies.get('pzuid'), expires=3600 * 24)
            self._session_attributes.set('power_guide_hash', data['session']['power_guide_hash'], expires=3600 * 24)
            return self._authed
        else:
            return None

    def _watch(self):
        self.logger.debug('_watch ...')
        match = self._url_re.match(self.url)
        if not match:
            self.logger.debug('_watch ... no match')
            return
        channel = match.group('channel')
        vod_id = match.group('vod_id')
        recording_id = match.group('recording_id')

        cookies = {
            'beaker.session.id': self._session_attributes.get('beaker.session.id'),
            'pzuid': self._session_attributes.get('pzuid')
        }

        watch_url = []
        if channel:
            params, watch_url = self._watch_live(channel, cookies)
        elif vod_id:
            params, watch_url = self._watch_vod(vod_id)
        elif recording_id:
            params, watch_url = self._watch_recording(recording_id)

        if not watch_url:
            self.logger.debug('Missing watch_url')
            return

        res = []
        try:
            res = http.post(watch_url, headers=self.headers, data=params, cookies=cookies)
        except Exception as e:
            if '404 Client Error' in str(e):
                self.logger.error('Unfortunately streaming is not permitted in this country or this channel does not exist.')
            elif '402 Client Error: Payment Required' in str(e):
                self.logger.error('Paid subscription required for this channel.')
                self.logger.info('If paid subscription exist, use --zattoo-purge-credentials to start a new session.')
            else:
                self.logger.error(str(e))
            return

        self.logger.debug('Found post data')
        data = http.json(res)

        if data['success']:
            for hls_url in data['stream']['watch_urls']:
                for s in HLSStream.parse_variant_playlist(self.session, hls_url['url']).items():
                    yield s

    def _watch_live(self, channel, cookies):
        self.logger.debug('_watch_live ... Channel: {0}'.format(channel))
        watch_url = self.API_WATCH.format(self.base_url)

        channels_url = self.API_CHANNELS.format(self.base_url, self._session_attributes.get('power_guide_hash'))
        res = http.get(channels_url, headers=self.headers, cookies=cookies)
        data = http.json(res, schema=self._channels_schema)

        c_list = []
        for d in data:
            for c in d['channels']:
                c_list.append(c)

        cid = []
        zattoo_list = []
        for c in c_list:
            zattoo_list.append(c['display_alias'])
            if c['display_alias'] == channel:
                cid = c['cid']

        self.logger.debug('Available zattoo channels in this country: {0}'.format(', '.join(sorted(zattoo_list))))

        if not cid:
            cid = channel

        self.logger.debug('CHANNEL ID: {0}'.format(cid))

        params = {
            'cid': cid,
            'https_watch_urls': True,
            'stream_type': 'hls'
        }
        return params, watch_url

    def _watch_recording(self, recording_id):
        self.logger.debug('_watch_recording ...')
        watch_url = self.API_WATCH_REC.format(self.base_url, recording_id)
        params = {
            'https_watch_urls': True,
            'stream_type': 'hls'
        }
        return params, watch_url

    def _watch_vod(self, vod_id):
        self.logger.debug('_watch_vod ...')
        watch_url = self.API_WATCH_VOD.format(self.base_url, vod_id)
        params = {
            'https_watch_urls': True,
            'stream_type': 'hls'
        }
        return params, watch_url

    def _get_streams(self):
        email = self.get_option('email')
        password = self.get_option('password')

        if self.options.get('purge_credentials'):
            self._session_attributes.set('beaker.session.id', None, expires=0)
            self._session_attributes.set('expires', None, expires=0)
            self._session_attributes.set('power_guide_hash', None, expires=0)
            self._session_attributes.set('pzuid', None, expires=0)
            self._session_attributes.set('uuid', None, expires=0)
            self._authed = False
            self.logger.info('All credentials were successfully removed.')

        if not self._authed and (not email and not password):
            self.logger.error('A login for Zattoo is required, use --zattoo-email EMAIL --zattoo-password PASSWORD to set them')
            return

        if self._authed:
            if self._expires < time.time():
                # login after 24h
                expires = time.time() + 3600 * 24
                self._session_attributes.set('expires', expires, expires=3600 * 24)
                self._authed = False

        if not self._authed:
            __hello = self._hello()
            if not self._login(email, password, __hello):
                self.logger.error('Failed to login, check your username/password')
                return

        return self._watch()
Example #22
0
    "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):
        return _url_re.match(url)

    @Plugin.broken()
Example #23
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
Example #24
0
    }]),
    validate.optional("hlsvp"):
    validate.text,
    validate.optional("live_playback"):
    validate.transform(bool),
    validate.optional("reason"):
    validate.text,
    "status":
    validate.text
})
_search_schema = validate.Schema(
    {"items": [{
        "id": {
            "videoId": validate.text
        }
    }]}, validate.get("items"))

_channelid_re = re.compile(r'meta itemprop="channelId" content="([^"]+)"')
_livechannelid_re = re.compile(
    r'meta property="og:video:url" content="([^"]+)')
_url_re = re.compile(
    r"""
    https?://
    (?:
    (?:\w+\.)?youtube(?:-nocookie)?\.com
    (?:
        (?:
            /(watch.+v=|embed/|v/)
            (?P<video_id>[0-9A-z_-]{11})
        )
        |
Example #25
0
        /
        (?P<video_type>[bcv])
        /
        (?P<video_id>\d+)
    )?
    (?:
        /
        (?P<clip_name>[\w]+)
    )?
""", 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: [{
Example #26
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"))
Example #27
0
        validate.optional("hlsvp"): validate.text,
        validate.optional("live_playback"): validate.transform(bool),
        validate.optional("reason"): validate.text,
        validate.optional("title"): validate.text,
        "status": validate.text
    }
)
_search_schema = validate.Schema(
    {
        "items": [{
            "id": {
                "videoId": validate.text
            }
        }]
    },
    validate.get("items")
)

_channelid_re = re.compile(r'meta itemprop="channelId" content="([^"]+)"')
_livechannelid_re = re.compile(r'meta property="og:video:url" content="([^"]+)')
_url_re = re.compile(r"""
    https?://
    (?:
    (?:\w+\.)?youtube(?:-nocookie)?\.com
    (?:
        (?:
            /(watch.+v=|embed/|v/)
            (?P<video_id>[0-9A-z_-]{11})
        )
        |
        (?:
Example #28
0
    {
        "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)),
    "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):
Example #29
0
    ],
    "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),
            validate.get("contentUrl")
        )
    )
Example #30
0
_sd_re = re.compile(r'"SD"\s*:\s*"(\d+)"')
_hd_re = re.compile(r'"HD"\s*:\s*"(\d+)"')
_od_re = re.compile(r'"OD"\s*:\s*"(\d+)"')

_room_schema = validate.Schema(
    {
        "data":
        validate.any(
            validate.text, dict, {
                "videoinfo":
                validate.any(validate.text, {
                    "plflag_list": validate.text,
                    "plflag": validate.text
                })
            })
    }, validate.get("data"))


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

    def _get_streams(self):
        match = _url_re.match(self.url)
        channel = match.group("channel")

        res = http.get(self.url)

        try:
            channel = int(channel)