예제 #1
0
 def test_swf_decompress(self):
     # FYI, not a valid SWF
     swf = b"FWS " + b"0000" + b"test data 12345"
     swf_compressed = b"CWS " + b"0000" + base64.b64decode(
         b"eJwrSS0uUUhJLElUMDQyNjEFACpTBJo=")
     self.assertEqual(swf, swfdecompress(swf_compressed))
     self.assertEqual(swf, swfdecompress(swf))
예제 #2
0
def parse_swf(data):
    data = swfdecompress(data)
    fd = BytesIO(data[8:])
    frame_size = read_rect(fd)
    frame_rate = U16LE.read(fd)
    frame_count = U16LE.read(fd)
    tags = list(read_tags(fd))

    return SWF(frame_size, frame_rate, frame_count, tags)
예제 #3
0
    def _pv_params(cls, session, pvswf, pv, **request_params):
        """Returns any parameters needed for Akamai HD player verification.

        Algorithm originally documented by KSV, source:
        http://stream-recorder.com/forum/showpost.php?p=43761&postcount=13
        """

        try:
            data, hdntl = pv.split(";")
        except ValueError:
            data = pv
            hdntl = ""

        cache = Cache(filename="stream.json")
        key = "akamaihd-player:" + pvswf
        cached = cache.get(key)

        request_params = deepcopy(request_params)
        headers = request_params.pop("headers", {})
        if cached:
            headers["If-Modified-Since"] = cached["modified"]
        swf = session.http.get(pvswf, headers=headers, **request_params)

        if cached and swf.status_code == 304:  # Server says not modified
            hash = cached["hash"]
        else:
            # Calculate SHA-256 hash of the uncompressed SWF file, base-64
            # encoded
            hash = sha256()
            hash.update(swfdecompress(swf.content))
            hash = base64.b64encode(hash.digest()).decode("ascii")
            modified = swf.headers.get("Last-Modified", "")

            # Only save in cache if a valid date is given
            if len(modified) < 40:
                cache.set(key, dict(hash=hash, modified=modified))

        msg = "st=0~exp=9999999999~acl=*~data={0}!{1}".format(data, hash)
        auth = hmac.new(AKAMAIHD_PV_KEY, msg.encode("ascii"), sha256)
        pvtoken = "{0}~hmac={1}".format(msg, auth.hexdigest())

        # The "hdntl" parameter can be accepted as a cookie or passed in the
        # query string, but the "pvtoken" parameter can only be in the query
        # string
        params = [("pvtoken", pvtoken)]
        params.extend(parse_qsl(hdntl, keep_blank_values=True))

        return params
예제 #4
0
    def generate(self):
        if not self.stream.swf:
            raise StreamError("A SWF URL is required to create session token")

        res = self.stream.session.http.get(self.stream.swf,
                                           exception=StreamError)
        data = swfdecompress(res.content)

        md5 = hashlib.md5()
        md5.update(data)

        data = bytes(self.stream.sessionid, "ascii") + md5.digest()
        sig = hmac.new(b"foo", data, hashlib.sha1)
        b64 = base64.encodestring(sig.digest())
        token = str(b64, "ascii").replace("\n", "")

        return token
예제 #5
0
    def _get_rtmp_stream(self, swfurl):
        res = http.get(swfurl)
        swf = swfdecompress(res.content)
        match = _rtmp_re.search(swf)
        if not match:
            return

        res = http.get(match.group(1))
        rtmp, playpath = rtmpparse(res.text)
        params = {
            "rtmp": rtmp,
            "pageUrl": self.url,
            "playpath": playpath,
            "swfUrl": swfurl,
            "live": True
        }

        return RTMPStream(self.session, params)
예제 #6
0
    def _get_rtmp_stream(self, swfurl):
        res = http.get(swfurl)
        swf = swfdecompress(res.content)
        match = _rtmp_re.search(swf)
        if not match:
            return

        res = http.get(match.group(1))
        rtmp, playpath = rtmpparse(res.text)
        params = {
            "rtmp": rtmp,
            "pageUrl": self.url,
            "playpath": playpath,
            "swfUrl": swfurl,
            "live": True
        }

        return RTMPStream(self.session, params)
예제 #7
0
    def _get_streams(self):
        res = http.get(self.url)
        match = _swf_player_re.search(res.text)
        if match is None:
            return
        swf_url = "http://vaughnlive.tv" + match.group(1)
        self.logger.debug("Using swf url: {0}", swf_url)

        swfres = http.get(swf_url)
        swfdata = swfdecompress(swfres.content).decode("latin1")

        player_version_m = re.search(r"0\.\d+\.\d+\.\d+", swfdata)
        info_url_domain_m = re.search(r"\w+\.vaughnsoft\.net", swfdata)
        info_url_path_m = re.search(r"/video/edge/[a-zA-Z0-9_]+-", swfdata)

        player_version = player_version_m and player_version_m.group(0)
        info_url_domain = info_url_domain_m and info_url_domain_m.group(0)
        info_url_path = info_url_path_m and info_url_path_m.group(0)

        if player_version and info_url_domain and info_url_path:
            self.logger.debug(
                "Found player_version={0}, info_url_domain={1}, info_url_path={2}",
                player_version, info_url_domain, info_url_path)
            match = _url_re.match(self.url)
            params = {
                "channel":
                match.group("channel").lower(),
                "domain":
                DOMAIN_MAP.get(match.group("domain"), match.group("domain")),
                "version":
                player_version,
                "ms":
                random.randint(0, 999),
                "random":
                random.random(),
                "site":
                info_url_domain,
                "path":
                info_url_path
            }
            info_url = INFO_URL.format(**params)
            self.logger.debug("Loading info url: {0}",
                              INFO_URL.format(**params))

            info = http.get(info_url, schema=_schema)
            if not info:
                self.logger.info("This stream is currently unavailable")
                return

            app = "live"
            self.logger.debug("Streaming server is: {0}", info["server"])
            if info["server"].endswith(":1337"):
                app = "live-{0}".format(info["ingest"].lower())

            stream = RTMPStream(
                self.session, {
                    "rtmp": "rtmp://{0}/live".format(info["server"]),
                    "app": "{0}?{1}".format(app, info["token"]),
                    "swfVfy": swf_url,
                    "pageUrl": self.url,
                    "live": True,
                    "playpath": "{domain}_{channel}".format(**params),
                })

            return dict(live=stream)
        else:
            self.logger.info(
                "Found player_version={0}, info_url_domain={1}, info_url_path={2}",
                player_version, info_url_domain, info_url_path)
            if not player_version:
                self.logger.error("Could not detect player_version")
            if not info_url_domain:
                self.logger.error("Could not detect info_url_domain")
            if not info_url_path:
                self.logger.error("Could not detect info_url_path")
예제 #8
0
 def test_swf_decompress(self):
     # FYI, not a valid SWF
     swf = b"FWS " + b"0000" + b"test data 12345"
     swf_compressed = b"CWS " + b"0000" + base64.b64decode(b"eJwrSS0uUUhJLElUMDQyNjEFACpTBJo=")
     self.assertEqual(swf, swfdecompress(swf_compressed))
     self.assertEqual(swf, swfdecompress(swf))