diff --git a/pyatv/support/opack.py b/pyatv/support/opack.py index e177cfd2c..c04ea2a24 100644 --- a/pyatv/support/opack.py +++ b/pyatv/support/opack.py @@ -1,7 +1,6 @@ """Support for the OPACK serialization format. Notes: - * Absolute time (0x06) is not implemented (can unpack as integer, not pack) * Pack implementation does not implement UID referencing * Likely other cases missing """ @@ -15,6 +14,8 @@ _SIZED_INT_TYPES: Dict[int, Type] = {} +_OPACK_TIME_OFFSET: float = 978307200.0 + def _sized_int(value: int, size: int) -> int: """Return an int subclass with a size attribute. @@ -44,7 +45,9 @@ def _pack(data, object_list): elif isinstance(data, UUID): packed_bytes = b"\x05" + data.bytes elif isinstance(data, datetime): - raise NotImplementedError("absolute time") + packed_bytes = b"\x06" + struct.pack( + ">d", data.timestamp() - _OPACK_TIME_OFFSET + ) elif isinstance(data, int): size_hint = getattr(data, "size", None) # if created with _sized_int() if data < 0x28 and not size_hint: @@ -154,8 +157,12 @@ def _unpack(data, object_list): value = UUID(bytes=data[1:17]) remaining = data[17:] elif data[0] == 0x06: - # TODO: Dummy implementation: only parse as integer - value, remaining = int.from_bytes(data[1:9], byteorder="little"), data[9:] + value, remaining = ( + datetime.fromtimestamp( + struct.unpack(">d", data[1:9])[0] + _OPACK_TIME_OFFSET + ), + data[9:], + ) elif 0x08 <= data[0] <= 0x2F: value, remaining = data[0] - 8, data[1:] add_to_object_list = False diff --git a/tests/support/test_opack.py b/tests/support/test_opack.py index e337d855c..77cd11f79 100644 --- a/tests/support/test_opack.py +++ b/tests/support/test_opack.py @@ -36,8 +36,7 @@ def test_pack_uuid(): def test_pack_absolute_time(): - with pytest.raises(NotImplementedError): - pack(datetime.now()) + assert pack(datetime.fromtimestamp(978307200.0)) == b"\x06" + (b"\x00" * 8) def test_pack_small_integers(): @@ -223,8 +222,10 @@ def test_unpack_uuid(): def test_unpack_absolute_time(): - # TODO: This is not implemented, it only parses the time stamp as an integer - assert unpack(b"\x06\x01\x00\x00\x00\x00\x00\x00\x00") == (1, b"") + assert unpack(b"\x06\x00\x00\x00\x00\x00\x00\x00\x00") == ( + datetime.fromtimestamp(978307200.0), + b"", + ) def test_unpack_small_integers():