Exemple #1
0
    def _choose_server(self, json):
        res = urlget(self.GEOIPURL)
        loc = res_json(res)
        loc = [loc["latitude"], loc["longitude"]]
        sel_dist = float("inf")
        i = 0
        primary = -1
        secondary = -1

        for server in json["server"]:
            res = urlget(self.GEOURL+server["server"]["name"]+"&sensor=false")
            cord = res_json(res)
            cord = [cord["results"][0]["geometry"]["location"]["lat"], cord["results"][0]["geometry"]["location"]["lng"]]
            cur_dist = self._distance(loc, cord)

            if cur_dist < sel_dist:
                sel_dist = cur_dist

                if server["server"]["used"] < 90:
                    # nearest server with load < 90%
                    primary = i
                else:
                    # nearest server with load > 90%
                    secondary = i

            i += 1

        if primary == -1:
            # if all servers have load over 90% use nearest one
            return secondary

        return primary
Exemple #2
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        media_is_live = 0

        match = re.search(r".*hitbox.tv/([^/]*)/?(\d+)?", self.url)
        if not match:
            raise NoStreamsError(self.url)

        stream_name, media_id = match.groups()

        if stream_name != "video":
            res = urlget(LIVE_API.format(stream_name))
            json = res_json(res)
            livestream = verifyjson(json, "livestream")
            media_id = verifyjson(livestream[0], "media_id")
            media_is_live = int(verifyjson(livestream[0], "media_is_live"))
            if not media_is_live:
                raise NoStreamsError(self.url)

        media_type = "live" if media_is_live else "video"
        res = urlget(PLAYER_API.format(media_type, media_id))
        json = res_json(res)
        clip = verifyjson(json, "clip")
        live = verifyjson(clip, "live")
        bitrates = verifyjson(clip, "bitrates")

        streams = {}
        if live:
            for bitrate in bitrates:
                connection_provider = clip.get("connectionProvider",
                                               "clustering")
                plugins = verifyjson(json, "plugins")
                provider_plugin = verifyjson(plugins, connection_provider)
                swf = verifyjson(provider_plugin, "url")
                rtmp = verifyjson(provider_plugin, "netConnectionUrl")
                quality = self._get_quality(verifyjson(bitrate, "label"))
                url = verifyjson(bitrate, "url")

                streams[quality] = RTMPStream(
                    self.session, {
                        "rtmp": rtmp,
                        "pageUrl": self.url,
                        "playpath": url,
                        "swfVfy": SWF_BASE + swf,
                        "live": True
                    })
        else:
            for bitrate in bitrates:
                base_url = verifyjson(clip, "baseUrl")
                url = verifyjson(bitrate, "url")
                quality = self._get_quality(verifyjson(bitrate, "label"))
                streams[quality] = HTTPStream(self.session,
                                              base_url + "/" + url)

        return streams
Exemple #3
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        media_is_live = 0

        match = re.search(r".*hitbox.tv/([^/]*)/?(\d+)?", self.url)
        if not match:
            raise NoStreamsError(self.url)

        stream_name, media_id = match.groups()

        if stream_name != "video":
            res = urlget(LIVE_API.format(stream_name))
            json = res_json(res)
            livestream = verifyjson(json, "livestream")
            media_id = verifyjson(livestream[0], "media_id")
            media_is_live = int(verifyjson(livestream[0], "media_is_live"))
            if not media_is_live:
                raise NoStreamsError(self.url)

        media_type = "live" if media_is_live else "video"
        res = urlget(PLAYER_API.format(media_type, media_id))
        json = res_json(res)
        clip = verifyjson(json, "clip")
        live = verifyjson(clip, "live")
        bitrates = verifyjson(clip, "bitrates")

        streams = {}
        if live:
            for bitrate in bitrates:
                connection_provider = clip.get("connectionProvider", "clustering")
                plugins = verifyjson(json, "plugins")
                provider_plugin = verifyjson(plugins, connection_provider)
                swf = verifyjson(provider_plugin, "url")
                rtmp = verifyjson(provider_plugin, "netConnectionUrl")
                quality = self._get_quality(verifyjson(bitrate, "label"))
                url = verifyjson(bitrate, "url")

                streams[quality] = RTMPStream(self.session, {
                    "rtmp": rtmp,
                    "pageUrl": self.url,
                    "playpath": url,
                    "swfVfy": SWF_BASE + swf,
                    "live": True
                })
        else:
            for bitrate in bitrates:
                base_url = verifyjson(clip, "baseUrl")
                url = verifyjson(bitrate, "url")
                quality = self._get_quality(verifyjson(bitrate, "label"))
                streams[quality] = HTTPStream(self.session,
                                              base_url + "/" + url)

        return streams
Exemple #4
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
Exemple #5
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        res = urlget(self.url, params=dict(output="json"))
        json = res_json(res)

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

        streams = {}
        video = verifyjson(json, "video")
        videos = verifyjson(video, "videoReferences")

        for video in videos:
            if not ("url" in video and "playerType" in video):
                continue

            if video["playerType"] == "flash":
                if video["url"].startswith("rtmp"):
                    stream = RTMPStream(
                        self.session,
                        {"rtmp": video["url"], "pageUrl": self.PageURL, "swfVfy": self.SWFURL, "live": True},
                    )
                    streams[str(video["bitrate"]) + "k"] = stream
            elif video["playerType"] == "ios":
                try:
                    hlsstreams = HLSStream.parse_variant_playlist(self.session, video["url"])
                    streams.update(hlsstreams)
                except IOError as err:
                    self.logger.warning("Failed to get variant playlist: {0}", err)

        return streams
Exemple #6
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
Exemple #7
0
    def _get_stream(self, channel_id, quality):
        params = dict(channel_id=channel_id, quality=quality)
        res = urlopen(CHINFO_URL, data=params, headers=AJAX_HEADERS,
                      session=self.rsession)
        json = res_json(res)

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

        info = json[0]
        rtmp = info.get("serverURL")
        playpath = info.get("streamName")
        if not (rtmp and playpath):
            raise NoStreamsError(self.url)

        app = self._get_rtmp_app(rtmp)
        if not app:
            raise NoStreamsError(self.url)

        return RTMPStream(self.session, {
            "rtmp": rtmp,
            "pageUrl": self.url,
            "swfUrl": SWF_URL,
            "playpath": playpath,
            "app": app,
            "live": True
        })
Exemple #8
0
    def _get_vod_stream(self, movie_id):
        res = urlopen(VODINFO_URL.format(movie_id), headers=AJAX_HEADERS,
                      session=self.rsession)
        json = res_json(res)
        json = json and json.get("data")
        json = json and json.get("streams")

        if not json:
            raise NoStreamsError(self.url)

        streams = {}
        for quality in ("low", "high"):
            stream = json.get(quality)
            if not stream:
                continue

            rtmp = stream.get("url")
            app = self._get_rtmp_app(rtmp)
            if not app:
                continue

            playpath = stream.get("name")
            if ".mp4" in playpath:
                playpath = "mp4:" + playpath

            streams[quality] = RTMPStream(self.session, {
                "rtmp": rtmp,
                "pageUrl": self.url,
                "swfUrl": SWF_URL,
                "playpath": playpath,
                "app": app,
            })

        return streams
Exemple #9
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
Exemple #10
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
Exemple #11
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        res = urlget(self.url)

        match = re.search("flashplayer: \"(.+.swf)\".+streamer: \"(.+)\".+file: \"(.+).flv\"", res.text, re.DOTALL)
        if not match:
            raise NoStreamsError(self.url)

        params = {
            "rtmp": match.group(2),
            "pageUrl": self.url,
            "swfVfy": match.group(1),
            "playpath" : match.group(3),
            "live": True
        }

        match = re.search("(http(s)?://.+/server/server.php\?id=\d+)",
                          res.text)
        if match:
            token_url = match.group(1)
            res = res_json(urlget(token_url, headers=dict(Referer=self.url)))
            token = res.get("token")
            if token:
                params["token"] = token

        streams = {}
        streams["live"] = RTMPStream(self.session, params, redirect=True)

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

        match = re.search(
            "flashplayer: \"(.+.swf)\".+streamer: \"(.+)\".+file: \"(.+).flv\"",
            res.text, re.DOTALL)
        if not match:
            raise NoStreamsError(self.url)

        params = {
            "rtmp": match.group(2),
            "pageUrl": self.url,
            "swfVfy": match.group(1),
            "playpath": match.group(3),
            "live": True
        }

        match = re.search("(http(s)?://.+/server.php\?id=\d+)", res.text)
        if match:
            token_url = match.group(1)
            res = res_json(urlget(token_url, headers=dict(Referer=self.url)))
            token = res.get("token")
            if token:
                params["token"] = token

        streams = {}
        streams["live"] = RTMPStream(self.session, params)

        return streams
Exemple #13
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
Exemple #14
0
    def _get_streams(self):
        res = urlget(self.url)
        channel_id = self._find_channel_id(res.text)
        if not channel_id:
            return

        stream_id = self._get_stream_id(channel_id)
        if not stream_id:
            return

        res = urlget(STREAM_API_URL.format(stream_id),
                     params=dict(format="all"))
        json = res_json(res)
        data = verifyjson(json, "data")
        items = verifyjson(data, "items")

        streams = {}
        for stream in filter(valid_stream, items):
            parser = STREAM_TYPES[stream["format"]]

            try:
                streams.update(parser(self.session, stream["url"]))
            except IOError as err:
                if not re.search(r"(404|400) Client Error", str(err)):
                    self.logger.error("Failed to extract {0} streams: {1}",
                                      stream["format"].upper(), err)

        return streams
    def find(self, channel, password=None, **extra_params):
        url = self.url(USHER_FIND_PATH, channel)
        params = dict(p=int(random() * 999999), type="any",
                      private_code=password or "null", **extra_params)

        return res_json(urlget(url, params=params),
                        "stream info JSON")
Exemple #16
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")

        streams = {}

        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
Exemple #17
0
    def _get_stream(self, channel_id, quality):
        params = dict(channel_id=channel_id, quality=quality)
        res = urlopen(CHINFO_URL, data=params, headers=AJAX_HEADERS,
                      session=self.rsession)
        json = res_json(res)

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

        info = json[0]
        rtmp = info.get("serverURL")
        playpath = info.get("streamName")
        if not (rtmp and playpath):
            raise NoStreamsError(self.url)

        parsed = urlparse(rtmp)
        if not parsed.scheme.startswith("rtmp"):
            raise NoStreamsError(self.url)

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

        return RTMPStream(self.session, {
            "rtmp": rtmp,
            "pageUrl": self.url,
            "swfUrl": SWF_URL,
            "playpath": playpath,
            "app": app,
            "live": True
        })
Exemple #18
0
    def _get_streams_from_id(self, stream_id):
        res = urlget(CONFIG_URL, params=dict(id=stream_id))
        config = res_json(res)
        media = verifyjson(config, "media")

        if not (media and isinstance(media, list)):
            return

        streams = {}
        media = media[0]
        hds_manifest = media.get("name")
        hls_manifest = media.get("hlsUrl")

        if hds_manifest:
            try:
                hds_streams = HDSStream.parse_manifest(self.session,
                                                       hds_manifest)
                streams.update(hds_streams)
            except IOError as err:
                if not re.search(r"(404|400) Client Error", str(err)):
                    self.logger.error("Failed to parse HDS manifest: {0}", err)

        if hls_manifest:
            try:
                hls_streams = HLSStream.parse_variant_playlist(self.session,
                                                               hls_manifest,
                                                               nameprefix="mobile_")
                streams.update(hls_streams)
            except IOError as err:
                if not re.search(r"(404|400) Client Error", str(err)):
                    self.logger.error("Failed to parse HLS playlist: {0}", err)

        return streams
    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}", sel.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 = urlget(self.APIURL.format(match.group(1), time()),
                     params=dict(output="json"))
        json = res_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
Exemple #20
0
    def call(self, path, **extra_params):
        params = dict(as3="t", **extra_params)

        if self.oauth_token:
            params["oauth_token"] = self.oauth_token

        url = "{0}{1}.json".format(TWITCH_API_HOST, path)
        res = urlget(url, params=params, session=self.session)

        return res_json(res)
    def _get_rtmp_streams(self):
        chansub = self._authenticate()

        url = self.StreamInfoURL.format(self.channelname)
        params = dict(
            b_id="true",
            group="",
            private_code="null",
            p=int(random.random() * 999999),
            channel_subscription=chansub,
            type="any",
        )

        self.logger.debug("Fetching stream info")
        res = urlget(url, params=params)
        json = res_json(res, "stream info JSON")

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

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

        streams = {}
        swfurl, swfhash, swfsize = self._verify_swf()

        for info in json:
            if not ("connect" in info and "play" in info and "type" in info):

                continue

            stream = RTMPStream(
                self.session,
                {
                    "rtmp": ("{0}/{1}").format(info["connect"], info["play"]),
                    "swfUrl": swfurl,
                    "swfhash": swfhash,
                    "swfsize": swfsize,
                    "live": True,
                },
            )

            if "display" in info:
                sname = info["display"]
            else:
                sname = info["type"]

            if "token" in info:
                stream.params["jtv"] = info["token"]
            else:
                self.logger.warning("No token found for stream {0}, this stream may fail to play", sname)

            streams[sname] = stream

        return streams
    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"
Exemple #23
0
    def _get_rtmp_streams(self):
        chansub = self._authenticate()

        url = self.StreamInfoURL.format(self.channelname)
        params = dict(b_id="true",
                      group="",
                      private_code="null",
                      p=int(random.random() * 999999),
                      channel_subscription=chansub,
                      type="any")

        self.logger.debug("Fetching stream info")
        res = urlget(url, params=params)
        json = res_json(res, "stream info JSON")

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

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

        streams = {}
        swfurl, swfhash, swfsize = self._verify_swf()

        for info in json:
            if not ("connect" in info and "play" in info and "type" in info):

                continue

            stream = RTMPStream(
                self.session, {
                    "rtmp": ("{0}/{1}").format(info["connect"], info["play"]),
                    "swfUrl": swfurl,
                    "swfhash": swfhash,
                    "swfsize": swfsize,
                    "live": True
                })

            if "display" in info:
                sname = info["display"]
            else:
                sname = info["type"]

            if "token" in info:
                stream.params["jtv"] = info["token"]
            else:
                self.logger.warning(
                    "No token found for stream {0}, this stream may fail to play",
                    sname)

            streams[sname] = stream

        return streams
Exemple #24
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}", sel.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 = urlget(self.APIURL.format(match.group(1), time()), params=dict(output="json"))
        json = res_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
Exemple #25
0
    def _get_stream_id(self, channel_id):
        res = urlget(CONFIG_API_URL, params=dict(id=channel_id))
        config = res_json(res)
        media = verifyjson(config, "media")

        if not (media and isinstance(media, list)):
            return

        media = media[0]
        if not isinstance(media, dict):
            return

        return media.get("channel")
    def call(self, path, format="json", host=None, **extra_params):
        params = dict(as3="t", **extra_params)

        if self.oauth_token:
            params["oauth_token"] = self.oauth_token

        url = "https://api.{0}{1}.{2}".format(host or self.host, path, format)
        res = urlget(url, params=params, session=self.session)

        if format == "json":
            return res_json(res)
        elif format == "xml":
            return res_xml(res)
        else:
            return res
Exemple #27
0
    def call(self, path, format="json", host=None, **extra_params):
        params = dict(as3="t", **extra_params)

        if self.oauth_token:
            params["oauth_token"] = self.oauth_token

        url = "https://api.{0}{1}.{2}".format(host or self.host, path, format)
        res = urlget(url, params=params, session=self.session)

        if format == "json":
            return res_json(res)
        elif format == "xml":
            return res_xml(res)
        else:
            return res
Exemple #28
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        res = urlget(self.url, params=dict(output="json"))
        json = res_json(res)

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

        streams = {}
        video = verifyjson(json, "video")
        videos = verifyjson(video, "videoReferences")

        for video in videos:
            if not ("url" in video and "playerType" in video):
                continue

            url = video["url"]

            if video["playerType"] == "flash":
                if url.startswith("rtmp"):
                    stream = RTMPStream(
                        self.session, {
                            "rtmp": url,
                            "pageUrl": self.PageURL,
                            "swfVfy": self.SWFURL,
                            "live": True
                        })
                    streams[str(video["bitrate"]) + "k"] = stream
                elif "manifest.f4m" in url:
                    try:
                        hdsstreams = HDSStream.parse_manifest(
                            self.session, url)
                        streams.update(hdsstreams)
                    except IOError as err:
                        self.logger.warning("Failed to get HDS manifest: {0}",
                                            err)

            elif video["playerType"] == "ios":
                try:
                    hlsstreams = HLSStream.parse_variant_playlist(
                        self.session, url)
                    streams.update(hlsstreams)
                except IOError as err:
                    self.logger.warning("Failed to get variant playlist: {0}",
                                        err)

        return streams
Exemple #29
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
    def create_playlist_token(self, channel):
        url = self.url(HLS_TOKEN_PATH, channel)
        params = dict(type="iphone", allow_cdn="true")

        try:
            res = urlget(url, params=params, exception=IOError)
        except IOError:
            return None

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

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

        token = verifyjson(json[0], "token")
        hashed = hmac.new(HLS_TOKEN_KEY,
                          bytes(token, "utf8"),
                          sha1)

        return "{0}:{1}".format(hashed.hexdigest(), token)
Exemple #31
0
    def _get_streams(self):
        if not RTMPStream.is_usable(self.session):
            raise PluginError("rtmpdump is not usable and required by Hashd plugin")
        
        self.logger.debug("Fetching stream info")
        res = urlget(self.url.rstrip("/").lower()+".json?first=true")
        json = res_json(res)

        if not isinstance(json, dict):
            raise PluginError("Invalid JSON response")
        elif not ("live" in json or "file" in json):
            raise PluginError("Invalid JSON response")
     
        if "file" in json:
            streams = self._parse_vod(json)
        elif json["live"]:
            streams = self._parse_live(json)
        else:
            raise NoStreamsError(self.url)
           
        return streams
Exemple #32
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.HLSPlaylistURL.format(self.channelname)

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

                payload = dict(channel=self.channelname, type="iphone")
                urlopen(self.HLSTranscodeRequest, data=payload)

                return {}

        return playlist
Exemple #33
0
    def _api_call(self, entrypoint, params):
        '''Makes a call against the api.
        :param entrypoint: API method to call.
        :param params: parameters to include in the request data.
        '''
        url = API_URL.format(entrypoint)

        # default params
        params.update({
            'version': API_VERSION,
            'locale': API_LOCALE,
        })

        if self.session_id:
            params['session_id'] = self.session_id

        response = utils.urlget(url, params=params, session=self.session)
        json_response = utils.res_json(response)

        if json_response['error']:
            raise APIError(json_response['message'])

        return json_response
Exemple #34
0
    def _api_call(self, entrypoint, params):
        '''Makes a call against the api.
        :param entrypoint: API method to call.
        :param params: parameters to include in the request data.
        '''
        url = API_URL.format(entrypoint)

        # default params
        params.update({
            'version': API_VERSION,
            'locale': API_LOCALE,
        })

        if self.session_id:
            params['session_id'] = self.session_id

        response = utils.urlget(url, params=params, session=self.session)
        json_response = utils.res_json(response)

        if json_response['error']:
            raise APIError(json_response['message'])

        return json_response
Exemple #35
0
    def _get_desktop_streams(self):
        self.logger.debug("Fetching stream info")
        res = urlget(self.url)

        match = re.search('flashplayer: "(.+.swf)".+streamer: "(.+)"' '.+file: "(.+).flv"', res.text, re.DOTALL)
        if not match:
            raise NoStreamsError(self.url)

        rtmpurl = match.group(2).replace("\\/", "/")
        parsed = urlparse(rtmpurl)

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

        params = {
            "rtmp": rtmpurl,
            "app": app,
            "pageUrl": self.url,
            "swfVfy": match.group(1),
            "playpath": match.group(3),
            "live": True,
        }

        match = re.search("(http(s)?://.+/server.php\?id=\d+)", res.text)
        if match:
            token_url = match.group(1)
            res = res_json(urlget(token_url, headers=dict(Referer=self.url)))
            token = res.get("token")
            if token:
                params["token"] = token

        streams = {}
        streams["live"] = RTMPStream(self.session, params)

        return streams
Exemple #36
0
    def _get_stream(self, channel_id, quality):
        params = dict(channel_id=channel_id, quality=quality)
        res = urlopen(CHINFO_URL,
                      data=params,
                      headers=AJAX_HEADERS,
                      session=self.rsession)
        json = res_json(res)

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

        info = json[0]
        rtmp = info.get("serverURL")
        playpath = info.get("streamName")
        if not (rtmp and playpath):
            raise NoStreamsError(self.url)

        parsed = urlparse(rtmp)
        if not parsed.scheme.startswith("rtmp"):
            raise NoStreamsError(self.url)

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

        return RTMPStream(
            self.session, {
                "rtmp": rtmp,
                "pageUrl": self.url,
                "swfUrl": SWF_URL,
                "playpath": playpath,
                "app": app,
                "live": True
            })
Exemple #37
0
    def _get_rtmp_streams(self, channelname):
        self.logger.debug("Fetching stream info")
        res = urlget(STREAM_INFO_URL.format(channelname))
        json = res_json(res)

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

        if not json:
            raise PluginError("JSON is empty")

        # This is ugly, not sure how to fix it.
        back_json_node = json["sequence"][0]["layerList"][0]
        if back_json_node["name"] != "background":
            raise PluginError("JSON data has unexpected structure")

        rep_node = self._get_node_by_name(back_json_node["sequenceList"],
                                          "reporting")["layerList"]
        main_node = self._get_node_by_name(back_json_node["sequenceList"],
                                           "main")["layerList"]

        if not (rep_node and main_node):
            raise PluginError("Error parsing stream RTMP url")

        swfurl = self._get_node_by_name(
            rep_node, "reporting")["param"]["extraParams"]["videoSwfURL"]
        feeds_params = self._get_node_by_name(main_node, "video")["param"]

        if not (swfurl and feeds_params):
            raise PluginError("Error parsing stream RTMP url")

        # Different feed qualities are available are a dict under "live"
        # In some cases where there's only 1 quality available,
        # it seems the "live" is absent. We use the single stream available
        # under the "customURL" key.
        streams = {}
        if "mode" in feeds_params and feeds_params["mode"] == "live":
            for key, quality in QUALITY_MAP.items():
                url = feeds_params.get("{0}URL".format(key))
                if not url:
                    continue

                try:
                    res = urlget(url, exception=IOError)
                except IOError:
                    continue

                match = re.match(RTMP_SPLIT_REGEX, res.text)
                if not match:
                    self.logger.warning("Failed to split RTMP URL: {0}",
                                        res.text)
                    continue

                stream = RTMPStream(
                    self.session, {
                        "rtmp": match.group("host"),
                        "app": match.group("app"),
                        "playpath": match.group("playpath"),
                        "swfVfy": swfurl,
                        "live": True
                    })

                self.logger.debug("Adding URL: {0}", res.text)
                streams[quality] = stream

        return streams
    def _get_rtmp_streams(self, channelname):
        self.logger.debug("Fetching stream info")

        url = self.StreamInfoURL.format(channelname)

        self.logger.debug("JSON data url: {0}", url)

        res = urlget(url)
        json = res_json(res)

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

        if len(json) == 0:
            raise PluginError("JSON is empty")

        # This is ugly, not sure how to fix it.
        back_json_node = json["sequence"][0]["layerList"][0]
        if back_json_node["name"] != "background":
            raise PluginError("JSON data has unexpected structure")

        rep_node = self._get_node_by_name(back_json_node["sequenceList"], "reporting")["layerList"]
        main_node = self._get_node_by_name(back_json_node["sequenceList"], "main")["layerList"]

        if not (rep_node and main_node):
            raise PluginError("Error parsing stream RTMP url")

        swfurl = self._get_node_by_name(rep_node, "reporting")["param"]["extraParams"]["videoSwfURL"]
        feeds_params = self._get_node_by_name(main_node, "video")["param"]

        if not (swfurl and feeds_params):
            raise PluginError("Error parsing stream RTMP url")

        streams = {}

        # Different feed qualities are available are a dict under "live"
        # In some cases where there's only 1 quality available,
        # it seems the "live" is absent. We use the single stream available
        # under the "customURL" key.

        if "mode" in feeds_params and feeds_params["mode"] == "live":

            for key, quality in self.QualityMap.items():

                url_key = '{0}URL'.format(key)
                if url_key not in feeds_params:
                    continue
                else:
                    url = feeds_params[url_key]

                info = {}

                try:
                    res = urlget(url, exception=IOError)
                except IOError:
                    continue

                rtmpurl = res.text
                stream = RTMPStream(self.session, {
                    "rtmp": rtmpurl,
                    "swfVfy": swfurl,
                    "live": True
                })
                self.logger.debug("Adding URL: {0}", rtmpurl)

                streams[quality] = stream

        return streams
Exemple #39
0
    def _get_rtmp_streams(self, channelname):
        self.logger.debug("Fetching stream info")
        res = urlget(STREAM_INFO_URL.format(channelname))
        json = res_json(res)

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

        if not json:
            raise PluginError("JSON is empty")

        # This is ugly, not sure how to fix it.
        back_json_node = json["sequence"][0]["layerList"][0]
        if back_json_node["name"] != "background":
            raise PluginError("JSON data has unexpected structure")

        rep_node = self._get_node_by_name(back_json_node["sequenceList"], "reporting")["layerList"]
        main_node = self._get_node_by_name(back_json_node["sequenceList"], "main")["layerList"]

        if not (rep_node and main_node):
            raise PluginError("Error parsing stream RTMP url")

        swfurl = self._get_node_by_name(rep_node, "reporting")["param"]["extraParams"]["videoSwfURL"]
        feeds_params = self._get_node_by_name(main_node, "video")["param"]

        if not (swfurl and feeds_params):
            raise PluginError("Error parsing stream RTMP url")


        # Different feed qualities are available are a dict under "live"
        # In some cases where there's only 1 quality available,
        # it seems the "live" is absent. We use the single stream available
        # under the "customURL" key.
        streams = {}
        if "mode" in feeds_params and feeds_params["mode"] == "live":
            for key, quality in QUALITY_MAP.items():
                url = feeds_params.get("{0}URL".format(key))
                if not url:
                    continue

                try:
                    res = urlget(url, exception=IOError)
                except IOError:
                    continue

                match = re.match(RTMP_SPLIT_REGEX, res.text)
                if not match:
                    self.logger.warning("Failed to split RTMP URL: {0}",
                                        res.text)
                    continue

                stream = RTMPStream(self.session, {
                    "rtmp": match.group("host"),
                    "app": match.group("app"),
                    "playpath": match.group("playpath"),
                    "swfVfy": swfurl,
                    "live": True
                })

                self.logger.debug("Adding URL: {0}", res.text)
                streams[quality] = stream

        return streams