Esempio n. 1
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 = self.session.http.get(self.url,
                                         schema=self._player_url_schema)
        if data_url:
            res = self.session.http.get(urljoin(self.url, data_url))
            stream_info = self.session.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)
Esempio n. 2
0
    def test_xml_findall(self):
        el = Element("parent")
        children = [Element("child") for i in range(10)]
        for child in children:
            el.append(child)

        assert validate(xml_findall("child"), el) == children
Esempio n. 3
0
    def test_xml_findall(self):
        el = Element("parent")
        children = [Element("child") for i in range(10)]
        for child in children:
            el.append(child)

        assert validate(xml_findall("child"), el) == children
Esempio n. 4
0
 def test_failure_schema(self):
     with pytest.raises(validate.ValidationError) as cm:
         validate.validate(validate.xml_findall("*"), "not-an-element")
     assert_validationerror(
         cm.value, """
         ValidationError(Callable):
           iselement('not-an-element') is not true
     """)
Esempio n. 5
0
    def _get_streams(self):
        if not self.matches[0]:
            self._domain = urlparse(self.url).netloc
            iframes = self.session.http.get(
                self.url,
                schema=validate.Schema(
                    validate.parse_html(),
                    validate.xml_findall(".//iframe[@src]"),
                    validate.filter(lambda elem: urlparse(
                        elem.attrib.get("src")).netloc == "ott.streann.com")))
            if not iframes:
                log.error("Could not find 'ott.streann.com' iframe")
                return
            self.url = iframes[0].attrib.get("src")

        if not self._domain and self.get_option("url"):
            self._domain = urlparse(self.get_option("url")).netloc

        if self._domain is None:
            log.error("Missing source URL, use --streann-url")
            return

        self.session.http.headers.update({"Referer": self.url})
        # Get the query string
        encrypted_data = urlparse(self.url).query
        data = base64.b64decode(encrypted_data)
        # and decrypt it
        passphrase = self.passphrase()
        if passphrase:
            log.debug("Found passphrase")
            params = decrypt_openssl(data, passphrase)
            config = parse_qsd(params.decode("utf8"))
            log.trace("config: {0!r}".format(config))
            token = self.get_token(**config)
            if not token:
                return
            hls_url = self.stream_url.format(time=self.time,
                                             deviceId=self.device_id,
                                             token=token,
                                             **config)
            log.debug("URL={0}".format(hls_url))
            return HLSStream.parse_variant_playlist(
                self.session, hls_url, acceptable_status=(200, 403, 404, 500))
Esempio n. 6
0
    def _streams_brightcove_js(self, root):
        re_js_src = re.compile(r"^[\w/]+/main\.\w+\.js$")
        re_js_brightcove_video = re.compile(
            r'i\?\([A-Z]="[^"]+",y="(?P<video_id>[0-9]+).*"data-account"\s*:\s*"(?P<account_id>[0-9]+)',
        )
        schema_brightcove_js = validate.Schema(
            validate.xml_findall(r".//script[@src]"),
            validate.filter(
                lambda elem: re_js_src.search(elem.attrib.get("src"))),
            validate.get(0), str,
            validate.transform(lambda src: urljoin(self.url, src)))
        schema_brightcove_js2 = validate.Schema(
            validate.transform(re_js_brightcove_video.search),
            validate.union_get("account_id", "video_id"))
        try:
            js_url = schema_brightcove_js.validate(root)
            log.debug(f"JS URL: {js_url}")
            account_id, video_id = self.session.http.get(
                js_url, schema=schema_brightcove_js2)
        except (PluginError, TypeError):
            return

        return self._brightcove(account_id, video_id)
Esempio n. 7
0
from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.stream import HLSStream, HDSStream

STREAM_INFO_URL = "http://live.daserste.de/{0}/livestream.xml"
SWF_URL = "http://live.daserste.de/lib/br-player/swf/main.swf"
STREAMING_TYPES = {
    "streamingUrlLive": ("HDS", partial(HDSStream.parse_manifest,
                                        pvswf=SWF_URL)),
    "streamingUrlIPhone": ("HLS", HLSStream.parse_variant_playlist)
}

_url_re = re.compile(r"http(s)?://live.daserste.de/(?P<channel>[^/?]+)?")

_livestream_schema = validate.Schema(
    validate.xml_findall("video/*"),
    validate.filter(lambda e: e.tag in STREAMING_TYPES),
    validate.map(lambda e: (STREAMING_TYPES.get(e.tag), e.text)),
    validate.transform(dict),
)


class ard_live(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(STREAM_INFO_URL.format(channel))
Esempio n. 8
0
            }
        ),
        "clientlibs": validate.all(
            validate.transform(_clientlibs_re.search),
            validate.get(2),
            validate.text
        )
    })
)

_language_schema = validate.Schema(
    validate.xml_findtext("./country_code")
)

_xml_to_srt_schema = validate.Schema(
    validate.xml_findall(".//body/div"),
    [
        validate.union([validate.all(
            validate.getattr("attrib"),
            validate.get("{http://www.w3.org/XML/1998/namespace}lang")
        ),
            validate.all(
                validate.xml_findall("./p"),
                validate.transform(lambda x: list(enumerate(x, 1))),
                [
                    validate.all(
                        validate.union({
                            "i": validate.get(0),
                            "begin": validate.all(
                                validate.get(1),
                                validate.getattr("attrib"),
Esempio n. 9
0
"""

import re

from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.stream import HLSStream

API_BASE = "http://gox.gomexp.com/cgi-bin"
API_URL_APP = API_BASE + "/app_api.cgi"
API_URL_LIVE = API_BASE + "/gox_live.cgi"

_url_re = re.compile("http(s)?://(www\.)?gomexp.com")

_entries_schema = validate.Schema(
    validate.xml_findall("./ENTRY/*/[@reftype='live'][@href]"),
    [validate.get("href")])


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

    def _get_live_cubeid(self):
        res = http.get(API_URL_APP, params=dict(mode="get_live"))
        root = http.xml(res)
        return root.findtext("./cube/cubeid")

    def _get_streams(self):
        cubeid = self._get_live_cubeid()
Esempio n. 10
0
STREAM_INFO_URL = "http://live.daserste.de/{0}/livestream.xml"
SWF_URL = "http://live.daserste.de/lib/br-player/swf/main.swf"
STREAMING_TYPES = {
    "streamingUrlLive": (
        "HDS", partial(HDSStream.parse_manifest, pvswf=SWF_URL)
    ),
    "streamingUrlIPhone": (
        "HLS", HLSStream.parse_variant_playlist
    )
}

_url_re = re.compile("http(s)?://live.daserste.de/(?P<channel>[^/?]+)?")

_livestream_schema = validate.Schema(
    validate.xml_findall("video/*"),
    validate.filter(lambda e: e.tag in STREAMING_TYPES),
    validate.map(lambda e: (STREAMING_TYPES.get(e.tag), e.text)),
    validate.transform(dict),
)

class ard_live(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(STREAM_INFO_URL.format(channel))
        urls = http.xml(res, schema=_livestream_schema)
Esempio n. 11
0
from streamlink.stream import RTMPStream

_url_re = re.compile(r"http(s)?://(\w+.)?beam.pro/(?P<channel>[^/]+)")

CHANNEL_INFO = "https://beam.pro/api/v1/channels/{0}"
CHANNEL_MANIFEST = "https://beam.pro/api/v1/channels/{0}/manifest.smil"

_assets_schema = validate.Schema(
    validate.union({
        "base": validate.all(
            validate.xml_find("./head/meta"),
            validate.get("base"),
            validate.url(scheme="rtmp")
        ),
        "videos": validate.all(
            validate.xml_findall(".//video"),
            [
                validate.union({
                    "src": validate.all(
                        validate.get("src"),
                        validate.text
                    ),
                    "height": validate.all(
                        validate.get("height"),
                        validate.text,
                        validate.transform(int)
                    )
                })
            ]
        )
    })
Esempio n. 12
0
 def _schema_consent(data):
     schema_consent = validate.Schema(
         validate.parse_html(),
         validate.xml_findall(".//input[@type='hidden']"))
     return schema_consent.validate(data)
class DeutscheWelle(Plugin):
    default_channel = "1"
    url_re = re.compile(r"https?://(?:www\.)?dw\.com/")

    channel_re = re.compile(r'''<a.*?data-id="(\d+)".*?class="ici"''')
    live_stream_div = re.compile(
        r'''
        <div\s+class="mediaItem"\s+data-channel-id="(\d+)".*?>.*?
        <input\s+type="hidden"\s+name="file_name"\s+value="(.*?)"\s*>.*?<div
    ''', re.DOTALL | re.VERBOSE)

    smil_api_url = "http://www.dw.com/smil/{}"
    html5_api_url = "http://www.dw.com/html5Resource/{}"
    vod_player_type_re = re.compile(
        r'<input type="hidden" name="player_type" value="(?P<stream_type>.+?)">'
    )
    stream_vod_data_re = re.compile(
        r'<input\s+type="hidden"\s+name="file_name"\s+value="(?P<stream_url>.+?)">.*?'
        r'<input\s+type="hidden"\s+name="media_id"\s+value="(?P<stream_id>\d+)">',
        re.DOTALL)

    smil_schema = validate.Schema(
        validate.union({
            "base":
            validate.all(validate.xml_find(".//meta"),
                         validate.xml_element(attrib={"base": validate.text}),
                         validate.get("base")),
            "streams":
            validate.all(validate.xml_findall(".//switch/*"), [
                validate.all(
                    validate.getattr("attrib"), {
                        "src":
                        validate.text,
                        "system-bitrate":
                        validate.all(
                            validate.text,
                            validate.transform(int),
                        ),
                        validate.optional("width"):
                        validate.all(validate.text, validate.transform(int))
                    })
            ])
        }))

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

    def _create_stream(self, url, quality=None):
        if url.startswith('rtmp://'):
            return (quality, RTMPStream(self.session, {'rtmp': url}))
        if url.endswith('.m3u8'):
            return HLSStream.parse_variant_playlist(self.session, url).items()

        return (quality, HTTPStream(self.session, url))

    def _get_live_streams(self, page):
        # check if a different language has been selected
        qs = dict(parse_qsl(urlparse(self.url).query))
        channel = qs.get("channel")

        if not channel:
            m = self.channel_re.search(page.text)
            channel = m and m.group(1)

        self.logger.debug("Using sub-channel ID: {0}", channel)

        # extract the streams from the page, mapping between channel-id and stream url
        media_items = self.live_stream_div.finditer(page.text)
        stream_map = dict([mi.groups((1, 2)) for mi in media_items])

        stream_url = stream_map.get(str(channel) or self.default_channel)
        if stream_url:
            return self._create_stream(stream_url)

    def _get_vod_streams(self, stream_type, page):
        m = self.stream_vod_data_re.search(page.text)
        if m is None:
            return
        stream_url, stream_id = m.groups()

        if stream_type == "video":
            stream_api_id = "v-{}".format(stream_id)
            default_quality = "vod"
        elif stream_type == "audio":
            stream_api_id = "a-{}".format(stream_id)
            default_quality = "audio"
        else:
            return

        # Retrieve stream embedded in web page
        yield self._create_stream(stream_url, default_quality)

        # Retrieve streams using API
        res = self.session.http.get(self.smil_api_url.format(stream_api_id))
        videos = self.session.http.xml(res, schema=self.smil_schema)

        for video in videos['streams']:
            url = videos["base"] + video["src"]
            if url == stream_url or url.replace("_dwdownload.",
                                                ".") == stream_url:
                continue

            if video["system-bitrate"] > 0:
                # If width is available, use it to select the best stream
                # amongst those with same bitrate
                quality = "{}k".format(
                    (video["system-bitrate"] + video.get("width", 0)) // 1000)
            else:
                quality = default_quality

            yield self._create_stream(url, quality)

    def _get_streams(self):
        res = self.session.http.get(self.url)
        m = self.vod_player_type_re.search(res.text)
        if m is None:
            return

        stream_type = m.group("stream_type")
        if stream_type == "dwlivestream":
            return self._get_live_streams(res)

        return self._get_vod_streams(stream_type, res)
Esempio n. 14
0
"""

import re

from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.stream import HLSStream

API_BASE = "http://gox.gomexp.com/cgi-bin"
API_URL_APP = API_BASE + "/app_api.cgi"
API_URL_LIVE = API_BASE + "/gox_live.cgi"

_url_re = re.compile(r"http(s)?://(www\.)?gomexp.com")

_entries_schema = validate.Schema(
    validate.xml_findall("./ENTRY/*/[@reftype='live'][@href]"),
    [validate.get("href")]
)


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

    def _get_live_cubeid(self):
        res = http.get(API_URL_APP, params=dict(mode="get_live"))
        root = http.xml(res)
        return root.findtext("./cube/cubeid")

    def _get_streams(self):
Esempio n. 15
0
    },
    validate.optional("playerUri"): validate.text
})
_smil_schema = validate.Schema(validate.union({
    "http_base": validate.all(
        validate.xml_find("{http://www.w3.org/2001/SMIL20/Language}head/"
                          "{http://www.w3.org/2001/SMIL20/Language}meta"
                          "[@name='httpBase']"),
        validate.xml_element(attrib={
            "content": validate.text
        }),
        validate.get("content")
    ),
    "videos": validate.all(
        validate.xml_findall("{http://www.w3.org/2001/SMIL20/Language}body/"
                             "{http://www.w3.org/2001/SMIL20/Language}switch/"
                             "{http://www.w3.org/2001/SMIL20/Language}video"),
        [
            validate.all(
                validate.xml_element(attrib={
                    "src": validate.text,
                    "system-bitrate": validate.all(
                        validate.text,
                        validate.transform(int)
                    )
                }),
                validate.transform(
                    lambda e: (e.attrib["src"], e.attrib["system-bitrate"])
                )
            )
        ],
Esempio n. 16
0
 def test_simple(self, element):
     assert validate.validate(validate.xml_findall("*"), element) == [
         element[0], element[1], element[2]
     ]
Esempio n. 17
0
class WWENetwork(Plugin):
    url_re = re.compile(r"https?://network.wwe.com")
    content_id_re = re.compile(r'''"content_id" : "(\d+)"''')
    playback_scenario = "HTTP_CLOUD_WIRED"
    login_url = "https://secure.net.wwe.com/workflow.do"
    login_page_url = "https://secure.net.wwe.com/enterworkflow.do?flowId=account.login&forwardUrl=http%3A%2F%2Fnetwork.wwe.com"
    api_url = "https://ws.media.net.wwe.com/ws/media/mf/op-findUserVerifiedEvent/v-2.3"
    _info_schema = validate.Schema(
        validate.union({
            "status":
            validate.union({
                "code":
                validate.all(validate.xml_findtext(".//status-code"),
                             validate.transform(int)),
                "message":
                validate.xml_findtext(".//status-message"),
            }),
            "urls":
            validate.all(validate.xml_findall(".//url"),
                         [validate.getattr("text")]),
            validate.optional("fingerprint"):
            validate.xml_findtext(".//updated-fingerprint"),
            validate.optional("session_key"):
            validate.xml_findtext(".//session-key"),
            "session_attributes":
            validate.all(validate.xml_findall(".//session-attribute"), [
                validate.getattr("attrib"),
                validate.union({
                    "name": validate.get("name"),
                    "value": validate.get("value")
                })
            ])
        }))
    arguments = PluginArguments(
        PluginArgument("email",
                       required=True,
                       metavar="EMAIL",
                       requires=["password"],
                       help="""
        The email associated with your WWE Network account,
        required to access any WWE Network stream.
        """),
        PluginArgument("password",
                       sensitive=True,
                       metavar="PASSWORD",
                       help="""
        A WWE Network account password to use with --wwenetwork-email.
        """))

    def __init__(self, url):
        super(WWENetwork, self).__init__(url)
        http.headers.update({"User-Agent": useragents.CHROME})
        self._session_attributes = Cache(filename="plugin-cache.json",
                                         key_prefix="wwenetwork:attributes")
        self._session_key = self.cache.get("session_key")
        self._authed = self._session_attributes.get(
            "ipid") and self._session_attributes.get("fprt")

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

    def login(self, email, password):
        self.logger.debug("Attempting login as {0}", email)
        # sets some required cookies to login
        http.get(self.login_page_url)
        # login
        res = http.post(self.login_url,
                        data=dict(registrationAction='identify',
                                  emailAddress=email,
                                  password=password,
                                  submitButton=""),
                        headers={"Referer": self.login_page_url},
                        allow_redirects=False)

        self._authed = "Authentication Error" not in res.text
        if self._authed:
            self._session_attributes.set("ipid",
                                         res.cookies.get("ipid"),
                                         expires=3600 * 1.5)
            self._session_attributes.set("fprt",
                                         res.cookies.get("fprt"),
                                         expires=3600 * 1.5)

        return self._authed

    def _update_session_attribute(self, key, value):
        if value:
            self._session_attributes.set(key, value,
                                         expires=3600 * 1.5)  # 1h30m expiry
            http.cookies.set(key, value)

    @property
    def session_key(self):
        return self._session_key

    @session_key.setter
    def session_key(self, value):
        self.cache.set("session_key", value)
        self._session_key = value

    def _get_media_info(self, content_id):
        """
        Get the info about the content, based on the ID
        :param content_id:
        :return:
        """
        params = {
            "identityPointId": self._session_attributes.get("ipid"),
            "fingerprint": self._session_attributes.get("fprt"),
            "contentId": content_id,
            "playbackScenario": self.playback_scenario,
            "platform": "WEB_MEDIAPLAYER_5",
            "subject": "LIVE_EVENT_COVERAGE",
            "frameworkURL": "https://ws.media.net.wwe.com",
            "_": int(time.time())
        }
        if self.session_key:
            params["sessionKey"] = self.session_key
        url = self.api_url.format(id=content_id)
        res = http.get(url, params=params)
        return http.xml(res, ignore_ns=True, schema=self._info_schema)

    def _get_content_id(self):
        #  check the page to find the contentId
        res = http.get(self.url)
        m = self.content_id_re.search(res.text)
        if m:
            return m.group(1)

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

        if not self._authed and (not email and not password):
            self.logger.error(
                "A login for WWE Network is required, use --wwenetwork-email/"
                "--wwenetwork-password to set them")
            return

        if not self._authed:
            if not self.login(email, password):
                self.logger.error(
                    "Failed to login, check your username/password")
                return

        content_id = self._get_content_id()
        if content_id:
            self.logger.debug("Found content ID: {0}", content_id)
            info = self._get_media_info(content_id)
            if info["status"]["code"] == 1:
                # update the session attributes
                self._update_session_attribute("fprt", info.get("fingerprint"))
                for attr in info["session_attributes"]:
                    self._update_session_attribute(attr["name"], attr["value"])

                if info.get("session_key"):
                    self.session_key = info.get("session_key")
                for url in info["urls"]:
                    for s in HLSStream.parse_variant_playlist(
                            self.session, url,
                            name_fmt="{pixels}_{bitrate}").items():
                        yield s
            else:
                raise PluginError(
                    "Could not load streams: {message} ({code})".format(
                        **info["status"]))
Esempio n. 18
0
from streamlink.stream import HDSStream, RTMPStream

ASSET_URL = "http://prima.tv4play.se/api/web/asset/{0}/play"
SWF_URL = "http://www.tv4play.se/flash/tv4video.swf"

_url_re = re.compile(
    """
    http(s)?://(www\.)?
    (?:
        tv4play.se/program/[^\?/]+|
        fotbollskanalen.se/video
    )
    .+(video_id|videoid)=(?P<video_id>\d+)
""", re.VERBOSE)

_asset_schema = validate.Schema(validate.xml_findall("items/item"), [
    validate.all(
        validate.xml_findall("*"), validate.map(lambda e: (e.tag, e.text)),
        validate.transform(dict), {
            "base": validate.text,
            "bitrate": validate.all(validate.text, validate.transform(int)),
            "url": validate.text
        })
])


class TV4Play(Plugin):
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url)
    "h264_aac_f4f_http_f4m_http": (
        "HDS", HDSStream.parse_manifest
    ),
    "h264_aac_ts_http_m3u8_http": (
        "HLS", HLSStream.parse_variant_playlist
    )
}

_url_re = re.compile("""
    http(s)?://(\w+\.)?zdf.de/zdfmediathek(\#)?/.+
    /(live|video)
    /(?P<video_id>\d+)
""", re.VERBOSE | re.IGNORECASE)

_schema = validate.Schema(
    validate.xml_findall("video/formitaeten/formitaet"),
    [
        validate.union({
            "type": validate.get("basetype"),
            "quality": validate.xml_findtext("quality"),
            "url": validate.all(
                validate.xml_findtext("url"),
                validate.url()
            )
        })
    ]
)


class zdf_mediathek(Plugin):
    @classmethod
Esempio n. 20
0
                "init": validate.text,
                validate.optional("ss_id"): validate.text,
                validate.optional("mv_id"): validate.text,
                validate.optional("device_cd"): validate.text,
                validate.optional("ss1_prm"): validate.text,
                validate.optional("ss2_prm"): validate.text,
                validate.optional("ss3_prm"): validate.text
            }),
        "clientlibs":
        validate.all(validate.transform(_clientlibs_re.search),
                     validate.get(2), validate.text)
    }))

_language_schema = validate.Schema(validate.xml_findtext("./country_code"))

_xml_to_srt_schema = validate.Schema(validate.xml_findall(".//body/div"), [
    validate.union([
        validate.all(
            validate.getattr("attrib"),
            validate.get("{http://www.w3.org/XML/1998/namespace}lang")),
        validate.all(
            validate.xml_findall("./p"),
            validate.transform(lambda x: list(enumerate(x, 1))), [
                validate.all(
                    validate.union({
                        "i":
                        validate.get(0),
                        "begin":
                        validate.all(
                            validate.get(1), validate.getattr("attrib"),
                            validate.get("begin"),
Esempio n. 21
0
 def test_empty(self, element):
     assert validate.validate(validate.xml_findall("missing"),
                              element) == []
Esempio n. 22
0
class Rtve(Plugin):
    _re_idAsset = re.compile(r"\"idAsset\":\"(\d+)\"")
    secret_key = base64.b64decode("eWVMJmRhRDM=")
    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 = "https://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 = "https://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))

    arguments = PluginArguments(PluginArgument("mux-subtitles",
                                               is_global=True))

    def __init__(self, url):
        super().__init__(url)
        self.zclient = ZTNRClient(self.secret_key, self.session)

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

    def _get_quality_map(self, content_id):
        res = self.session.http.get(self.video_api.format(id=content_id))
        data = self.session.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] = f"{item['height']}p"
        return qmap

    def _get_streams(self):
        res = self.session.http.get(self.url)
        m = self._re_idAsset.search(res.text)
        if m:
            content_id = m.group(1)
            log.debug(f"Found content with id: {content_id}")
            stream_data = self.zclient.get_cdn_list(content_id,
                                                    schema=self.cdn_schema)
            quality_map = None

            streams = []
            for stream in stream_data:
                # only use one stream
                _one_m3u8 = False
                _one_mp4 = False
                for url in stream["urls"]:
                    p_url = urlparse(url)
                    if p_url.path.endswith(".m3u8"):
                        if _one_m3u8:
                            continue
                        try:
                            streams.extend(
                                HLSStream.parse_variant_playlist(
                                    self.session, url).items())
                            _one_m3u8 = True
                        except OSError as err:
                            log.error(str(err))
                    elif p_url.path.endswith(".mp4"):
                        if _one_mp4:
                            continue
                        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)))
                        _one_mp4 = True

            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
Esempio n. 23
0
class BBCiPlayer(Plugin):
    url_re = re.compile(
        r"""https?://(?:www\.)?bbc.co.uk/iplayer/
        (
            episode/(?P<episode_id>\w+)|
            live/(?P<channel_name>\w+)
        )
    """, re.VERBOSE)
    vpid_re = re.compile(r'"vpid"\s*:\s*"(\w+)"')
    tvip_re = re.compile(r'event_master_brand=(\w+?)&')
    swf_url = "http://emp.bbci.co.uk/emp/SMPf/1.18.3/StandardMediaPlayerChromelessFlash.swf"
    hash = base64.b64decode(
        b"N2RmZjc2NzFkMGM2OTdmZWRiMWQ5MDVkOWExMjE3MTk5MzhiOTJiZg==")
    api_url = (
        "http://open.live.bbc.co.uk/mediaselector/5/select/"
        "version/2.0/mediaset/{platform}/vpid/{vpid}/atk/{vpid_hash}/asn/1/")
    platforms = ("pc", "iptv-all")

    mediaselector_schema = validate.Schema(
        validate.transform(partial(parse_xml, ignore_ns=True)),
        validate.union({
            "hds":
            validate.xml_findall(
                ".//media[@kind='video']//connection[@transferFormat='hds']"),
            "hls":
            validate.xml_findall(
                ".//media[@kind='video']//connection[@transferFormat='hls']")
        }),
        {
            validate.text:
            validate.all(
                [
                    validate.all(validate.getattr("attrib"),
                                 validate.get("href"))
                ],
                validate.transform(lambda x: list(set(x)))  # unique
            )
        })

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

    @classmethod
    def _hash_vpid(cls, vpid):
        return sha1(cls.hash + str(vpid).encode("utf8")).hexdigest()

    def find_vpid(self, url):
        self.logger.debug("Looking for vpid on {0}", url)
        res = http.get(url)
        m = self.vpid_re.search(res.text)
        return m and m.group(1)

    def find_tvip(self, url):
        self.logger.debug("Looking for tvip on {0}", url)
        res = http.get(url)
        m = self.tvip_re.search(res.text)
        return m and m.group(1)

    def mediaselector(self, vpid):
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid,
                                      vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            stream_urls = http.get(url, schema=self.mediaselector_schema)
            for surl in stream_urls.get("hls"):
                for s in HLSStream.parse_variant_playlist(self.session,
                                                          surl).items():
                    yield s
            for surl in stream_urls.get("hds"):
                for s in HDSStream.parse_manifest(self.session, surl).items():
                    yield s

    def _get_streams(self):
        m = self.url_re.match(self.url)
        episode_id = m.group("episode_id")
        channel_name = m.group("channel_name")

        if episode_id:
            self.logger.debug("Loading streams for episode: {0}", episode_id)
            vpid = self.find_vpid(self.url)
            if vpid:
                self.logger.debug("Found VPID: {0}", vpid)
                for s in self.mediaselector(vpid):
                    yield s
            else:
                self.logger.error("Could not find VPID for episode {0}",
                                  episode_id)
        elif channel_name:
            self.logger.debug("Loading stream for live channel: {0}",
                              channel_name)
            tvip = self.find_tvip(self.url)
            if tvip:
                self.logger.debug("Found TVIP: {0}", tvip)
                for s in self.mediaselector(tvip):
                    yield s
Esempio n. 24
0
class AdultSwim(Plugin):
    API_URL = "http://www.adultswim.com/videos/api/v2/videos/{id}?fields=stream"
    vod_api = " http://www.adultswim.com/videos/api/v0/assets"

    url_re = re.compile(r"""https?://(?:www\.)?adultswim\.com/videos
            (?:/(streams))?
            (?:/([^/]+))?
            (?:/([^/]+))?
            """, re.VERBOSE)
    _stream_data_re = re.compile(r"(?:__)?AS_INITIAL_DATA(?:__)? = (\{.*?});", re.M | re.DOTALL)

    live_schema = validate.Schema({
        u"streams": {
            validate.text: {u"stream": validate.text,
                            u"isLive": bool,
                            u"archiveEpisodes": [{
                                u"id": validate.text,
                                u"slug": validate.text,
                            }]}}

    })
    vod_id_schema = validate.Schema({u"show": {u"sluggedVideo": {u"id": validate.text}}},
                                    validate.transform(lambda x: x["show"]["sluggedVideo"]["id"]))
    _api_schema = validate.Schema({
        u'status': u'ok',
        u'data': {u'stream': {
            u'assets': [{u'url': validate.url()}]
        }}
    })
    _vod_api_schema = validate.Schema(
        validate.all(
            validate.xml_findall(".//files/file"),
            [validate.xml_element,
             validate.transform(lambda v: {"bitrate": v.attrib.get("bitrate"), "url": v.text})
             ]
        )
    )

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

    def _make_hls_hds_stream(self, func, stream, *args, **kwargs):
        return func(self.session, stream["url"], *args, **kwargs)

    def _get_show_streams(self, stream_data, show, episode, platform="desktop"):
        video_id = parse_json(stream_data.group(1), schema=self.vod_id_schema)
        res = http.get(self.vod_api, params={"platform": platform, "id": video_id})

        # create a unique list of the stream manifest URLs
        streams = []
        urldups = []
        for stream in parse_xml(res.text, schema=self._vod_api_schema):
            if stream["url"] not in urldups:
                streams.append(stream)
                urldups.append(stream["url"])

        mapper = StreamMapper(lambda fmt, strm: strm["url"].endswith(fmt))
        mapper.map(".m3u8", self._make_hls_hds_stream, HLSStream.parse_variant_playlist)
        mapper.map(".f4m", self._make_hls_hds_stream, HDSStream.parse_manifest, is_akamai=True)
        mapper.map(".mp4", lambda s: (s["bitrate"]+"k", HTTPStream(self.session, s["url"])))

        for q, s in mapper(streams):
            yield q, s

    def _get_live_stream(self, stream_data, show, episode=None):
        # parse the stream info as json
        stream_info = parse_json(stream_data.group(1), schema=self.live_schema)
        # get the stream ID
        stream_id = None
        show_info = stream_info[u"streams"][show]

        if episode:
            self.logger.debug("Loading replay of episode: {0}/{1}", show, episode)
            for epi in show_info[u"archiveEpisodes"]:
                if epi[u"slug"] == episode:
                    stream_id = epi[u"id"]
        elif show_info["isLive"] or not len(show_info[u"archiveEpisodes"]):
            self.logger.debug("Loading LIVE streams for: {0}", show)
            stream_id = show_info[u"stream"]
        else:  # off-air
            if len(show_info[u"archiveEpisodes"]):
                epi = show_info[u"archiveEpisodes"][0]
                self.logger.debug("Loading replay of episode: {0}/{1}", show, epi[u"slug"])
                stream_id = epi[u"id"]
            else:
                self.logger.error("This stream is currently offline")
                return


        if stream_id:
            api_url = self.API_URL.format(id=stream_id)

            res = http.get(api_url, headers={"User-Agent": useragents.SAFARI_8})
            stream_data = http.json(res, schema=self._api_schema)

            mapper = StreamMapper(lambda fmt, surl: surl.endswith(fmt))
            mapper.map(".m3u8", HLSStream.parse_variant_playlist, self.session)
            mapper.map(".f4m", HDSStream.parse_manifest, self.session)

            stream_urls = [asset[u"url"] for asset in stream_data[u'data'][u'stream'][u'assets']]
            for q, s in mapper(stream_urls):
                yield q, s

        else:
            self.logger.error("Couldn't find the stream ID for this stream: {}".format(show))

    def _get_streams(self):
        # get the page
        url_match = self.url_re.match(self.url)
        live_stream, show_name, episode_name = url_match.groups()
        if live_stream:
            show_name = show_name or "live-stream"

        res = http.get(self.url, headers={"User-Agent": useragents.SAFARI_8})
        # find the big blob of stream info in the page
        stream_data = self._stream_data_re.search(res.text)

        if stream_data:
            if live_stream:
                streams = self._get_live_stream(stream_data, show_name, episode_name)
            else:
                self.logger.debug("Loading VOD streams for: {0}/{1}", show_name, episode_name)
                streams = self._get_show_streams(stream_data, show_name, episode_name)

            # De-dup the streams, some of the mobile streams overlap the desktop streams
            dups = set()
            for q, s in streams:
                if hasattr(s, "args") and "url" in s.args:
                    if s.args["url"] not in dups:
                        yield q, s
                        dups.add(s.args["url"])
                else:
                    yield q, s

        else:
            self.logger.error("Couldn't find the stream data for this stream: {}".format(show_name))
Esempio n. 25
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(parse_xml), 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
Esempio n. 26
0
            validate.optional("_server"):
            validate.text,
            "_stream":
            validate.any(validate.text, [validate.text]),
            "_quality":
            validate.any(int, validate.text)
        }]
    }]
})
_smil_schema = validate.Schema(
    validate.union({
        "base":
        validate.all(validate.xml_find("head/meta"), validate.get("base"),
                     validate.url(scheme="http")),
        "videos":
        validate.all(validate.xml_findall("body/seq/video"),
                     [validate.get("src")])
    }))


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

    def _get_http_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "vod")
        urls = info["_stream"]
        if not isinstance(info["_stream"], list):
            urls = [urls]
Esempio n. 27
0
        }]
    }]
})
_smil_schema = validate.Schema(
    validate.union({
        "base": validate.all(
            validate.xml_find("head/meta"),
            validate.get("base"),
            validate.url(scheme="http")
        ),
        "cdn": validate.all(
            validate.xml_find("head/meta"),
            validate.get("cdn")
        ),
        "videos": validate.all(
            validate.xml_findall("body/seq/video"),
            [validate.get("src")]
        )
    })
)


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

    def _get_http_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "vod")
        urls = info["_stream"]
        if not isinstance(info["_stream"], list):
Esempio n. 28
0
class BBCiPlayer(Plugin):
    url_re = re.compile(
        r"""https?://(?:www\.)?bbc.co.uk/iplayer/
        (
            episode/(?P<episode_id>\w+)|
            live/(?P<channel_name>\w+)
        )
    """, re.VERBOSE)
    vpid_re = re.compile(r'"ident_id"\s*:\s*"(\w+)"')
    tvip_re = re.compile(r'event_master_brand=(\w+?)&')
    account_locals_re = re.compile(r'window.bbcAccount.locals\s*=\s*(\{.*?});')
    swf_url = "http://emp.bbci.co.uk/emp/SMPf/1.18.3/StandardMediaPlayerChromelessFlash.swf"
    hash = base64.b64decode(
        b"N2RmZjc2NzFkMGM2OTdmZWRiMWQ5MDVkOWExMjE3MTk5MzhiOTJiZg==")
    api_url = (
        "http://open.live.bbc.co.uk/mediaselector/5/select/"
        "version/2.0/mediaset/{platform}/vpid/{vpid}/atk/{vpid_hash}/asn/1/")
    platforms = ("pc", "iptv-all")
    config_url = "http://www.bbc.co.uk/idcta/config"
    auth_url = "https://account.bbc.com/signin"

    config_schema = validate.Schema(
        validate.transform(parse_json), {
            "signin_url": validate.url(),
            "identity": {
                "cookieAgeDays": int,
                "accessTokenCookieName": validate.text,
                "idSignedInCookieName": validate.text
            }
        })
    mediaselector_schema = validate.Schema(
        validate.transform(partial(parse_xml, ignore_ns=True)),
        validate.union({
            "hds":
            validate.xml_findall(
                ".//media[@kind='video']//connection[@transferFormat='hds']"),
            "hls":
            validate.xml_findall(
                ".//media[@kind='video']//connection[@transferFormat='hls']")
        }),
        {
            validate.text:
            validate.all(
                [
                    validate.all(validate.getattr("attrib"),
                                 validate.get("href"))
                ],
                validate.transform(lambda x: list(set(x)))  # unique
            )
        })
    options = PluginOptions({"password": None, "username": None})

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

    @classmethod
    def _hash_vpid(cls, vpid):
        return sha1(cls.hash + str(vpid).encode("utf8")).hexdigest()

    def find_vpid(self, url, res=None):
        self.logger.debug("Looking for vpid on {0}", url)
        # Use pre-fetched page if available
        res = res or http.get(url)
        m = self.vpid_re.search(res.text)
        return m and m.group(1)

    def find_tvip(self, url):
        self.logger.debug("Looking for tvip on {0}", url)
        res = http.get(url)
        m = self.tvip_re.search(res.text)
        return m and m.group(1)

    def mediaselector(self, vpid):
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid,
                                      vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            stream_urls = http.get(url, schema=self.mediaselector_schema)
            for surl in stream_urls.get("hls"):
                for s in HLSStream.parse_variant_playlist(self.session,
                                                          surl).items():
                    yield s
            for surl in stream_urls.get("hds"):
                for s in HDSStream.parse_manifest(self.session, surl).items():
                    yield s

    def login(self, ptrt_url, context="tvandiplayer"):
        # get the site config, to find the signin url
        config = http.get(self.config_url,
                          params=dict(ptrt=ptrt_url),
                          schema=self.config_schema)

        res = http.get(config["signin_url"],
                       params=dict(userOrigin=context, context=context),
                       headers={"Referer": self.url})
        m = self.account_locals_re.search(res.text)
        if m:
            auth_data = parse_json(m.group(1))
            res = http.post(self.auth_url,
                            params=dict(context=auth_data["userOrigin"],
                                        ptrt=auth_data["ptrt"]["value"],
                                        userOrigin=auth_data["userOrigin"],
                                        nonce=auth_data["nonce"]),
                            data=dict(jsEnabled="false",
                                      attempts=0,
                                      username=self.get_option("username"),
                                      password=self.get_option("password")))
            # redirects to ptrt_url on successful login
            if res.url == ptrt_url:
                return res
        else:
            self.logger.error(
                "Could not authenticate, could not find the authentication nonce"
            )

    def _get_streams(self):
        self.logger.info(
            "A TV License is required to watch BBC iPlayer streams, see the BBC website for more "
            "information: https://www.bbc.co.uk/iplayer/help/tvlicence")
        page_res = None
        if self.get_option("username"):
            page_res = self.login(self.url)
            if not page_res:
                self.logger.error(
                    "Could not authenticate, check your username and password")
                return

        m = self.url_re.match(self.url)
        episode_id = m.group("episode_id")
        channel_name = m.group("channel_name")

        if episode_id:
            self.logger.debug("Loading streams for episode: {0}", episode_id)
            vpid = self.find_vpid(self.url, res=page_res)
            if vpid:
                self.logger.debug("Found VPID: {0}", vpid)
                for s in self.mediaselector(vpid):
                    yield s
            else:
                self.logger.error("Could not find VPID for episode {0}",
                                  episode_id)
        elif channel_name:
            self.logger.debug("Loading stream for live channel: {0}",
                              channel_name)
            tvip = self.find_tvip(self.url)
            if tvip:
                self.logger.debug("Found TVIP: {0}", tvip)
                for s in self.mediaselector(tvip):
                    yield s
Esempio n. 29
0
class Beam(Plugin):
    api_url = "https://beam.pro/api/v1/{type}/{id}"
    channel_manifest = "https://beam.pro/api/v1/channels/{id}/manifest.{type}"

    _vod_schema = validate.Schema({
        "state": "AVAILABLE",
        "vods": [{
            "baseUrl": validate.url(),
            "data": validate.any(None, {
                "Height": int
            }),
            "format": validate.text
            }]
        },
        validate.get("vods"),
        validate.filter(lambda x: x["format"] in ("raw", "hls")),
        [validate.union({
            "url": validate.get("baseUrl"),
            "format": validate.get("format"),
            "height": validate.all(validate.get("data"), validate.get("Height"))
        })])
    _assets_schema = validate.Schema(
        validate.union({
            "base": validate.all(
                validate.xml_find("./head/meta"),
                validate.get("base"),
                validate.url(scheme="rtmp")
            ),
            "videos": validate.all(
                validate.xml_findall(".//video"),
                [
                    validate.union({
                        "src": validate.all(
                            validate.get("src"),
                            validate.text
                        ),
                        "height": validate.all(
                            validate.get("height"),
                            validate.text,
                            validate.transform(int)
                        )
                    })
                ]
            )
        })
    )

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

    def _get_vod_stream(self, vod_id):
        res = http.get(self.api_url.format(type="recordings", id=vod_id))
        for sdata in http.json(res, schema=self._vod_schema):
            if sdata["format"] == "hls":
                hls_url = urljoin(sdata["url"], "manifest.m3u8")
                yield "{0}p".format(sdata["height"]), HLSStream(self.session, hls_url)
            elif sdata["format"] == "raw":
                raw_url = urljoin(sdata["url"], "source.mp4")
                yield "{0}p".format(sdata["height"]), HTTPStream(self.session, raw_url)

    def _get_live_stream(self, channel):
        res = http.get(self.api_url.format(type="channels", id=channel))
        channel_info = http.json(res)

        if not channel_info["online"]:
            return

        res = http.get(self.channel_manifest.format(id=channel_info["id"], type="smil"))
        assets = http.xml(res, schema=self._assets_schema)

        for video in assets["videos"]:
            name = "{0}p".format(video["height"])
            stream = RTMPStream(self.session, {
                "rtmp": "{0}/{1}".format(assets["base"], video["src"])
            })
            yield name, stream

        for s in HLSStream.parse_variant_playlist(self.session,
                                                  self.channel_manifest.format(id=channel_info["id"], type="m3u8")).items():
            yield s

    def _get_streams(self):
        params = dict(parse_qsl(urlparse(self.url).query))
        vod_id = params.get("vod")
        match = _url_re.match(self.url)
        channel = match.group("channel")

        if vod_id:
            self.logger.debug("Looking for VOD {0} from channel: {1}", vod_id, channel)
            return self._get_vod_stream(vod_id)
        else:
            self.logger.debug("Looking for channel: {0}", channel)
            return self._get_live_stream(channel)
Esempio n. 30
0
    validate.optional("lsPlayerSwfUrl"): validate.text,
    validate.optional("hdPlayerSwfUrl"): validate.text
})
_smil_schema = validate.Schema(validate.union({
    "http_base": validate.all(
        validate.xml_find("{http://www.w3.org/2001/SMIL20/Language}head/"
                          "{http://www.w3.org/2001/SMIL20/Language}meta"
                          "[@name='httpBase']"),
        validate.xml_element(attrib={
            "content": validate.text
        }),
        validate.get("content")
    ),
    "videos": validate.all(
        validate.xml_findall("{http://www.w3.org/2001/SMIL20/Language}body/"
                             "{http://www.w3.org/2001/SMIL20/Language}switch/"
                             "{http://www.w3.org/2001/SMIL20/Language}video"),
        [
            validate.all(
                validate.xml_element(attrib={
                    "src": validate.text,
                    "system-bitrate": validate.all(
                        validate.text,
                        validate.transform(int)
                    )
                }),
                validate.transform(
                    lambda e: (e.attrib["src"], e.attrib["system-bitrate"])
                )
            )
        ],
Esempio n. 31
0
from streamlink.stream import RTMPStream

_url_re = re.compile("http(s)?://(\w+.)?beam.pro/(?P<channel>[^/]+)")

CHANNEL_INFO = "https://beam.pro/api/v1/channels/{0}"
CHANNEL_MANIFEST = "https://beam.pro/api/v1/channels/{0}/manifest.smil"

_assets_schema = validate.Schema(
    validate.union({
        "base": validate.all(
            validate.xml_find("./head/meta"),
            validate.get("base"),
            validate.url(scheme="rtmp")
        ),
        "videos": validate.all(
            validate.xml_findall(".//video"),
            [
                validate.union({
                    "src": validate.all(
                        validate.get("src"),
                        validate.text
                    ),
                    "height": validate.all(
                        validate.get("height"),
                        validate.text,
                        validate.transform(int)
                    )
                })
            ]
        )
    })
Esempio n. 32
0
class Rtve(Plugin):
    secret_key = base64.b64decode("eWVMJmRhRDM=")
    url_re = re.compile(r"""
        https?://(?:www\.)?rtve\.es/(?:directo|infantil|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))
    arguments = PluginArguments(
        PluginArgument(
            "mux-subtitles",
            action="store_true",
            help="""
        Automatically mux available subtitles in to the output stream.
        """
        )
    )

    @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.session.http.headers = {"User-Agent": useragents.SAFARI_8}
        self.zclient = ZTNRClient(self.secret_key, self.session)

    def _get_content_id(self):
        res = self.session.http.get(self.url)
        for div in itertags(res.text, "div"):
            if div.attributes.get("data-id"):
                return int(div.attributes.get("data-id"))
        else:
            log.error("Failed to get content_id")

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

    def _get_quality_map(self, content_id):
        res = self.session.http.get(self.video_api.format(id=content_id))
        data = self.session.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:
            log.debug(f"Found content with id: {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 ".m3u8" in url:
                        try:
                            streams.extend(HLSStream.parse_variant_playlist(self.session, url).items())
                        except (IOError, OSError) as err:
                            log.error(str(err))
                    elif ((url.endswith("mp4") or url.endswith("mov") or url.endswith("avi"))
                          and self.session.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
Esempio n. 33
0
    def _get_streams(self):
        try:
            scripts = self.session.http.get(
                self.url,
                schema=validate.Schema(
                    validate.parse_html(),
                    validate.xml_findall(
                        ".//script[@type='application/json'][@data-ssr-name]"),
                    [
                        validate.union((validate.get("data-ssr-name"),
                                        validate.all(validate.getattr("text"),
                                                     validate.parse_json())))
                    ]))
        except PluginError:
            log.error("Could not find any stream data")
            return

        for _data_ssr_name, _data_json in scripts:
            video_url = None
            log.trace(f"Found _data_ssr_name={_data_ssr_name}")

            if _data_ssr_name == "pages/Broadcasts/Broadcasts":
                self.title, video_url, is_live = validate.Schema(
                    {
                        "currentLivestream": {
                            "is_live": bool,
                            "title": str,
                            "stream": validate.url(),
                        }
                    }, validate.get("currentLivestream"),
                    validate.union_get("title", "stream",
                                       "is_live")).validate(_data_json)
                if not is_live:
                    log.error(self._msg_live_offline)
                    continue

            elif _data_ssr_name == "pages/Livestream/Livestream":
                self.title, video_url, is_live = validate.Schema(
                    {
                        "streamIsLive": bool,
                        "title": str,
                        "stream": validate.url(),
                    }, validate.union_get("title", "stream",
                                          "streamIsLive")).validate(_data_json)
                if not is_live:
                    log.error(self._msg_live_offline)
                    continue

            elif _data_ssr_name in self.vod_keys.keys():
                _key = self.vod_keys[_data_ssr_name]
                self.title, video_url = validate.Schema(
                    {
                        _key: {
                            "title": str,
                            "aspect_ratios": {
                                "profiles":
                                validate.all([{
                                    "name": str,
                                    "url": validate.url(),
                                }],
                                             validate.filter(lambda p: p[
                                                 "name"] == "hls_unencrypted"))
                            }
                        }
                    }, validate.get(_key),
                    validate.union_get("title",
                                       ("aspect_ratios", "profiles", 0,
                                        "url"))).validate(_data_json)

            if video_url is not None:
                return HLSStream.parse_variant_playlist(
                    self.session, video_url)
Esempio n. 34
0
class RTE(Plugin):
    VOD_API_URL = 'http://www.rte.ie/rteavgen/getplaylist/?type=web&format=json&id={0}'
    LIVE_API_URL = 'http://feeds.rasset.ie/livelistings/playlist'

    _url_re = re.compile(
        r'http://www\.rte\.ie/player/[a-z0-9]+/(?:show/[a-z-]+-[0-9]+/(?P<video_id>[0-9]+)|live/(?P<channel_id>[0-9]+))'
    )

    _vod_api_schema = validate.Schema({
        'current_date':
        validate.text,
        'shows':
        validate.Schema(
            list,
            validate.length(1),
            validate.get(0),
            validate.Schema({
                'valid_start':
                validate.text,
                'valid_end':
                validate.text,
                'media:group':
                validate.Schema(
                    list,
                    validate.length(1),
                    validate.get(0),
                    validate.Schema(
                        {
                            'hls_server': validate.url(),
                            'hls_url': validate.text,
                            'hds_server': validate.url(),
                            'hds_url': validate.text,
                            # API returns RTMP streams that don't seem to work, ignore them
                            # 'url': validate.any(
                            #     validate.url(scheme="rtmp"),
                            #     validate.url(scheme="rtmpe")
                            # )
                        },
                        validate.transform(lambda x: [
                            x['hls_server'] + x['hls_url'], x['hds_server'] +
                            x['hds_url']
                        ])),
                ),
            }),
        )
    })

    _live_api_schema = validate.Schema(
        validate.xml_findall('.//{http://search.yahoo.com/mrss/}content'), [
            validate.all(validate.xml_element(attrib={'url': validate.url()}),
                         validate.get('url'))
        ])
    _live_api_iphone_schema = validate.Schema(
        list, validate.length(1), validate.get(0),
        validate.Schema({'fullUrl': validate.any(validate.url(), 'none')},
                        validate.get('fullUrl')))

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

    def _get_streams(self):
        match = self._url_re.match(self.url)
        video_id = match.group('video_id')

        if video_id is not None:
            # VOD
            res = http.get(self.VOD_API_URL.format(video_id))
            stream_data = http.json(res, schema=self._vod_api_schema)

            # Check whether video format is expired
            current_date = datetime.strptime(stream_data['current_date'],
                                             '%Y-%m-%dT%H:%M:%S.%f')
            valid_start = datetime.strptime(
                stream_data['shows']['valid_start'], '%Y-%m-%dT%H:%M:%S')
            valid_end = datetime.strptime(stream_data['shows']['valid_end'],
                                          '%Y-%m-%dT%H:%M:%S')
            if current_date < valid_start or current_date > valid_end:
                self.logger.error(
                    'Failed to access stream, may be due to expired content')
                return

            streams = stream_data['shows']['media:group']
        else:
            # Live
            channel_id = match.group('channel_id')
            # Get live streams for desktop
            res = http.get(self.LIVE_API_URL, params={'channelid': channel_id})
            streams = http.xml(res, schema=self._live_api_schema)

            # Get HLS streams for Iphone
            res = http.get(self.LIVE_API_URL,
                           params={
                               'channelid': channel_id,
                               'platform': 'iphone'
                           })
            stream = http.json(res, schema=self._live_api_iphone_schema)
            if stream != 'none':
                streams.append(stream)

        for stream in streams:
            if '.f4m' in stream:
                for s in HDSStream.parse_manifest(self.session,
                                                  stream).items():
                    yield s
            if '.m3u8' in stream:
                for s in HLSStream.parse_variant_playlist(
                        self.session, stream).items():
                    yield s
Esempio n. 35
0
from streamlink.stream import HDSStream, RTMPStream

ASSET_URL = "http://prima.tv4play.se/api/web/asset/{0}/play"
SWF_URL = "http://www.tv4play.se/flash/tv4video.swf"

_url_re = re.compile(r"""
    http(s)?://(www\.)?
    (?:
        tv4play.se/program/[^\?/]+|
        fotbollskanalen.se/video
    )
    .+(video_id|videoid)=(?P<video_id>\d+)
""", re.VERBOSE)

_asset_schema = validate.Schema(
    validate.xml_findall("items/item"),
    [
        validate.all(
            validate.xml_findall("*"),
            validate.map(lambda e: (e.tag, e.text)),
            validate.transform(dict),
            {
                "base": validate.text,
                "bitrate": validate.all(
                    validate.text, validate.transform(int)
                ),
                "url": validate.text
            }
        )
    ]
)