Example #1
0
    def test_basic(self):
        assert validate(1, 1) == 1

        assert validate(int, 1) == 1

        assert validate(transform(int), "1") == 1

        assert validate(text, "abc") == "abc"
        assert validate(text, u"日本語") == u"日本語"
        assert validate(transform(text), 1) == "1"

        assert validate(list, ["a", 1]) == ["a", 1]
        assert validate(dict, {"a": 1}) == {"a": 1}

        assert validate(lambda n: 0 < n < 5, 3) == 3
Example #2
0
    def test_all(self):
        assert validate(all(int, lambda n: 0 < n < 5), 3) == 3

        assert validate(all(transform(int), lambda n: 0 < n < 5), 3.33) == 3
Example #3
0
CHANNEL_RESULT_OK = 1

QUALITYS = ["original", "hd", "sd"]

QUALITY_WEIGHTS = {
    "original": 1080,
    "hd": 720,
    "sd": 480
}

_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")
        ),
Example #4
0
    "73": "token"
}
BLOCKED_MSG_FORMAT = (
    "You have crossed the free viewing limit. You have been blocked for "
    "{0} minutes. Try again in {1} minutes"
)
BLOCK_TYPE_VIEWING_LIMIT = 1
BLOCK_TYPE_NO_SLOTS = 11

_url_re = re.compile(r"http(s)?://(\w+\.)?weeb.tv/(channel|online)/(?P<channel>[^/&?]+)")
_schema = validate.Schema(
    dict,
    validate.map(lambda k, v: (PARAMS_KEY_MAP.get(k, k), v)),
    validate.any(
        {
            "status": validate.transform(int),
            "rtmp": validate.url(scheme="rtmp"),
            "playpath": validate.text,
            "multibitrate": validate.all(
                validate.transform(int),
                validate.transform(bool)
            ),
            "block_type": validate.transform(int),
            validate.optional("token"): validate.text,
            validate.optional("block_time"): validate.text,
            validate.optional("reconnect_time"): validate.text,
        },
        {
            "status": validate.transform(int),
        },
    )
import re

from streamlink.compat import urlparse
from streamlink.plugin import Plugin
from streamlink.plugin.api import StreamMapper, http, validate
from streamlink.stream import HLSStream, RTMPStream

CHANNEL_URL = "http://www.mobileonline.tv/channel.php"

_url_re = re.compile("http(s)?://(\w+\.)?(ilive.to|streamlive.to)/.*/(?P<channel>\d+)")
_link_re = re.compile("<a href=(\S+) target=\"_blank\"")
_schema = validate.Schema(
    validate.transform(_link_re.findall),
)


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

    def _create_hls_streams(self, url):
        try:
            streams = HLSStream.parse_variant_playlist(self.session, url)
            return streams.items()
        except IOError as err:
            self.logger.warning("Failed to extract HLS streams: {0}", err)

    def _create_rtmp_stream(self, url):
        parsed = urlparse(url)
        if parsed.query:
Example #6
0
            validate.xml_element(attrib={"content": validate.text}),
            validate.get("content")),
        "videos":
        validate.all(
            validate.xml_findall(
                "{http://www.w3.org/2001/SMIL20/Language}body/"
                "{http://www.w3.org/2001/SMIL20/Language}switch/"
                "{http://www.w3.org/2001/SMIL20/Language}video"),
            [
                validate.all(
                    validate.xml_element(
                        attrib={
                            "src":
                            validate.text,
                            "system-bitrate":
                            validate.all(validate.text, validate.transform(
                                int))
                        }),
                    validate.transform(lambda e: (e.attrib["src"], e.attrib[
                        "system-bitrate"])))
            ],
        )
    }))


class Livestream(Plugin):
    @classmethod
    def default_stream_types(cls, streams):
        return ["akamaihd", "hls"]

    @classmethod
    def can_handle_url(self, url):
Example #7
0
                            scheme="http",
                            path=validate.endswith(".m3u8")
                        ),
                        validate.optional("video_encode_id"): validate.text
                    }]
                )
            }
        )
    },
    validate.get("stream_data")
)
_login_schema = validate.Schema({
    "auth": validate.text,
    "expires": validate.all(
        validate.text,
        validate.transform(parse_timestamp)
    ),
    "user": {
        "username": validate.any(validate.text, None),
        "email": validate.text
    }
})
_session_schema = validate.Schema(
    {
        "session_id": validate.text
    },
    validate.get("session_id")
)


class CrunchyrollAPIError(Exception):
Example #8
0
from streamlink.plugin import Plugin, PluginError, PluginArguments, PluginArgument
from streamlink.plugin.api import validate, useragents
from streamlink.plugin.api.utils import itertags, parse_query
from streamlink.stream import HTTPStream, HLSStream
from streamlink.stream.ffmpegmux import MuxedStream
from streamlink.utils import parse_json, search_dict
from streamlink.utils.encoding import maybe_decode

log = logging.getLogger(__name__)


_config_schema = validate.Schema(
    {
        validate.optional("player_response"): validate.all(
            validate.text,
            validate.transform(parse_json),
            {
                validate.optional("streamingData"): {
                    validate.optional("hlsManifestUrl"): validate.text,
                    validate.optional("formats"): [{
                        "itag": int,
                        validate.optional("url"): validate.text,
                        validate.optional("cipher"): validate.text,
                        "qualityLabel": validate.text
                    }],
                    validate.optional("adaptiveFormats"): [{
                        "itag": int,
                        "mimeType": validate.all(
                            validate.text,
                            validate.transform(
                                lambda t:
Example #9
0
_url_re = re.compile("""
    http(s)?://(\w+\.)?aliez.tv
    (?:
        /live/[^/]+
    )?
    (?:
        /video/\d+/[^/]+
    )?
""", re.VERBOSE)
_file_re = re.compile("\"?file\"?:\s+['\"]([^'\"]+)['\"]")
_swf_url_re = re.compile("swfobject.embedSWF\(\"([^\"]+)\",")

_schema = validate.Schema(
    validate.union({
        "urls": validate.all(
            validate.transform(_file_re.findall),
            validate.map(unquote),
            [validate.url()]
        ),
        "swf": validate.all(
            validate.transform(_swf_url_re.search),
            validate.any(
                None,
                validate.all(
                    validate.get(1),
                    validate.url(
                        scheme="http",
                        path=validate.endswith("swf")
                    )
                )
            )
Example #10
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 = {
Example #11
0
from streamlink.stream import HLSStream

try:
    from HTMLParser import HTMLParser
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")
                    )
                }]
            }]
        )
Example #12
0
import re

from itertools import chain

from streamlink.compat import urlparse
from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
from streamlink.stream import HLSStream, HTTPStream, RTMPStream

SWF_URL = "http://www.arte.tv/player/v2/jwplayer6/mediaplayer.6.6.swf"

_url_re = re.compile("http(s)?://(\w+\.)?arte.tv/")
_json_re = re.compile("arte_vp_(?:live-)?url=(['\"])(.+?)\\1")

_schema = validate.Schema(
    validate.transform(_json_re.search),
    validate.any(
        None,
        validate.all(
            validate.get(2),
            validate.url(scheme="http")
        )
    )
)
_video_schema = validate.Schema({
    "videoJsonPlayer": {
        "VSR": validate.any(
            [],
            {
                validate.text: {
                    "height": int,
Example #13
0
from streamlink.plugin.api import http, validate
from streamlink.plugin.api.utils import parse_query
from streamlink.stream import RTMPStream


VIEW_LIVE_API_URL = "http://api.afreeca.tv/live/view_live.php"
VIEW_LIVE_API_URL_TW = "http://api.afreecatv.com.tw/live/view_live.php"
VIEW_LIVE_API_URL_JP = "http://api.afreecatv.jp/live/view_live.php"

_url_re = re.compile("http(s)?://(\w+\.)?(afreecatv.com.tw|afreeca.tv|afreecatv.jp)/(?P<channel>[\w\-_]+)")
_url_re_tw = re.compile("http(s)?://(\w+\.)?(afreecatv.com.tw)/(?P<channel>[\w\-_]+)")
_url_re_jp = re.compile("http(s)?://(\w+\.)?(afreecatv.jp)/(?P<channel>[\w\-_]+)")
_flashvars_re = re.compile('<param name="flashvars" value="([^"]+)" />')

_flashvars_schema = validate.Schema(
    validate.transform(_flashvars_re.findall),
    validate.get(0),
    validate.transform(parse_query),
    validate.any(
        {
            "s": validate.text,
            "id": validate.text
        },
        {}
    )
)
_view_live_schema = validate.Schema(
    {
        "channel": {
            "strm": [{
                "bps": validate.text,
Example #14
0
        validate.optional("state"): {
            "stream": {
                "qualities": [validate.text],
                "rootUrl": validate.url(scheme="rtmp")
            }
        }
    },
    validate.get("state")
)

_vod_schema = validate.Schema(
    {
        "name": validate.text,
        "channel_slug": validate.text,
        "title": validate.text,
        "created_at": validate.transform(int)
    },
)

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

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

        return Plugin.stream_weight(key)
Example #15
0
 def test_dict_keys(self):
     assert validate({text: int},
                     {"a": 1, "b": 2}) == {"a": 1, "b": 2}
     assert validate({transform(text): transform(int)},
                     {1: 3.14, 3.14: 1}) == {"1": 3, "3.14": 1}
Example #16
0
class Gulli(Plugin):
    LIVE_PLAYER_URL = 'https://replay.gulli.fr/jwplayer/embedstreamtv'
    VOD_PLAYER_URL = 'https://replay.gulli.fr/jwplayer/embed/{0}'

    _url_re = re.compile(
        r'https?://replay\.gulli\.fr/(?:Direct|.+/(?P<video_id>VOD[0-9]+))')
    _playlist_re = re.compile(r'sources: (\[.+?\])', re.DOTALL)
    _vod_video_index_re = re.compile(
        r'jwplayer\(idplayer\).playlistItem\((?P<video_index>[0-9]+)\)')
    _mp4_bitrate_re = re.compile(r'.*_(?P<bitrate>[0-9]+)\.mp4')

    _video_schema = validate.Schema(
        validate.all(
            validate.transform(
                lambda x: re.sub(r'"?file"?:\s*[\'"](.+?)[\'"],?',
                                 r'"file": "\1"',
                                 x,
                                 flags=re.DOTALL)),
            validate.transform(
                lambda x: re.sub(r'"?\w+?"?:\s*function\b.*?(?<={).*(?=})',
                                 "",
                                 x,
                                 flags=re.DOTALL)),
            validate.transform(parse_json),
            [validate.Schema({'file': validate.url()})]))

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

    def _get_streams(self):
        match = self._url_re.match(self.url)
        video_id = match.group('video_id')
        if video_id is not None:
            # VOD
            live = False
            player_url = self.VOD_PLAYER_URL.format(video_id)
        else:
            # Live
            live = True
            player_url = self.LIVE_PLAYER_URL

        res = self.session.http.get(player_url)
        playlist = re.findall(self._playlist_re, res.text)
        index = 0
        if not live:
            # Get the index for the video on the playlist
            match = self._vod_video_index_re.search(res.text)
            if match is None:
                return
            index = int(match.group('video_index'))

        if not playlist:
            return
        videos = self._video_schema.validate(playlist[index])

        for video in videos:
            video_url = video['file']

            # Ignore non-supported MSS streams
            if 'isml/Manifest' in video_url:
                continue

            try:
                if '.m3u8' in video_url:
                    for stream in HLSStream.parse_variant_playlist(
                            self.session, video_url).items():
                        yield stream
                elif '.mp4' in video_url:
                    match = self._mp4_bitrate_re.match(video_url)
                    if match is not None:
                        bitrate = '%sk' % match.group('bitrate')
                    else:
                        bitrate = 'vod'
                    yield bitrate, HTTPStream(self.session, video_url)
            except IOError as err:
                if '403 Client Error' in str(err):
                    self.logger.error(
                        'Failed to access stream, may be due to geo-restriction'
                    )
                raise
Example #17
0
class Reuters(Plugin):
    _url_re = re.compile(r'https?://(.*?\.)?reuters\.(com|tv)')
    _id_re = re.compile(r'(/l/|id=)(?P<id>.*?)(/|\?|$)')
    _iframe_url = 'https://www.reuters.tv/l/{0}/?nonav=true'
    _hls_re = re.compile(r'''(?<!')https://[^"';!<>]+\.m3u8''')
    _json_re = re.compile(r'''(?P<data>{.*});''')
    _data_schema = validate.Schema(
        validate.transform(_json_re.search),
        validate.any(
            None,
            validate.all(
                validate.get('data'), validate.transform(parse_json), {
                    'title':
                    validate.text,
                    'items': [{
                        'title':
                        validate.text,
                        'type':
                        validate.text,
                        'resources':
                        [{
                            'mimeType': validate.text,
                            'uri': validate.url(),
                            validate.optional('protocol'): validate.text,
                            validate.optional('entityType'): validate.text,
                        }]
                    }],
                })))

    def __init__(self, url):
        super().__init__(url)
        self.session.http.headers.update({'User-Agent': useragents.FIREFOX})
        self.title = None

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

    def get_title(self):
        if not self.title:
            self._get_data()
        return self.title

    def _get_data(self):
        res = self.session.http.get(self.url)
        for script in itertags(res.text, 'script'):
            if script.attributes.get(
                    'type'
            ) == 'text/javascript' and '#rtvIframe' in script.text:
                m = self._id_re.search(self.url)
                if m and m.group('id'):
                    log.debug('ID: {0}'.format(m.group('id')))
                    res = self.session.http.get(
                        self._iframe_url.format(m.group('id')))

        for script in itertags(res.text, 'script'):
            if script.attributes.get(
                    'type') == 'text/javascript' and 'RTVJson' in script.text:
                data = self._data_schema.validate(script.text)
                if not data:
                    continue
                self.title = data['title']
                for item in data['items']:
                    if data['title'] == item['title']:
                        log.trace('{0!r}'.format(item))
                        log.debug('Type: {0}'.format(item['type']))
                        for res in item['resources']:
                            if res['mimeType'] == 'application/x-mpegURL':
                                return res['uri']

        # fallback
        for title in itertags(res.text, 'title'):
            self.title = title.text
        m = self._hls_re.search(res.text)
        if not m:
            log.error('Unsupported PageType.')
            return
        return m.group(0)

    def _get_streams(self):
        hls_url = self._get_data()
        if not hls_url:
            return
        log.debug('URL={0}'.format(hls_url))
        return HLSStream.parse_variant_playlist(self.session, hls_url)
Example #18
0
import re

from streamlink.compat import urlparse
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):
Example #19
0
class OKru(Plugin):
    _data_re = re.compile(
        r'''data-options=(?P<q>["'])(?P<data>{[^"']+})(?P=q)''')

    _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 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({'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']})
Example #20
0
import re

from streamlink.plugin import Plugin
from streamlink.plugin.api import http, validate
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)
Example #21
0
class Picarto(Plugin):
    CHANNEL_API_URL = "https://api.picarto.tv/v1/channel/name/{channel}"
    VIDEO_API_URL = "https://picarto.tv/process/channel"
    RTMP_URL = "rtmp://{server}:1935/play/"
    RTMP_PLAYPATH = "golive+{channel}?token={token}"
    HLS_URL = "https://{server}/hls/{channel}/index.m3u8?token={token}"

    # Regex for all usable URLs
    _url_re = re.compile(
        r"""
        https?://(?:\w+\.)?picarto\.tv/(?:videopopout/)?([^&?/]+)
    """, re.VERBOSE)

    # Regex for VOD extraction
    _vod_re = re.compile(r'''(?<=#vod-player", )(\{.*?\})''')

    data_schema = validate.Schema(
        validate.transform(_vod_re.search),
        validate.any(
            None,
            validate.all(validate.get(0), validate.transform(parse_json), {
                "vod": validate.url(),
            })))

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

    def _create_hls_stream(self, server, channel, token):
        streams = HLSStream.parse_variant_playlist(self.session,
                                                   self.HLS_URL.format(
                                                       server=server,
                                                       channel=channel,
                                                       token=token),
                                                   verify=False)
        if len(streams) > 1:
            self.logger.debug("Multiple HLS streams found")
            return streams
        elif len(streams) == 0:
            self.logger.warning("No HLS streams found when expected")
            return {}
        else:
            # one HLS streams, rename it to live
            return {"live": list(streams.values())[0]}

    def _create_flash_stream(self, server, channel, token):
        params = {
            "rtmp": self.RTMP_URL.format(server=server),
            "playpath": self.RTMP_PLAYPATH.format(token=token, channel=channel)
        }
        return RTMPStream(self.session, params=params)

    def _get_vod_stream(self, page):
        data = self.data_schema.validate(page.text)

        if data:
            return HLSStream.parse_variant_playlist(self.session, data["vod"])

    def _get_streams(self):
        url_channel_name = self._url_re.match(self.url).group(1)

        # Handle VODs first, since their "channel name" is different
        if url_channel_name.endswith(".flv"):
            self.logger.debug("Possible VOD stream...")
            page = self.session.http.get(self.url)
            vod_streams = self._get_vod_stream(page)
            if vod_streams:
                for s in vod_streams.items():
                    yield s
                return
            else:
                self.logger.warning("Probably a VOD stream but no VOD found?")

        ci = self.session.http.get(
            self.CHANNEL_API_URL.format(channel=url_channel_name),
            raise_for_status=False)

        if ci.status_code == 404:
            self.logger.error(
                "The channel {0} does not exist".format(url_channel_name))
            return

        channel_api_json = json.loads(ci.text)

        if channel_api_json["online"] != True:
            self.logger.error("The channel {0} is currently offline".format(
                url_channel_name))
            return

        server = None
        token = "public"
        channel = channel_api_json["name"]

        # Extract preferred edge server and available techs from the undocumented channel API
        channel_server_res = self.session.http.post(
            self.VIDEO_API_URL, data={"loadbalancinginfo": channel})
        info_json = json.loads(channel_server_res.text)
        pref = info_json["preferedEdge"]
        for i in info_json["edges"]:
            if i["id"] == pref:
                server = i["ep"]
                break
        self.logger.debug(
            "Using load balancing server {0} : {1} for channel {2}", pref,
            server, channel)

        for i in info_json["techs"]:
            if i["label"] == "HLS":
                for s in self._create_hls_stream(server, channel,
                                                 token).items():
                    yield s
            elif i["label"] == "RTMP Flash":
                stream = self._create_flash_stream(server, channel, token)
                yield "live", stream
Example #22
0
    if not formatsmap:
        return formats

    for format in formatsmap.split(","):
        s = format.split("/")
        (w, h) = s[1].split("x")
        formats[int(s[0])] = "{0}p".format(h)

    return formats


_config_schema = validate.Schema(
    {
        validate.optional("fmt_list"): validate.all(
            validate.text,
            validate.transform(parse_fmt_list)
        ),
        validate.optional("url_encoded_fmt_stream_map"): validate.all(
            validate.text,
            validate.transform(parse_stream_map),
            [{
                "itag": validate.all(
                    validate.text,
                    validate.transform(int)
                ),
                "quality": validate.text,
                "url": validate.url(scheme="http"),
                validate.optional("s"): validate.text,
                validate.optional("stereo3d"): validate.all(
                    validate.text,
                    validate.transform(int),
Example #23
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))
Example #24
0
)
_video_flashvars_re = re.compile(
    "<embed width=\"486\" height=\"326\" flashvars=\"([^\"]+)\""
)

_live_schema = validate.Schema({
    "streams": [{
        "name": validate.text,
        "quality": validate.text,
        "url": validate.url(scheme="rtmp")
    }]
})
_schema = validate.Schema(
    validate.union({
        "export_url": validate.all(
            validate.transform(_live_export_re.search),
            validate.any(
                None,
                validate.get(1),
            )
        ),
        "video_flashvars": validate.all(
            validate.transform(_video_flashvars_re.search),
            validate.any(
                None,
                validate.all(
                    validate.get(1),
                    validate.transform(parse_query),
                    {
                        "_111pix_serverURL": validate.url(scheme="rtmp"),
                        "en_flash_providerName": validate.text
Example #25
0
                            scheme="http",
                            path=validate.endswith(".m3u8")
                        ),
                        validate.optional("video_encode_id"): validate.text
                    }]
                )
            }
        )
    },
    validate.get("stream_data")
)
_login_schema = validate.Schema({
    "auth": validate.text,
    "expires": validate.all(
        validate.text,
        validate.transform(parse_timestamp)
    ),
    "user": {
        "username": validate.any(validate.text, None),
        "email": validate.text
    }
})
_session_schema = validate.Schema(
    {
        "session_id": validate.text
    },
    validate.get("session_id")
)


class CrunchyrollAPIError(Exception):
Example #26
0
from streamlink.plugin import Plugin
from streamlink.plugin.api import validate
from streamlink.stream import HLSStream

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")
Example #27
0
        validate.xml_element(attrib={
            "content": validate.text
        }),
        validate.get("content")
    ),
    "videos": validate.all(
        validate.xml_findall("{http://www.w3.org/2001/SMIL20/Language}body/"
                             "{http://www.w3.org/2001/SMIL20/Language}switch/"
                             "{http://www.w3.org/2001/SMIL20/Language}video"),
        [
            validate.all(
                validate.xml_element(attrib={
                    "src": validate.text,
                    "system-bitrate": validate.all(
                        validate.text,
                        validate.transform(int)
                    )
                }),
                validate.transform(
                    lambda e: (e.attrib["src"], e.attrib["system-bitrate"])
                )
            )
        ],
    )
}))


class Livestream(Plugin):
    @classmethod
    def default_stream_types(cls, streams):
        return ["akamaihd", "hls"]
Example #28
0
import re

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

_url_re = re.compile(r"http(s)?://(www\.)?openrec.tv/(live|movie)/[^/?&]+")
_playlist_url_re = re.compile(r"data-(source)?file=\"(?P<url>[^\"]+)\"")
_schema = validate.Schema(validate.transform(_playlist_url_re.findall), [
    validate.union({
        "isSource":
        validate.all(validate.get(0),
                     validate.transform(lambda s: s == "source")),
        "url":
        validate.all(
            validate.get(1),
            validate.url(scheme="http", path=validate.endswith(".m3u8")))
    })
])


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

    @classmethod
    def stream_weight(cls, stream):
        if stream == "source":
            return 1080 + 1, "openrectv"
        return Plugin.stream_weight(stream)
Example #29
0
)
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,
        [{
            "name": validate.text,
            "streams": validate.all(
                _amf3_array,
                [{
                    "streamName": validate.text,
                    "bitrate": float,
                }],
Example #30
0
        validate.optional("state"): {
            "stream": {
                "qualities": [validate.text],
                "rootUrl": validate.url(scheme="rtmp")
            }
        }
    },
    validate.get("state")
)

_vod_schema = validate.Schema(
    {
        "name": validate.text,
        "channel_slug": validate.text,
        "title": validate.text,
        "created_at": validate.transform(int)
    },
)

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

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

        return Plugin.stream_weight(key)
Example #31
0
_quality_re = re.compile("(\d+p)$")
_url_re = re.compile("""
    http(s)?://(www\.)?hitbox.tv
    /(?P<channel>[^/]+)
    (?:
        /(?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")),
Example #32
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(Filmon, self).__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 is_py3:
            adapter = TLSSecLevel1Adapter()
            self.session.http.mount("https://filmon.com", adapter)
            self.session.http.mount("https://www.filmon.com", adapter)
            self.session.http.mount("https://vms-admin.filmon.com/", adapter)

        # get cookies
        self.session.http.get(self.url)

        if vod_id:
            data = self.api.vod(vod_id)
            for _, stream in data["streams"].items():
                if stream["url"].endswith(".m3u8"):
                    streams = HLSStream.parse_variant_playlist(self.session, stream["url"])
                    if not streams:
                        yield stream["quality"], HLSStream(self.session, stream["url"])
                    else:
                        for s in streams.items():
                            yield s
                elif stream["url"].endswith(".mp4"):
                    yield stream["quality"], HTTPStream(self.session, stream["url"])
                else:
                    log.error("Unsupported stream type")
                    return
        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("Found channel ID: {0}".format(_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("Found cached channel ID: {0}".format(_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("Reset cached channel: {0}".format(channel))

                raise
Example #33
0
class CeskatelevizeAPI2:
    _player_api = 'https://playlist.ceskatelevize.cz/'
    _url_re = re.compile(r'http(s)?://([^.]*.)?ceskatelevize.cz')
    _playlist_info_re = re.compile(
        r'{\s*"type":\s*"([a-z]+)",\s*"id":\s*"(\w+)"')
    _playlist_schema = validate.Schema({
        "CODE": validate.contains("OK"),
        "RESULT": {
            "playlist": [{
                "streamUrls": {
                    "main": validate.url(),
                }
            }]
        }
    })
    _ctcomp_re = re.compile(
        r'data-ctcomp="Video"\sdata-video-id="(?P<val1>[^"]*)"\sdata-ctcomp-data="(?P<val2>[^"]+)">'
    )
    _ctcomp_schema = validate.Schema(
        validate.text, validate.transform(_ctcomp_re.findall),
        validate.transform(
            lambda vl: [{
                "video-id": v[0],
                "ctcomp-data": json.loads(html_unescape(v[1]))
            } for v in vl]))
    _playlist_info_schema = validate.Schema({
        "type":
        validate.text,
        "id":
        validate.any(validate.text, int),
        "key":
        validate.text,
        "date":
        validate.text,
        "requestSource":
        validate.text,
        "drm":
        int,
        validate.optional("canBePlay"):
        int,
        validate.optional("assetId"):
        validate.text,
        "quality":
        validate.text,
        validate.optional("region"):
        int
    })

    def __init__(self, session, url, res=None):
        self.session = session
        self.url = url
        self.response = res

    def _get_streams(self):
        if self.response is None:
            infos = self.session.http.get(self.url, schema=self._ctcomp_schema)
        else:
            infos = self.session.http.json(self.response,
                                           schema=self._ctcomp_schema)
        if not infos:
            # playlist infos not found
            raise PluginError('Cannot find playlist infos!')

        vod_prio = len(infos) == 2
        for info in infos:
            try:
                pl = info['ctcomp-data']['source']['playlist'][0]
            except KeyError:
                raise PluginError('Cannot find playlist info!')

            pl = self._playlist_info_schema.validate(pl)
            if vod_prio and pl['type'] != 'VOD':
                continue

            log.trace('{0!r}'.format(info))
            if pl['type'] == 'LIVE':
                data = {
                    "contentType":
                    "live",
                    "items": [{
                        "id": pl["id"],
                        "assetId": pl["assetId"],
                        "key": pl["key"],
                        "playerType": "dash",
                        "date": pl["date"],
                        "requestSource": pl["requestSource"],
                        "drm": pl["drm"],
                        "quality": pl["quality"],
                    }]
                }
            elif pl['type'] == 'VOD':
                data = {
                    "contentType":
                    "vod",
                    "items": [{
                        "id": pl["id"],
                        "key": pl["key"],
                        "playerType": "dash",
                        "date": pl["date"],
                        "requestSource": pl["requestSource"],
                        "drm": pl["drm"],
                        "canBePlay": pl["canBePlay"],
                        "quality": pl["quality"],
                        "region": pl["region"]
                    }]
                }

        headers = {
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        }

        data = json.dumps(data)
        response = self.session.http.post(self._player_api,
                                          data="data={}".format(quote(data)),
                                          headers=headers)
        json_data = self.session.http.json(response,
                                           schema=self._playlist_schema)
        log.trace('{0!r}'.format(json_data))
        playlist = json_data['RESULT']['playlist'][0]['streamUrls']['main']
        yield from DASHStream.parse_manifest(self.session, playlist).items()
Example #34
0
class Mitele(Plugin):
    url_re = re.compile(r"https?://(?:www.)?mitele.es/directo/(\w+)")
    supported_channels = ("telecinco", "bemad", "boing", "cuatro")
    app_key = "56c3464fe4b0b8a18ac02511"
    session_url = "https://appgrid-api.cloud.accedo.tv/session"
    config_url = "https://appgrid-api.cloud.accedo.tv/metadata/general_configuration, web_configuration?" \
                 "sessionKey={key}"
    channel_id_url = "http://indalo.mediaset.es/mmc-player/api/mmc/v1/{channel}/live/flash.json"
    stream_info_url = "http://player.ooyala.com/sas/player_api/v2/authorization/embed_code/{key}/{yoo}?" \
                      "device=html5&domain=www.mitele.es"
    session_schema = validate.Schema({
        "sessionKey":
        validate.text,
        "expiration":
        validate.transform(
            lambda d: datetime.strptime(d, "%Y%m%dT%H:%M:%S+0000"))
    })
    config_schema = validate.Schema({
        "general_configuration": {
            "api_configuration": {
                "ooyala_discovery": {
                    "api_key": validate.text
                }
            }
        }
    })
    channel_id_schema = validate.Schema(
        validate.all({"locations": [{
            "yoo": validate.text
        }]}, validate.get("locations"), validate.get(0), validate.get("yoo")))
    stream_info_schema = validate.Schema({
        "authorization_data": {
            validate.text: {
                "authorized":
                bool,
                "message":
                validate.text,
                validate.optional("streams"): [{
                    "delivery_type": validate.text,
                    "url": {
                        "format":
                        "encoded",
                        "data":
                        validate.all(
                            validate.text, validate.transform(b64decode),
                            validate.transform(lambda d: d.decode("utf8")),
                            validate.url())
                    }
                }]
            }
        }
    })

    @classmethod
    def can_handle_url(cls, url):
        m = cls.url_re.match(url)
        return m and m.group(1) in cls.supported_channels

    @property
    def session_key(self):
        """
        Get a cached or new session key, uuid is a random uuid (type 4)
        :return:
        """
        session_key = self.cache.get("sessionKey")
        if session_key:
            self.logger.debug("Using cached sessionKey")
            return session_key
        else:
            self.logger.debug("Requesting new sessionKey")
            uuid = uuid4()
            res = http.get(self.session_url,
                           params=dict(appKey=self.app_key, uuid=uuid))
            data = parse_json(res.text, schema=self.session_schema)
            # when to expire the sessionKey, -1 hour for good measure
            expires_in = (data["expiration"] -
                          datetime.now()).total_seconds() - 3600
            self.cache.set("sessionKey",
                           data["sessionKey"],
                           expires=expires_in)
            return data["sessionKey"]

    @property
    def config(self):
        """
        Get the API config data
        """
        config_res = http.get(self.config_url.format(key=self.session_key))
        return parse_json(config_res.text, schema=self.config_schema)

    def get_channel_id(self, channel):
        """
        Get the ID of the channel form the name
        :param channel: channel name
        :return: channel id
        """
        channel_id_res = http.get(self.channel_id_url.format(channel=channel))
        return parse_json(channel_id_res.text, schema=self.channel_id_schema)

    def get_stream_info(self, key, channel_id):
        """
        Get details about the streams
        :param key: API key
        :param channel_id: channel id
        :return: stream info
        """
        stream_info_res = http.get(
            self.stream_info_url.format(key=key, yoo=channel_id))
        return parse_json(stream_info_res.text, schema=self.stream_info_schema)

    def _get_streams(self):
        channel = self.url_re.match(self.url).group(1)

        key, sig = self.config["general_configuration"]["api_configuration"][
            "ooyala_discovery"]["api_key"].split(".")
        self.logger.debug("Got api key: {}.{}", key, sig)

        channel_id = self.get_channel_id(channel)
        self.logger.debug("Got channel ID {} for channel {}", channel_id,
                          channel)

        data = self.get_stream_info(key, channel_id)

        stream_info = data["authorization_data"][channel_id]

        if stream_info["authorized"]:
            for stream in stream_info["streams"]:
                if stream["delivery_type"] == "hls":
                    for s in HLSStream.parse_variant_playlist(
                            self.session, stream["url"]["data"]).items():
                        yield s

        else:
            self.logger.error("Cannot load streams: {}",
                              stream_info["message"])
Example #35
0
class SteamBroadcastPlugin(Plugin):
    _url_re = re.compile(r"https?://steamcommunity.com/broadcast/watch/(\d+)")
    _steamtv_url_re = re.compile(r"https?://steam.tv/(\w+)")
    _watch_broadcast_url = "https://steamcommunity.com/broadcast/watch/"
    _get_broadcast_url = "https://steamcommunity.com/broadcast/getbroadcastmpd/"
    _user_agent = "streamlink/{}".format(streamlink.__version__)
    _broadcast_schema = Schema({
        "success":
        validate.any("ready", "unavailable", "waiting", "waiting_to_start",
                     "waiting_for_start"),
        "retry":
        int,
        "broadcastid":
        validate.any(validate.text, int),
        validate.optional("url"):
        validate.url(),
        validate.optional("viewertoken"):
        validate.text
    })
    _get_rsa_key_url = "https://steamcommunity.com/login/getrsakey/"
    _rsa_key_schema = validate.Schema({
        "publickey_exp":
        validate.all(validate.text, validate.transform(lambda x: int(x, 16))),
        "publickey_mod":
        validate.all(validate.text, validate.transform(lambda x: int(x, 16))),
        "success":
        True,
        "timestamp":
        validate.text,
        "token_gid":
        validate.text
    })
    _dologin_url = "https://steamcommunity.com/login/dologin/"
    _dologin_schema = validate.Schema({
        "success":
        bool,
        "requires_twofactor":
        bool,
        validate.optional("message"):
        validate.text,
        validate.optional("emailauth_needed"):
        bool,
        validate.optional("emaildomain"):
        validate.text,
        validate.optional("emailsteamid"):
        validate.text,
        validate.optional("login_complete"):
        bool,
        validate.optional("captcha_needed"):
        bool,
        validate.optional("captcha_gid"):
        validate.any(validate.text, int)
    })
    _captcha_url = "https://steamcommunity.com/public/captcha.php?gid={}"

    arguments = PluginArguments(
        PluginArgument("email",
                       metavar="EMAIL",
                       requires=["password"],
                       help="""
            A Steam account email address to access friends/private streams
            """),
        PluginArgument("password",
                       metavar="PASSWORD",
                       sensitive=True,
                       help="""
            A Steam account password to use with --steam-email.
            """))

    def __init__(self, url):
        super(SteamBroadcastPlugin, self).__init__(url)
        self.session.http.headers["User-Agent"] = self._user_agent

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

    @property
    def donotcache(self):
        return str(int(time.time() * 1000))

    def encrypt_password(self, email, password):
        """
        Get the RSA key for the user and encrypt the users password
        :param email: steam account
        :param password: password for account
        :return: encrypted password
        """
        res = self.session.http.get(self._get_rsa_key_url,
                                    params=dict(username=email,
                                                donotcache=self.donotcache))
        rsadata = self.session.http.json(res, schema=self._rsa_key_schema)

        rsa = RSA.construct(
            (rsadata["publickey_mod"], rsadata["publickey_exp"]))
        cipher = PKCS1_v1_5.new(rsa)
        return base64.b64encode(cipher.encrypt(
            password.encode("utf8"))), rsadata["timestamp"]

    def dologin(self,
                email,
                password,
                emailauth="",
                emailsteamid="",
                captchagid="-1",
                captcha_text="",
                twofactorcode=""):
        """
        Logs in to Steam

        """
        epassword, rsatimestamp = self.encrypt_password(email, password)

        login_data = {
            'username': email,
            "password": epassword,
            "emailauth": emailauth,
            "loginfriendlyname": "Streamlink",
            "captchagid": captchagid,
            "captcha_text": captcha_text,
            "emailsteamid": emailsteamid,
            "rsatimestamp": rsatimestamp,
            "remember_login": True,
            "donotcache": self.donotcache,
            "twofactorcode": twofactorcode
        }

        res = self.session.http.post(self._dologin_url, data=login_data)

        resp = self.session.http.json(res, schema=self._dologin_schema)

        if not resp[u"success"]:
            if resp.get(u"captcha_needed"):
                # special case for captcha
                captchagid = resp[u"captcha_gid"]
                log.error(
                    "Captcha result required, open this URL to see the captcha: {}"
                    .format(self._captcha_url.format(captchagid)))
                try:
                    captcha_text = self.input_ask("Captcha text")
                except FatalPluginError:
                    captcha_text = None
                if not captcha_text:
                    return False
            else:
                # If the user must enter the code that was emailed to them
                if resp.get(u"emailauth_needed"):
                    if not emailauth:
                        try:
                            emailauth = self.input_ask(
                                "Email auth code required")
                        except FatalPluginError:
                            emailauth = None
                        if not emailauth:
                            return False
                    else:
                        raise SteamLoginFailed("Email auth key error")

                # If the user must enter a two factor auth code
                if resp.get(u"requires_twofactor"):
                    try:
                        twofactorcode = self.input_ask(
                            "Two factor auth code required")
                    except FatalPluginError:
                        twofactorcode = None
                    if not twofactorcode:
                        return False

                if resp.get(u"message"):
                    raise SteamLoginFailed(resp[u"message"])

            return self.dologin(email,
                                password,
                                emailauth=emailauth,
                                emailsteamid=resp.get(u"emailsteamid", u""),
                                captcha_text=captcha_text,
                                captchagid=captchagid,
                                twofactorcode=twofactorcode)
        elif resp.get("login_complete"):
            return True
        else:
            log.error("Something when wrong when logging in to Steam")
            return False

    def login(self, email, password):
        log.info("Attempting to login to Steam as {}".format(email))
        return self.dologin(email, password)

    def _get_broadcast_stream(self, steamid, viewertoken=0, sessionid=None):
        log.debug("Getting broadcast stream: sessionid={0}".format(sessionid))
        res = self.session.http.get(self._get_broadcast_url,
                                    params=dict(broadcastid=0,
                                                steamid=steamid,
                                                viewertoken=viewertoken,
                                                sessionid=sessionid))
        return self.session.http.json(res, schema=self._broadcast_schema)

    def _get_streams(self):
        streamdata = None
        if self.get_option("email"):
            if self.login(self.get_option("email"),
                          self.get_option("password")):
                log.info("Logged in as {0}".format(self.get_option("email")))
                self.save_cookies(lambda c: "steamMachineAuth" in c.name)

        # Handle steam.tv URLs
        if self._steamtv_url_re.match(self.url) is not None:
            # extract the steam ID from the page
            res = self.session.http.get(self.url)
            for div in itertags(res.text, 'div'):
                if div.attributes.get("id") == "webui_config":
                    broadcast_data = html_unescape(
                        div.attributes.get("data-broadcast"))
                    steamid = parse_json(broadcast_data).get("steamid")
                    self.url = self._watch_broadcast_url + steamid

        # extract the steam ID from the URL
        steamid = self._url_re.match(self.url).group(1)
        res = self.session.http.get(
            self.url)  # get the page to set some cookies
        sessionid = res.cookies.get('sessionid')

        while streamdata is None or streamdata[u"success"] in (
                "waiting", "waiting_for_start"):
            streamdata = self._get_broadcast_stream(steamid,
                                                    sessionid=sessionid)

            if streamdata[u"success"] == "ready":
                return DASHStream.parse_manifest(self.session,
                                                 streamdata["url"])
            elif streamdata[u"success"] == "unavailable":
                log.error("This stream is currently unavailable")
                return
            else:
                r = streamdata[u"retry"] / 1000.0
                log.info(
                    "Waiting for stream, will retry again in {} seconds...".
                    format(r))
                time.sleep(r)
Example #36
0
class Mjunoon(Plugin):
    login_url = 'https://cdn2.mjunoon.tv:9191/v2/auth/login'
    stream_url = 'https://cdn2.mjunoon.tv:9191/v2/streaming-url'

    is_live_channel_re = re.compile(r'"isLiveBroadcast":\s*"(true|undefined)"')

    main_chunk_js_url_re = re.compile(
        r'<script src="(/static/js/main\.\w+\.chunk\.js)"></script>')

    js_credentials_re = re.compile(
        r'data:{email:"(?P<email>.*?)",password:"******"}')

    js_cipher_data_re = re.compile(
        r'createDecipheriv\("(?P<algorithm>.*?)","(?P<key>.*?)","(?P<iv>.*?)"\)'
    )

    token_schema = validate.Schema({
        'token': validate.text,
        'token_type': validate.text,
        'expires_in': int,
    })

    encrypted_data_schema = validate.Schema({
        'eData': validate.text,
    }, validate.get('eData'))

    stream_schema = validate.Schema(
        {
            'data': {
                'live_stream_url':
                validate.url(),
                'channel_name':
                validate.text,
                'meta_title':
                validate.any(None, validate.text),
                'genres':
                validate.all(
                    validate.transform(lambda x: x.split(',')[0]),
                    validate.text,
                ),
            },
        }, validate.get('data'))

    encryption_algorithm = {
        'aes-256-cbc': AES.MODE_CBC,
    }

    def get_data(self):
        js_data = {}
        res = self.session.http.get(self.url)

        m = self.is_live_channel_re.search(res.text)
        if not m:
            return

        if m.group(1) == "true":
            js_data['type'] = 'channel'
        else:
            js_data['type'] = 'episode'

        m = self.main_chunk_js_url_re.search(res.text)
        if not m:
            log.error('Failed to get main chunk JS URL')
            return

        res = self.session.http.get(urljoin(self.url, m.group(1)))

        m = self.js_credentials_re.search(res.text)
        if not m:
            log.error('Failed to get credentials')
            return

        js_data['credentials'] = m.groupdict()

        m = self.js_cipher_data_re.search(res.text)
        if not m:
            log.error('Failed to get cipher data')
            return

        js_data['cipher_data'] = m.groupdict()

        return js_data

    def decrypt_data(self, cipher_data, encrypted_data):
        cipher = AES.new(
            bytes(cipher_data['key'], 'utf-8'),
            self.encryption_algorithm[cipher_data['algorithm']],
            bytes(cipher_data['iv'], 'utf-8'),
        )

        return unpad(cipher.decrypt(binascii.unhexlify(encrypted_data)), 16,
                     'pkcs7')

    def get_stream(self, slug, js_data):
        token_data = {}
        token_data['token'] = self.cache.get('token')
        token_data['token_type'] = self.cache.get('token_type')

        if token_data['token'] and token_data['token_type']:
            log.debug('Using cached token')
        else:
            log.debug('Getting new token')

            res = self.session.http.post(
                self.login_url,
                json=js_data['credentials'],
            )
            token_data = self.session.http.json(res, schema=self.token_schema)
            log.debug('Token={0}'.format(token_data["token"]))

            self.cache.set('token',
                           token_data['token'],
                           expires=token_data['expires_in'])
            self.cache.set('token_type',
                           token_data['token_type'],
                           expires=token_data['expires_in'])

        headers = {
            'Authorization':
            '{0} {1}'.format(token_data["token_type"], token_data["token"])
        }
        data = {
            'slug': slug,
            'type': js_data['type'],
        }
        res = self.session.http.post(
            self.stream_url,
            headers=headers,
            json=data,
        )
        encrypted_data = self.session.http.json(
            res, schema=self.encrypted_data_schema)

        stream_data = parse_json(
            self.decrypt_data(js_data['cipher_data'], encrypted_data),
            schema=self.stream_schema,
        )

        self.author = stream_data['channel_name']
        self.category = stream_data['genres']
        self.title = stream_data['meta_title']

        return stream_data['live_stream_url']

    def _get_streams(self):
        slug = self.match.group(1)
        log.debug('Slug={0}'.format(slug))

        js_data = self.get_data()
        if not js_data:
            return

        log.debug('JS data={0}'.format(js_data))

        hls_url = self.get_stream(slug, js_data)
        log.debug('HLS URL={0}'.format(hls_url))

        return HLSStream.parse_variant_playlist(self.session, hls_url)
Example #37
0
class YouTube(Plugin):
    _oembed_url = "https://www.youtube.com/oembed"
    _video_info_url = "https://youtube.com/get_video_info"

    _oembed_schema = validate.Schema(
        {
            "author_name": validate.all(validate.text,
                                        validate.transform(maybe_decode)),
            "title": validate.all(validate.text,
                                  validate.transform(maybe_decode))
        }
    )

    # There are missing itags
    adp_video = {
        137: "1080p",
        299: "1080p60",  # HFR
        264: "1440p",
        308: "1440p60",  # HFR
        266: "2160p",
        315: "2160p60",  # HFR
        138: "2160p",
        302: "720p60",  # HFR
        135: "480p",
        133: "240p",
        160: "144p",
    }
    adp_audio = {
        140: 128,
        141: 256,
        171: 128,
        249: 48,
        250: 64,
        251: 160,
        256: 256,
        258: 258,
    }

    arguments = PluginArguments(
        PluginArgument(
            "api-key",
            sensitive=True,
            help=argparse.SUPPRESS  # no longer used
        )
    )

    def __init__(self, url):
        super(YouTube, self).__init__(url)
        parsed = urlparse(self.url)
        if parsed.netloc == 'gaming.youtube.com':
            self.url = urlunparse(parsed._replace(netloc='www.youtube.com'))

        self.author = None
        self.title = None
        self.video_id = None
        self.session.http.headers.update({'User-Agent': useragents.CHROME})

    def get_author(self):
        if self.author is None:
            self.get_oembed
        return self.author

    def get_title(self):
        if self.title is None:
            self.get_oembed
        return self.title

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

    @classmethod
    def stream_weight(cls, stream):
        match_3d = re.match(r"(\w+)_3d", stream)
        match_hfr = re.match(r"(\d+p)(\d+)", stream)
        if match_3d:
            weight, group = Plugin.stream_weight(match_3d.group(1))
            weight -= 1
            group = "youtube_3d"
        elif match_hfr:
            weight, group = Plugin.stream_weight(match_hfr.group(1))
            weight += 1
            group = "high_frame_rate"
        else:
            weight, group = Plugin.stream_weight(stream)

        return weight, group

    @property
    def get_oembed(self):
        if self.video_id is None:
            self.video_id = self._find_video_id(self.url)

        params = {
            "url": "https://www.youtube.com/watch?v={0}".format(self.video_id),
            "format": "json"
        }
        res = self.session.http.get(self._oembed_url, params=params)
        data = self.session.http.json(res, schema=self._oembed_schema)
        self.author = data["author_name"]
        self.title = data["title"]

    def _create_adaptive_streams(self, info, streams):
        adaptive_streams = {}
        best_audio_itag = None

        # Extract audio streams from the adaptive format list
        streaming_data = info.get("player_response", {}).get("streamingData", {})
        for stream_info in streaming_data.get("adaptiveFormats", []):
            if "url" not in stream_info:
                continue
            stream_params = dict(parse_qsl(stream_info["url"]))
            if "itag" not in stream_params:
                continue
            itag = int(stream_params["itag"])
            # extract any high quality streams only available in adaptive formats
            adaptive_streams[itag] = stream_info["url"]

            stream_type, stream_format = stream_info["mimeType"]

            if stream_type == "audio":
                stream = HTTPStream(self.session, stream_info["url"])
                name = "audio_{0}".format(stream_format)
                streams[name] = stream

                # find the best quality audio stream m4a, opus or vorbis
                if best_audio_itag is None or self.adp_audio[itag] > self.adp_audio[best_audio_itag]:
                    best_audio_itag = itag

        if best_audio_itag and adaptive_streams and MuxedStream.is_usable(self.session):
            aurl = adaptive_streams[best_audio_itag]
            for itag, name in self.adp_video.items():
                if itag in adaptive_streams:
                    vurl = adaptive_streams[itag]
                    log.debug("MuxedStream: v {video} a {audio} = {name}".format(
                        audio=best_audio_itag,
                        name=name,
                        video=itag,
                    ))
                    streams[name] = MuxedStream(self.session,
                                                HTTPStream(self.session, vurl),
                                                HTTPStream(self.session, aurl))

        return streams

    def _find_video_id(self, url):

        m = _url_re.match(url)
        if m.group("video_id"):
            log.debug("Video ID from URL")
            return m.group("video_id")

        res = self.session.http.get(url)
        datam = _ytdata_re.search(res.text)
        if datam:
            data = parse_json(datam.group(1))
            # find the videoRenderer object, where there is a LVE NOW badge
            for vid_ep in search_dict(data, 'currentVideoEndpoint'):
                video_id = vid_ep.get("watchEndpoint", {}).get("videoId")
                if video_id:
                    log.debug("Video ID from currentVideoEndpoint")
                    return video_id
            for x in search_dict(data, 'videoRenderer'):
                if x.get("viewCountText", {}).get("runs"):
                    if x.get("videoId"):
                        log.debug("Video ID from videoRenderer (live)")
                        return x["videoId"]
                for bstyle in search_dict(x.get("badges", {}), "style"):
                    if bstyle == "BADGE_STYLE_TYPE_LIVE_NOW":
                        if x.get("videoId"):
                            log.debug("Video ID from videoRenderer (live)")
                            return x["videoId"]

        if "/embed/live_stream" in url:
            for link in itertags(res.text, "link"):
                if link.attributes.get("rel") == "canonical":
                    canon_link = link.attributes.get("href")
                    if canon_link != url:
                        if canon_link.endswith("v=live_stream"):
                            log.debug("The video is not available")
                            break
                        else:
                            log.debug("Re-directing to canonical URL: {0}".format(canon_link))
                            return self._find_video_id(canon_link)

        raise PluginError("Could not find a video on this page")

    def _get_stream_info(self, video_id):
        # normal
        _params_1 = {"el": "detailpage"}
        # age restricted
        _params_2 = {"el": "embedded"}
        # embedded restricted
        _params_3 = {"eurl": "https://youtube.googleapis.com/v/{0}".format(video_id)}

        count = 0
        info_parsed = None
        for _params in (_params_1, _params_2, _params_3):
            count += 1
            params = {"video_id": video_id}
            params.update(_params)

            res = self.session.http.get(self._video_info_url, params=params)
            info_parsed = parse_query(res.content if is_py2 else res.text, name="config", schema=_config_schema)
            player_response = info_parsed.get("player_response", {})
            playability_status = player_response.get("playabilityStatus", {})
            if (playability_status.get("status") != "OK"):
                reason = playability_status.get("reason")
                log.debug("get_video_info - {0}: {1}".format(
                    count, reason)
                )
                continue
            self.author = player_response.get("videoDetails", {}).get("author")
            self.title = player_response.get("videoDetails", {}).get("title")
            log.debug("get_video_info - {0}: Found data".format(count))
            break

        return info_parsed

    def _get_streams(self):
        is_live = False

        self.video_id = self._find_video_id(self.url)
        log.debug("Using video ID: {0}", self.video_id)

        info = self._get_stream_info(self.video_id)
        if info and info.get("status") == "fail":
            log.error("Could not get video info: {0}".format(info.get("reason")))
            return
        elif not info:
            log.error("Could not get video info")
            return

        if info.get("player_response", {}).get("videoDetails", {}).get("isLive"):
            log.debug("This video is live.")
            is_live = True

        streams = {}
        protected = False
        if (info.get("player_response", {}).get("streamingData", {}).get("adaptiveFormats", [{}])[0].get("cipher")
           or info.get("player_response", {}).get("streamingData", {}).get("adaptiveFormats", [{}])[0].get("signatureCipher")
           or info.get("player_response", {}).get("streamingData", {}).get("formats", [{}])[0].get("cipher")):
            protected = True
            log.debug("This video may be protected.")

        for stream_info in info.get("player_response", {}).get("streamingData", {}).get("formats", []):
            if "url" not in stream_info:
                continue
            stream = HTTPStream(self.session, stream_info["url"])
            name = stream_info["qualityLabel"]

            streams[name] = stream

        if not is_live:
            streams = self._create_adaptive_streams(info, streams)

        hls_manifest = info.get("player_response", {}).get("streamingData", {}).get("hlsManifestUrl")
        if hls_manifest:
            try:
                hls_streams = HLSStream.parse_variant_playlist(
                    self.session, hls_manifest, namekey="pixels"
                )
                streams.update(hls_streams)
            except IOError as err:
                log.warning("Failed to extract HLS streams: {0}", err)

        if not streams and protected:
            raise PluginError("This plugin does not support protected videos, "
                              "try youtube-dl instead")

        return streams
Example #38
0
            validate.xml_find("./head/meta"),
            validate.get("base"),
            validate.url(scheme="rtmp")
        ),
        "videos": validate.all(
            validate.xml_findall(".//video"),
            [
                validate.union({
                    "src": validate.all(
                        validate.get("src"),
                        validate.text
                    ),
                    "height": validate.all(
                        validate.get("height"),
                        validate.text,
                        validate.transform(int)
                    )
                })
            ]
        )
    })
)

class Beam(Plugin):
    @classmethod
    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")
Example #39
0
class DeutscheWelle(Plugin):
    default_channel = "1"
    url_re = re.compile(r"https?://(?:www\.)?dw\.com/")

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            yield self._create_stream(url, quality)

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

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

        return self._get_vod_streams(stream_type, res)
Example #40
0
import re

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

_url_re = re.compile(r"http(s)?://(\w+.)?chaturbate.com/[^/?&]+")
_playlist_url_re = re.compile(r"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:
Example #41
0
from streamlink.plugin import Plugin, pluginmatcher
from streamlink.plugin.api import validate
from streamlink.plugin.api.useragents import CHROME as USER_AGENT
from streamlink.stream.hls import HLSStream
from streamlink.stream.http import HTTPStream

HUAJIAO_URL = "http://www.huajiao.com/l/{}"
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"

_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)))))


@pluginmatcher(
    re.compile(r"https?://(www\.)?huajiao\.com/l/(?P<channel>[^/]+)"))
class Huajiao(Plugin):
    def _get_streams(self):
        channel = self.match.group("channel")

        self.session.http.headers.update({"User-Agent": USER_AGENT})
        self.session.http.verify = False
Example #42
0
STREAM_INFO_URL = "http://live.daserste.de/{0}/livestream.xml"
SWF_URL = "http://live.daserste.de/lib/br-player/swf/main.swf"
STREAMING_TYPES = {
    "streamingUrlLive": ("HDS", partial(HDSStream.parse_manifest,
                                        pvswf=SWF_URL)),
    "streamingUrlIPhone": ("HLS", HLSStream.parse_variant_playlist)
}

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

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


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

    def _get_streams(self):
        match = _url_re.match(self.url)
        channel = match.group("channel")
        res = http.get(STREAM_INFO_URL.format(channel))
        urls = http.xml(res, schema=_livestream_schema)

        streams = {}
Example #43
0
STREAMING_TYPES = {
    "h264_aac_f4f_http_f4m_http": (
        "HDS", HDSStream.parse_manifest
    ),
    "h264_aac_ts_http_m3u8_http": (
        "HLS", HLSStream.parse_variant_playlist
    )
}

_url_re = re.compile(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(
    {
Example #44
0
class AfreecaTV(Plugin):
    _re_bno = re.compile(r"var nBroadNo = (?P<bno>\d+);")
    _re_url = re.compile(
        r"https?://play\.afreecatv\.com/(?P<username>\w+)(?:/(?P<bno>:\d+))?")

    CHANNEL_API_URL = "http://live.afreecatv.com/afreeca/player_live_api.php"
    CHANNEL_RESULT_OK = 1
    QUALITYS = ["original", "hd", "sd"]
    QUALITY_WEIGHTS = {
        "original": 1080,
        "hd": 720,
        "sd": 480,
    }

    _schema_channel = validate.Schema(
        {
            "CHANNEL": {
                "RESULT": validate.transform(int),
                validate.optional("BPWD"): str,
                validate.optional("BNO"): str,
                validate.optional("RMD"): str,
                validate.optional("AID"): str,
                validate.optional("CDN"): str,
            }
        }, validate.get("CHANNEL"))
    _schema_stream = validate.Schema({
        validate.optional("view_url"):
        validate.url(scheme=validate.any("rtmp", "http")),
        "stream_status":
        str,
    })

    arguments = PluginArguments(
        PluginArgument(
            "username",
            sensitive=True,
            requires=["password"],
            metavar="USERNAME",
            help="The username used to register with afreecatv.com."),
        PluginArgument(
            "password",
            sensitive=True,
            metavar="PASSWORD",
            help=
            "A afreecatv.com account password to use with --afreeca-username."
        ),
        PluginArgument("purge-credentials",
                       action="store_true",
                       help="""
        Purge cached AfreecaTV credentials to initiate a new session
        and reauthenticate.
        """),
    )

    def __init__(self, url):
        super().__init__(url)
        self._authed = (self.session.http.cookies.get("PdboxBbs")
                        and self.session.http.cookies.get("PdboxSaveTicket")
                        and self.session.http.cookies.get("PdboxTicket")
                        and self.session.http.cookies.get("PdboxUser")
                        and self.session.http.cookies.get("RDB"))

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

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

        return Plugin.stream_weight(key)

    def _get_channel_info(self, broadcast, username):
        data = {
            "bid": username,
            "bno": broadcast,
            "mode": "landing",
            "player_type": "html5",
            "type": "live",
        }
        res = self.session.http.post(self.CHANNEL_API_URL, data=data)
        return self.session.http.json(res, schema=self._schema_channel)

    def _get_hls_key(self, broadcast, username, quality):
        data = {
            "bid": username,
            "bno": broadcast,
            "pwd": "",
            "quality": quality,
            "type": "pwd"
        }
        res = self.session.http.post(self.CHANNEL_API_URL, data=data)
        return self.session.http.json(res, schema=self._schema_channel)

    def _get_stream_info(self, broadcast, quality, cdn, rmd):
        params = {
            "return_type": cdn,
            "broad_key": f"{broadcast}-flash-{quality}-hls",
        }
        res = self.session.http.get(f"{rmd}/broad_stream_assign.html",
                                    params=params)
        return self.session.http.json(res, schema=self._schema_stream)

    def _get_hls_stream(self, broadcast, username, quality, cdn, rmd):
        keyjson = self._get_hls_key(broadcast, username, quality)

        if keyjson["RESULT"] != self.CHANNEL_RESULT_OK:
            return
        key = keyjson["AID"]

        info = self._get_stream_info(broadcast, quality, cdn, rmd)

        if "view_url" in info:
            return AfreecaHLSStream(self.session,
                                    info["view_url"],
                                    params={"aid": key})

    def _login(self, username, password):
        data = {
            "szWork": "login",
            "szType": "json",
            "szUid": username,
            "szPassword": password,
            "isSaveId": "true",
            "isSavePw": "false",
            "isSaveJoin": "false",
            "isLoginRetain": "Y",
        }
        res = self.session.http.post(
            "https://login.afreecatv.com/app/LoginAction.php", data=data)
        data = self.session.http.json(res)
        log.trace(f"{data!r}")
        if data["RESULT"] == self.CHANNEL_RESULT_OK:
            self.save_cookies()
            return True
        else:
            return False

    def _get_streams(self):
        login_username = self.get_option("username")
        login_password = self.get_option("password")

        self.session.http.headers.update({"Referer": self.url})

        if self.options.get("purge_credentials"):
            self.clear_cookies()
            self._authed = False
            log.info("All credentials were successfully removed")

        if self._authed:
            log.debug("Attempting to authenticate using cached cookies")
        elif login_username and login_password:
            log.debug("Attempting to login using username and password")
            if self._login(login_username, login_password):
                log.info("Login was successful")
            else:
                log.error("Failed to login")

        m = self._re_url.match(self.url).groupdict()
        username = m["username"]
        bno = m["bno"]
        if bno is None:
            res = self.session.http.get(self.url)
            m = self._re_bno.search(res.text)
            if not m:
                log.error("Could not find broadcast number.")
                return
            bno = m.group("bno")

        channel = self._get_channel_info(bno, username)
        log.trace(f"{channel!r}")
        if channel.get("BPWD") == "Y":
            log.error("Stream is Password-Protected")
            return
        elif channel.get("RESULT") == -6:
            log.error("Login required")
            return
        elif channel.get("RESULT") != self.CHANNEL_RESULT_OK:
            return

        (broadcast, rmd, cdn) = (channel["BNO"], channel["RMD"],
                                 channel["CDN"])
        if not (broadcast and rmd and cdn):
            return

        for qkey in self.QUALITYS:
            hls_stream = self._get_hls_stream(broadcast, username, qkey, cdn,
                                              rmd)
            if hls_stream:
                yield qkey, hls_stream
Example #45
0
                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.any(validate.text, None),
    "expires":
    validate.all(validate.text, validate.transform(parse_timestamp)),
    "user": {
        "username": validate.any(validate.text, None),
        "email": validate.text
    }
})
_session_schema = validate.Schema({"session_id": validate.text},
                                  validate.get("session_id"))


class CrunchyrollAPIError(Exception):
    """Exception thrown by the Crunchyroll API when an error occurs"""
    def __init__(self, msg, code):
        Exception.__init__(self, msg)
        self.msg = msg
        self.code = code
Example #46
0
class Rtve(Plugin):
    secret_key = base64.b64decode("eWVMJmRhRDM=")
    url_re = re.compile(r"""
        https?://(?:www\.)?rtve\.es/(?:directo|infantil|noticias|television|deportes|alacarta|drmn)/.*?/?
    """, re.VERBOSE)
    cdn_schema = validate.Schema(
        validate.transform(partial(parse_xml, invalid_char_entities=True)),
        validate.xml_findall(".//preset"),
        [
            validate.union({
                "quality": validate.all(validate.getattr("attrib"),
                                        validate.get("type")),
                "urls": validate.all(
                    validate.xml_findall(".//url"),
                    [validate.getattr("text")]
                )
            })
        ]
    )
    subtitles_api = "http://www.rtve.es/api/videos/{id}/subtitulos.json"
    subtitles_schema = validate.Schema({
        "page": {
            "items": [{
                "src": validate.url(),
                "lang": validate.text
            }]
        }
    },
        validate.get("page"),
        validate.get("items"))
    video_api = "http://www.rtve.es/api/videos/{id}.json"
    video_schema = validate.Schema({
        "page": {
            "items": [{
                "qualities": [{
                    "preset": validate.text,
                    "height": int
                }]
            }]
        }
    },
        validate.get("page"),
        validate.get("items"),
        validate.get(0))

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

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

    def __init__(self, url):
        Plugin.__init__(self, url)
        self.session.http.headers = {"User-Agent": useragents.SAFARI_8}
        self.zclient = ZTNRClient(self.secret_key, self.session)

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

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

    def _get_quality_map(self, content_id):
        res = self.session.http.get(self.video_api.format(id=content_id))
        data = self.session.http.json(res, schema=self.video_schema)
        qmap = {}
        for item in data["qualities"]:
            qname = {"MED": "Media", "HIGH": "Alta", "ORIGINAL": "Original"}.get(item["preset"], item["preset"])
            qmap[qname] = 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
Example #47
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:
Example #48
0
class BBCiPlayer(Plugin):
    url_re = re.compile(
        r"""https?://(?:www\.)?bbc.co.uk/iplayer/
        (
            episode/(?P<episode_id>\w+)|
            live/(?P<channel_name>\w+)
        )
    """, re.VERBOSE)
    mediator_re = re.compile(
        r'window\.mediatorDefer\s*=\s*page\([^,]*,\s*(\{.*?})\);', re.DOTALL)
    tvip_re = re.compile(r'event_master_brand=(\w+?)&')
    account_locals_re = re.compile(r'window.bbcAccount.locals\s*=\s*(\{.*?});')
    swf_url = "http://emp.bbci.co.uk/emp/SMPf/1.18.3/StandardMediaPlayerChromelessFlash.swf"
    hash = base64.b64decode(
        b"N2RmZjc2NzFkMGM2OTdmZWRiMWQ5MDVkOWExMjE3MTk5MzhiOTJiZg==")
    api_url = (
        "http://open.live.bbc.co.uk/mediaselector/6/select/"
        "version/2.0/mediaset/{platform}/vpid/{vpid}/format/json/atk/{vpid_hash}/asn/1/"
    )
    platforms = ("pc", "iptv-all")
    config_url = "http://www.bbc.co.uk/idcta/config"
    auth_url = "https://account.bbc.com/signin"

    config_schema = validate.Schema(
        validate.transform(parse_json), {
            "signin_url": validate.url(),
            "identity": {
                "cookieAgeDays": int,
                "accessTokenCookieName": validate.text,
                "idSignedInCookieName": validate.text
            }
        })
    mediator_schema = validate.Schema(
        {"episode": {
            "versions": [{
                "id": validate.text
            }]
        }}, validate.get("episode"), validate.get("versions"), validate.get(0),
        validate.get("id"))
    mediaselector_schema = validate.Schema(
        validate.transform(parse_json), {
            "media": [{
                "connection":
                [{
                    validate.optional("href"): validate.url(),
                    validate.optional("transferFormat"): validate.text
                }],
                "kind":
                validate.text
            }]
        }, validate.get("media"),
        validate.filter(lambda x: x["kind"] == "video"))
    options = PluginOptions({"password": None, "username": None})

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

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

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

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

    def mediaselector(self, vpid):
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid,
                                      vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            self.logger.debug("Info API request: {0}", url)
            stream_urls = http.get(url, schema=self.mediaselector_schema)
            for media in stream_urls:
                for connection in media["connection"]:
                    if connection.get("transferFormat") == "hds":
                        for s in HDSStream.parse_manifest(
                                self.session, connection["href"]).items():
                            yield s
                    if connection.get("transferFormat") == "hls":
                        for s in HLSStream.parse_variant_playlist(
                                self.session, connection["href"]).items():
                            yield s

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

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

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

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

        if episode_id:
            self.logger.debug("Loading streams for episode: {0}", episode_id)
            vpid = self.find_vpid(self.url, res=page_res)
            if vpid:
                self.logger.debug("Found VPID: {0}", vpid)
                for s in self.mediaselector(vpid):
                    yield s
            else:
                self.logger.error("Could not find VPID for episode {0}",
                                  episode_id)
        elif channel_name:
            self.logger.debug("Loading stream for live channel: {0}",
                              channel_name)
            tvip = self.find_tvip(self.url)
            if tvip:
                self.logger.debug("Found TVIP: {0}", tvip)
                for s in self.mediaselector(tvip):
                    yield s
Example #49
0
from streamlink.plugin.api.utils import parse_json
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
            }
Example #50
0
STATUS_OFFLINE = 0

#hls source is not stable, lower priority
STREAM_WEIGHTS = {"live": 1080}

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

_json_re = re.compile(r"window\.oPageConfig\.oRoom\s*=\s*({.+?});")

_roomID_schema = validate.Schema(
    validate.all(
        validate.transform(_json_re.search),
        validate.any(
            None,
            validate.all(
                validate.get(1), validate.transform(parse_json),
                {"id": validate.all(validate.text, validate.transform(int))
                 }))))

_room_schema = validate.Schema(
    {
        "data":
        validate.any(
            None, {
                "status": validate.all(validate.text, validate.transform(int)),
                "videoId": validate.text
            })
Example #51
0
    if not formatsmap:
        return formats

    for format in formatsmap.split(","):
        s = format.split("/")
        (w, h) = s[1].split("x")
        formats[int(s[0])] = "{0}p".format(h)

    return formats


_config_schema = validate.Schema(
    {
        validate.optional("fmt_list"): validate.all(
            validate.text,
            validate.transform(parse_fmt_list)
        ),
        validate.optional("url_encoded_fmt_stream_map"): validate.all(
            validate.text,
            validate.transform(parse_stream_map),
            [{
                "itag": validate.all(
                    validate.text,
                    validate.transform(int)
                ),
                "quality": validate.text,
                "url": validate.url(scheme="http"),
                validate.optional("s"): validate.text,
                validate.optional("stereo3d"): validate.all(
                    validate.text,
                    validate.transform(int),
import re

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

_url_re = re.compile(r"https?://(www\.)?ok\.ru/(live|video)/\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/ and for ok.ru VoDs: http://www.ok.ru/video/
    """
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url) is not None

    def _get_streams(self):
        headers = {'User-Agent': useragents.CHROME, 'Referer': self.url}

        hls = self.session.http.get(self.url, headers=headers, schema=_schema)
        if hls:
            hls = hls.replace(u'\\\\u0026', u'&')
        return HLSStream.parse_variant_playlist(self.session,
                                                hls,
Example #53
0
API_URL = "https://www.zhanqi.tv/api/static/v2.1/room/domain/{0}.json"

STATUS_ONLINE = 4
STATUS_OFFLINE = 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)
Example #54
0
class BTV(Plugin):
    options = PluginOptions({"username": None, "password": None})
    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 = 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 = 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 = 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")
Example #55
0
    "low": 540,
    "middle": 720,
    "source": 1080
}

_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,
Example #56
0
class WWENetwork(Plugin):
    url_re = re.compile(r"https?://network.wwe.com")
    content_id_re = re.compile(r'''"content_id" : "(\d+)"''')
    playback_scenario = "HTTP_CLOUD_WIRED"
    login_url = "https://secure.net.wwe.com/workflow.do"
    login_page_url = "https://secure.net.wwe.com/enterworkflow.do?flowId=account.login&forwardUrl=http%3A%2F%2Fnetwork.wwe.com"
    api_url = "https://ws.media.net.wwe.com/ws/media/mf/op-findUserVerifiedEvent/v-2.3"
    _info_schema = validate.Schema(
        validate.union({
            "status":
            validate.union({
                "code":
                validate.all(validate.xml_findtext(".//status-code"),
                             validate.transform(int)),
                "message":
                validate.xml_findtext(".//status-message"),
            }),
            "urls":
            validate.all(validate.xml_findall(".//url"),
                         [validate.getattr("text")]),
            validate.optional("fingerprint"):
            validate.xml_findtext(".//updated-fingerprint"),
            validate.optional("session_key"):
            validate.xml_findtext(".//session-key"),
            "session_attributes":
            validate.all(validate.xml_findall(".//session-attribute"), [
                validate.getattr("attrib"),
                validate.union({
                    "name": validate.get("name"),
                    "value": validate.get("value")
                })
            ])
        }))
    options = PluginOptions({
        "email": None,
        "password": None,
    })

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

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

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

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

        return self._authed

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

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

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

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

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

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

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

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

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

                if info.get("session_key"):
                    self.session_key = info.get("session_key")
                for url in info["urls"]:
                    for s in HLSStream.parse_variant_playlist(
                            self.session, url,
                            name_fmt="{pixels}_{bitrate}").items():
                        yield s
            else:
                raise PluginError(
                    "Could not load streams: {message} ({code})".format(
                        **info["status"]))
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(
        {
Example #58
0
    def _get_streams(self):
        parsed_html = self.session.http.get(self.url,
                                            schema=validate.Schema(
                                                validate.parse_html()))

        iframe_url = validate.validate(
            validate.Schema(
                validate.xml_xpath_string(
                    ".//script[contains(text(), '/embedIframeJs/')]/text()"),
                validate.any(
                    None,
                    validate.all(
                        validate.transform(self.iframe_url_re.search),
                        validate.any(
                            None, validate.all(validate.get(1),
                                               validate.url())),
                    )),
            ), parsed_html)

        if not iframe_url:
            return

        m = self.partner_ids_re.search(iframe_url)
        if not m:
            log.error("Failed to find partner IDs in IFRAME URL")
            return

        p = m.group(1)
        sp = m.group(2)

        json = self.session.http.get(
            iframe_url,
            schema=validate.Schema(
                validate.transform(self.json_re.search),
                validate.any(
                    None,
                    validate.all(
                        validate.get(1),
                        validate.transform(self.unescape_quotes),
                        validate.parse_json(),
                        validate.any(
                            {
                                "entryResult": {
                                    "contextData": {
                                        "isSiteRestricted": bool,
                                        "isCountryRestricted": bool,
                                        "isSessionRestricted": bool,
                                        "isIpAddressRestricted": bool,
                                        "isUserAgentRestricted": bool,
                                        "flavorAssets": [{
                                            "id": str,
                                        }],
                                    },
                                    "meta": {
                                        "id": str,
                                        "name": str,
                                        "categories": validate.any(None, str),
                                    },
                                },
                            }, {"error": str}),
                    )),
            ))

        if not json:
            return

        if "error" in json:
            log.error(f"API error: {json['error']}")
            return

        json = json.get("entryResult")

        if self.is_restricted(json["contextData"]):
            return

        self.id = json["meta"]["id"]
        self.title = json["meta"]["name"]
        self.author = validate.validate(
            validate.Schema(
                validate.xml_xpath_string(
                    ".//h1[contains(@class, 'btn-title')]/text()"), ),
            parsed_html)
        if json["meta"]["categories"]:
            self.category = json["meta"]["categories"]

        for asset in json["contextData"]["flavorAssets"]:
            yield from HLSStream.parse_variant_playlist(
                self.session,
                (f"https://cdnapisec.kaltura.com/p/{p}/sp/{sp}/playManifest/entryId/{json['meta']['id']}"
                 f"/flavorIds/{asset['id']}/format/applehttp/protocol/https/a.m3u8"
                 ),
                name_fmt="{pixels}_{bitrate}",
            ).items()
Example #59
0
from streamlink.stream import (HTTPStream, HLSStream)

USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
HUAJIAO_URL = "http://www.huajiao.com/l/{}"
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)
Example #60
0
    if not formatsmap:
        return formats

    for format in formatsmap.split(","):
        s = format.split("/")
        (w, h) = s[1].split("x")
        formats[int(s[0])] = "{0}p".format(h)

    return formats


_config_schema = validate.Schema(
    {
        validate.optional("fmt_list"): validate.all(
            validate.text,
            validate.transform(parse_fmt_list)
        ),
        validate.optional("url_encoded_fmt_stream_map"): validate.all(
            validate.text,
            validate.transform(parse_stream_map),
            [{
                "itag": validate.all(
                    validate.text,
                    validate.transform(int)
                ),
                "quality": validate.text,
                "url": validate.url(scheme="http"),
                validate.optional("s"): validate.text,
                validate.optional("stereo3d"): validate.all(
                    validate.text,
                    validate.transform(int),