コード例 #1
0
ファイル: wrappers.py プロジェクト: AlexELEC/TVLINK-AE-PC
class StreamIOIterWrapper(io.IOBase):
    """Wraps a iterator and turn it into a file-like object"""
    def __init__(self, iterator):
        self.iterator = iterator
        self.buffer = Buffer()

    def read(self, size=-1):
        if size < 0:
            size = self.buffer.length

        while self.buffer.length < size:
            try:
                chunk = next(self.iterator)
                self.buffer.write(chunk)
            except StopIteration:
                break

        return self.buffer.read(size)

    def close(self):
        pass
コード例 #2
0
ファイル: test_buffer.py プロジェクト: galaks1/streamlink-27
class TestBuffer(unittest.TestCase):
    def setUp(self):
        self.buffer = Buffer()

    def test_write(self):
        self.buffer.write(b"1" * 8192)
        self.buffer.write(b"2" * 4096)

        self.assertEqual(self.buffer.length, 8192 + 4096)

    def test_read(self):
        self.buffer.write(b"1" * 8192)
        self.buffer.write(b"2" * 4096)

        self.assertEqual(self.buffer.length, 8192 + 4096)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.read(), b"2" * 4096)
        self.assertEqual(self.buffer.read(4096), b"")
        self.assertEqual(self.buffer.read(), b"")
        self.assertEqual(self.buffer.length, 0)

    def test_readwrite(self):
        self.buffer.write(b"1" * 8192)
        self.assertEqual(self.buffer.length, 8192)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.length, 4096)

        self.buffer.write(b"2" * 4096)
        self.assertEqual(self.buffer.length, 8192)
        self.assertEqual(self.buffer.read(1), b"1")
        self.assertEqual(self.buffer.read(4095), b"1" * 4095)
        self.assertEqual(self.buffer.read(8192), b"2" * 4096)
        self.assertEqual(self.buffer.read(8192), b"")
        self.assertEqual(self.buffer.read(), b"")
        self.assertEqual(self.buffer.length, 0)

    def test_close(self):
        self.buffer.write(b"1" * 8192)
        self.assertEqual(self.buffer.length, 8192)

        self.buffer.close()
        self.buffer.write(b"2" * 8192)
        self.assertEqual(self.buffer.length, 8192)

    def test_reuse_input(self):
        """Objects should be reusable after write()"""

        original = b"original"
        tests = [bytearray(original)]
        try:
            m = memoryview(bytearray(original))
        except NameError:  # Python 2.6 does not have "memoryview"
            pass
        else:
            # Python 2.7 doesn't do bytes(memoryview) properly
            if bytes(m) == original:
                tests.append(m)

        for data in tests:
            self.buffer.write(data)
            data[:] = b"reused!!"
            self.assertEqual(self.buffer.read(), original)

    def test_read_empty(self):
        self.assertRaises(StopIteration,
                          lambda: next(self.buffer._iterate_chunks(10)))
コード例 #3
0
ファイル: akamaihd.py プロジェクト: yuviDX/streamlink
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
コード例 #4
0
ファイル: test_buffer.py プロジェクト: sheldon0531/streamlink
class TestBuffer(unittest.TestCase):
    def setUp(self):
        self.buffer = Buffer()

    def test_write(self):
        self.buffer.write(b"1" * 8192)
        self.buffer.write(b"2" * 4096)

        self.assertEqual(self.buffer.length, 8192 + 4096)

    def test_read(self):
        self.buffer.write(b"1" * 8192)
        self.buffer.write(b"2" * 4096)

        self.assertEqual(self.buffer.length, 8192 + 4096)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.read(), b"2" * 4096)
        self.assertEqual(self.buffer.read(4096), b"")
        self.assertEqual(self.buffer.read(), b"")
        self.assertEqual(self.buffer.length, 0)

    def test_readwrite(self):
        self.buffer.write(b"1" * 8192)
        self.assertEqual(self.buffer.length, 8192)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.length, 4096)

        self.buffer.write(b"2" * 4096)
        self.assertEqual(self.buffer.length, 8192)
        self.assertEqual(self.buffer.read(1), b"1")
        self.assertEqual(self.buffer.read(4095), b"1" * 4095)
        self.assertEqual(self.buffer.read(8192), b"2" * 4096)
        self.assertEqual(self.buffer.read(8192), b"")
        self.assertEqual(self.buffer.read(), b"")
        self.assertEqual(self.buffer.length, 0)

    def test_close(self):
        self.buffer.write(b"1" * 8192)
        self.assertEqual(self.buffer.length, 8192)

        self.buffer.close()
        self.buffer.write(b"2" * 8192)
        self.assertEqual(self.buffer.length, 8192)

    def test_reuse_input(self):
        """Objects should be reusable after write()"""

        original = b"original"
        tests = [bytearray(original)]
        try:
            m = memoryview(bytearray(original))
        except NameError:  # Python 2.6 does not have "memoryview"
            pass
        else:
            # Python 2.7 doesn't do bytes(memoryview) properly
            if bytes(m) == original:
                tests.append(m)

        for data in tests:
            self.buffer.write(data)
            data[:] = b"reused!!"
            self.assertEqual(self.buffer.read(), original)

    def test_read_empty(self):
        self.assertRaises(
            StopIteration,
            lambda: next(self.buffer._iterate_chunks(10)))
コード例 #5
0
ファイル: test_buffer.py プロジェクト: zxlhhyccc/streamlink
class TestBuffer(unittest.TestCase):
    def setUp(self):
        self.buffer = Buffer()

    def test_write(self):
        self.buffer.write(b"1" * 8192)
        self.buffer.write(b"2" * 4096)

        self.assertEqual(self.buffer.length, 8192 + 4096)

    def test_read(self):
        self.buffer.write(b"1" * 8192)
        self.buffer.write(b"2" * 4096)

        self.assertEqual(self.buffer.length, 8192 + 4096)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.read(), b"2" * 4096)
        self.assertEqual(self.buffer.read(4096), b"")
        self.assertEqual(self.buffer.read(), b"")
        self.assertEqual(self.buffer.length, 0)

    def test_readwrite(self):
        self.buffer.write(b"1" * 8192)
        self.assertEqual(self.buffer.length, 8192)
        self.assertEqual(self.buffer.read(4096), b"1" * 4096)
        self.assertEqual(self.buffer.length, 4096)

        self.buffer.write(b"2" * 4096)
        self.assertEqual(self.buffer.length, 8192)
        self.assertEqual(self.buffer.read(1), b"1")
        self.assertEqual(self.buffer.read(4095), b"1" * 4095)
        self.assertEqual(self.buffer.read(8192), b"2" * 4096)
        self.assertEqual(self.buffer.read(8192), b"")
        self.assertEqual(self.buffer.read(), b"")
        self.assertEqual(self.buffer.length, 0)

    def test_close(self):
        self.buffer.write(b"1" * 8192)
        self.assertEqual(self.buffer.length, 8192)

        self.buffer.close()
        self.buffer.write(b"2" * 8192)
        self.assertEqual(self.buffer.length, 8192)

    def test_reuse_input(self):
        """Objects should be reusable after write()"""

        original = b"original"
        tests = [bytearray(original), memoryview(bytearray(original))]

        for data in tests:
            self.buffer.write(data)
            data[:] = b"reused!!"
            self.assertEqual(self.buffer.read(), original)

    def test_read_empty(self):
        self.assertRaises(
            StopIteration,
            lambda: next(self.buffer._iterate_chunks(10)))