Example #1
0
    def clips(self, clipname):
        query = """{{
            clip(slug: "{clipname}") {{
                broadcaster {{
                    displayName
                }}
                title
                game {{
                    name
                }}
                videoQualities {{
                    quality
                    sourceURL
                }}
            }}
        }}""".format(clipname=clipname)

        return self.call_gql(
            {"query": query},
            schema=validate.Schema(
                {
                    "data": {
                        "clip":
                        validate.any(
                            None,
                            validate.all(
                                {
                                    "broadcaster":
                                    validate.all(
                                        {"displayName": validate.text},
                                        validate.get("displayName")),
                                    "title":
                                    validate.text,
                                    "game":
                                    validate.all({"name": validate.text},
                                                 validate.get("name")),
                                    "videoQualities": [
                                        validate.all(
                                            {
                                                "quality":
                                                validate.all(
                                                    validate.text,
                                                    validate.transform(
                                                        lambda q: "{0}p".
                                                        format(q))),
                                                "sourceURL":
                                                validate.url()
                                            },
                                            validate.union(
                                                (validate.get("quality"),
                                                 validate.get("sourceURL"))))
                                    ]
                                },
                                validate.union(
                                    (validate.get("broadcaster"),
                                     validate.get("title"),
                                     validate.get("game"),
                                     validate.get("videoQualities")))))
                    }
                }, validate.get("data"), validate.get("clip")))
Example #2
0
class TestUnionSchema:
    upper = validate.transform(str.upper)

    def test_dict_success(self):
        schema = validate.union({
            "foo": str,
            "bar": self.upper,
            validate.optional("baz"): int,
        })
        assert validate.validate(schema, "value") == {
            "foo": "value",
            "bar": "VALUE"
        }

    def test_dict_failure(self):
        with pytest.raises(validate.ValidationError) as cm:
            validate.validate(validate.union({"foo": int}), "value")
        assert_validationerror(
            cm.value, """
            ValidationError(UnionSchema):
              Could not validate union
              Context(dict):
                Unable to validate union 'foo'
                Context(type):
                  Type of 'value' should be int, but is str
        """)

    @pytest.mark.parametrize(
        "schema, expected",
        [
            (validate.union([str, upper]), ["value", "VALUE"]),
            (validate.union((str, upper)), ("value", "VALUE")),
            (validate.union({str, upper}), {"value", "VALUE"}),
            (validate.union(frozenset(
                (str, upper))), frozenset(("value", "VALUE"))),
        ],
        ids=[
            "list",
            "tuple",
            "set",
            "frozenset",
        ],
    )
    def test_sequence(self, schema, expected):
        result = validate.validate(schema, "value")
        assert result == expected

    def test_failure_schema(self):
        with pytest.raises(validate.ValidationError) as cm:
            validate.validate(validate.union(None), None)
        assert_validationerror(
            cm.value, """
            ValidationError(UnionSchema):
              Could not validate union
              Context:
                Invalid union type: NoneType
        """)
Example #3
0
    def _get_streams(self):
        self.id, self.title = self.session.http.get(
            self.url,
            schema=validate.Schema(
                validate.parse_html(),
                validate.union((
                    validate.xml_xpath_string(
                        ".//script[@class='dacast-video'][@id]/@id"),
                    validate.xml_xpath_string(".//head/title[1]/text()"),
                ))))

        if not self.id:
            return

        if re.match(r"\w+_\w+_\w+", self.id):
            provider = "dacast"
        else:
            provider = "universe"

        data = self.session.http.get(
            f"https://playback.dacast.com/content/access?contentId={self.id}&provider={provider}",
            acceptable_status=(200, 400, 403, 404),
            schema=validate.Schema(
                validate.parse_json(),
                validate.any(
                    {"error": str},
                    {"hls": validate.url()},
                )))

        if data.get("error"):
            log.error(data["error"])
            return

        return HLSStream.parse_variant_playlist(self.session, data["hls"])
Example #4
0
 def access_token(self, endpoint, asset):
     return self.call("/api/{0}/{1}/access_token".format(endpoint, asset),
                      private=True,
                      schema=validate.Schema(
                          {
                              "token": validate.text,
                              "sig": validate.text
                          },
                          validate.union((validate.get("sig"),
                                          validate.get("token")))))
Example #5
0
 def test_failure_schema(self):
     with pytest.raises(validate.ValidationError) as cm:
         validate.validate(validate.union(None), None)
     assert_validationerror(
         cm.value, """
         ValidationError(UnionSchema):
           Could not validate union
           Context:
             Invalid union type: NoneType
     """)
Example #6
0
 def test_dict_success(self):
     schema = validate.union({
         "foo": str,
         "bar": self.upper,
         validate.optional("baz"): int,
     })
     assert validate.validate(schema, "value") == {
         "foo": "value",
         "bar": "VALUE"
     }
Example #7
0
 def test_dict_failure(self):
     with pytest.raises(validate.ValidationError) as cm:
         validate.validate(validate.union({"foo": int}), "value")
     assert_validationerror(
         cm.value, """
         ValidationError(UnionSchema):
           Could not validate union
           Context(dict):
             Unable to validate union 'foo'
             Context(type):
               Type of 'value' should be int, but is str
     """)
Example #8
0
 def channel_from_video_id(self, video_id):
     return self.call("/kraken/videos/{0}".format(video_id), schema=validate.Schema(
         {
             "channel": {
                 "_id": validate.any(int, validate.text),
                 "name": validate.text
             }
         },
         validate.get("channel"),
         validate.union((
             validate.all(validate.get("_id"), validate.transform(int)),
             validate.all(validate.get("name"), validate.transform(lambda n: n.lower()))
         ))
     ))
Example #9
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)
Example #10
0
 def _get_streams(self):
     hls_url, self.title = self.session.http.get(
         self.url,
         schema=validate.Schema(
             validate.parse_html(),
             validate.union((
                 validate.xml_xpath_string(
                     ".//video/source[@src][@type='application/x-mpegURL'][1]/@src"
                 ),
                 validate.xml_xpath_string(".//head/title[1]/text()"),
             ))))
     if not hls_url:
         return
     return HLSStream.parse_variant_playlist(self.session,
                                             hls_url,
                                             headers={"Referer": self.url})
Example #11
0
 def stream_rerun(self, channel_id):
     return self.call("/kraken/streams/{0}".format(channel_id), schema=validate.Schema(
         {
             "stream": validate.any(None, validate.all({
                 "stream_type": validate.text,
                 "broadcast_platform": validate.text,
                 "channel": validate.all({
                     "broadcaster_software": validate.text
                 }, validate.get("broadcaster_software"))
             }, validate.union((
                 validate.get("stream_type"),
                 validate.get("broadcast_platform"),
                 validate.get("channel")
             ))))
         },
         validate.get("stream")
     ))
Example #12
0
 def _schema_consent(data):
     schema_consent = validate.Schema(
         validate.parse_html(),
         validate.any(
             validate.xml_find(".//form[@action='https://consent.youtube.com/s']"),
             validate.all(
                 validate.xml_xpath(".//form[@action='https://consent.youtube.com/save']"),
                 validate.filter(lambda elem: elem.xpath(".//input[@type='hidden'][@name='set_ytc'][@value='true']")),
                 validate.get(0),
             )
         ),
         validate.union((
             validate.get("action"),
             validate.xml_xpath(".//input[@type='hidden']"),
         )),
     )
     return schema_consent.validate(data)
Example #13
0
 def hosted_channel(self, channel_id):
     return self.call("/hosts", subdomain="tmi", include_logins=1, host=channel_id, schema=validate.Schema(
         {
             "hosts": [{
                 "host_id": int,
                 "target_id": int,
                 "target_login": validate.text,
                 "target_display_name": validate.text
             }]
         },
         validate.get("hosts"),
         validate.get(0),
         validate.union((
             validate.get("host_id"),
             validate.get("target_id"),
             validate.get("target_login"),
             validate.get("target_display_name")
         ))
     ))
Example #14
0
    def _get_streams(self):
        stream_id, has_token, hls_url, dash_url = self.session.http.get(
            self.url,
            schema=validate.Schema(
                validate.parse_html(),
                validate.xml_find(".//*[@data-video-id]"),
                validate.union((
                    validate.get("data-video-id"),
                    validate.all(
                        validate.get("data-video-has-token"),
                        validate.transform(lambda val: val and val != "false"),
                    ),
                    validate.get("data-vjs-clip-hls-url"),
                    validate.get("data-vjs-clip-dash-url"),
                )),
            ),
        )

        if dash_url and has_token:
            token = self._get_stream_token(stream_id, "dash")
            parsed = urlsplit(dash_url)
            dash_url = urlunsplit(
                parsed._replace(path=f"{token}{parsed.path}"))
            return DASHStream.parse_manifest(
                self.session,
                dash_url,
                headers={"Referer": self.url},
            )

        if not hls_url:
            return

        if has_token:
            token = self._get_stream_token(stream_id, "hls")
            hls_url = f"{hls_url}?{token}"

        return HLSStream.parse_variant_playlist(
            self.session,
            hls_url,
            headers={"Referer": self.url},
        )
Example #15
0
 def access_token(self, is_live, channel_or_vod):
     request = {
         "operationName": "PlaybackAccessToken",
         "extensions": {
             "persistedQuery": {
                 "version": 1,
                 "sha256Hash": "0828119ded1c13477966434e15800ff57ddacf13ba1911c129dc2200705b0712"
             }
         },
         "variables": {
             "isLive": is_live,
             "login": channel_or_vod if is_live else "",
             "isVod": not is_live,
             "vodID": channel_or_vod if not is_live else "",
             "playerType": "embed"
         }
     }
     subschema = validate.any(None, validate.all(
         {
             "value": validate.text,
             "signature": validate.text,
             "__typename": "PlaybackAccessToken"
         },
         validate.union((
             validate.get("signature"),
             validate.get("value")
         ))
     ))
     return self.call_gql(request, schema=validate.Schema(
         {"data": validate.any(
             validate.all(
                 {"streamPlaybackAccessToken": subschema},
                 validate.get("streamPlaybackAccessToken")
             ),
             validate.all(
                 {"videoPlaybackAccessToken": subschema},
                 validate.get("videoPlaybackAccessToken")
             )
         )},
         validate.get("data")
     ))
Example #16
0
class Mixer(Plugin):
    api_url = "https://mixer.com/api/v1/{type}/{id}"

    _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"))
            })
        ])

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

    def _get_api_res(self, api_type, api_id):
        try:
            res = self.session.http.get(
                self.api_url.format(type=api_type, id=api_id))
            return res
        except Exception as e:
            if "404" in str(e):
                self.logger.error("invalid {0} - {1}".format(api_type, api_id))
            elif "429" in str(e):
                self.logger.error(
                    "Too Many Requests, API rate limit exceeded.")
            raise NoStreamsError(self.url)

    def _get_vod_stream(self, vod_id):
        res = self._get_api_res("recordings", vod_id)

        for sdata in self.session.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)

    def _get_live_stream(self, channel):
        res = self._get_api_res("channels", channel)

        channel_info = self.session.http.json(res)
        if not channel_info["online"]:
            return

        user_id = channel_info["id"]
        hls_url = self.api_url.format(type="channels",
                                      id="{0}/manifest.m3u8".format(user_id))
        for s in HLSStream.parse_variant_playlist(self.session,
                                                  hls_url).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)
Example #17
0
})
_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"])
                )
            )
        ],
    )
}))
Example #18
0
    )?
""", re.VERBOSE)
_file_re = re.compile("\"?file\"?:\s+['\"]([^'\"]+)['\"]")
_swf_url_re = re.compile("swfobject.embedSWF\(\"([^\"]+)\",")

_schema = validate.Schema(
    validate.union({
        "urls": validate.all(
            validate.transform(_file_re.findall),
            validate.map(unquote),
            [validate.url()]
        ),
        "swf": validate.all(
            validate.transform(_swf_url_re.search),
            validate.any(
                None,
                validate.all(
                    validate.get(1),
                    validate.url(
                        scheme="http",
                        path=validate.endswith("swf")
                    )
                )
            )
        )
    })
)


class Aliez(Plugin):
    @classmethod
    def can_handle_url(self, url):
Example #19
0
    )?
    (?:
        (?P<minutes>\d+)m
    )?
    (?:
        (?P<seconds>\d+)s
    )?
""", re.VERBOSE)

_access_token_schema = validate.Schema(
    {
        "token": validate.text,
        "sig": validate.text
    },
    validate.union((
        validate.get("sig"),
        validate.get("token")
    ))
)
_token_schema = validate.Schema(
    {
        "chansub": {
            "restricted_bitrates": validate.all(
                [validate.text],
                validate.filter(
                    lambda n: not re.match(r"(.+_)?archives|live|chunked", n)
                )
            )
        }
    },
    validate.get("chansub")
)
Example #20
0
_url_re = re.compile(
    r"""
    https?://(\w+\.)?aliez.\w+/
    (?:live/[^/]+|video/\d+/[^/]+)
""", re.VERBOSE)
_file_re = re.compile(r"\"?file\"?:\s+['\"]([^'\"]+)['\"]")
_swf_url_re = re.compile(r"swfobject.embedSWF\(\"([^\"]+)\",")

_schema = validate.Schema(
    validate.union({
        "urls":
        validate.all(validate.transform(_file_re.findall),
                     validate.map(unquote), [validate.url()]),
        "swf":
        validate.all(
            validate.transform(_swf_url_re.search),
            validate.any(
                None,
                validate.all(
                    validate.get(1),
                    validate.url(scheme="http",
                                 path=validate.endswith("swf")))))
    }))


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

    def _get_streams(self):
        res = self.session.http.get(self.url, schema=_schema)
_url_re = re.compile(r"http(s)?://(\w+\.)?seemeplay.ru/")
_player_re = re.compile(
    r"""
    SMP.(channel|video).player.init\({
    \s+file:\s+"([^"]+)"
""", re.VERBOSE)

_schema = validate.Schema(
    validate.transform(_player_re.search),
    validate.any(
        None,
        validate.union({
            "type":
            validate.get(1),
            "url":
            validate.all(
                validate.get(2),
                validate.url(scheme="http"),
            ),
        })))


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

    def _get_streams(self):
        res = http.get(self.url, schema=_schema)
        if not res:
            return
Example #22
0
 def test_union(self):
     assert validate(union((get("foo"), get("bar"))),
                     {"foo": "alpha", "bar": "beta"}) == ("alpha", "beta")
Example #23
0
})
_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"])
                )
            )
        ],
    )
}))
Example #24
0
 validate.union({
     "export_url":
     validate.all(validate.transform(_live_export_re.search),
                  validate.any(
                      None,
                      validate.get(1),
                  )),
     "video_flashvars":
     validate.all(
         validate.transform(_video_flashvars_re.search),
         validate.any(
             None,
             validate.all(
                 validate.get(1), validate.transform(parse_query), {
                     "_111pix_serverURL": validate.url(scheme="rtmp"),
                     "en_flash_providerName": validate.text
                 }))),
     "history_video":
     validate.all(
         validate.transform(_history_re.search),
         validate.any(
             None, validate.all(validate.get(1),
                                validate.url(scheme="http")))),
     "standby_video":
     validate.all(
         validate.transform(_replay_json_re.search),
         validate.any(
             None,
             validate.all(validate.get(1), validate.transform(parse_json),
                          [{
                              "streamName": validate.url(scheme="http")
                          }])))
 }))
Example #25
0
from streamlink.stream import HLSStream, HTTPStream

_url_re = re.compile(r"http(s)?://(\w+\.)?seemeplay.ru/")
_player_re = re.compile(r"""
    SMP.(channel|video).player.init\({
    \s+file:\s+"([^"]+)"
""", re.VERBOSE)

_schema = validate.Schema(
    validate.transform(_player_re.search),
    validate.any(
        None,
        validate.union({
            "type": validate.get(1),
            "url": validate.all(
                validate.get(2),
                validate.url(scheme="http"),
            ),
        })
    )
)


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

    def _get_streams(self):
        res = http.get(self.url, schema=_schema)
        if not res:
Example #26
0
        /
        (?P<video_type>[bcv])(?:ideo)?
        /
        (?P<video_id>\d+)
    )?
    (?:
        /
        (?P<clip_name>[\w]+)
    )?
""", re.VERBOSE)

_access_token_schema = validate.Schema(
    {
        "token": validate.text,
        "sig": validate.text
    }, validate.union((validate.get("sig"), validate.get("token"))))
_token_schema = validate.Schema(
    {
        "chansub": {
            "restricted_bitrates":
            validate.all([validate.text],
                         validate.filter(lambda n: not re.match(
                             r"(.+_)?archives|live|chunked", n)))
        }
    }, validate.get("chansub"))
_user_schema = validate.Schema(
    {validate.optional("display_name"): validate.text},
    validate.get("display_name"))
_video_schema = validate.Schema({
    "chunks": {
        validate.text: [{
Example #27
0
_clientlibs_re = re.compile(r"""<script.*?src=(['"])(.*?/clientlibs_anime_watch.*?\.js)\1""")

_schema = validate.Schema(
    validate.union({
        "flashvars": validate.all(
            validate.transform(_flashvars_re.search),
            validate.get(1),
            validate.transform(_flashvar_re.findall),
            validate.map(lambda v: (v[1], v[3])),
            validate.transform(dict),
            {
                "s": validate.text,
                "country": validate.text,
                "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(
Example #28
0
 validate.union({
     "export_url": validate.all(
         validate.transform(_live_export_re.search),
         validate.any(
             None,
             validate.get(1),
         )
     ),
     "video_flashvars": validate.all(
         validate.transform(_video_flashvars_re.search),
         validate.any(
             None,
             validate.all(
                 validate.get(1),
                 validate.transform(parse_query),
                 {
                     "_111pix_serverURL": validate.url(scheme="rtmp"),
                     "en_flash_providerName": validate.text
                 }
             )
         )
     ),
     "history_video": validate.all(
         validate.transform(_history_re.search),
         validate.any(
             None,
             validate.all(
                 validate.get(1),
                 validate.url(scheme="http")
             )
         )
     ),
     "standby_video": validate.all(
         validate.transform(_replay_json_re.search),
         validate.any(
             None,
             validate.all(
                 validate.get(1),
                 validate.transform(parse_json),
                 [{
                     "streamName": validate.url(scheme="http")
                 }]
             )
         )
     )
 })
Example #29
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
Example #30
0
        "_mediaStreamArray": [{
            validate.optional("_server"): validate.text,
            "_stream": validate.any(validate.text, [validate.text]),
            "_quality": validate.any(int, validate.text)
        }]
    }]
})
_smil_schema = validate.Schema(
    validate.union({
        "base": validate.all(
            validate.xml_find("head/meta"),
            validate.get("base"),
            validate.url(scheme="http")
        ),
        "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)
Example #31
0
    "_mediaArray": [{
        "_mediaStreamArray": [{
            validate.optional("_server"):
            validate.text,
            "_stream":
            validate.any(validate.text, [validate.text]),
            "_quality":
            validate.any(int, validate.text)
        }]
    }]
})
_smil_schema = validate.Schema(
    validate.union({
        "base":
        validate.all(validate.xml_find("head/meta"), validate.get("base"),
                     validate.url(scheme="http")),
        "videos":
        validate.all(validate.xml_findall("body/seq/video"),
                     [validate.get("src")])
    }))


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

    def _get_http_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "vod")
        urls = info["_stream"]
        if not isinstance(info["_stream"], list):
            urls = [urls]
Example #32
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
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)
Example #34
0
from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.stream import HLSStream

STREAM_INFO_URL = "https://api.periscope.tv/api/v2/getAccessPublic"

STATUS_GONE = 410
STATUS_UNAVAILABLE = (STATUS_GONE,)

_url_re = re.compile(r"http(s)?://(www\.)?(periscope|pscp)\.tv/[^/]+/(?P<broadcast_id>[\w\-\=]+)")
_stream_schema = validate.Schema(
    validate.any(
        None,
        validate.union({
            "hls_url": validate.all(
                {"hls_url": validate.url(scheme="http")},
                validate.get("hls_url")
            ),
        }),
        validate.union({
            "replay_url": validate.all(
                {"replay_url": validate.url(scheme="http")},
                validate.get("replay_url")
            ),
        }),
    ),
)


class Periscope(Plugin):
    @classmethod
    def can_handle_url(cls, url):
Example #35
0
""", re.VERBOSE)

_swf_player_re = re.compile(
    r'swfobject.embedSWF\("(/\d+/swf/[0-9A-Za-z]+\.swf)"')

_schema = validate.Schema(
    validate.any(
        validate.all(u"<error></error>", validate.transform(lambda x: None)),
        validate.all(
            validate.transform(lambda s: s.split(";")), validate.length(3),
            validate.union({
                "server":
                validate.all(validate.get(0), validate.text),
                "token":
                validate.all(
                    validate.get(1), validate.text,
                    validate.startswith(":mvnkey-"),
                    validate.transform(lambda s: s[len(":mvnkey-"):])),
                "ingest":
                validate.all(validate.get(2), validate.text)
            }))))


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

    def _get_streams(self):
        res = http.get(self.url)
        match = _swf_player_re.search(res.text)
Example #36
0
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)
                    )
                })
            ]
        )
    })
)


class Beam(Plugin):
Example #37
0
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)
                    )
                })
            ]
        )
    })
)

class Beam(Plugin):
    @classmethod
Example #38
0
class AnimeLab(Plugin):
    url_re = re.compile(r"https?://(?:www\.)?animelab\.com/player/")
    login_url = "https://www.animelab.com/login"
    video_collection_re = re.compile(r"VideoCollection\((\[.*?\])\);")
    playlist_position_re = re.compile(r"playlistPosition\s*=\s*(\d+);")
    video_collection_schema = validate.Schema(
        validate.union({
            "position": validate.all(
                validate.transform(playlist_position_re.search),
                validate.any(
                    None,
                    validate.all(validate.get(1), validate.transform(int))
                )
            ),
            "playlist": validate.all(
                validate.transform(video_collection_re.search),
                validate.any(
                    None,
                    validate.all(
                        validate.get(1),
                        validate.transform(parse_json)
                    )
                )
            )
        })
    )
    arguments = PluginArguments(
        PluginArgument(
            "email",
            requires=["password"],
            metavar="EMAIL",
            help="The email address used to register with animelab.com."
        ),
        PluginArgument(
            "password",
            sensitive=True,
            metavar="PASSWORD",
            help="A animelab.com account password to use with --animelab-email."
        )
    )

    @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 to log in as {0}", email)
        res = http.post(self.login_url,
                        data=dict(email=email, password=password),
                        allow_redirects=False,
                        raise_for_status=False)
        loc = res.headers.get("Location", "")
        if "geoblocked" in loc.lower():
            self.logger.error("AnimeLab is not available in your territory")
        elif res.status_code >= 400:
            self.logger.error("Failed to login to AnimeLab, check your email/password combination")
        else:
            return True

        return False

    def _get_streams(self):
        email, password = self.get_option("email"), self.get_option("password")
        if not email or not password:
            self.logger.error("AnimeLab requires authentication, use --animelab-email "
                              "and --animelab-password to set your email/password combination")
            return

        if self.login(email, password):
            self.logger.info("Successfully logged in as {0}", email)
            video_collection = http.get(self.url, schema=self.video_collection_schema)
            if video_collection["playlist"] is None or video_collection["position"] is None:
                return

            data = video_collection["playlist"][video_collection["position"]]

            self.logger.debug("Found {0} version {1} hard-subs",
                              data["language"]["name"],
                              "with" if data["hardSubbed"] else "without")

            for video in data["videoInstances"]:
                if video["httpUrl"]:
                    q = video["videoQuality"]["description"]
                    s = HTTPStream(self.session, video["httpUrl"])
                    yield q, s
Example #39
0
 def test_union(self):
     assert validate(union((get("foo"), get("bar"))), {
         "foo": "alpha",
         "bar": "beta"
     }) == ("alpha", "beta")