Example #1
0
    def _get_streams(self, type):
        self.channelname = self._get_channel_name(self.url)

        if not self.channelname:
            raise NoStreamsError(self.url)

        streams = {}
        
        if type in (None, StreamType.RTMP):
            if RTMPStream.is_usable(self.session):
                try:
                    rtmpstreams = self._get_rtmp_streams()
                    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")

        if type in (None, StreamType.HLS):
            try:
                hlsstreams = self._get_hls_streams()
                if len(streams) > 0:
                    hlssuffix = "_hls"
                else:
                    hlssuffix = ""

                for name, stream in hlsstreams.items():
                    streams[name + hlssuffix] = stream
            except PluginError as err:
                self.logger.error("Error when fetching HLS stream info: {0}", str(err))

        return streams
Example #2
0
    def _check_vod_key(self, nodeip, nodeid, userno, userip):
        try:
            conn = socket.create_connection((nodeip, self.KeyCheckPort),
                                            timeout=30)
        except socket.error as err:
            raise PluginError(("Failed to connect to key check server: {0}").format(str(err)))

        msg = "Login,0,{userno},{nodeid},{userip}\n".format(nodeid=nodeid,
                                                            userno=userno,
                                                            userip=userip)

        try:
            conn.sendall(bytes(msg, "ascii"))
            res = conn.recv(4096)
        except IOError as err:
            raise PluginError(("Failed to communicate with key check server: {0}").format(str(err)))

        if len(res) == 0:
            raise PluginError("Empty response from key check server")

        conn.close()

        res = str(res, "ascii").strip().split(",")

        return res[-1]
Example #3
0
    def _get_streams(self):
        self.channelname = self._get_channel_name(self.url)

        if not self.channelname:
            raise NoStreamsError(self.url)

        streams = {}

        if RTMPStream.is_usable(self.session):
            try:
                rtmpstreams = self._get_rtmp_streams()
                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()

            for name, stream in hlsstreams.items():
                if name in streams:
                    streams[name] = [streams[name], stream]
                else:
                    streams[name] = stream

        except PluginError as err:
            self.logger.error("Error when fetching HLS stream info: {0}", str(err))

        return streams
Example #4
0
    def _get_streams(self):
        self.channelname = self._get_channel_name(self.url)

        if not self.channelname:
            raise NoStreamsError(self.url)

        streams = {}

        if RTMPStream.is_usable(self.session):
            try:
                rtmpstreams = self._get_rtmp_streams()
                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()
            if len(streams) > 0:
                hlssuffix = "_hls"
            else:
                hlssuffix = ""

            for name, stream in hlsstreams.items():
                streams[name + hlssuffix] = stream
        except PluginError as err:
            self.logger.error("Error when fetching HLS stream info: {0}", str(err))

        return streams
Example #5
0
    def _check_vod_key(self, nodeip, nodeid, userno, userip):
        try:
            conn = socket.create_connection((nodeip, self.KeyCheckPort),
                                            timeout=15)
        except socket.error as err:
            raise PluginError(
                ("Failed to connect to key check server: {0}").format(
                    str(err)))

        msg = "Login,0,{userno},{nodeid},{userip}\n".format(nodeid=nodeid,
                                                            userno=userno,
                                                            userip=userip)

        try:
            conn.sendall(bytes(msg, "ascii"))
            res = conn.recv(4096)
        except IOError as err:
            raise PluginError(
                ("Failed to communicate with key check server: {0}").format(
                    str(err)))

        if len(res) == 0:
            raise PluginError("Empty response from key check server")

        conn.close()

        res = str(res, "ascii").strip().split(",")

        return res[-1]
Example #6
0
    def _get_streams(self):
        channelid = self._get_channel_id(self.url)

        if not channelid:
            raise NoStreamsError(self.url)

        self.logger.debug("Fetching stream info")
        res = urlget(self.AMFURL.format(channelid))

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

        result = None
        for message in packet.messages:
            if message.target_uri == "/1/onResult":
                result = message.value
                break

        if not result:
            raise PluginError("No result found in AMF packet")

        streams = {}

        if "liveHttpUrl" in result:
            try:
                hlsstreams = HLSStream.parse_variant_playlist(
                    self.session, result["liveHttpUrl"])
                streams.update(hlsstreams)
            except IOError as err:
                self.logger.warning("Failed to get variant playlist: {0}", err)

        if "streamName" in result:
            if "cdnUrl" in result:
                cdn = result["cdnUrl"]
            elif "fmsUrl" in result:
                cdn = result["fmsUrl"]
            else:
                self.logger.warning("Missing cdnUrl and fmsUrl from result")
                return streams

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

            streams[streamname] = self._create_stream(cdn,
                                                      result["streamName"])

        if "streamVersions" in result:
            for version, info in result["streamVersions"].items():
                if "streamVersionCdn" in info:
                    for name, cdn in info["streamVersionCdn"].items():
                        if "cdnStreamUrl" in cdn and "cdnStreamName" in cdn:
                            streams["cdn_" + name] = self._create_stream(
                                cdn["cdnStreamUrl"], cdn["cdnStreamName"])

        return streams
Example #7
0
    def _get_streams(self):
        self.logger.debug("Fetching stream info")
        res = urlget(self.url, params=dict(output="json"))

        if res.json is None:
            raise PluginError("No JSON data in stream info")

        streams = {}
        video = verifyjson(res.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
Example #8
0
    def _get_streams(self):
        channelid = self._get_channel_id(self.url)

        if not channelid:
            raise NoStreamsError(self.url)


        self.logger.debug("Fetching stream info")
        res = urlget(self.AMFURL.format(channelid))

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

        result = None
        for message in packet.messages:
            if message.target_uri == "/1/onResult":
                result = message.value
                break

        if not result:
            raise PluginError("No result found in AMF packet")

        streams = {}

        if "liveHttpUrl" in result:
            try:
                hlsstreams = HLSStream.parse_variant_playlist(self.session,
                                                              result["liveHttpUrl"])
                streams.update(hlsstreams)
            except IOError as err:
                self.logger.warning("Failed to get variant playlist: {0}", err)

        if "streamName" in result:
            if "cdnUrl" in result:
                cdn = result["cdnUrl"]
            elif "fmsUrl" in result:
                cdn = result["fmsUrl"]
            else:
                self.logger.warning("Missing cdnUrl and fmsUrl from result")
                return streams

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

            streams[streamname] = self._create_stream(cdn, result["streamName"])

        if "streamVersions" in result:
            for version, info in result["streamVersions"].items():
                if "streamVersionCdn" in info:
                    for name, cdn in info["streamVersionCdn"].items():
                        if "cdnStreamUrl" in cdn and "cdnStreamName" in cdn:
                            streams["cdn_" + name] = self._create_stream(cdn["cdnStreamUrl"],
                                                                         cdn["cdnStreamName"])


        return streams
Example #9
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
Example #10
0
    def _get_channel_info(self, url):
        self.logger.debug("Fetching channel info")

        data = urlget(url, opener=urlopener)

        channelid = None
        swfurl = None

        match = re.search(b'flashvars.config = "livecfg/(\d+)', data)
        if match:
            channelid = int(match.group(1))

        match = re.search(b"document.location.hash='/live/(\d+)'", data)
        if match:
            channelid = int(match.group(1))

        match = re.search(b"xajax_load_live_config\((\d+),", data)
        if match:
            channelid = int(match.group(1))

        match = re.search(b"""swfobject.embedSWF\(\n.+"(.+)", "player",""", data)
        if match:
            swfurl = str(match.group(1), "utf8")

        return (channelid, swfurl)
Example #11
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
Example #12
0
    def _get_channel_name(self, url):
        fd = urllib.urlopen(url)
        data = fd.read()
        fd.close()

        match = re.search(b"live_facebook_embed_player\.swf\?channel=(\w+)", data)
        if match:
            return str(match.group(1), "ascii")
Example #13
0
    def _get_streams(self):
        (channelid, swfurl) = self._get_channel_info(self.url)

        if not (channelid and swfurl):
            raise NoStreamsError(self.url)

        self.logger.debug("Fetching stream info")
        res = urlget(self.ConfigURL.format(channelid))

        try:
            dom = xml.dom.minidom.parseString(res.text)
        except Exception as err:
            raise PluginError(("Unable to parse config XML: {0})").format(err))

        streams = {}
        channels = dom.getElementsByTagName("channels")[0]
        clip = channels.getElementsByTagName("clip")[0]

        self.logger.debug("Verifying SWF: {0}", swfurl)
        swfhash, swfsize = swfverify(swfurl)

        for item in clip.getElementsByTagName("item"):
            base = item.getAttribute("base")
            if not base:
                continue

            if base[0] == "$":
                ref = re.match("\${(.+)}", base).group(1)
                base = self.CDN[ref]

            for streamel in item.getElementsByTagName("stream"):
                altcount = 1
                name = streamel.getAttribute("label").lower().replace(" ", "_")
                playpath = streamel.getAttribute("name")

                stream = RTMPStream(
                    self.session,
                    {
                        "rtmp": ("{0}/{1}").format(base, playpath),
                        "live": True,
                        "swfhash": swfhash,
                        "swfsize": swfsize,
                        "pageUrl": self.url,
                    },
                )

                if not name in streams:
                    streams[name] = stream
                else:
                    if altcount == 1:
                        streams[name + "_alt"] = stream
                    else:
                        streams[name + "_alt" + str(altcount)] = stream

                    altcount += 1

        return streams
Example #14
0
    def _get_streams(self):
        self.channelname = self._get_channel_name(self.url)

        if not self.channelname:
            raise NoStreamsError(self.url)

        streams = {}

        if RTMPStream.is_usable(self.session):
            try:
                rtmpstreams = self._get_rtmp_streams()

                for name, stream in rtmpstreams.items():
                    if "iphone" in name:
                        name = name.replace("iphone", "mobile_")

                    streams[name] = stream
            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()

            for name, stream in hlsstreams.items():
                if name in ("high", "low"):
                    name = "mobile_{0}".format(name)

                if "iphone" in name:
                    name = name.replace("iphone", "mobile_")

                if name in streams:
                    streams[name] = [streams[name], stream]
                else:
                    streams[name] = stream

        except PluginError as err:
            self.logger.error("Error when fetching HLS stream info: {0}",
                              str(err))

        return streams
Example #15
0
    def _get_streams(self, type):
        if type not in (None, StreamType.RTMP):
            return {}
    
        (liveid, swfurl) = self._get_channel_info(self.url)

        if not (liveid and swfurl):
            raise NoStreamsError(self.url)

        if not self._is_live(liveid):
            raise NoStreamsError(self.url)

        self.logger.debug("Fetching stream info")
        res = urlget(self.ConfigURL.format(liveid))

        try:
            dom = xml.dom.minidom.parseString(res.text)
        except Exception as err:
            raise PluginError(("Unable to parse config XML: {0})").format(err))

        streams = {}
        channels = dom.getElementsByTagName("channels")[0]
        clip = channels.getElementsByTagName("clip")[0]
        items = clip.getElementsByTagName("item")

        for item in items:
            base = item.getAttribute("base")
            if not base:
                continue

            if base[0] == "$":
                ref = re.match("\${(.+)}", base).group(1)
                base = self.CDN[ref]

            for streamel in item.getElementsByTagName("stream"):
                name = streamel.getAttribute("label").lower().replace(" ", "_")
                playpath = streamel.getAttribute("name")

                stream = RTMPStream(self.session, {
                    "rtmp": ("{0}/{1}").format(base, playpath),
                    "live": True,
                    "swfVfy": swfurl,
                    "pageUrl": self.url
                })

                if not name in streams:
                    streams[name] = stream
                else:
                    index = items.index(item)

                    if index == 1:
                        streams[name + "_alt"] = stream
                    else:
                        streams[name + "_alt" + str(index)] = stream

        return streams
Example #16
0
    def _get_streams(self):
        (channelid, swfurl) = self._get_channel_info(self.url)

        if not (channelid and swfurl):
            raise NoStreamsError(self.url)

        self.logger.debug("Fetching stream info")
        res = urlget(self.ConfigURL.format(channelid))

        try:
            dom = xml.dom.minidom.parseString(res.text)
        except Exception as err:
            raise PluginError(("Unable to parse config XML: {0})").format(err))

        streams = {}
        channels = dom.getElementsByTagName("channels")[0]
        clip = channels.getElementsByTagName("clip")[0]

        self.logger.debug("Verifying SWF: {0}", swfurl)
        swfhash, swfsize = swfverify(swfurl)

        for item in clip.getElementsByTagName("item"):
            base = item.getAttribute("base")
            if not base:
                continue

            if base[0] == "$":
                ref = re.match("\${(.+)}", base).group(1)
                base = self.CDN[ref]

            for streamel in item.getElementsByTagName("stream"):
                altcount = 1
                name = streamel.getAttribute("label").lower().replace(" ", "_")
                playpath = streamel.getAttribute("name")

                stream = RTMPStream(self.session, {
                    "rtmp": ("{0}/{1}").format(base, playpath),
                    "live": True,
                    "swfhash": swfhash,
                    "swfsize": swfsize,
                    "pageUrl": self.url
                })

                if not name in streams:
                    streams[name] = stream
                else:
                    if altcount == 1:
                        streams[name + "_alt"] = stream
                    else:
                        streams[name + "_alt" + str(altcount)] = stream

                    altcount += 1

        return streams
Example #17
0
    def _get_streams(self):
        self.channelname = self._get_channel_name(self.url)

        if not self.channelname:
            raise NoStreamsError(self.url)

        streams = {}

        if RTMPStream.is_usable(self.session):
            try:
                rtmpstreams = self._get_rtmp_streams()

                for name, stream in rtmpstreams.items():
                    if "iphone" in name:
                        name = name.replace("iphone", "mobile_")

                    streams[name] = stream
            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()

            for name, stream in hlsstreams.items():
                if name in ("high", "low"):
                    name = "mobile_{0}".format(name)

                if "iphone" in name:
                    name = name.replace("iphone", "mobile_")

                if name in streams:
                    streams[name] = [streams[name], stream]
                else:
                    streams[name] = stream

        except PluginError as err:
            self.logger.error("Error when fetching HLS stream info: {0}", str(err))

        return streams
Example #18
0
    def _create_stream_key(self, url):
        parsed = urlparse(url)
        params = parse_qsd(parsed.query)
        keys = ["uno", "nodeid"]

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

        userip = self._get_user_ip()
        nodeip = parsed.netloc

        try:
            conn = socket.create_connection(
                (nodeip, self.VODStreamKeyCheckPort), timeout=30)
        except socket.error as err:
            raise PluginError(
                ("Failed to connect to key check server: {0}").format(
                    str(err)))

        msg = "Login,0,{userno},{nodeid},{userip}\n".format(
            nodeid=params["nodeid"], userno=params["uno"], userip=userip)

        try:
            conn.sendall(bytes(msg, "ascii"))
            res = conn.recv(4096)
        except IOError as err:
            raise PluginError(
                ("Failed to communicate with key check server: {0}").format(
                    str(err)))

        if len(res) == 0:
            raise PluginError("Empty response from key check server")

        conn.close()

        res = str(res, "ascii").strip().split(",")

        return res[-1]
Example #19
0
    def _get_streams(self):
        (liveid, swfurl) = self._get_channel_info(self.url)

        if not (liveid and swfurl):
            raise NoStreamsError(self.url)

        if not self._is_live(liveid):
            raise NoStreamsError(self.url)

        self.logger.debug("Fetching stream info")
        res = urlget(self.ConfigURL.format(liveid))

        dom = res_xml(res, "config XML")

        streams = {}
        channels = dom.getElementsByTagName("channels")[0]
        clip = channels.getElementsByTagName("clip")[0]
        items = clip.getElementsByTagName("item")

        for item in items:
            base = item.getAttribute("base")
            if not base:
                continue

            if base[0] == "$":
                ref = re.match("\${(.+)}", base).group(1)
                base = self.CDN[ref]

            for streamel in item.getElementsByTagName("stream"):
                name = streamel.getAttribute("label").lower().replace(" ", "_")
                playpath = streamel.getAttribute("name")

                stream = RTMPStream(self.session, {
                    "rtmp": ("{0}/{1}").format(base, playpath),
                    "live": True,
                    "swfVfy": swfurl,
                    "pageUrl": self.url
                })

                if not name in streams:
                    streams[name] = stream
                else:
                    index = items.index(item)

                    if index == 1:
                        streams[name + "_alt"] = stream
                    else:
                        streams[name + "_alt" + str(index)] = stream

        return streams
Example #20
0
    def _get_streams(self):
        channelid = self._get_channel_id(self.url)

        if not channelid:
            raise NoStreamsError(self.url)

        self.logger.debug("Fetching stream info")
        data = urlget(self.JSONURL.format(channelid))

        try:
            info = json.loads(str(data, "utf8"))
        except ValueError as err:
            raise PluginError(("Unable to parse JSON: {0})").format(err))

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

        self.logger.debug("Verifying SWF: {0}", self.SWFURL)
        swfhash, swfsize = swfverify(self.SWFURL)

        for video in videos:
            if not ("url" in video and "playerType" in video and video["playerType"] == "flash"):
                continue

            stream = RTMPStream(self.session, {
                "rtmp": video["url"],
                "pageUrl": self.PageURL,
                "swfhash": swfhash,
                "swfsize": swfsize,
                "live": True
            })
            streams[str(video["bitrate"]) + "k"] = stream


        return streams
Example #21
0
    def _create_stream_key(self, url):
        parsed = urlparse(url)
        params = parse_qsd(parsed.query)
        keys = ["uno", "nodeid"]

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

        userip = self._get_user_ip()
        nodeip = parsed.netloc

        try:
            conn = socket.create_connection((nodeip, self.VODStreamKeyCheckPort),
                                            timeout=30)
        except socket.error as err:
            raise PluginError(("Failed to connect to key check server: {0}").format(str(err)))

        msg = "Login,0,{userno},{nodeid},{userip}\n".format(nodeid=params["nodeid"],
                                                            userno=params["uno"],
                                                            userip=userip)

        try:
            conn.sendall(bytes(msg, "ascii"))
            res = conn.recv(4096)
        except IOError as err:
            raise PluginError(("Failed to communicate with key check server: {0}").format(str(err)))

        if len(res) == 0:
            raise PluginError("Empty response from key check server")

        conn.close()

        res = str(res, "ascii").strip().split(",")

        return res[-1]
Example #22
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
Example #23
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
Example #24
0
    def _get_stream_info(self, url):
        data = urlget(url)
        config = None

        match = re.search(b"'PLAYER_CONFIG': (.+)\n.+}\);", data)
        if match:
            config = match.group(1)

        match = re.search(b"yt.playerConfig = (.+)\;\n", data)
        if match:
            config = match.group(1)

        if config:
            try:
                parsed = json.loads(str(config, "utf8"))
            except ValueError as err:
                raise PluginError(("Unable to parse config JSON: {0})").format(err))

            return parsed
Example #25
0
    def _get_streams(self):
        res = urlget(self.PlayerURL)
        urls = re.findall("return \"(rtmp://.+)\"", res.text)
        streams = {}

        for i, url in enumerate(urls):
            if i >= len(self.Streams):
                name = "stream_" + str(i)
            else:
                name = self.Streams[i]

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

        return streams
Example #26
0
    def _get_streams(self):
        res = urlget(self.PlayerURL)
        urls = re.findall("return \"(rtmp://.+)\"", res.text)
        streams = {}

        for i, url in enumerate(urls):
            if i >= len(self.Streams):
                name = "stream_" + str(i)
            else:
                name = self.Streams[i]

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

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

        if res.json is None:
            raise PluginError("No JSON data in stream info")

        streams = {}
        video = verifyjson(res.json, "video")
        videos = verifyjson(video, "videoReferences")
        swfhash, swfsize = (None, None)

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

            if video["playerType"] == "flash":
                if video["url"].startswith("rtmp"):
                    if not swfhash:
                        self.logger.debug("Verifying SWF: {0}", self.SWFURL)
                        swfhash, swfsize = swfverify(self.SWFURL)

                    stream = RTMPStream(self.session, {
                        "rtmp": video["url"],
                        "pageUrl": self.PageURL,
                        "swfhash": swfhash,
                        "swfsize": swfsize,
                        "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
Example #29
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
Example #30
0
    def get_vod_streams(self):
        match = re.search("flashvars\s+=\s+({.+?});", self.res.text)

        if not match:
            raise NoStreamsError(self.url)

        flashvars = parse_json(match.group(1), "flashvars JSON")

        match = re.search("var jsonData\s+= eval \((.+?)\);", self.res.text,
                          re.DOTALL)

        if not match:
            raise NoStreamsError(self.url)

        playlists = parse_json(match.group(1), "playlist JSON")

        self.logger.info("Playlist items found:")
        for i, playlist in enumerate(playlists):
            for fvars in playlist:
                if self.url[-1] != "/":
                    url = self.url + "/"
                else:
                    url = self.url

                url = urljoin(url, "?set={1}&lang={0}".format(i, fvars["set"]))

                self.logger.info("[Set {1} ({0})] {2}", self.Lang[i],
                                 fvars["set"], url)

        params = parse_qsd(urlparse(self.url).query)
        currentset = int(params.get("set", "1"))
        lang = int(params.get("lang", "0"))

        flashvars.update(playlists[lang][currentset - 1])
        flashvars["uip"] = self._get_user_ip()

        streams = {}

        for level, levelname in self.VODQualityLevels.items():
            params = self._create_gox_params(flashvars, level)

            res = urlget(self.GOXVODURL, params=params, session=self.rsession)

            gox = GOXFile(res.text)
            entries = gox.filter_entries("vod")

            for entry in entries:
                streamurl = entry.ref[0]
                params = {}

                try:
                    params["key"] = self._create_stream_key(streamurl)
                except PluginError as err:
                    self.logger.warning("{0}", str(err))
                    continue

                streams[levelname] = HTTPStream(self.session,
                                                streamurl,
                                                params=params)

        if len(streams) == 0:
            self.logger.warning(("Unable to access any streams, "
                                 "make sure you have access to this VOD"))

        return streams
Example #31
0
    def _get_channel_name(self, url):
        data = urlget(url)
        match = re.search(b"live_facebook_embed_player\.swf\?channel=(\w+)", data)

        if match:
            return str(match.group(1), "ascii")
Example #32
0
    def get_vod_streams(self):
        match = re.search("flashvars\s+=\s+({.+?});", self.res.text)

        if not match:
            raise NoStreamsError(self.url)

        flashvars = parse_json(match.group(1), "flashvars JSON")

        match = re.search("var jsonData\s+= eval \((.+?)\);",
                             self.res.text, re.DOTALL)

        if not match:
            raise NoStreamsError(self.url)

        playlists = parse_json(match.group(1), "playlist JSON")

        self.logger.info("Playlist items found:")
        for i, playlist in enumerate(playlists):
            for fvars in playlist:
                if self.url[-1] != "/":
                    url = self.url + "/"
                else:
                    url = self.url

                url = urljoin(url, "?set={1}&lang={0}".format(i,
                              fvars["set"]))

                self.logger.info("[Set {1} ({0})] {2}", self.Lang[i],
                                                        fvars["set"],
                                                        url)

        params = parse_qsd(urlparse(self.url).query)
        currentset = int(params.get("set", "1"))
        lang = int(params.get("lang", "0"))

        flashvars.update(playlists[lang][currentset - 1])
        flashvars["uip"] = self._get_user_ip()

        streams = {}

        for level, levelname in self.VODQualityLevels.items():
            params = self._create_gox_params(flashvars, level)

            res = urlget(self.GOXVODURL, params=params,
                         session=self.rsession)

            gox = GOXFile(res.text)
            entries = gox.filter_entries("vod")

            for entry in entries:
                streamurl = entry.ref[0]
                params = {}

                try:
                    params["key"] = self._create_stream_key(streamurl)
                except PluginError as err:
                    self.logger.warning("{0}", str(err))
                    continue

                streams[levelname] = HTTPStream(self.session, streamurl,
                                                params=params)

        if len(streams) == 0:
            self.logger.warning(("Unable to access any streams, "
                                 "make sure you have access to this VOD"))

        return streams
Example #33
0
 def get_amf_value(data, key):
     pattern = ("{0}\x02..(.*?)\x00").format(key)
     match = re.search(bytes(pattern, "ascii"), data)
     if match:
         return str(match.group(1), "ascii")
Example #34
0
    def _get_streams(self):
        channelid = self._get_channel_id(self.url)

        if not channelid:
            raise NoStreamsError(self.url)


        self.logger.debug("Fetching stream info")
        res = urlget(self.AMFURL.format(channelid))

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

        result = None
        for message in packet.messages:
            if message.target_uri == "/1/onResult":
                result = message.value
                break

        if not result:
            raise PluginError("No result found in AMF packet")

        streams = {}

        if RTMPStream.is_usable(self.session) and "streamName" in result:
            if "cdnUrl" in result:
                cdn = result["cdnUrl"]
            elif "fmsUrl" in result:
                cdn = result["fmsUrl"]
            else:
                self.logger.warning("Missing cdnUrl and fmsUrl from result")
                return streams

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

            streams[streamname] = self._create_stream(cdn, result["streamName"])

        if RTMPStream.is_usable(self.session) and "streamVersions" in result:
            for version, info in result["streamVersions"].items():
                if "streamVersionCdn" in info:
                    for name, cdn in info["streamVersionCdn"].items():
                        if "cdnStreamUrl" in cdn and "cdnStreamName" in cdn:
                            cdnname = "live_alt_{0}".format(name)
                            streams[cdnname] = self._create_stream(cdn["cdnStreamUrl"],
                                                                   cdn["cdnStreamName"])

        # On some channels the AMF API will not return any streams,
        # attempt to access the HLS playlist directly instead.
        #
        # HLS streams are created on demand, so we may have to wait
        # for a transcode to be started.
        attempts = 10
        playlist_url = result.get("liveHttpUrl",
                                  self.HLSPlaylistURL.format(channelid))

        while attempts:
            try:
                hls_streams = HLSStream.parse_variant_playlist(self.session,
                                                               playlist_url)
                streams.update(hls_streams)
            except IOError:
                # Channel is probably offline
                break

            if streams:
                break

            attempts -= 1
            sleep(3)

        return streams