Beispiel #1
0
class Garena(Plugin):
    API_INFO = "https://garena.live/api/channel_info_get"
    API_STREAM = "https://garena.live/api/channel_stream_get"

    _info_schema = validate.Schema({
        "reply":
        validate.any({
            "channel_id": int,
        }, None),
        "result":
        validate.text
    })
    _stream_schema = validate.Schema({
        "reply":
        validate.any(
            {
                "streams": [{
                    "url": validate.text,
                    "resolution": int,
                    "bitrate": int,
                    "format": int
                }]
            }, None),
        "result":
        validate.text
    })

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

    def _post_api(self, api, payload, schema):
        res = http.post(api, json=payload)
        data = http.json(res, schema=schema)

        if data["result"] == "success":
            post_data = data["reply"]
            return post_data

    def _get_streams(self):
        match = _url_re.match(self.url)
        if match.group("alias"):
            payload = {"alias": match.group("alias")}
            info_data = self._post_api(self.API_INFO, payload,
                                       self._info_schema)
            channel_id = info_data["channel_id"]
        elif match.group("channel_id"):
            channel_id = int(match.group("channel_id"))

        if channel_id:
            payload = {"channel_id": channel_id}
            stream_data = self._post_api(self.API_STREAM, payload,
                                         self._stream_schema)
            for stream in stream_data["streams"]:
                n = "{0}p".format(stream["resolution"])
                if stream["format"] == 3:
                    s = HLSStream(self.session, stream["url"])
                    yield n, s
Beispiel #2
0
class NineAnime(Plugin):
    _episode_info_url = "//9anime.to/ajax/episode/info"

    _info_schema = validate.Schema({
        "grabber": validate.url(),
        "params": {
            "id": validate.text,
            "token": validate.text,
            "options": validate.text,
        }
    })

    _streams_schema = validate.Schema({
        "token":
        validate.text,
        "error":
        None,
        "data": [{
            "label": validate.text,
            "file": validate.url(),
            "type": "mp4"
        }]
    })

    _url_re = re.compile(r"https?://9anime.to/watch/(?:[^.]+?\.)(\w+)/(\w+)")

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

    def add_scheme(self, url):
        # update the scheme for the grabber url if required
        if url.startswith("//"):
            url = "{0}:{1}".format(urlparse(self.url).scheme, url)
        return url

    def _get_streams(self):
        match = self._url_re.match(self.url)
        film_id, episode_id = match.groups()

        headers = {"Referer": self.url, "User-Agent": useragents.FIREFOX}

        # Get the info about the Episode, including the Grabber API URL
        info_res = http.get(self.add_scheme(self._episode_info_url),
                            params=dict(update=0, film=film_id, id=episode_id),
                            headers=headers)
        info = http.json(info_res, schema=self._info_schema)

        # Get the data about the streams from the Grabber API
        grabber_url = self.add_scheme(info["grabber"])
        stream_list_res = http.get(grabber_url,
                                   params=info["params"],
                                   headers=headers)
        stream_data = http.json(stream_list_res, schema=self._streams_schema)

        for stream in stream_data["data"]:
            yield stream["label"], HTTPStream(self.session, stream["file"])
Beispiel #3
0
class Euronews(Plugin):
    _url_re = re.compile(r"http(?:s)?://(\w+)\.?euronews.com/(live|.*)")
    _re_vod = re.compile(
        r'<meta\s+property="og:video"\s+content="(http.*?)"\s*/>')
    _live_api_url = "http://{0}.euronews.com/api/watchlive.json"
    _live_schema = validate.Schema({u"url": validate.url()})
    _stream_api_schema = validate.Schema({
        u'status':
        u'ok',
        u'primary':
        validate.url(),
        validate.optional(u'backup'):
        validate.url()
    })

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

    def _get_vod_stream(self):
        """
        Find the VOD video url
        :return: video url
        """
        res = http.get(self.url)
        video_urls = self._re_vod.findall(res.text)
        if len(video_urls):
            return dict(vod=HTTPStream(self.session, video_urls[0]))

    def _get_live_streams(self, subdomain):
        """
        Get the live stream in a particular language
        :param subdomain:
        :return:
        """
        res = http.get(self._live_api_url.format(subdomain))
        live_res = http.json(res, schema=self._live_schema)
        api_res = http.get(live_res[u"url"])
        stream_data = http.json(api_res, schema=self._stream_api_schema)
        return HLSStream.parse_variant_playlist(self.session,
                                                stream_data[u'primary'])

    def _get_streams(self):
        """
        Find the streams for euronews
        :return:
        """
        match = self._url_re.match(self.url)
        subdomain, path = match.groups()

        if path == "live":
            return self._get_live_streams(subdomain)
        else:
            return self._get_vod_stream()
Beispiel #4
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.")
Beispiel #5
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)}
Beispiel #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
Beispiel #7
0
 def test_parse_xml_validate(self):
     expected = ET.Element("test", {"foo": "bar"})
     actual = parse_xml(u"""<test foo="bar"/>""",
                        schema=validate.Schema(
                            xml_element(tag="test", attrib={"foo": text})))
     self.assertEqual(expected.tag, actual.tag)
     self.assertEqual(expected.attrib, actual.attrib)
Beispiel #8
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)
Beispiel #9
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)
Beispiel #10
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"])
Beispiel #11
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})
Beispiel #12
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)
Beispiel #13
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
Beispiel #14
0
 def test_parse_qsd(self):
     self.assertEqual({
         "test": "1",
         "foo": "bar"
     },
                      parse_qsd("test=1&foo=bar",
                                schema=validate.Schema({
                                    "test": validate.text,
                                    "foo": "bar"
                                })))
Beispiel #15
0
 def test_parse_json(self):
     self.assertEqual({}, parse_json("{}"))
     self.assertEqual({"test": 1}, parse_json("""{"test": 1}"""))
     self.assertEqual({"test": 1},
                      parse_json("""{"test": 1}""",
                                 schema=validate.Schema({"test": 1})))
     self.assertRaises(PluginError, parse_json, """{"test: 1}""")
     self.assertRaises(IOError,
                       parse_json,
                       """{"test: 1}""",
                       exception=IOError)
     self.assertRaises(PluginError, parse_json, """{"test: 1}""" * 10)
Beispiel #16
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.")
Beispiel #17
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
Beispiel #18
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)
Beispiel #19
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'])
Beispiel #20
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)
Beispiel #21
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
Beispiel #22
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"])
Beispiel #23
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)
Beispiel #24
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)
Beispiel #25
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)
Beispiel #26
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)
Beispiel #27
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"])
Beispiel #28
0
    "domains": [
        "camsoda.com",
    ],
    "geo_blocked": [],
    "notes": "",
    "live": True,
    "vod": False,
    "last_update": "2017-11-18",
}

_url_re = re.compile(r"http(s)?://(www\.)?camsoda\.com/(?P<username>[^\"\']+)")

_api_user_schema = validate.Schema({
    "status": validate.any(int, validate.text),
    validate.optional("user"): {
        "online": validate.any(int, validate.text),
        "chatstatus": validate.text,
    }
})

_api_video_schema = validate.Schema({
    "token": validate.text,
    "app": validate.text,
    "edge_servers": [validate.text],
    "stream_name": validate.text
})


class Camsoda(Plugin):
    API_URL_USER = "******"
    API_URL_VIDEO = "https://www.camsoda.com/api/v1/video/vtoken/{0}?username=guest_{1}"
Beispiel #29
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()
Beispiel #30
0
    "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):
        return _url_re.match(url)

    @Plugin.broken()