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