Beispiel #1
0
    def _get_streams(self):
        channelid = urlparse(
            self.url).path.rstrip("/").rpartition("/")[-1].lower()

        self.logger.debug("Fetching stream info")
        headers = {"Referer": self.url}
        options = dict(id=channelid)
        res = urlget(self.StreamInfoURL, headers=headers, params=options)
        json = res_json(res, "stream info JSON")

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")

        if not ("rtmp" in json and "streamname" in json):
            raise NoStreamsError(self.url)

        if not RTMPStream.is_usable(self.session):
            raise PluginError(
                "rtmpdump is not usable and required by Owncast plugin")

        rtmp = json["rtmp"]
        playpath = json["streamname"]

        streams = {}
        streams["live"] = RTMPStream(
            self.session, {
                "rtmp": rtmp,
                "pageUrl": self.url,
                "swfUrl": self.SWFURL,
                "playpath": playpath,
                "live": True
            })

        return streams
Beispiel #2
0
    def _get_hls_streams(self):
        url = self.HLSStreamTokenURL.format(self.channelname)

        try:
            res = urlget(url,
                         params=dict(type="any", connection="wifi"),
                         exception=IOError)
        except IOError:
            self.logger.debug("HLS streams not available")
            return {}

        json = res_json(res, "stream token JSON")

        if not isinstance(json, list):
            raise PluginError("Invalid JSON response")

        if len(json) == 0:
            raise PluginError("No stream token in JSON")

        token = verifyjson(json[0], "token")
        hashed = hmac.new(self.HLSStreamTokenKey, bytes(token, "utf8"), sha1)
        fulltoken = hashed.hexdigest() + ":" + token
        url = self.HLSSPlaylistURL.format(self.channelname)

        try:
            params = dict(token=fulltoken, hd="true")
            playlist = HLSStream.parse_variant_playlist(self.session,
                                                        url,
                                                        params=params)
        except IOError as err:
            raise PluginError(err)

        return playlist
Beispiel #3
0
    def _get_player_params(self):
        res = urlopen(self.url)

        match = re.search("<param name=\"playerKey\" value=\"(.+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'playerKey' in player params")

        key = match.group(1)

        match = re.search("<param name=\"@videoPlayer\" value=\"(\d+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'videoPlayer' in player params")

        video_player = match.group(1)

        match = re.search("<param name=\"playerID\" value=\"(\d+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'playerID' in player params")

        player_id = match.group(1)

        match = re.search("<!-- live on -->", res.text)
        is_live = not not match

        return key, video_player, player_id, is_live
Beispiel #4
0
    def _get_streams(self):
        parsed = urlparse(self.url)

        if parsed.fragment:
            channelid = parsed.fragment
        else:
            channelid = parsed.path.rpartition("view/")[-1]

        if not channelid:
            raise NoStreamsError(self.url)

        channelid = channelid.lower().replace("/", "_")

        self.logger.debug("Fetching stream info")
        res = urlget(self.APIURL.format(channelid))
        json = res_json(res)

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")
        elif not ("success" in json and "payload" in json):
            raise PluginError("Invalid JSON response")
        elif json["success"] == False:
            raise NoStreamsError(self.url)

        streams = {}
        streams["live"] = HTTPStream(self.session, json["payload"])

        return streams
Beispiel #5
0
    def _get_player_params(self, retries=3):
        res = http.get(self.url)
        match = re.search("<param name=\"playerKey\" value=\"(.+)\" />",
                          res.text)
        if not match:
            # The HTML returned sometimes doesn't contain the parameters
            if not retries:
                raise PluginError("Missing key 'playerKey' in player params")
            else:
                return self._get_player_params(retries - 1)

        key = match.group(1)

        match = re.search("<param.+name=\"@videoPlayer\" value=\"(.+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'videoPlayer' in player params")
        video_player = match.group(1)

        match = re.search("<param name=\"playerID\" value=\"(\d+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'playerID' in player params")
        player_id = match.group(1)

        match = re.search("<!-- live on -->", res.text)
        if not match:
            match = re.search("<div id=\"channel_live\">", res.text)
        is_live = not not match

        return key, video_player, player_id, is_live
Beispiel #6
0
    def _create_flv_playlist(self, template):
        res = http.get(template)
        json = http.json(res)

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")

        parsed = urlparse(template)
        try:
            url_template = '{0}://{1}{2}'.format(parsed.scheme, parsed.netloc,
                                                 json['template'])
            segment_max = reduce(lambda i, j: i + j[0], json['fragments'], 0)
            duration = json['duration']
        except KeyError:
            raise PluginError('Unexpected JSON response')

        substreams = [
            HTTPStream(self.session,
                       url_template.replace('$fragment$', str(i)))
            for i in range(1, segment_max + 1)
        ]

        return FLVPlaylist(self.session,
                           streams=substreams,
                           duration=duration,
                           skip_header=True,
                           flatten_timestamps=True)
Beispiel #7
0
    def _get_vod_streams(self, channelname):
        res = http.get(self.url)
        match = re.search('autoURL%22%3A%22(.*?)%22', res.text)
        if not match:
            raise PluginError('Error retrieving manifest url')
        manifest_url = unquote(match.group(1)).replace('\\', '')

        try:
            res = http.get(manifest_url)
            manifest = http.json(res)
        except:
            raise PluginError('Error retrieving manifest')

        # A fallback host (http://proxy-xx...) is sometimes provided
        # that we could make us of.
        streams = {}
        for params in manifest.get('alternates', []):
            name = params.get('name')
            template = params.get('template')
            if not (name and template):
                continue

            name = '{0}p'.format(name)
            streams[name] = self._create_flv_playlist(template)

        return streams
Beispiel #8
0
    def _get_player_params(self):
        res = urlopen(self.url)

        match = re.search("<param name=\"playerKey\" value=\"(.+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'playerKey' in player params")

        key = match.group(1)

        match = re.search("<param name=\"@videoPlayer\" value=\"(\d+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'videoPlayer' in player params")

        video_player = match.group(1)

        match = re.search("<param name=\"playerID\" value=\"(\d+)\" />",
                          res.text)
        if not match:
            raise PluginError("Missing key 'playerID' in player params")

        player_id = match.group(1)

        match = re.search(
            "<img src=\".+/static/images/channels/live_check.png\" />",
            res.text)
        is_live = not not match

        return key, video_player, player_id, is_live
Beispiel #9
0
    def _get_rtmp_streams(self, text):
        match = re.search("streamer=(rtmp://.+?)&", text)
        if not match:
            raise PluginError(
                ("No RTMP streamer found on URL {0}").format(self.url))

        rtmp = match.group(1)

        match = re.search("<meta content=\"(http://.+?\.swf)\?", text)
        if not match:
            self.logger.warning(
                "Failed to get player SWF URL location on URL {0}", self.url)
        else:
            self.SWFURL = match.group(1)
            self.logger.debug("Found player SWF URL location {0}", self.SWFURL)

        match = re.search("<meta content=\"(.+)\" name=\"item-id\" />", text)
        if not match:
            raise PluginError(
                ("Missing channel item-id on URL {0}").format(self.url))

        res = http.get(self.APIURL.format(match.group(1), time()),
                       params=dict(output="json"))
        json = http.json(res)

        if not isinstance(json, list):
            raise PluginError("Invalid JSON response")

        rtmplist = {}

        for jdata in json:
            if "stream_name" not in jdata or "type" not in jdata:
                continue

            if "rtmp" not in jdata["type"]:
                continue

            playpath = jdata["stream_name"]

            if "token" in jdata and jdata["token"]:
                playpath += jdata["token"]

            if len(json) == 1:
                stream_name = "live"
            else:
                stream_name = jdata["stream_name"]

            rtmplist[stream_name] = RTMPStream(
                self.session, {
                    "rtmp": rtmp,
                    "pageUrl": self.url,
                    "swfVfy": self.SWFURL,
                    "playpath": playpath,
                    "live": True
                })

        return rtmplist
Beispiel #10
0
    def _get_streams(self):
        # If email option given, try to login
        if self.options.get("email"):
            res = http.get(self.LOGINPAGEURL)
            match = re.search('<meta content="([^"]+)" name="csrf-token"',
                              res.text)
            if not match:
                raise PluginError("Missing CSRF Token: " + self.LOGINPAGEURL)
            csrf_token = match.group(1)

            email = self.options.get("email")
            password = self.options.get("password")

            res = http.post(
                self.LOGINPOSTURL,
                data={
                    'authenticity_token': csrf_token,
                    'channel_id': '',
                    'commit': 'Login',
                    'plan_id': '',
                    'session[email]': email,
                    'session[password]': password,
                    'utf8': "\xE2\x9C\x93",  # Check Mark Character
                })

            self.logger.debug("Login account info: {0}", res.text)
            result = http.json(res)
            if result.get('email', 'no-mail') != email:
                raise PluginError("Invalid account")

        res = http.get(self.url)

        streams = {}

        if RTMPStream.is_usable(self.session):
            try:
                rtmpstreams = self._get_rtmp_streams(res.text)
                streams.update(rtmpstreams)
            except PluginError as err:
                self.logger.error("Error when fetching RTMP stream info: {0}",
                                  str(err))
        else:
            self.logger.warning(
                "rtmpdump is not usable, only HLS streams will be available")

        try:
            hlsstreams = self._get_hls_streams(res.text)
            streams.update(hlsstreams)
        except PluginError as err:
            self.logger.error("Error when fetching HLS stream info: {0}",
                              str(err))

        return streams
Beispiel #11
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        res = urlget(self.url)

        match = re.search("var current_channel = (.*);", res.text)
        if match:
            json = parse_json(match.group(1))
        else:
            raise NoStreamsError(self.url)

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")
        elif not "streams" in json:
            raise NoStreamsError(self.url)

        if not RTMPStream.is_usable(self.session):
            raise PluginError(
                "rtmpdump is not usable and required by Filmon plugin")

        match = re.search("var flash_config = (.*);", res.text)
        if match:
            config = parse_json(match.group(1))
            if "streamer" in config:
                self.SWFURL = urljoin(self.SWFURL, config["streamer"])

        streams = {}

        for stream in json["streams"]:
            if not ("url" in stream and "name" in stream):
                continue

            parsed = urlparse(stream["url"])

            if not parsed.scheme.startswith("rtmp"):
                continue

            if parsed.query:
                app = "{0}?{1}".format(parsed.path[1:], parsed.query)
            else:
                app = parsed.path[1:]

            name = stream["quality"]
            streams[name] = RTMPStream(
                self.session, {
                    "rtmp": stream["url"],
                    "pageUrl": self.url,
                    "swfUrl": self.SWFURL,
                    "playpath": stream["name"],
                    "app": app,
                    "live": True
                })

        return streams
Beispiel #12
0
    def _get_streams(self):
        country_code = urlparse(self.url).netloc.split(".")[0]

        self.logger.debug("Fetching stream info")
        res = urlget(self.APIURL)
        json = res_json(res)

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")
        elif not ("primary" in json or "secondary" in json):
            raise PluginError("Invalid JSON response")

        if not RTMPStream.is_usable(self.session):
            raise PluginError(
                "rtmpdump is not usable and required by Euronews plugin")

        streams = {}

        self.logger.debug("Euronews Countries:{0}",
                          " ".join(json["primary"].keys()))

        if not (country_code in json["primary"]
                or country_code in json["secondary"]):
            res = urlget(self.GEOIPURL)
            geo = res_json(res)
            if isinstance(json, dict) and "country_code" in geo:
                country_code = geo["country_code"].lower()
                if not (country_code in json["primary"]
                        or country_code in json["secondary"]):
                    country_code = "en"
            else:
                country_code = "en"

        for site in ("primary", "secondary"):
            for quality in json[site][country_code]["rtmp_flash"]:
                stream = json[site][country_code]["rtmp_flash"][quality]
                name = quality + "k"
                if site == "secondary":
                    name += "_alt"
                streams[name] = RTMPStream(
                    self.session, {
                        "rtmp": stream["server"],
                        "playpath": stream["name"],
                        "swfUrl": self.SWFURL,
                        "live": True
                    })

        if len(streams) == 0:
            raise NoStreamsError(self.url)

        return streams
Beispiel #13
0
    def _get_player_params(self, retries=5):
        try:
            res = http.get(self.url, headers=HTTP_HEADERS)
        except PluginError as err:
            # The server sometimes gives us 404 for no reason
            if "404" in str(err) and retries:
                sleep(1)
                return self._get_player_params(retries - 1)
            else:
                raise

        match = re.search("<param name=\"playerKey\" value=\"(.+)\" />",
                          res.text)
        if not match:
            # The HTML returned sometimes doesn't contain the parameters
            if not retries:
                raise PluginError("Missing key 'playerKey' in player params")
            else:
                sleep(1)
                return self._get_player_params(retries - 1)

        key = match.group(1)
        match = re.search("AZUBU.setVar\(\"firstVideoRefId\", \"(.+)\"\);",
                          res.text)
        if not match:
            # The HTML returned sometimes doesn't contain the parameters
            if not retries:
                raise PluginError("Unable to find video reference")
            else:
                sleep(1)
                return self._get_player_params(retries - 1)

        video_player = "ref:" + match.group(1)
        match = re.search("<param name=\"playerID\" value=\"(\d+)\" />",
                          res.text)
        if not match:
            # The HTML returned sometimes doesn't contain the parameters
            if not retries:
                raise PluginError("Missing key 'playerID' in player params")
            else:
                sleep(1)
                return self._get_player_params(retries - 1)

        player_id = match.group(1)
        match = re.search("<!-- live on -->", res.text)
        if not match:
            match = re.search("<div id=\"channel_live\">", res.text)
        is_live = not not match

        return key, video_player, player_id, is_live
Beispiel #14
0
    def _get_streams_from_amf(self):
        if not RTMPStream.is_usable(self.session):
            raise NoStreamsError(self.url)

        res = urlget(AMF_URL.format(self.channel_id))

        try:
            packet = AMFPacket.deserialize(BytesIO(res.content))
        except (IOError, AMFError) as err:
            raise PluginError("Failed to parse AMF packet: {0}".format(err))

        for message in packet.messages:
            if message.target_uri == "/1/onResult":
                result = message.value
                break
        else:
            raise PluginError("No result found in AMF packet")

        streams = {}
        stream_name = result.get("streamName")
        if stream_name:
            cdn = result.get("cdnUrl") or result.get("fmsUrl")
            if cdn:
                stream = self._create_rtmp_stream(cdn, stream_name)

                if "videoCodec" in result and result["videoCodec"][
                        "height"] > 0:
                    stream_name = "{0}p".format(
                        int(result["videoCodec"]["height"]))
                else:
                    stream_name = "live"

                streams[stream_name] = stream
            else:
                self.logger.warning("Missing cdnUrl and fmsUrl from result")

        stream_versions = result.get("streamVersions")
        if stream_versions:
            for version, info in stream_versions.items():
                stream_version_cdn = info.get("streamVersionCdn", {})

                for name, cdn in filter(valid_cdn, stream_version_cdn.items()):
                    stream = self._create_rtmp_stream(cdn["cdnStreamUrl"],
                                                      cdn["cdnStreamName"])
                    stream_name = "live_alt_{0}".format(name)
                    streams[stream_name] = stream

        return streams
Beispiel #15
0
    def _get_rtmp_streams(self, channelname):
        options = dict(l="info",
                       a="xmlClipPath",
                       clip_id=channelname,
                       rid=time())
        res = urlget(self.APIURL, params=options)

        dom = res_xml(res)
        rtmpurl = dom.getElementsByTagName("url")
        rtmp = None

        if len(rtmpurl) > 0:
            rtmp = get_node_text(rtmpurl[0])
        else:
            raise PluginError(
                ("No RTMP Streams found on URL {0}").format(self.url))

        rtmplist = {}
        rtmplist["live"] = RTMPStream(self.session, {
            "rtmp": rtmp,
            "swfVfy": self.SWFURL,
            "live": True
        })

        return rtmplist
Beispiel #16
0
    def _get_live_streams(self):
        self._authenticate()
        sig, token = self._access_token()
        url = self.usher.select(self.channel,
                                password=self.options.get("password"),
                                nauthsig=sig,
                                nauth=token)

        try:
            streams = HLSStream.parse_variant_playlist(self.session, url)
        except IOError as err:
            err = str(err)
            if "404 Client Error" in err or "Failed to parse playlist" in err:
                return
            else:
                raise PluginError(err)

        try:
            token = parse_json(token)
            chansub = verifyjson(token, "chansub")
            restricted_bitrates = verifyjson(chansub, "restricted_bitrates")

            for name in filter(
                    lambda n: not re.match(r"(.+_)?archives|live", n),
                    restricted_bitrates):
                self.logger.warning(
                    "The quality '{0}' is not available "
                    "since it requires a subscription.", name)
        except PluginError:
            pass

        return dict(starmap(self._check_stream_name, streams.items()))
Beispiel #17
0
    def _get_live_streams(self):
        self._authenticate()
        sig, token = self._access_token()
        url = self.usher.select(self.channel,
                                password=self.options.get("password"),
                                nauthsig=sig,
                                nauth=token)

        try:
            streams = HLSStream.parse_variant_playlist(self.session, url)
        except IOError as err:
            err = str(err)
            if "404 Client Error" in err or "Failed to parse playlist" in err:
                return
            else:
                raise PluginError(err)

        try:
            token = parse_json(token, schema=_token_schema)
            for name in token["restricted_bitrates"]:
                if name not in streams:
                    self.logger.warning("The quality '{0}' is not available "
                                        "since it requires a subscription.",
                                        name)
        except PluginError:
            pass

        return dict(starmap(self._check_stream_name, streams.items()))
Beispiel #18
0
    def _get_streams(self):
        if not CAN_DECRYPT:
            raise PluginError("Need pyCrypto installed to decrypt streams")

        json = self._get_stream_info(self.url)

        if not json:
            return

        if json.get("status", 0) == 0:
            return

        parts = []
        for media in json.get("media", []):
            if media.get("id") < 0:
                continue
            for part in media.get("parts", []):
                if part.get("duration") < 0:
                    continue
                parts.append(part)

        if not parts:
            return

        streams = {}
        for quality in QUALITY_MAP:
            streams[quality] = BeatStream(self.session, parts, quality)

        return streams
Beispiel #19
0
    def _get_streams(self):
        if not RTMPStream.is_usable(self.session):
            raise PluginError(
                "rtmpdump is not usable and required by Filmon plugin")

        self.logger.debug("Fetching stream info")
        res = http.get(self.url)

        match = re.search("movie_id=(\d+)", res.text)
        if match:
            return self._get_vod_stream(match.group(1))

        match = re.search("/channels/(\d+)/extra_big_logo.png", res.text)
        if not match:
            return

        channel_id = match.group(1)
        streams = {}
        for quality in ("low", "high"):
            try:
                streams[quality] = self._get_stream(channel_id, quality)
            except NoStreamsError:
                pass

        return streams
Beispiel #20
0
    def _get_hls_streams(self, type="live"):
        self._authenticate()
        sig, token = self._access_token(type)
        if type == "live":
            url = self.usher.channel(self.channel, sig=sig, token=token)
        elif type == "video":
            url = self.usher.video(self.video_id, nauthsig=sig, nauth=token)

        try:
            streams = HLSStream.parse_variant_playlist(self.session, url)
        except IOError as err:
            err = str(err)
            if "404 Client Error" in err or "Failed to parse playlist" in err:
                return
            else:
                raise PluginError(err)

        try:
            token = parse_json(token, schema=_token_schema)
            for name in token["restricted_bitrates"]:
                if name not in streams:
                    self.logger.warning(
                        "The quality '{0}' is not available "
                        "since it requires a subscription.", name)
        except PluginError:
            pass

        return streams
Beispiel #21
0
    def _get_swf_url(self):
        res = http.get(self.url)
        match = _swf_url_re.search(res.text)
        if not match:
            raise PluginError("Unable to find SWF URL in the HTML")

        return match.group(1)
Beispiel #22
0
    def _create_gox_params(self, flashvars, level):
        flashvars["adstate"] = "0"
        flashvars["goxkey"] = self.GOXHashKey
        flashvars["level"] = str(level)

        keys = [
            "leagueid", "conid", "goxkey", "level", "uno", "uip", "adstate"
        ]

        if "playmode" in flashvars and flashvars["playmode"] == "vod":
            keys += ["vjoinid", "nid"]

        goxkey = hashlib.md5()
        params = {}

        for key in keys:
            if not key in flashvars:
                raise PluginError(
                    ("Missing key '{0}' in flashvars").format(key))

            goxkey.update(bytes(flashvars[key], "ascii"))
            params[key] = flashvars[key]

        params["goxkey"] = goxkey.hexdigest()

        return params
Beispiel #23
0
    def _get_streams(self):
        channelname = urlparse(
            self.url).path.rstrip("/").rpartition("/")[-1].lower()

        self.logger.debug("Fetching stream info")

        headers = {"Referer": self.url}

        res = urlget(self.PlayerURL.format(channelname), headers=headers)
        match = re.search("'FlashVars', '(id=\d+)&", res.text)
        if not match:
            raise NoStreamsError(self.url)

        channelname += "?" + match.group(1)
        res = urlget(self.BalancerURL, headers=headers)

        match = re.search("redirect=(.+)", res.text)
        if not match:
            raise PluginError(
                "Error retrieving RTMP address from loadbalancer")

        rtmp = match.group(1)
        streams = {}
        streams["live"] = RTMPStream(
            self.session, {
                "rtmp": "rtmp://{0}/live/{1}".format(rtmp, channelname),
                "pageUrl": self.url,
                "swfVfy": self.SWFURL,
                "conn": "S:OK",
                "live": True
            })

        return streams
Beispiel #24
0
    def _parse_event_url(self, prefix, data):
        match = re.search(' \"(.*)\";', data)

        if not match:
            raise PluginError("Event live page URL not found")

        return urljoin(prefix, match.group(1))
Beispiel #25
0
    def _authenticate(self, username=None, password=None, cookies=None):
        if (username is None or password is None) and cookies is None:
            raise PluginError(
                "GOMTV.net requires a username and password or a cookie")

        if cookies is not None:
            for cookie in cookies.split(";"):
                try:
                    name, value = cookie.split("=")
                except ValueError:
                    continue

                self.rsession.cookies[name.strip()] = value.strip()

            self.logger.info("Attempting to authenticate with cookies")
        else:
            form = dict(cmd="login",
                        rememberme="1",
                        mb_username=username,
                        mb_password=password)

            self.logger.info(
                "Attempting to authenticate with username and password")

            urlopen(self.LoginURL,
                    data=form,
                    headers=self.LoginHeaders,
                    session=self.rsession)

        res = urlget(self.LoginCheckURL, session=self.rsession)

        if "Please need login" in res.text:
            raise PluginError("Authentication failed")

        if "SES_USERNICK" in self.rsession.cookies:
            username = self.rsession.cookies["SES_USERNICK"]
            self.logger.info(
                ("Successfully logged in as {0}").format(username))

        if username and password:
            cookie = ""
            for v in ("SES_MEMBERNO", "SES_STATE", "SES_MEMBERNICK",
                      "SES_USERNICK"):
                if v in self.rsession.cookies:
                    cookie += "{0}={1}; ".format(v, self.rsession.cookies[v])

            self.logger.info("Cookie for reusing this session: {0}", cookie)
Beispiel #26
0
    def _get_hls_streams(self, text):
        match = re.search("\"(http://.+\.m3u8)\"", text)
        if not match:
            raise PluginError(
                ("No HLS playlist found on URL {0}").format(self.url))

        playlisturl = match.group(1)
        self.logger.debug("Playlist URL is {0}", playlisturl)
        playlist = {}

        try:
            playlist = HLSStream.parse_variant_playlist(
                self.session, playlisturl)
        except IOError as err:
            raise PluginError(err)

        return playlist
Beispiel #27
0
    def _parse_result(self, res):
        streams = {}

        if not hasattr(res, "programmedContent"):
            raise PluginError("Invalid result")

        player = res.programmedContent["videoPlayer"]

        if not hasattr(player, "mediaDTO"):
            raise PluginError("Invalid result")

        for i, rendition in player.mediaDTO.renditions.items():
            stream = AkamaiHDStream(self.session, rendition.defaultURL)
            streamname = "{0}p".format(rendition.frameHeight)
            streams[streamname] = stream

        return streams
Beispiel #28
0
    def _get_hls_streams(self):
        url = self.HLSStreamTokenURL.format(self.channelname)

        try:
            res = urlget(url,
                         params=dict(type="iphone",
                                     connection="wifi",
                                     allow_cdn="true"),
                         exception=IOError)
        except IOError:
            self.logger.debug("HLS streams not available")
            return {}

        json = res_json(res, "stream token JSON")

        if not isinstance(json, list):
            raise PluginError("Invalid JSON response")

        if len(json) == 0:
            raise PluginError("No stream token in JSON")

        token = verifyjson(json[0], "token")
        hashed = hmac.new(self.HLSStreamTokenKey, bytes(token, "utf8"), sha1)
        fulltoken = hashed.hexdigest() + ":" + token
        url = self.HLSSPlaylistURL.format(self.channelname)

        try:
            params = dict(token=fulltoken, hd="true", allow_cdn="true")
            playlist = HLSStream.parse_variant_playlist(self.session,
                                                        url,
                                                        params=params)
        except IOError as err:
            if "404" in err:
                raise PluginError(err)
            else:
                self.logger.debug("Requesting mobile transcode")

                payload = dict(channel=self.channelname, type="iphone")
                urlopen("http://usher.twitch.tv/stream/transcode_iphone.json",
                        data=payload)

                return {}

        return playlist
Beispiel #29
0
    def _parse_result(self, res):
        streams = {}

        if not hasattr(res, "programmedContent"):
            raise PluginError("Invalid result")

        player = res.programmedContent["videoPlayer"]

        if not hasattr(player, "mediaDTO"):
            raise PluginError("Invalid result")

        renditions = sorted(player.mediaDTO.renditions.values(),
                            key=attrgetter("encodingRate"))

        for stream_name, rendition in zip(STREAM_NAMES, renditions):
            stream = AkamaiHDStream(self.session, rendition.defaultURL)
            streams[stream_name] = stream

        return streams
Beispiel #30
0
    def _check_channel_live(self, channelname):
        url = self.MetadataURL.format(channelname)
        res = urlget(url, params=dict(fields="mode"))
        json = res_json(res)

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")

        mode = verifyjson(json, "mode")

        return mode == "live"