def open(self): method = self.args.get("method", "GET") timeout = self.session.options.get("http-timeout") res = self.session.http.request(method=method, stream=True, exception=StreamError, timeout=timeout, **self.args) fd = StreamIOIterWrapper(res.iter_content(8192)) if self.buffered: fd = StreamIOThreadWrapper(self.session, fd, timeout=timeout) return fd
def open(self): self.guid = cache_bust_string(12) self.islive = None self.sessionid = None self.flv = None self.buffer = Buffer() self.completed_handshake = False url = self.StreamURLFormat.format(host=self.host, streamname=self.streamname) params = self._create_params(seek=self.seek) log.debug(f"Opening host={self.host} streamname={self.streamname}") try: res = self.session.http.get(url, stream=True, params=params) self.fd = StreamIOIterWrapper(res.iter_content(8192)) except Exception as err: raise StreamError(str(err)) self.handshake(self.fd) return self
def open(self): reqargs = self.session.http.valid_request_args(**self.args) reqargs.setdefault("method", "GET") timeout = self.session.options.get("stream-timeout") res = self.session.http.request( stream=True, exception=StreamError, timeout=timeout, **reqargs, ) fd = StreamIOIterWrapper(res.iter_content(8192)) if self.buffered: fd = StreamIOThreadWrapper(self.session, fd, timeout=timeout) return fd
def test_iter(self): def generator(): yield b"1" * 8192 yield b"2" * 4096 yield b"3" * 2048 fd = StreamIOIterWrapper(generator()) self.assertEqual(fd.read(4096), b"1" * 4096) self.assertEqual(fd.read(2048), b"1" * 2048) self.assertEqual(fd.read(2048), b"1" * 2048) self.assertEqual(fd.read(1), b"2") self.assertEqual(fd.read(4095), b"2" * 4095) self.assertEqual(fd.read(1536), b"3" * 1536) self.assertEqual(fd.read(), b"3" * 512)
def open(self): method = self.args.get("method", "GET") timeout = self.session.http.timeout #print ('timeout:', timeout) res = self.session.http.request(method=method, stream=True, exception=StreamError, timeout=timeout, **self.args) #print ('res:', res) fd = StreamIOIterWrapper(res.iter_content(8192)) if self.buffered: fd = StreamIOThreadWrapper(self.session, fd, timeout=timeout) self.fdclose = fd return fd
def open(self): args = self.args.copy() method = args.pop("method", "GET") timeout = self.session.options.get("stream-timeout") chunk_size = self.session.get_option("chunk-size") res = self.session.http.request(method=method, stream=True, exception=StreamError, timeout=timeout, **valid_args(args)) fd = StreamIOIterWrapper(res.iter_content(chunk_size)) if self.buffered: fd = StreamIOThreadWrapper(self.session, fd, timeout=timeout, chunk_size=chunk_size) self.fdclose = fd return fd
class AkamaiHDStreamIO(io.IOBase): Version = "2.5.8" FlashVersion = "LNX 11,1,102,63" StreamURLFormat = "{host}/{streamname}" ControlURLFormat = "{host}/control/{streamname}" ControlData = b":)" TokenGenerators = {"c11e59dea648d56e864fc07a19f717b9": Auth3TokenGenerator} StatusComplete = 3 StatusError = 4 Errors = { 1: "Stream not found", 2: "Track not found", 3: "Seek out of bounds", 4: "Authentication failed", 5: "DVR disabled", 6: "Invalid bitrate test" } def __init__(self, session, url, swf=None, seek=None): parsed = urlparse(url) self.session = session self.host = ("{scheme}://{netloc}").format(scheme=parsed.scheme, netloc=parsed.netloc) self.streamname = parsed.path[1:] self.swf = swf self.seek = seek def open(self): self.guid = cache_bust_string(12) self.islive = None self.sessionid = None self.flv = None self.buffer = Buffer() self.completed_handshake = False url = self.StreamURLFormat.format(host=self.host, streamname=self.streamname) params = self._create_params(seek=self.seek) log.debug(f"Opening host={self.host} streamname={self.streamname}") try: res = self.session.http.get(url, stream=True, params=params) self.fd = StreamIOIterWrapper(res.iter_content(8192)) except Exception as err: raise StreamError(str(err)) self.handshake(self.fd) return self def handshake(self, fd): try: self.flv = FLV(fd) except FLVError as err: raise StreamError(str(err)) self.buffer.write(self.flv.header.serialize()) log.debug("Attempting to handshake") for i, tag in enumerate(self.flv): if i == 10: raise StreamError( "No OnEdge metadata in FLV after 10 tags, probably not a AkamaiHD stream" ) self.process_tag(tag, exception=StreamError) if self.completed_handshake: log.debug("Handshake successful") break def process_tag(self, tag, exception=IOError): if isinstance(tag.data, ScriptData) and tag.data.name == "onEdge": self._on_edge(tag.data.value, exception=exception) self.buffer.write(tag.serialize()) def send_token(self, token): headers = {"x-Akamai-Streaming-SessionToken": token} log.debug("Sending new session token") self.send_control("sendingNewToken", headers=headers, swf=self.swf) def send_control(self, cmd, headers=None, **params): if not headers: headers = {} url = self.ControlURLFormat.format(host=self.host, streamname=self.streamname) headers["x-Akamai-Streaming-SessionID"] = self.sessionid params = self._create_params(cmd=cmd, **params) return self.session.http.post(url, headers=headers, params=params, data=self.ControlData, exception=StreamError) def read(self, size=-1): if not (self.flv and self.fd): return b"" if self.buffer.length: return self.buffer.read(size) else: return self.fd.read(size) def _create_params(self, **extra): params = dict(v=self.Version, fp=self.FlashVersion, r=cache_bust_string(5), g=self.guid) params.update(extra) return params def _generate_session_token(self, data64): swfdata = base64.decodestring(bytes(data64, "ascii")) md5 = hashlib.md5() md5.update(swfdata) hash = md5.hexdigest() if hash in self.TokenGenerators: generator = self.TokenGenerators[hash](self) return generator.generate() else: raise StreamError( ("No token generator available for hash '{0}'").format(hash)) def _on_edge(self, data, exception=IOError): def updateattr(attr, key): if key in data: setattr(self, attr, data[key]) log.debug("onEdge data") for key, val in data.items(): if isinstance(val, str): val = val[:50] log.debug(f" {key}={val}") updateattr("islive", "isLive") updateattr("sessionid", "session") updateattr("status", "status") updateattr("streamname", "streamName") if self.status == self.StatusComplete: self.flv = None elif self.status == self.StatusError: errornum = data["errorNumber"] if errornum in self.Errors: msg = self.Errors[errornum] else: msg = "Unknown error" raise exception("onEdge error: " + msg) if not self.completed_handshake: if "data64" in data: sessiontoken = self._generate_session_token(data["data64"]) else: sessiontoken = None self.send_token(sessiontoken) self.completed_handshake = True
def write(self, fragment, res, chunk_size=8192): fd = StreamIOIterWrapper(res.iter_content(chunk_size)) self.convert_fragment(fragment, fd)