示例#1
0
    {
        "data": validate.any(
            validate.text,
            dict,
            {
                "videoinfo": validate.any(
                    validate.text,
                    {
                        "plflag_list": validate.text,
                        "plflag": validate.text
                    }
                )
            }
        )
    },
    validate.get("data"))


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

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

        res = http.get(self.url)

        try:
            channel = int(channel)
示例#2
0
class IDF1(Plugin):
    DACAST_API_URL = 'https://json.dacast.com/b/{}/{}/{}'
    DACAST_TOKEN_URL = 'https://services.dacast.com/token/i/b/{}/{}/{}'

    _video_id_re = re.compile(
        r"""
            dacast\('(?P<broadcaster_id>\d+)_(?P<video_type>[a-z]+)_(?P<video_id>\d+)',\s*'replay_content',\s*data\);
        """, re.VERBOSE)
    _video_id_alt_re = re.compile(
        r'''
            <script\s+
                src="https://player.dacast.com/js/player.js"\s+
                id="(?P<broadcaster_id>\d+)_(?P<video_type>[cf])_(?P<video_id>\d+)"
        ''', re.VERBOSE)
    _player_url = 'http://ssl.p.jwpcdn.com/player/v/7.12.6/jwplayer.flash.swf'

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

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

    _user_agent = useragents.IE_11

    def _get_streams(self):
        res = self.session.http.get(self.url)
        match = self._video_id_re.search(
            res.text) or self._video_id_alt_re.search(res.text)
        if match is None:
            return
        broadcaster_id = match.group('broadcaster_id')
        video_type = match.group('video_type')
        video_id = match.group('video_id')

        videos = self.session.http.get(self.DACAST_API_URL.format(
            broadcaster_id, video_type, video_id),
                                       schema=self._api_schema)
        token = self.session.http.get(self.DACAST_TOKEN_URL.format(
            broadcaster_id, video_type, video_id),
                                      schema=self._token_schema,
                                      headers={'referer': self.url})
        parsed = []

        for video_url in videos:
            video_url += token

            # Ignore duplicate video URLs
            if video_url in parsed:
                continue
            parsed.append(video_url)

            # Ignore HDS streams (broken)
            if '.m3u8' in video_url:
                for s in HLSStream.parse_variant_playlist(
                        self.session, video_url).items():
                    yield s
示例#3
0
            None,
            {
                "streams": validate.all(
                    [{
                        "quality": validate.any(validate.text, None),
                        "url": validate.url(
                            scheme="http",
                            path=validate.endswith(".m3u8")
                        ),
                        validate.optional("video_encode_id"): validate.text
                    }]
                )
            }
        )
    },
    validate.get("stream_data")
)
_login_schema = validate.Schema({
    "auth": validate.text,
    "expires": validate.all(
        validate.text,
        validate.transform(parse_timestamp)
    ),
    "user": {
        "username": validate.any(validate.text, None),
        "email": validate.text
    }
})
_session_schema = validate.Schema(
    {
        "session_id": validate.text
示例#4
0
_embed_url_re = re.compile(
    '<meta itemprop="embedURL" content="http://www.viagame.com/embed/video/([^"]+)"'
)
_store_data_re = re.compile("window.fluxData\s*=\s*JSON.parse\(\"(.+)\"\);")
_url_re = re.compile("http(s)?://(www\.)?viagame.com/channels/.+")

_store_schema = validate.Schema(
    {
        "initialStoresData": [{
            "instanceName": validate.text,
            "storeName": validate.text,
            "initialData": validate.any(dict, list)
        }]
    },
    validate.get("initialStoresData")
)
_match_store_schema = validate.Schema(
    {
        "match": {
            "id": validate.text,
            "type": validate.text,
            "videos": [{
                "id": validate.text,
                "play_id": validate.text,
            }]
        }
    },
    validate.get("match")
)
示例#5
0
        /(?P<media_id>[^/]+)
    )?
""", re.VERBOSE)

_live_schema = validate.Schema(
    {
        "livestream": [{
            "media_is_live": validate.all(
                validate.text,
                validate.transform(int),
                validate.transform(bool)
            ),
            "media_id": validate.text
        }],
    },
    validate.get("livestream"),
    validate.length(1),
    validate.get(0)
)
_player_schema = validate.Schema(
    {
        "clip": {
            "baseUrl": validate.any(None, validate.text),
            "bitrates": validate.all(
                validate.filter(lambda b: b.get("url") and b.get("label")),
                [{
                    "label": validate.text,
                    "url": validate.text,
                }],
            )
        },
示例#6
0
import re

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

YOUTUBE_URL = "https://www.youtube.com/watch?v={0}"
_url_re = re.compile(r'http(s)?://www\.skai.gr/.*')
_youtube_id = re.compile(r'<span\s+itemprop="contentUrl"\s+href="(.*)"></span>', re.MULTILINE)
_youtube_url_schema = validate.Schema(
    validate.all(
        validate.transform(_youtube_id.search),
        validate.any(
            None,
            validate.all(
                validate.get(1),
                validate.text
            )
        )
    )
)


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

    def _get_streams(self):
        channel_id = http.get(self.url, schema=_youtube_url_schema)
        if channel_id:
            return self.session.streams(YOUTUBE_URL.format(channel_id))
示例#7
0
    def _get_streams(self):
        channels = self.get_channels()

        if not channels:
            log.error("No channels found")
            return

        log.debug(f"channels={channels}")

        channel_id = self.match.group("channel")
        if channel_id is None:
            channel_id, channel_code = next(iter(channels.items()))
        elif channel_id in channels:
            channel_code = channels[channel_id]
        else:
            log.error(f"Unknown channel ID: {channel_id}")
            return

        log.info(f"Channel: {channel_code}")

        json = self.session.http.post(
            "https://www.htv.com.vn/HTVModule/Services/htvService.aspx",
            data={
                "method": "GetScheduleList",
                "channelid": channel_id,
                "template": "AjaxSchedules.xslt",
                "channelcode": channel_code,
                "date": date.today().strftime("%d-%m-%Y"),
            },
            schema=validate.Schema(
                validate.parse_json(),
                {
                    "success": bool,
                    "chanelUrl": validate.url(),
                },
            ),
        )

        if not json["success"]:
            log.error("API error: success not true")
            return

        hls_url = self.session.http.get(
            json["chanelUrl"],
            headers={"Referer": self.url},
            schema=validate.Schema(
                validate.parse_html(),
                validate.xml_xpath_string(
                    ".//script[contains(text(), 'playlist.m3u8')]/text()"),
                validate.any(
                    None,
                    validate.all(
                        validate.transform(self.hls_url_re.search),
                        validate.any(
                            None, validate.all(validate.get(1),
                                               validate.url())),
                    )),
            ),
        )

        if hls_url:
            return HLSStream.parse_variant_playlist(
                self.session,
                hls_url,
                headers={"Referer": "https://hplus.com.vn/"},
            )
示例#8
0
from streamlink.stream import HLSStream
from streamlink.plugin.api import useragents
from streamlink.utils import update_scheme

HUYA_URL = "http://m.huya.com/%s"

_url_re = re.compile(r'http(s)?://(www\.)?huya.com/(?P<channel>[^/]+)', re.VERBOSE)
_hls_re = re.compile(r'^\s*<video\s+id="html5player-video"\s+src="(?P<url>[^"]+)"', re.MULTILINE)

_hls_schema = validate.Schema(
    validate.all(
        validate.transform(_hls_re.search),
        validate.any(
            None,
            validate.all(
                validate.get('url'),
                validate.transform(str)
            )
        )
    )
)


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

    def _get_streams(self):
        match = _url_re.match(self.url)
        channel = match.group("channel")
示例#9
0
class Schoolism(Plugin):
    url_re = re.compile(
        r"https?://(?:www\.)?schoolism\.com/(viewAssignment|watchLesson).php")
    login_url = "https://www.schoolism.com/index.php"
    key_time_url = "https://www.schoolism.com/video-html/key-time.php"
    playlist_re = re.compile(r"var allVideos\s*=\s*(\[.*\]);", re.DOTALL)
    js_to_json = partial(re.compile(r'(?!<")(\w+):(?!/)').sub, r'"\1":')
    fix_brackets = partial(re.compile(r',\s*\}').sub, r'}')
    playlist_schema = validate.Schema(
        validate.transform(playlist_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1),
                validate.transform(js_to_json),
                validate.transform(fix_brackets),  # remove invalid ,
                validate.transform(parse_json),
                [{
                    "sources":
                    validate.all(
                        [{
                            validate.optional("playlistTitle"): validate.text,
                            "title": validate.text,
                            "src": validate.text,
                            "type": validate.text,
                        }],
                        # only include HLS streams
                        # validate.filter(lambda s: s["type"] == "application/x-mpegurl")
                    )
                }])))

    arguments = PluginArguments(
        PluginArgument("email",
                       required=True,
                       requires=["password"],
                       metavar="EMAIL",
                       help="""
        The email associated with your Schoolism account,
        required to access any Schoolism stream.
        """),
        PluginArgument(
            "password",
            sensitive=True,
            metavar="PASSWORD",
            help="A Schoolism account password to use with --schoolism-email."
        ),
        PluginArgument("part",
                       type=int,
                       default=1,
                       metavar="PART",
                       help="""
        Play part number PART of the lesson, or assignment feedback video.

        Defaults is 1.
        """))

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

    def login(self, email, password):
        """
        Login to the schoolism account and return the users account
        :param email: (str) email for account
        :param password: (str) password for account
        :return: (str) users email
        """
        if self.options.get("email") and self.options.get("password"):
            res = self.session.http.post(self.login_url,
                                         data={
                                             "email": email,
                                             "password": password,
                                             "redirect": None,
                                             "submit": "Login"
                                         })

            if res.cookies.get("password") and res.cookies.get("email"):
                return res.cookies.get("email")
            else:
                log.error(
                    "Failed to login to Schoolism, incorrect email/password combination"
                )
        else:
            log.error(
                "An email and password are required to access Schoolism streams"
            )

    def _get_streams(self):
        user = self.login(self.options.get("email"),
                          self.options.get("password"))
        if user:
            log.debug("Logged in to Schoolism as {0}", user)
            res = self.session.http.get(
                self.url, headers={"User-Agent": useragents.SAFARI_8})
            lesson_playlist = self.playlist_schema.validate(res.text)

            part = self.options.get("part")
            video_type = "Lesson" if "lesson" in self.url_re.match(
                self.url).group(1).lower() else "Assignment Feedback"

            log.info("Attempting to play {0} Part {1}", video_type, part)
            found = False

            # make request to key-time api, to get key specific headers
            _ = self.session.http.get(
                self.key_time_url, headers={"User-Agent": useragents.SAFARI_8})

            for i, video in enumerate(lesson_playlist, 1):
                if video["sources"] and i == part:
                    found = True
                    for source in video["sources"]:
                        if source['type'] == "video/mp4":
                            yield "live", HTTPStream(self.session,
                                                     source["src"],
                                                     headers={
                                                         "User-Agent":
                                                         useragents.SAFARI_8,
                                                         "Referer": self.url
                                                     })
                        elif source['type'] == "application/x-mpegurl":
                            for s in HLSStream.parse_variant_playlist(
                                    self.session,
                                    source["src"],
                                    headers={
                                        "User-Agent": useragents.SAFARI_8,
                                        "Referer": self.url
                                    }).items():
                                yield s

            if not found:
                log.error("Could not find {0} Part {1}", video_type, part)
示例#10
0
""", re.VERBOSE)

_live_schema = validate.Schema(
    {
        "livestream": [{
            "media_user_name":
            validate.text,
            validate.optional("media_hosted_media"):
            object,
            "media_is_live":
            validate.all(validate.text, validate.transform(int),
                         validate.transform(bool)),
            "media_id":
            validate.text
        }],
    }, validate.get("livestream"), validate.length(1), validate.get(0))
_player_schema = validate.Schema({
    "clip": {
        "baseUrl":
        validate.any(None, validate.text),
        "bitrates":
        validate.all(
            validate.filter(lambda b: b.get("url") and b.get("label")),
            [{
                "label": validate.text,
                "url": validate.text,
            }],
        )
    },
    validate.optional("playlist"): [{
        validate.optional("connectionProvider"):
示例#11
0
CHANNEL_INFO_URL = "http://api.plu.cn/tga/streams/%s"
QQ_STREAM_INFO_URL = "http://info.zb.qq.com/?cnlid=%d&cmd=2&stream=%d&system=1&sdtfrom=113"
PLU_STREAM_INFO_URL = "http://livestream.plu.cn/live/getlivePlayurl?roomId=%d"
_quality_re = re.compile(r"\d+x(\d+)$")
_url_re = re.compile(r"http://(star|y)\.longzhu\.(?:tv|com)/(m\/)?(?P<domain>[a-z0-9]+)")

_channel_schema = validate.Schema(
    {
        "data": validate.any(None, {
            "channel": validate.any(None, {
                "id": int,
                "vid": int
            })
        })
    },
    validate.get("data")
)

_plu_schema = validate.Schema(
    {
        "playLines": [{
            "urls": [{
                "securityUrl": validate.url(scheme=validate.any("rtmp", "http")),
                "resolution": validate.text,
                "ext": validate.text
            }]
        }]
    }
)

_qq_schema = validate.Schema(
示例#12
0
})
_media_schema = validate.Schema(
    {
        "stream_data":
        validate.any(
            None, {
                "streams":
                validate.all([{
                    "quality":
                    validate.text,
                    "url":
                    validate.url(scheme="http",
                                 path=validate.endswith(".m3u8"))
                }], validate.filter(lambda s: s["quality"] != "adaptive"))
            })
    }, validate.get("stream_data"))
_login_schema = validate.Schema({
    "auth":
    validate.text,
    "expires":
    validate.all(validate.text, validate.transform(parse_timestamp)),
    "user": {
        "username": validate.text
    }
})
_session_schema = validate.Schema({"session_id": validate.text},
                                  validate.get("session_id"))


class CrunchyrollAPIError(Exception):
    """Exception thrown by the Crunchyroll API when an error occurs"""
示例#13
0
        /
        (?P<video_id>\d+)
    )?
    (?:
        /(?:clip/)?
        (?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")
示例#14
0
# Regex to match video ID
_id_re = re.compile(r"""data-video-id=['"](?P<id>[^'"]+)['"]""")
_old_id_re = re.compile(r"/(?:video|klipp)/(?P<id>[0-9]+)/")

# New video schema used with API call
_video_schema = validate.Schema(
    {
        "videoReferences": validate.all(
            [{
                "url": validate.text,
                "format": validate.text
            }],
        ),
    },
    validate.get("videoReferences")
)

# Old video schema
_old_video_schema = validate.Schema(
    {
        "video": {
            "videoReferences": validate.all(
                [{
                    "url": validate.text,
                    "playerType": validate.text
                }],
            ),
        }
    },
    validate.get("video"),
示例#15
0
class N13TV(Plugin):
    url_re = re.compile(r"https?://(?:www\.)?13tv\.co\.il/(live|.*?/)")
    api_url = "https://13tv-api.oplayer.io/api/getlink/"
    main_js_url_re = re.compile(
        r'type="text/javascript" src="(.*?main\..+\.js)"')
    user_id_re = re.compile(r'"data-ccid":"(.*?)"')
    video_name_re = re.compile(r'"videoRef":"(.*?)"')
    server_addr_re = re.compile(r'(.*[^/])(/.*)')
    media_file_re = re.compile(r'(.*)(\.[^\.].*)')

    live_schema = validate.Schema(
        validate.all([{
            'Link': validate.url()
        }], validate.get(0), validate.get('Link')))

    vod_schema = validate.Schema(
        validate.all([{
            'ShowTitle':
            validate.text,
            'ProtocolType':
            validate.all(validate.text,
                         validate.transform(lambda x: x.replace("://", ""))),
            'ServerAddress':
            validate.text,
            'MediaRoot':
            validate.text,
            'MediaFile':
            validate.text,
            'Bitrates':
            validate.text,
            'StreamingType':
            validate.text,
            'Token':
            validate.all(validate.text,
                         validate.transform(lambda x: x.lstrip("?")))
        }], validate.get(0)))

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

    def _get_live(self, user_id):
        res = self.session.http.get(self.api_url,
                                    params=dict(userId=user_id,
                                                serverType="web",
                                                ch=1,
                                                cdnName="casttime"))

        url = self.session.http.json(res, schema=self.live_schema)
        log.debug("URL={0}".format(url))

        return HLSStream.parse_variant_playlist(self.session, url)

    def _get_vod(self, user_id, video_name):
        res = self.session.http.get(urljoin(self.api_url,
                                            "getVideoByFileName"),
                                    params=dict(userId=user_id,
                                                videoName=video_name,
                                                serverType="web",
                                                callback="x"))

        vod_data = self.session.http.json(res, schema=self.vod_schema)

        if video_name == vod_data['ShowTitle']:
            host, base_path = self.server_addr_re.search(
                vod_data['ServerAddress']).groups()
            if not host or not base_path:
                raise PluginError("Could not split 'ServerAddress' components")

            base_file, file_ext = self.media_file_re.search(
                vod_data['MediaFile']).groups()
            if not base_file or not file_ext:
                raise PluginError("Could not split 'MediaFile' components")

            media_path = "{0}{1}{2}{3}{4}{5}".format(
                base_path, vod_data['MediaRoot'], base_file,
                vod_data['Bitrates'], file_ext, vod_data['StreamingType'])
            log.debug("Media path={0}".format(media_path))

            vod_url = urlunparse((vod_data['ProtocolType'], host, media_path,
                                  '', vod_data['Token'], ''))
            log.debug("URL={0}".format(vod_url))

            return HLSStream.parse_variant_playlist(self.session, vod_url)

    def _get_streams(self):
        m = self.url_re.match(self.url)
        url_type = m and m.group(1)
        log.debug("URL type={0}".format(url_type))

        res = self.session.http.get(self.url)

        if url_type != "live":
            m = self.video_name_re.search(res.text)
            video_name = m and m.group(1)
            if not video_name:
                raise PluginError('Could not determine video_name')
            log.debug("Video name={0}".format(video_name))

        m = self.main_js_url_re.search(res.text)
        main_js_path = m and m.group(1)
        if not main_js_path:
            raise PluginError('Could not determine main_js_path')
        log.debug("Main JS path={0}".format(main_js_path))

        res = self.session.http.get(urljoin(self.url, main_js_path))

        m = self.user_id_re.search(res.text)
        user_id = m and m.group(1)
        if not user_id:
            raise PluginError('Could not determine user_id')
        log.debug("User ID={0}".format(user_id))

        if url_type == "live":
            return self._get_live(user_id)
        else:
            return self._get_vod(user_id, video_name)
示例#16
0
import re

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

_url_re = re.compile(r"https?://(www\.)?ok\.ru/live/\d+")
_vod_re = re.compile(r";(?P<hlsurl>[^;]+video\.m3u8.+?)\\&quot;")

_schema = validate.Schema(
    validate.transform(_vod_re.search),
    validate.any(
        None,
        validate.all(
            validate.get("hlsurl"),
            validate.url()
        )
    )
)

class OK_live(Plugin):
    """
    Support for ok.ru live stream: http://www.ok.ru/live/
    """
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url) is not None

    def _get_streams(self):
        headers = {
示例#17
0
class Zattoo(Plugin):
    API_CHANNELS = '{0}/zapi/v2/cached/channels/{1}?details=False'
    API_HELLO = '{0}/zapi/session/hello'
    API_HELLO_V2 = '{0}/zapi/v2/session/hello'
    API_HELLO_V3 = '{0}/zapi/v3/session/hello'
    API_LOGIN = '******'
    API_LOGIN_V3 = '{0}/zapi/v3/account/login'
    API_SESSION = '{0}/zapi/v2/session'
    API_WATCH = '{0}/zapi/watch'
    API_WATCH_REC = '{0}/zapi/watch/recording/{1}'
    API_WATCH_VOD = '{0}/zapi/avod/videos/{1}/watch'

    STREAMS_ZATTOO = ['dash', 'hls', 'hls5']

    TIME_CONTROL = 60 * 60 * 2
    TIME_SESSION = 60 * 60 * 24 * 30

    _url_re = re.compile(r'''(?x)
        https?://
        (?P<base_url>
            (?:(?:
                iptv\.glattvision|www\.(?:myvisiontv|saktv|vtxtv)
            )\.ch
            )|(?:(?:
                mobiltv\.quickline|www\.quantum-tv|zattoo
            )\.com
            )|(?:(?:
                tvonline\.ewe|nettv\.netcologne|tvplus\.m-net
            )\.de
            )|(?:(?:
                player\.waly|www\.(?:1und1|netplus)
            )\.tv)
            |www\.bbv-tv\.net
            |www\.meinewelt\.cc
        )/
        (?:
            (?:
                recording(?:s\?recording=|/)
                |
                (?:ondemand/)?(?:watch/(?:[^/\s]+)(?:/[^/]+/))
            )(?P<recording_id>\d+)
            |
            (?:
                (?:live/|watch/)|(?:channels(?:/\w+)?|guide)\?channel=
            )(?P<channel>[^/\s]+)
            |
            ondemand(?:\?video=|/watch/)(?P<vod_id>[^-]+)
        )
        ''')

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

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

    _session_schema = validate.Schema(
        {
            'success': bool,
            'session': {
                'loggedin': bool
            }
        }, validate.get('session'))

    arguments = PluginArguments(
        PluginArgument("email",
                       requires=["password"],
                       metavar="EMAIL",
                       help="""
            The email associated with your zattoo account,
            required to access any zattoo stream.
            """),
        PluginArgument("password",
                       sensitive=True,
                       metavar="PASSWORD",
                       help="""
            A zattoo account password to use with --zattoo-email.
            """),
        PluginArgument("purge-credentials",
                       action="store_true",
                       help="""
            Purge cached zattoo credentials to initiate a new session
            and reauthenticate.
            """),
        PluginArgument('stream-types',
                       metavar='TYPES',
                       type=comma_list_filter(STREAMS_ZATTOO),
                       default=['hls'],
                       help='''
            A comma-delimited list of stream types which should be used,
            the following types are allowed:

            - {0}

            Default is "hls".
            '''.format('\n            - '.join(STREAMS_ZATTOO))))

    def __init__(self, url):
        super().__init__(url)
        self.domain = self._url_re.match(url).group('base_url')
        self._session_attributes = Cache(
            filename='plugin-cache.json',
            key_prefix='zattoo:attributes:{0}'.format(self.domain))
        self._uuid = self._session_attributes.get('uuid')
        self._authed = (self._session_attributes.get('power_guide_hash')
                        and self._uuid and self.session.http.cookies.get(
                            'pzuid', domain=self.domain)
                        and self.session.http.cookies.get('beaker.session.id',
                                                          domain=self.domain))
        self._session_control = self._session_attributes.get(
            'session_control', False)
        self.base_url = 'https://{0}'.format(self.domain)
        self.headers = {
            'User-Agent': useragents.CHROME,
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': self.base_url
        }

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

    def _hello(self):
        log.debug('_hello ...')

        # a new session is required for the app_token
        self.session.http.cookies = cookiejar_from_dict({})
        if self.base_url == 'https://zattoo.com':
            app_token_url = 'https://zattoo.com/client/token-2fb69f883fea03d06c68c6e5f21ddaea.json'
        elif self.base_url == 'https://www.quantum-tv.com':
            app_token_url = 'https://www.quantum-tv.com/token-4d0d61d4ce0bf8d9982171f349d19f34.json'
        else:
            app_token_url = self.base_url

        res = self.session.http.get(app_token_url)
        if self.base_url == 'https://www.quantum-tv.com':
            app_token = self.session.http.json(res)["session_token"]
            hello_url = self.API_HELLO_V3.format(self.base_url)
        elif self.base_url == 'https://zattoo.com':
            app_token = self.session.http.json(res)['app_tid']
            hello_url = self.API_HELLO_V2.format(self.base_url)
        else:
            match = self._app_token_re.search(res.text)
            app_token = match.group(1)
            hello_url = self.API_HELLO.format(self.base_url)

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

        if self.base_url == 'https://zattoo.com':
            params = {
                'uuid': __uuid,
                'app_tid': app_token,
                'app_version': '1.0.0'
            }
        else:
            params = {
                'client_app_token': app_token,
                'uuid': __uuid,
            }

        if self.base_url == 'https://www.quantum-tv.com':
            params['app_version'] = '3.2028.3'
        else:
            params['lang'] = 'en'
            params['format'] = 'json'

        res = self.session.http.post(hello_url,
                                     headers=self.headers,
                                     data=params)

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

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

        if self.base_url == 'https://quantum-tv.com':
            login_url = self.API_LOGIN_V3.format(self.base_url)
        else:
            login_url = self.API_LOGIN.format(self.base_url)

        try:
            res = self.session.http.post(login_url,
                                         headers=self.headers,
                                         data=params)
        except Exception as e:
            if '400 Client Error' in str(e):
                raise PluginError(
                    'Failed to login, check your username/password')
            raise e

        data = self.session.http.json(res)
        self._authed = data['success']
        log.debug('New Session Data')
        self.save_cookies(default_expires=self.TIME_SESSION)
        self._session_attributes.set('power_guide_hash',
                                     data['session']['power_guide_hash'],
                                     expires=self.TIME_SESSION)
        self._session_attributes.set('session_control',
                                     True,
                                     expires=self.TIME_CONTROL)

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

        params = {'https_watch_urls': True}
        if channel:
            watch_url = self.API_WATCH.format(self.base_url)
            params_cid = self._get_params_cid(channel)
            if not params_cid:
                return
            params.update(params_cid)
        elif vod_id:
            log.debug('Found vod_id: {0}'.format(vod_id))
            watch_url = self.API_WATCH_VOD.format(self.base_url, vod_id)
        elif recording_id:
            log.debug('Found recording_id: {0}'.format(recording_id))
            watch_url = self.API_WATCH_REC.format(self.base_url, recording_id)
        else:
            log.debug('Missing watch_url')
            return

        zattoo_stream_types = self.get_option('stream-types') or ['hls']
        for stream_type in zattoo_stream_types:
            params_stream_type = {'stream_type': stream_type}
            params.update(params_stream_type)

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

            data = self.session.http.json(res)
            log.debug('Found data for {0}'.format(stream_type))
            if data['success'] and stream_type in ['hls', 'hls5']:
                for url in data['stream']['watch_urls']:
                    for s in HLSStream.parse_variant_playlist(
                            self.session, url['url']).items():
                        yield s
            elif data['success'] and stream_type == 'dash':
                for url in data['stream']['watch_urls']:
                    for s in DASHStream.parse_manifest(self.session,
                                                       url['url']).items():
                        yield s

    def _get_params_cid(self, channel):
        log.debug('get channel ID for {0}'.format(channel))

        channels_url = self.API_CHANNELS.format(
            self.base_url, self._session_attributes.get('power_guide_hash'))

        try:
            res = self.session.http.get(channels_url, headers=self.headers)
        except Exception:
            log.debug('Force session reset for _get_params_cid')
            self.reset_session()
            return False

        data = self.session.http.json(res, schema=self._channels_schema)

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

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

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

        if not cid:
            cid = channel

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

        return {'cid': cid}

    def reset_session(self):
        self._session_attributes.set('power_guide_hash', None, expires=0)
        self._session_attributes.set('uuid', None, expires=0)
        self.clear_cookies()
        self._authed = False

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

        if self.options.get('purge_credentials'):
            self.reset_session()
            log.info('All credentials were successfully removed.')
        elif (self._authed and not self._session_control):
            # check every two hours, if the session is actually valid
            log.debug('Session control for {0}'.format(self.domain))
            res = self.session.http.get(self.API_SESSION.format(self.base_url))
            res = self.session.http.json(res, schema=self._session_schema)
            if res['loggedin']:
                self._session_attributes.set('session_control',
                                             True,
                                             expires=self.TIME_CONTROL)
            else:
                log.debug('User is not logged in')
                self._authed = False

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

        if not self._authed:
            self._hello()
            self._login(email, password)

        return self._watch()
示例#18
0
COOKIE_PARAMS = (
    "devicetype=desktop&"
    "preferred-player-odm=hlslink&"
    "preferred-player-live=hlslink"
)

_id_re = re.compile(r"/(?:program|direkte|serie/[^/]+)/([^/]+)")
_url_re = re.compile(r"https?://(tv|radio).nrk.no/")
_api_baseurl_re = re.compile(r'''apiBaseUrl:\s*["'](?P<baseurl>[^"']+)["']''')

_schema = validate.Schema(
    validate.transform(_api_baseurl_re.search),
    validate.any(
        None,
        validate.all(
            validate.get("baseurl"),
            validate.url(
                scheme="http"
            )
        )
    )
)

_mediaelement_schema = validate.Schema({
    "mediaUrl": validate.url(
        scheme="http",
        path=validate.endswith(".m3u8")
    )
})

示例#19
0
STREAM_API_URL = "https://playapi.mtgx.tv/v3/videos/stream/{0}"

_swf_url_re = re.compile(r"data-flashplayer-url=\"([^\"]+)\"")
_player_data_re = re.compile(r"window.fluxData\s*=\s*JSON.parse\(\"(.+)\"\);")

_stream_schema = validate.Schema(
    validate.any(
        None, validate.all({"msg": validate.text}),
        validate.all(
            {
                "streams":
                validate.all(
                    {validate.text: validate.any(validate.text, int, None)},
                    validate.filter(lambda k, v: isinstance(v, validate.text)))
            }, validate.get("streams"))))


class Viasat(Plugin):
    """Streamlink Plugin for Viasat"""

    _iframe_re = re.compile(
        r"""<iframe.+src=["'](?P<url>[^"']+)["'].+allowfullscreen""")
    _image_re = re.compile(
        r"""<meta\sproperty=["']og:image["']\scontent=".+/(?P<stream_id>\d+)/[^/]+\.jpg"""
    )

    _url_re = re.compile(
        r"""https?://(?:www\.)?
        (?:
            juicyplay\.dk
示例#20
0
    "h264_aac_ts_http_m3u8_http": (
        "HLS", HLSStream.parse_variant_playlist
    )
}

_url_re = re.compile(r"""
    http(s)?://(\w+\.)?zdf.de/
""", re.VERBOSE | re.IGNORECASE)
_api_json_re = re.compile(r'''data-zdfplayer-jsb=["'](?P<json>{.+?})["']''', re.S)

_api_schema = validate.Schema(
    validate.transform(_api_json_re.search),
    validate.any(
        None,
        validate.all(
            validate.get("json"),
            validate.transform(parse_json),
            {
                "content": validate.text,
                "apiToken": validate.text
            },
        )
    )
)

_documents_schema = validate.Schema(
    {
        "mainVideoContent": {
            "http://zdf.de/rels/target": {
                "http://zdf.de/rels/streams/ptmd": validate.text
            },
示例#21
0
_url_re = re.compile(r"http(s)?://(?:(\w+\.)?ardmediathek.de/tv|mediathek.daserste.de/)")
_media_id_re = re.compile(r"/play/(?:media|config)/(\d+)")
_media_schema = validate.Schema({
    "_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")
        ),
        "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):
示例#22
0
STREAM_API_URL = "https://playapi.mtgx.tv/v3/videos/stream/{0}"

_swf_url_re = re.compile(r"data-flashplayer-url=\"([^\"]+)\"")
_player_data_re = re.compile(r"window.fluxData\s*=\s*JSON.parse\(\"(.+)\"\);")

_stream_schema = validate.Schema(
    validate.any(
        None,
        validate.all({"msg": validate.text}),
        validate.all({
            "streams": validate.all(
                {validate.text: validate.any(validate.text, int, None)},
                validate.filter(lambda k, v: isinstance(v, validate.text))
            )
        }, validate.get("streams"))
    )
)


class Viasat(Plugin):
    """Streamlink Plugin for Viasat"""

    _iframe_re = re.compile(r"""<iframe.+src=["'](?P<url>[^"']+)["'].+allowfullscreen""")
    _image_re = re.compile(r"""<meta\sproperty=["']og:image["']\scontent=".+/(?P<stream_id>\d+)/[^/]+\.jpg""")

    _url_re = re.compile(r"""https?://(?:www\.)?
        (?:
            juicyplay\.dk
            |
            play\.nova\.bg
示例#23
0
from streamlink.plugin.api import useragents
from streamlink.utils import update_scheme

HUYA_URL = "http://m.huya.com/%s"

_url_re = re.compile(r'http(s)?://(www\.)?huya.com/(?P<channel>[^/]+)',
                     re.VERBOSE)
_hls_re = re.compile(
    r'^\s*<video\s+id="html5player-video"\s+src="(?P<url>[^"]+)"',
    re.MULTILINE)

_hls_schema = validate.Schema(
    validate.all(
        validate.transform(_hls_re.search),
        validate.any(
            None, validate.all(validate.get('url'), validate.transform(str)))))


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

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

        self.session.http.headers.update({"User-Agent": useragents.IPAD})
        # Some problem with SSL on huya.com now, do not use https

        hls_url = self.session.http.get(HUYA_URL % channel, schema=_hls_schema)
示例#24
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):
        cubeid = self._get_live_cubeid()
示例#25
0
    )?
    douyu.com/
    (?:
        show/(?P<vid>[^/&?]+)|
        (?P<channel>[^/&?]+)
    )
""", re.VERBOSE)

_room_id_re = re.compile(r'"room_id\\*"\s*:\s*(\d+),')
_room_id_alt_re = re.compile(r'data-onlineid=(\d+)')

_room_id_schema = validate.Schema(
    validate.all(
        validate.transform(_room_id_re.search),
        validate.any(None,
                     validate.all(validate.get(1), validate.transform(int)))))

_room_id_alt_schema = validate.Schema(
    validate.all(
        validate.transform(_room_id_alt_re.search),
        validate.any(None,
                     validate.all(validate.get(1), validate.transform(int)))))

_room_schema = validate.Schema(
    {
        "data":
        validate.any(
            None, {
                "show_status":
                validate.all(validate.text, validate.transform(int)),
                "rtmp_url":
示例#26
0
}

_url_re = re.compile(r"http(s)?://(?P<cdn>\w+\.)?afreeca(tv)?\.com/(?P<username>\w+)(/\d+)?")

_channel_schema = validate.Schema(
    {
        "CHANNEL": {
            "RESULT": validate.transform(int),
            validate.optional("BPWD"): validate.text,
            validate.optional("BNO"): validate.text,
            validate.optional("RMD"): validate.text,
            validate.optional("AID"): validate.text,
            validate.optional("CDN"): validate.text
        }
    },
    validate.get("CHANNEL")
)

_stream_schema = validate.Schema(
    {
        validate.optional("view_url"): validate.url(
            scheme=validate.any("rtmp", "http")
        ),
        "stream_status": validate.text
    }
)


class AfreecaTV(Plugin):
    login_url = "https://member.afreecatv.com:8111/login/LoginAction.php"
示例#27
0
class DLive(Plugin):
    _re_url = re.compile(
        r"""
        https?://(?:www\.)?dlive\.tv/
        (?:
            (?:p/(?P<video>[^/]+))
            |
            (?P<channel>[^/]+)
        )
    """, re.VERBOSE)
    _re_videoPlaybackUrl = re.compile(r'"playbackUrl"\s*:\s*"([^"]+\.m3u8)"')

    _schema_userByDisplayName = validate.Schema(
        {
            "data": {
                "userByDisplayName": {
                    "livestream": validate.any(None, {"title": validate.text}),
                    "username": validate.text
                }
            }
        }, validate.get("data"), validate.get("userByDisplayName"))
    _schema_videoPlaybackUrl = validate.Schema(
        validate.transform(_re_videoPlaybackUrl.search),
        validate.any(
            None,
            validate.all(
                validate.get(1), validate.transform(unquote_plus),
                validate.transform(
                    lambda url: (bytes(url, "utf-8").decode("unicode_escape")
                                 if is_py3 else url.decode("unicode_escape"))),
                validate.url())))

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

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

        return Plugin.stream_weight(key)

    def __init__(self, *args, **kwargs):
        super(DLive, self).__init__(*args, **kwargs)
        self.author = None
        self.title = None

        match = self._re_url.match(self.url)
        self.video = match.group("video")
        self.channel = match.group("channel")

    def get_author(self):
        return self.author

    def get_title(self):
        return self.title

    def _get_streams_video(self):
        log.debug("Getting video HLS streams for {0}".format(self.video))
        try:
            hls_url = self.session.http.get(
                self.url, schema=self._schema_videoPlaybackUrl)
            if hls_url is None:
                return
        except PluginError:
            return

        return HLSStream.parse_variant_playlist(self.session, hls_url)

    def _get_streams_live(self):
        log.debug("Getting live HLS streams for {0}".format(self.channel))
        try:
            data = json.dumps({
                "query":
                """query {{
                userByDisplayName(displayname:"{displayname}") {{
                    livestream {{
                        title
                    }}
                    username
                }}
            }}""".format(displayname=self.channel)
            })
            res = self.session.http.post("https://graphigo.prd.dlive.tv/",
                                         data=data)
            res = self.session.http.json(res,
                                         schema=self._schema_userByDisplayName)
            if res["livestream"] is None:
                return
        except PluginError:
            return

        self.author = self.channel
        self.title = res["livestream"]["title"]

        hls_url = "https://live.prd.dlive.tv/hls/live/{0}.m3u8".format(
            res["username"])

        return HLSStream.parse_variant_playlist(self.session, hls_url)

    def _get_streams(self):
        if self.video:
            return self._get_streams_video()
        elif self.channel:
            return self._get_streams_live()
示例#28
0
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):
示例#29
0
    def clips(self, clipname):
        queries = [
            self._gql_persisted_query(
                "VideoAccessToken_Clip",
                "36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11",
                slug=clipname),
            self._gql_persisted_query(
                "ClipsView",
                "4480c1dcc2494a17bb6ef64b94a5213a956afb8a45fe314c66b0d04079a93a8f",
                slug=clipname),
            self._gql_persisted_query(
                "ClipsTitle",
                "f6cca7f2fdfbfc2cecea0c88452500dae569191e58a265f97711f8f2a838f5b4",
                slug=clipname)
        ]

        return self.call(
            queries,
            schema=validate.Schema([
                validate.all(
                    {
                        "data": {
                            "clip": {
                                "playbackAccessToken":
                                validate.all({
                                    "signature": str,
                                    "value": str
                                }, validate.union_get("signature", "value")),
                                "videoQualities": [
                                    validate.all(
                                        {
                                            "frameRate":
                                            validate.transform(int),
                                            "quality": str,
                                            "sourceURL": validate.url()
                                        },
                                        validate.transform(lambda q: (
                                            f"{q['quality']}p{q['frameRate']}",
                                            q["sourceURL"])))
                                ]
                            }
                        }
                    }, validate.get(("data", "clip")),
                    validate.union_get("playbackAccessToken",
                                       "videoQualities")),
                validate.all(
                    {
                        "data": {
                            "clip": {
                                "broadcaster": {
                                    "displayName": str
                                },
                                "game": {
                                    "name": str
                                }
                            }
                        }
                    }, validate.get(("data", "clip")),
                    validate.union_get(("broadcaster", "displayName"),
                                       ("game", "name"))),
                validate.all({"data": {
                    "clip": {
                        "title": str
                    }
                }}, validate.get(("data", "clip", "title")))
            ]))
示例#30
0
class BBCiPlayer(Plugin):
    """
    Allows streaming of live channels from bbc.co.uk/iplayer/live/* and of iPlayer programmes from
    bbc.co.uk/iplayer/episode/*
    """
    mediator_re = re.compile(r'window\.__IPLAYER_REDUX_STATE__\s*=\s*({.*?});',
                             re.DOTALL)
    state_re = re.compile(
        r'window.__IPLAYER_REDUX_STATE__\s*=\s*({.*?});</script>')
    account_locals_re = re.compile(r'window.bbcAccount.locals\s*=\s*({.*?});')
    hash = base64.b64decode(
        b"N2RmZjc2NzFkMGM2OTdmZWRiMWQ5MDVkOWExMjE3MTk5MzhiOTJiZg==")
    api_url = "https://open.live.bbc.co.uk/mediaselector/6/select/version/2.0/mediaset/" \
              "{platform}/vpid/{vpid}/format/json/atk/{vpid_hash}/asn/1/"
    platforms = ("pc", "iptv-all")
    session_url = "https://session.bbc.com/session"
    auth_url = "https://account.bbc.com/signin"

    mediator_schema = validate.Schema({"versions": [{
        "id": validate.text
    }]}, validate.get("versions"), validate.get(0), validate.get("id"))
    mediaselector_schema = validate.Schema(
        validate.parse_json(), {
            "media": [{
                "connection":
                validate.all(
                    [{
                        validate.optional("href"): validate.url(),
                        validate.optional("transferFormat"): validate.text
                    }], validate.filter(lambda c: c.get("href"))),
                "kind":
                validate.text
            }]
        }, validate.get("media"),
        validate.filter(lambda x: x["kind"] == "video"))
    arguments = PluginArguments(
        PluginArgument("username",
                       requires=["password"],
                       metavar="USERNAME",
                       help="The username used to register with bbc.co.uk."),
        PluginArgument(
            "password",
            sensitive=True,
            metavar="PASSWORD",
            help=
            "A bbc.co.uk account password to use with --bbciplayer-username.",
            prompt="Enter bbc.co.uk account password"),
        PluginArgument("hd",
                       action="store_true",
                       help="""
            Prefer HD streams over local SD streams, some live programmes may
            not be broadcast in HD.
            """),
    )

    def __init__(self, url):
        super().__init__(url)
        self.url = urlunparse(urlparse(self.url)._replace(scheme="https"))

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

    def find_vpid(self, url, res=None):
        """
        Find the Video Packet ID in the HTML for the provided URL

        :param url: URL to download, if res is not provided.
        :param res: Provide a cached version of the HTTP response to search
        :type url: string
        :type res: requests.Response
        :return: Video Packet ID for a Programme in iPlayer
        :rtype: string
        """
        log.debug(f"Looking for vpid on {url}")
        # Use pre-fetched page if available
        res = res or self.session.http.get(url)
        m = self.mediator_re.search(res.text)
        vpid = m and parse_json(m.group(1), schema=self.mediator_schema)
        return vpid

    def find_tvip(self, url, master=False):
        log.debug("Looking for {0} tvip on {1}".format(
            "master" if master else "", url))
        res = self.session.http.get(url)
        m = self.state_re.search(res.text)
        data = m and parse_json(m.group(1))
        if data:
            channel = data.get("channel")
            if master:
                return channel.get("masterBrand")
            return channel.get("id")

    def mediaselector(self, vpid):
        urls = defaultdict(set)
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid,
                                      vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            log.debug(f"Info API request: {url}")
            medias = self.session.http.get(url,
                                           schema=self.mediaselector_schema)
            for media in medias:
                for connection in media["connection"]:
                    urls[connection.get("transferFormat")].add(
                        connection["href"])

        for stream_type, urls in urls.items():
            log.debug(f"{len(urls)} {stream_type} streams")
            for url in list(urls):
                try:
                    if stream_type == "hls":
                        yield from HLSStream.parse_variant_playlist(
                            self.session, url).items()
                    if stream_type == "dash":
                        yield from DASHStream.parse_manifest(
                            self.session, url).items()
                    log.debug(f"  OK:   {url}")
                except Exception:
                    log.debug(f"  FAIL: {url}")

    def login(self, ptrt_url):
        """
        Create session using BBC ID. See https://www.bbc.co.uk/usingthebbc/account/

        :param ptrt_url: The snapback URL to redirect to after successful authentication
        :type ptrt_url: string
        :return: Whether authentication was successful
        :rtype: bool
        """
        def auth_check(res):
            return ptrt_url in ([h.url for h in res.history] + [res.url])

        # make the session request to get the correct cookies
        session_res = self.session.http.get(self.session_url,
                                            params=dict(ptrt=ptrt_url))

        if auth_check(session_res):
            log.debug("Already authenticated, skipping authentication")
            return True

        res = self.session.http.post(self.auth_url,
                                     params=urlparse(session_res.url).query,
                                     data=dict(
                                         jsEnabled=True,
                                         username=self.get_option("username"),
                                         password=self.get_option('password'),
                                         attempts=0),
                                     headers={"Referer": self.url})

        return auth_check(res)

    def _get_streams(self):
        if not self.get_option("username"):
            log.error("BBC iPlayer requires an account you must login using "
                      "--bbciplayer-username and --bbciplayer-password")
            return
        log.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")
        if not self.login(self.url):
            log.error(
                "Could not authenticate, check your username and password")
            return

        episode_id = self.match.group("episode_id")
        channel_name = self.match.group("channel_name")

        if episode_id:
            log.debug(f"Loading streams for episode: {episode_id}")
            vpid = self.find_vpid(self.url)
            if vpid:
                log.debug(f"Found VPID: {vpid}")
                yield from self.mediaselector(vpid)
            else:
                log.error(f"Could not find VPID for episode {episode_id}")
        elif channel_name:
            log.debug(f"Loading stream for live channel: {channel_name}")
            if self.get_option("hd"):
                tvip = self.find_tvip(self.url, master=True) + "_hd"
                if tvip:
                    log.debug(f"Trying HD stream {tvip}...")
                    try:
                        yield from self.mediaselector(tvip)
                    except PluginError:
                        log.error(
                            "Failed to get HD streams, falling back to SD")
                    else:
                        return
            tvip = self.find_tvip(self.url)
            if tvip:
                log.debug(f"Found TVIP: {tvip}")
                yield from self.mediaselector(tvip)
示例#31
0
class BTV(Plugin):
    arguments = PluginArguments(
        PluginArgument("username",
                       metavar="USERNAME",
                       requires=["password"],
                       help="""
        A BTV username required to access any stream.
        """),
        PluginArgument("password",
                       sensitive=True,
                       metavar="PASSWORD",
                       help="""
        A BTV account password to use with --btv-username.
        """))
    url_re = re.compile(r"https?://(?:www\.)?btv\.bg/live/?")

    api_url = "http://www.btv.bg/lbin/global/player_config.php"
    check_login_url = "http://www.btv.bg/lbin/userRegistration/check_user_login.php"
    login_url = "https://www.btv.bg/bin/registration2/login.php?action=login&settings=0"

    media_id_re = re.compile(r"media_id=(\d+)")
    src_re = re.compile(r"src: \"(http.*?)\"")
    api_schema = validate.Schema(
        validate.all({
            "status": "ok",
            "config": validate.text
        }, validate.get("config"),
                     validate.all(
                         validate.transform(src_re.search),
                         validate.any(None, validate.get(1), validate.url()))))

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

    def login(self, username, password):
        res = self.session.http.post(self.login_url,
                                     data={
                                         "username": username,
                                         "password": password
                                     })
        if "success_logged_in" in res.text:
            return True
        else:
            return False

    def get_hls_url(self, media_id):
        res = self.session.http.get(self.api_url,
                                    params=dict(media_id=media_id))
        try:
            return parse_json(res.text, schema=self.api_schema)
        except PluginError:
            return

    def _get_streams(self):
        if not self.options.get("username") or not self.options.get(
                "password"):
            self.logger.error(
                "BTV requires registration, set the username and password"
                " with --btv-username and --btv-password")
        elif self.login(self.options.get("username"),
                        self.options.get("password")):
            res = self.session.http.get(self.url)
            media_match = self.media_id_re.search(res.text)
            media_id = media_match and media_match.group(1)
            if media_id:
                self.logger.debug("Found media id: {0}", media_id)
                stream_url = self.get_hls_url(media_id)
                if stream_url:
                    return HLSStream.parse_variant_playlist(
                        self.session, stream_url)
        else:
            self.logger.error(
                "Login failed, a valid username and password is required")
示例#32
0
except ImportError:
    from html.parser import HTMLParser

def html_unescape(s):
    parser = HTMLParser()
    return parser.unescape(s)

_url_re = re.compile(r"https?://(?:www\.)?vidio\.com/(?P<type>live|watch)/(?P<id>\d+)-(?P<name>[^/?#&]+)")
_clipdata_re = re.compile(r"""data-json-clips\s*=\s*(['"])(.*?)\1""")

_schema = validate.Schema(
    validate.transform(_clipdata_re.search),
    validate.any(
        None, 
        validate.all(
            validate.get(2),
            validate.transform(html_unescape),
            validate.transform(parse_json),
            [{
                "sources": [{
                    "file": validate.url(
                        scheme="http",
                        path=validate.endswith(".m3u8")
                    )
                }]
            }]
        )
    )
)

class Vidio(Plugin):
示例#33
0
from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.stream import HLSStream

COOKIE_PARAMS = ("devicetype=desktop&"
                 "preferred-player-odm=hlslink&"
                 "preferred-player-live=hlslink")

_id_re = re.compile("/(?:program|direkte|serie/[^/]+)/([^/]+)")
_url_re = re.compile("https?://(tv|radio).nrk.no/")
_api_baseurl_re = re.compile('apiBaseUrl:\s*"(?P<baseurl>[^"]+)"')

_schema = validate.Schema(
    validate.transform(_api_baseurl_re.search),
    validate.any(
        None, validate.all(validate.get("baseurl"),
                           validate.url(scheme="http"))))

_mediaelement_schema = validate.Schema(
    {"mediaUrl": validate.url(scheme="http", path=validate.endswith(".m3u8"))})


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

    def _get_streams(self):
        # Get the stream type from the url (tv/radio).
        stream_type = _url_re.match(self.url).group(1).upper()
        cookie = {"NRK_PLAYER_SETTINGS_{0}".format(stream_type): COOKIE_PARAMS}
示例#34
0
from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
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):
示例#35
0
_url_re = re.compile(
    r"""
    http(s)?://(www\.)?zhanqi.tv
    /(?P<channel>[^/]+)
""", re.VERBOSE)

_room_schema = validate.Schema(
    {
        "data":
        validate.any(
            None, {
                "status": validate.all(validate.text, validate.transform(int)),
                "videoId": validate.text
            })
    }, validate.get("data"))


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

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

        res = http.get(API_URL.format(channel))
        room = http.json(res, schema=_room_schema)
        if not room:
            self.logger.info("Not a valid room url.")
示例#36
0
        ),
        validate.optional("hlsvp"): validate.text,
        validate.optional("live_playback"): validate.transform(bool),
        validate.optional("reason"): validate.text,
        "status": validate.text
    }
)
_search_schema = validate.Schema(
    {
        "items": [{
            "id": {
                "videoId": validate.text
            }
        }]
    },
    validate.get("items")
)

_channelid_re = re.compile(r'meta itemprop="channelId" content="([^"]+)"')
_livechannelid_re = re.compile(r'meta property="og:video:url" content="([^"]+)')
_url_re = re.compile(r"""
    http(s)?://(\w+\.)?youtube.com
    (?:
        (?:
            /(watch.+v=|embed/|v/)
            (?P<video_id>[0-9A-z_-]{11})
        )
        |
        (?:
            /(user|channel)/(?P<user>[^/?]+)
        )
示例#37
0
 def _schema_canonical(self, data):
     schema_canonical = validate.Schema(
         validate.parse_html(),
         validate.xml_xpath_string(".//link[@rel='canonical'][1]/@href"),
         validate.transform(self.matcher.match), validate.get("video_id"))
     return schema_canonical.validate(data)
示例#38
0
import re

from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
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)
                    )
示例#39
0
class NPO(Plugin):
    api_url = "http://ida.omroep.nl/app.php/{endpoint}"
    url_re = re.compile(r"https?://(\w+\.)?(npo\.nl|zapp\.nl|zappelin\.nl)/")
    media_id_re = re.compile(r'''<npo-player\smedia-id=["'](?P<media_id>[^"']+)["']''')
    prid_re = re.compile(r'''(?:data(-alt)?-)?prid\s*[=:]\s*(?P<q>["'])(\w+)(?P=q)''')
    react_re = re.compile(r'''data-react-props\s*=\s*(?P<q>["'])(?P<data>.*?)(?P=q)''')

    auth_schema = validate.Schema({"token": validate.text}, validate.get("token"))
    streams_schema = validate.Schema({
        "items": [
            [{
                "label": validate.text,
                "contentType": validate.text,
                "url": validate.url(),
                "format": validate.text
            }]
        ]
    }, validate.get("items"), validate.get(0))
    stream_info_schema = validate.Schema(validate.any(
        validate.url(),
        validate.all({"errorcode": 0, "url": validate.url()}, validate.get("url"))
    ))
    arguments = PluginArguments(
        PluginArgument(
            "subtitles",
            action="store_true",
            help="""
        Include subtitles for the deaf or hard of hearing, if available.
        """
        )
    )

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

    def __init__(self, url):
        super(NPO, self).__init__(url)
        self._token = None
        self.session.http.headers.update({"User-Agent": useragents.CHROME})

    def api_call(self, endpoint, schema=None, params=None):
        url = self.api_url.format(endpoint=endpoint)
        res = self.session.http.get(url, params=params)
        return self.session.http.json(res, schema=schema)

    @property
    def token(self):
        if not self._token:
            self._token = self.api_call("auth", schema=self.auth_schema)
        return self._token

    def _get_prid(self, subtitles=False):
        res = self.session.http.get(self.url)
        bprid = None

        # Locate the asset id for the content on the page
        for alt, _, prid in self.prid_re.findall(res.text):
            if alt and subtitles:
                bprid = prid
            elif bprid is None:
                bprid = prid

        if bprid is None:
            m = self.react_re.search(res.text)
            if m:
                data = parse_json(m.group("data").replace("&quot;", '"'))
                bprid = data.get("mid")

        if bprid is None:
            m = self.media_id_re.search(res.text)
            if m:
                bprid = m.group('media_id')

        return bprid

    def _get_streams(self):
        asset_id = self._get_prid(self.get_option("subtitles"))

        if asset_id:
            self.logger.debug("Found asset id: {0}", asset_id)
            streams = self.api_call(asset_id, params=dict(adaptive="yes", token=self.token), schema=self.streams_schema)

            for stream in streams:
                if stream["format"] in ("adaptive", "hls", "mp4"):
                    if stream["contentType"] == "url":
                        stream_url = stream["url"]
                    else:
                        # using type=json removes the javascript function wrapper
                        info_url = stream["url"].replace("type=jsonp", "type=json")

                        # find the actual stream URL
                        stream_url = self.session.http.json(self.session.http.get(info_url), schema=self.stream_info_schema)

                    if stream["format"] in ("adaptive", "hls"):
                        for s in HLSStream.parse_variant_playlist(self.session, stream_url).items():
                            yield s
                    elif stream["format"] in ("mp3", "mp4"):
                        yield "vod", HTTPStream(self.session, stream_url)
示例#40
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")
示例#41
0
文件: okru.py 项目: yuviDX/streamlink
class OKru(Plugin):

    _data_re = re.compile(
        r'''data-options=(?P<q>["'])(?P<data>{[^"']+})(?P=q)''')
    _url_re = re.compile(r'''https?://(?:www\.)?ok\.ru/''')

    _metadata_schema = validate.Schema(
        validate.transform(parse_json),
        validate.any(
            {
                'videos':
                validate.any([], [{
                    'name': validate.text,
                    'url': validate.text,
                }]),
                validate.optional('hlsManifestUrl'):
                validate.text,
                validate.optional('hlsMasterPlaylistUrl'):
                validate.text,
                validate.optional('liveDashManifestUrl'):
                validate.text,
                validate.optional('rtmpUrl'):
                validate.text,
            }, None))
    _data_schema = validate.Schema(
        validate.all(
            validate.transform(_data_re.search), validate.get('data'),
            validate.transform(html_unescape), validate.transform(parse_json),
            validate.get('flashvars'),
            validate.any({'metadata': _metadata_schema},
                         {'metadataUrl': validate.transform(unquote)}, None)))

    QUALITY_WEIGHTS = {
        'full': 1080,
        '1080': 1080,
        'hd': 720,
        '720': 720,
        'sd': 480,
        '480': 480,
        '360': 360,
        'low': 360,
        'lowest': 240,
        'mobile': 144,
    }

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

    @classmethod
    def stream_weight(cls, key):
        weight = cls.QUALITY_WEIGHTS.get(key)
        if weight:
            return weight, 'okru'

        return Plugin.stream_weight(key)

    def _get_streams(self):
        self.session.http.headers.update({
            'User-Agent': useragents.FIREFOX,
            'Referer': self.url,
        })

        try:
            data = self.session.http.get(self.url, schema=self._data_schema)
        except PluginError:
            log.error('unable to validate _data_schema for {0}'.format(
                self.url))
            return

        metadata = data.get('metadata')
        metadata_url = data.get('metadataUrl')
        if metadata_url and not metadata:
            metadata = self.session.http.post(metadata_url,
                                              schema=self._metadata_schema)

        if metadata:
            log.trace('{0!r}'.format(metadata))
            for hls_url in [
                    metadata.get('hlsManifestUrl'),
                    metadata.get('hlsMasterPlaylistUrl')
            ]:
                if hls_url is not None:
                    yield from HLSStream.parse_variant_playlist(
                        self.session, hls_url).items()

            if metadata.get('videos'):
                for http_stream in metadata['videos']:
                    http_name = http_stream['name']
                    http_url = http_stream['url']
                    try:
                        http_name = '{0}p'.format(
                            self.QUALITY_WEIGHTS[http_name])
                    except KeyError:
                        pass
                    yield http_name, HTTPStream(self.session, http_url)

            if metadata.get('rtmpUrl'):
                yield 'live', RTMPStream(self.session,
                                         params={'rtmp': metadata['rtmpUrl']})
示例#42
0
_channels_schema = validate.Schema(
    {
        "Data": [{
            "Slug": validate.text,
            "StreamingServers": validate.all(
                [{
                    "LinkType": validate.text,
                    "Qualities": [
                        validate.all(
                            {
                                "Streams": validate.all(
                                    [
                                        validate.all(
                                            {"Stream": validate.text},
                                            validate.get("Stream")
                                        )
                                    ],
                                    validate.get(0)
                                )
                            },
                            validate.get("Streams")
                        )
                    ],
                    "Server": validate.text
                }],
                validate.filter(lambda s: s["LinkType"] in STREAMING_TYPES)
            )
        }]
    },
    validate.get("Data", {})
示例#43
0
class UHSClient(object):
    """
    API Client, reverse engineered by observing the interactions
    between the web browser and the ustream servers.
    """
    API_URL = "http://r{0}-1-{1}-{2}-{3}.ums.ustream.tv"
    APP_ID, APP_VERSION = 2, 1
    api_schama = validate.Schema([{"args": [object], "cmd": validate.text}])
    connect_schama = validate.Schema([{
        "args":
        validate.all([{
            "host": validate.text,
            "connectionId": validate.text
        }], validate.length(1)),
        "cmd":
        "tracking"
    }], validate.length(1), validate.get(0), validate.get("args"),
                                     validate.get(0))
    module_info_schema = validate.Schema(
        [validate.get("stream")], validate.filter(lambda r: r is not None))

    def __init__(self, session, media_id, application, **options):
        self.session = session
        self.session.http.headers.update({"User-Agent": useragents.IPHONE_6})
        self.logger = logging.getLogger("streamlink.plugin.ustream.apiclient")
        self.media_id = media_id
        self.application = application
        self.referrer = options.pop("referrer", None)
        self._host = None
        self.rsid = self.generate_rsid()
        self.rpin = self.generate_rpin()
        self._connection_id = None
        self._app_id = options.pop("app_id", self.APP_ID)
        self._app_version = options.pop("app_version", self.APP_VERSION)
        self._cluster = options.pop("cluster", "live")
        self._password = options.pop("password")

    def connect(self, **options):
        result = self.send_command(type="viewer",
                                   appId=self._app_id,
                                   appVersion=self._app_version,
                                   rsid=self.rsid,
                                   rpin=self.rpin,
                                   referrer=self.referrer,
                                   media=str(self.media_id),
                                   application=self.application,
                                   schema=self.connect_schama,
                                   password=self._password)

        self._host = "http://{0}".format(result["host"])
        self._connection_id = result["connectionId"]
        self.logger.debug("Got new host={0}, and connectionId={1}", self._host,
                          self._connection_id)
        return True

    def poll(self, schema=None, retries=5, timeout=5.0):
        stime = time.time()
        try:
            r = self.send_command(connectionId=self._connection_id,
                                  schema=schema,
                                  retries=retries,
                                  timeout=timeout)
        except PluginError as err:
            self.logger.debug("poll took {0:.2f}s: {1}",
                              time.time() - stime, err)
        else:
            self.logger.debug("poll took {0:.2f}s", time.time() - stime)
            return r

    def generate_rsid(self):
        return "{0:x}:{1:x}".format(randint(0, 1e10), randint(0, 1e10))

    def generate_rpin(self):
        return "_rpin.{0}".format(randint(0, 1e15))

    def send_command(self, schema=None, retries=5, timeout=5.0, **args):
        res = self.session.http.get(self.host,
                                    params=args,
                                    headers={
                                        "Referer": self.referrer,
                                        "User-Agent": useragents.IPHONE_6
                                    },
                                    retries=retries,
                                    timeout=timeout,
                                    retry_max_backoff=0.5)
        return self.session.http.json(res, schema=schema or self.api_schama)

    @property
    def host(self):
        host = self._host or self.API_URL.format(randint(
            0, 0xffffff), self.media_id, self.application,
                                                 "lp-" + self._cluster)
        return urljoin(host, "/1/ustream")
示例#44
0
import re

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

_url_re = re.compile("http(s)?://(\w+.)?chaturbate.com/[^/?&]+")
_playlist_url_re = re.compile("html \+= \"src='(?P<url>[^']+)'\";")
_schema = validate.Schema(
    validate.transform(_playlist_url_re.search),
    validate.any(
        None,
        validate.all(
            validate.get("url"),
            validate.url(
                scheme="http",
                path=validate.endswith(".m3u8")
            )
        )
    )
)


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

    def _get_streams(self):
        playlist_url = http.get(self.url, schema=_schema)
        if not playlist_url:
示例#45
0
class Rtve(Plugin):
    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 = "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", is_global=True)
    )

    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] = f"{item['height']}p"
        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 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
示例#46
0
from streamlink.stream import HLSStream
from streamlink.stream.ffmpegmux import MuxedStream, FFMPEGMuxer
from streamlink.stream.file import FileStream

HDCORE_VERSION = "3.2.0"

_url_re = re.compile(r"https?://www.daisuki.net/[^/]+/[^/]+/anime/watch\..+")
_flashvars_re = re.compile(r"var\s+flashvars\s*=\s*\{([^}]*?)};", re.DOTALL)
_flashvar_re = re.compile(r"""(['"])(.*?)\1\s*:\s*(['"])(.*?)\3""")
_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
            }
        ),
示例#47
0
class Zbiornik(Plugin):

    SWF_URL = 'https://zbiornik.tv/wowza.swf'

    _url_re = re.compile(
        r'^https?://(?:www\.)?zbiornik\.tv/(?P<channel>[^/]+)/?$')

    _streams_re = re.compile(r'''var\sstreams\s*=\s*(?P<data>\[.+\]);''')
    _user_re = re.compile(r'''var\suser\s*=\s*(?P<data>\{[^;]+\});''')

    _user_schema = validate.Schema({'wowzaIam': {
        'phash': validate.text,
    }}, validate.get('wowzaIam'))

    _streams_schema = validate.Schema([{
        'nick': validate.text,
        'broadcasturl': validate.text,
        'server': validate.text,
        'id': validate.text,
    }])

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

    def _get_streams(self):
        log.debug('Version 2018-07-12')
        log.info('This is a custom plugin. ')
        channel = self._url_re.match(self.url).group('channel')
        log.info('Channel: {0}'.format(channel))
        self.session.http.headers.update({'User-Agent': useragents.FIREFOX})
        self.session.http.parse_cookies('adult=1')
        res = self.session.http.get(self.url)

        m = self._streams_re.search(res.text)
        if not m:
            log.debug('No streams data found.')
            return

        m2 = self._user_re.search(res.text)
        if not m:
            log.debug('No user data found.')
            return

        _streams = parse_json(m.group('data'), schema=self._streams_schema)
        _user = parse_json(m2.group('data'), schema=self._user_schema)

        _x = []
        for _s in _streams:
            if _s.get('nick') == channel:
                _x = _s
                break

        if not _x:
            log.error('Channel is not available.')
            return

        app = 'videochat/?{0}'.format(_user['phash'])
        rtmp = 'rtmp://{0}/videochat/'.format(_x['server'])

        params = {
            'rtmp': rtmp,
            'pageUrl': self.url,
            'app': app,
            'playpath': _x['broadcasturl'],
            'swfVfy': self.SWF_URL,
            'live': True
        }
        return {'live': RTMPStream(self.session, params=params)}
示例#48
0
            "layerList": validate.all(
                [{
                    "name": validate.text,
                    validate.optional("param"): dict
                }],
                validate.filter(lambda l: l["name"] in ("video", "reporting"))
            )
        }]
    }]
}])
_media_schema = validate.Schema(
    validate.any(
        _media_inner_schema,
        validate.all(
            {"sequence": _media_inner_schema},
            validate.get("sequence")
        )
    )
)
_vod_playlist_schema = validate.Schema({
    "duration": float,
    "fragments": [[int, float]],
    "template": validate.text
})
_vod_manifest_schema = validate.Schema({
    "alternates": [{
        "height": int,
        "template": validate.text,
        validate.optional("failover"): [validate.text]
    }]
})
示例#49
0
class TVPlayer(Plugin):
    context_url = "http://tvplayer.com/watch/context"
    api_url = "http://api.tvplayer.com/api/v2/stream/live"
    login_url = "https://tvplayer.com/account/login"
    update_url = "https://tvplayer.com/account/update-detail"
    dummy_postcode = "SE1 9LT"  # location of ITV HQ in London

    url_re = re.compile(
        r"https?://(?:www.)?tvplayer.com/(:?watch/?|watch/(.+)?)")
    stream_attrs_re = re.compile(
        r'data-(resource|token|channel-id)\s*=\s*"(.*?)"', re.S)
    data_id_re = re.compile(r'data-id\s*=\s*"(.*?)"', re.S)
    login_token_re = re.compile(r'input.*?name="token".*?value="(\w+)"')
    stream_schema = validate.Schema(
        {
            "tvplayer":
            validate.Schema({
                "status":
                u'200 OK',
                "response":
                validate.Schema({
                    "stream":
                    validate.url(scheme=validate.any("http", "https")),
                    validate.optional("drmToken"):
                    validate.any(None, validate.text)
                })
            })
        }, validate.get("tvplayer"), validate.get("response"))
    context_schema = validate.Schema({
        "validate": validate.text,
        validate.optional("token"): validate.text,
        "platform": {
            "key": validate.text
        }
    })
    arguments = PluginArguments(
        PluginArgument(
            "email",
            help="The email address used to register with tvplayer.com.",
            metavar="EMAIL",
            requires=["password"]),
        PluginArgument("password",
                       sensitive=True,
                       help="The password for your tvplayer.com account.",
                       metavar="PASSWORD"))

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

    def __init__(self, url):
        super(TVPlayer, self).__init__(url)
        self.session.http.headers.update({"User-Agent": useragents.CHROME})

    def authenticate(self, username, password):
        res = self.session.http.get(self.login_url)
        match = self.login_token_re.search(res.text)
        token = match and match.group(1)
        res2 = self.session.http.post(self.login_url,
                                      data=dict(email=username,
                                                password=password,
                                                token=token),
                                      allow_redirects=False)
        # there is a 302 redirect on a successful login
        return res2.status_code == 302

    def _get_stream_data(self, resource, channel_id, token, service=1):
        # Get the context info (validation token and platform)
        self.logger.debug(
            "Getting stream information for resource={0}".format(resource))
        context_res = self.session.http.get(self.context_url,
                                            params={
                                                "resource": resource,
                                                "gen": token
                                            })
        context_data = self.session.http.json(context_res,
                                              schema=self.context_schema)
        self.logger.debug("Context data: {0}", str(context_data))

        # get the stream urls
        res = self.session.http.post(
            self.api_url,
            data=dict(service=service,
                      id=channel_id,
                      validate=context_data["validate"],
                      token=context_data.get("token"),
                      platform=context_data["platform"]["key"]),
            raise_for_status=False)

        return self.session.http.json(res, schema=self.stream_schema)

    def _get_stream_attrs(self, page):
        stream_attrs = dict(
            (k.replace("-", "_"), v.strip('"'))
            for k, v in self.stream_attrs_re.findall(page.text))

        if not stream_attrs.get("channel_id"):
            m = self.data_id_re.search(page.text)
            stream_attrs["channel_id"] = m and m.group(1)

        self.logger.debug("Got stream attributes: {0}", str(stream_attrs))
        valid = True
        for a in ("channel_id", "resource", "token"):
            if a not in stream_attrs:
                self.logger.debug("Missing '{0}' from stream attributes", a)
                valid = False

        return stream_attrs if valid else {}

    def _get_streams(self):
        if self.get_option("email") and self.get_option("password"):
            self.logger.debug("Logging in as {0}".format(
                self.get_option("email")))
            if not self.authenticate(self.get_option("email"),
                                     self.get_option("password")):
                self.logger.warning("Failed to login as {0}".format(
                    self.get_option("email")))

        # find the list of channels from the html in the page
        self.url = self.url.replace("https", "http")  # https redirects to http
        res = self.session.http.get(self.url)

        if "enter your postcode" in res.text:
            self.logger.info(
                "Setting your postcode to: {0}. "
                "This can be changed in the settings on tvplayer.com",
                self.dummy_postcode)
            res = self.session.http.post(
                self.update_url,
                data=dict(postcode=self.dummy_postcode),
                params=dict(return_url=self.url))

        stream_attrs = self._get_stream_attrs(res)
        if stream_attrs:
            stream_data = self._get_stream_data(**stream_attrs)

            if stream_data:
                if stream_data.get("drmToken"):
                    self.logger.error(
                        "This stream is protected by DRM can cannot be played")
                    return
                else:
                    return HLSStream.parse_variant_playlist(
                        self.session, stream_data["stream"])
        else:
            if "need to login" in res.text:
                self.logger.error(
                    "You need to login using --tvplayer-email/--tvplayer-password to view this stream"
                )
示例#50
0
        }, None)
    },
    validate.optional("playerUri"): validate.text,
    validate.optional("viewerPlusSwfUrl"): validate.url(scheme="http"),
    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(
示例#51
0
    }]),
    validate.optional("hlsvp"):
    validate.text,
    validate.optional("live_playback"):
    validate.transform(bool),
    validate.optional("reason"):
    validate.text,
    "status":
    validate.text
})
_search_schema = validate.Schema(
    {"items": [{
        "id": {
            "videoId": validate.text
        }
    }]}, validate.get("items"))

_channelid_re = re.compile(r'meta itemprop="channelId" content="([^"]+)"')
_livechannelid_re = re.compile(
    r'meta property="og:video:url" content="([^"]+)')
_url_re = re.compile(
    r"""
    http(s)?://(\w+\.)?youtube.com
    (?:
        (?:
            /(watch.+v=|embed/|v/)
            (?P<video_id>[0-9A-z_-]{11})
        )
        |
        (?:
            /(user|channel)/(?P<user>[^/?]+)
示例#52
0
_url_re = re.compile("""
    http(s)?://(www\.)?douyu.com
    /(?P<channel>[^/]+)
""", re.VERBOSE)

_room_id_re = re.compile(r'"room_id"\s*:\s*(\d+),')
_room_id_alt_re = re.compile(r'data-room_id="(\d+)"')

_room_id_schema = validate.Schema(
    validate.all(
        validate.transform(_room_id_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1),
                validate.transform(int)
            )
        )
    )
)

_room_id_alt_schema = validate.Schema(
    validate.all(
        validate.transform(_room_id_alt_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1),
                validate.transform(int)
            )
示例#53
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: [{
示例#54
0
import re

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

LOGIN_PAGE_URL = "http://www.livestation.com/en/users/new"
LOGIN_POST_URL = "http://www.livestation.com/en/sessions.json"

_csrf_token_re = re.compile("<meta content=\"([^\"]+)\" name=\"csrf-token\"")
_hls_playlist_re = re.compile("<meta content=\"([^\"]+.m3u8)\" property=\"og:video\" />")
_url_re = re.compile("http(s)?://(\w+\.)?livestation.com")

_csrf_token_schema = validate.Schema(
    validate.transform(_csrf_token_re.search),
    validate.any(None, validate.get(1))
)
_hls_playlist_schema = validate.Schema(
    validate.transform(_hls_playlist_re.search),
    validate.any(
        None,
        validate.all(
            validate.get(1),
            validate.url(scheme="http", path=validate.endswith(".m3u8"))
        )
    )
)
_login_schema = validate.Schema({
    "email": validate.text,
    validate.optional("errors"): validate.all(
        {
示例#55
0
class Filmon(Plugin):
    _channel_id_re = re.compile(
        r"""channel_id\s*=\s*(?P<quote>['"]?)(?P<value>\d+)(?P=quote)""")
    _channel_id_schema = validate.Schema(
        validate.transform(_channel_id_re.search),
        validate.any(None, validate.get("value")))

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

    TIME_CHANNEL = 60 * 60 * 24 * 365

    def __init__(self, url):
        super().__init__(url)
        parsed = urlparse(self.url)
        if parsed.path.startswith("/channel/"):
            self.url = urlunparse(
                parsed._replace(path=parsed.path.replace("/channel/", "/tv/")))
        self.api = FilmOnAPI(self.session)

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

        return Plugin.stream_weight(key)

    def _get_streams(self):
        channel = self.match.group("channel")
        vod_id = self.match.group("vod_id")
        is_group = self.match.group("is_group")

        if vod_id:
            data = self.api.vod(vod_id)
            for _, stream in data["streams"].items():
                streams = HLSStream.parse_variant_playlist(
                    self.session, stream["url"])
                if not streams:
                    yield stream["quality"], HLSStream(self.session,
                                                       stream["url"])
                else:
                    yield from streams.items()
        else:
            if channel and not channel.isdigit():
                _id = self.cache.get(channel)
                if _id is None:
                    _id = self.session.http.get(self.url,
                                                schema=self._channel_id_schema)
                    log.debug(f"Found channel ID: {_id}")
                    # do not cache a group url
                    if _id and not is_group:
                        self.cache.set(channel, _id, expires=self.TIME_CHANNEL)
                else:
                    log.debug(f"Found cached channel ID: {_id}")
            else:
                _id = channel

            if _id is None:
                raise PluginError(
                    "Unable to find channel ID: {0}".format(channel))

            try:
                data = self.api.channel(_id)
                for stream in data["streams"]:
                    yield stream["quality"], FilmOnHLS(
                        self.session, channel=_id, quality=stream["quality"])
            except Exception:
                if channel and not channel.isdigit():
                    self.cache.set(channel, None, expires=0)
                    log.debug(f"Reset cached channel: {channel}")

                raise
示例#56
0
    )?
""", re.VERBOSE)
_channel_id_re = re.compile("\"channelId\":(\d+)")

HLS_PLAYLIST_URL = (
    "http://iphone-streaming.ustream.tv"
    "/uhls/{0}/streams/live/iphone/playlist.m3u8"
)
RECORDED_URL = "http://tcdn.ustream.tv/video/{0}"
RTMP_URL = "rtmp://r{0}-1-{1}-channel-live.ums.ustream.tv:1935/ustream"
SWF_URL = "http://static-cdn1.ustream.tv/swf/live/viewer.rsl:505.swf"

_module_info_schema = validate.Schema(
    list,
    validate.length(1),
    validate.get(0),
    dict
)
_amf3_array = validate.Schema(
    validate.any(
        validate.all(
            {int: object},
            validate.transform(lambda a: list(a.values())),
        ),
        list
    )
)
_recorded_schema = validate.Schema({
    validate.optional("stream"): validate.all(
        _amf3_array,
        [{
示例#57
0
class RTBF(Plugin):
    GEO_URL = 'https://www.rtbf.be/api/geoloc'
    TOKEN_URL = 'https://token.rtbf.be/'
    RADIO_STREAM_URL = 'http://www.rtbfradioplayer.be/radio/liveradio/rtbf/radios/{}/config.json'

    _url_re = re.compile(
        r'https?://(?:www\.)?(?:rtbf\.be/auvio/.*\?l?id=(?P<video_id>[0-9]+)#?|rtbfradioplayer\.be/radio/liveradio/.+)'
    )
    _stream_size_re = re.compile(r'https?://.+-(?P<size>\d+p?)\..+?$')

    _video_player_re = re.compile(
        r'<iframe\s+class="embed-responsive-item\s+js-embed-iframe".*src="(?P<player_url>.+?)".*?</iframe>',
        re.DOTALL)
    _video_stream_data_re = re.compile(
        r'<div\s+id="js-embed-player"\s+class="js-embed-player\s+embed-player"\s+data-media="(.+?)"'
    )
    _radio_id_re = re.compile(r'var currentStationKey = "(?P<radio_id>.+?)"')

    _geo_schema = validate.Schema({
        'country': validate.text,
        'zone': validate.text
    })

    _video_stream_schema = validate.Schema(
        validate.transform(_video_stream_data_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1), validate.transform(html_unescape),
                validate.transform(parse_json), {
                    'geoLocRestriction':
                    validate.text,
                    validate.optional('isLive'):
                    bool,
                    validate.optional('startDate'):
                    validate.text,
                    validate.optional('endDate'):
                    validate.text,
                    'sources':
                    validate.any([],
                                 validate.Schema({
                                     validate.text:
                                     validate.any(None, '', validate.url())
                                 })),
                    validate.optional('urlHls'):
                    validate.any(None, '', validate.url()),
                    validate.optional('urlDash'):
                    validate.any(None, '', validate.url()),
                    validate.optional('streamUrlHls'):
                    validate.any(None, '', validate.url()),
                    validate.optional('streamUrlDash'):
                    validate.any(None, '', validate.url()),
                    validate.optional('drm'):
                    bool,
                })))

    _radio_stream_schema = validate.Schema({
        'audioUrls':
        validate.all([{
            'url': validate.url(),
            'mimeType': validate.text
        }])
    })

    def check_geolocation(self, geoloc_flag):
        if geoloc_flag == 'open':
            return True

        res = self.session.http.get(self.GEO_URL)
        data = self.session.http.json(res, schema=self._geo_schema)
        return data['country'] == geoloc_flag or data['zone'] == geoloc_flag

    def tokenize_stream(self, url):
        res = self.session.http.post(self.TOKEN_URL,
                                     data={'streams[url]': url})
        data = self.session.http.json(res)
        return data['streams']['url']

    @staticmethod
    def iso8601_to_epoch(date):
        # Convert an ISO 8601-formatted string date to datetime
        return datetime.datetime.strptime(date[:-6], '%Y-%m-%dT%H:%M:%S') + \
            datetime.timedelta(hours=int(date[-6:-3]), minutes=int(date[-2:]))

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

    def _get_radio_streams(self):
        res = self.session.http.get(self.url)
        match = self._radio_id_re.search(res.text)
        if match is None:
            return
        radio_id = match.group('radio_id')
        res = self.session.http.get(self.RADIO_STREAM_URL.format(radio_id))
        streams = self.session.http.json(res, schema=self._radio_stream_schema)

        for stream in streams['audioUrls']:
            match = self._stream_size_re.match(stream['url'])
            if match is not None:
                quality = '{}k'.format(match.group('size'))
            else:
                quality = stream['mimetype']
            yield quality, HTTPStream(self.session, stream['url'])

    def _get_video_streams(self):
        res = self.session.http.get(self.url)
        match = self._video_player_re.search(res.text)
        if match is None:
            return
        player_url = match.group('player_url')
        stream_data = self.session.http.get(player_url,
                                            schema=self._video_stream_schema)
        if stream_data is None:
            return

        # Check geolocation to prevent further errors when stream is parsed
        if not self.check_geolocation(stream_data['geoLocRestriction']):
            log.error('Stream is geo-restricted')
            return

        # Check whether streams are DRM-protected
        if stream_data.get('drm', False):
            log.error('Stream is DRM-protected')
            return

        now = datetime.datetime.now()
        try:
            if isinstance(stream_data['sources'], dict):
                urls = []
                for profile, url in stream_data['sources'].items():
                    if not url or url in urls:
                        continue
                    match = self._stream_size_re.match(url)
                    if match is not None:
                        quality = match.group('size')
                    else:
                        quality = profile
                    yield quality, HTTPStream(self.session, url)
                    urls.append(url)

            hls_url = stream_data.get('urlHls') or stream_data.get(
                'streamUrlHls')
            if hls_url:
                if stream_data.get('isLive', False):
                    # Live streams require a token
                    hls_url = self.tokenize_stream(hls_url)
                for stream in HLSStream.parse_variant_playlist(
                        self.session, hls_url).items():
                    yield stream

            dash_url = stream_data.get('urlDash') or stream_data.get(
                'streamUrlDash')
            if dash_url:
                if stream_data.get('isLive', False):
                    # Live streams require a token
                    dash_url = self.tokenize_stream(dash_url)
                for stream in DASHStream.parse_manifest(
                        self.session, dash_url).items():
                    yield stream

        except IOError as err:
            if '403 Client Error' in str(err):
                # Check whether video is expired
                if 'startDate' in stream_data:
                    if now < self.iso8601_to_epoch(stream_data['startDate']):
                        log.error('Stream is not yet available')
                elif 'endDate' in stream_data:
                    if now > self.iso8601_to_epoch(stream_data['endDate']):
                        log.error('Stream has expired')

    def _get_streams(self):
        match = self.can_handle_url(self.url)
        if match.group('video_id'):
            return self._get_video_streams()
        return self._get_radio_streams()
示例#58
0
LAPI_URL = "http://g2.live.360.cn/liveplay?stype=flv&channel={}&bid=huajiao&sn={}&sid={}&_rate=xd&ts={}&r={}&_ostype=flash&_delay=0&_sign=null&_ver=13"

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

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

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


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

    def _get_streams(self):
        match = _url_re.match(self.url)
        channel = match.group("channel")
示例#59
0
                    {
                        "type": "dash",
                        "file": validate.url(scheme="http")
                    }, {
                        "type": "hls",
                        "file": validate.url(scheme="http")
                    }, {
                        "type": "rtmp",
                        "file": validate.text,
                        "streamer": validate.url(scheme="rtmp")
                    }
                )
            ]
        }
    ],
    validate.get(0),
    validate.get("sources")
)


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

    def _get_streams(self):
        res = http.get(self.url)
        match = _playlist_url_re.search(res.text)
        if match is None:
            return