Skip to content

Commit

Permalink
feat: add utility method for getting attributes as map (#354)
Browse files Browse the repository at this point in the history
  • Loading branch information
JurgenR authored Nov 4, 2024
1 parent b65d4ac commit 3f94f70
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/aioslsk/distributed.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ async def _on_distributed_child_depth(
@on_message(DistributedSearchRequest.Request)
async def _on_distributed_search_request(
self, message: DistributedSearchRequest.Request, connection: PeerConnection):

await self.send_messages_to_children(message)

@on_message(DistributedServerSearchRequest.Request)
Expand Down
22 changes: 22 additions & 0 deletions src/aioslsk/protocol/primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
has been fully parsed. If not it will parse this field
"""
from dataclasses import dataclass, field, Field, fields, is_dataclass
import enum
import hashlib
import logging
import socket
Expand Down Expand Up @@ -64,6 +65,14 @@ def serialize(self, *args, **kwargs) -> bytes:
...


class AttributeKey(enum.Enum):
BITRATE = 0
DURATION = 1
VBR = 2
SAMPLE_RATE = 4
BIT_DEPTH = 5


def decode_string(value: bytes) -> str:
try:
return value.decode('utf-8')
Expand Down Expand Up @@ -473,6 +482,19 @@ def serialize(self) -> bytes:
array(self.attributes).serialize(Attribute)
)

def get_attribute_map(self) -> dict[AttributeKey, int]:
"""Converts the attribute list to a dictionary. The resulting dictionary
will only contain known attributes and attributes present in the list
"""
attribute_dict = {}
for attr in self.attributes:
try:
attribute_dict[AttributeKey(attr.key)] = attr.value
except ValueError:
pass

return attribute_dict


@dataclass(frozen=True, order=True)
class DirectoryData(ProtocolDataclass):
Expand Down
1 change: 1 addition & 0 deletions src/aioslsk/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ async def runner(self):


class Timer:
"""Re-schedulable timer which runs a callback after completion"""

def __init__(self, timeout: float, callback: TaskCoroutine):
self.timeout: float = timeout
Expand Down
1 change: 1 addition & 0 deletions src/aioslsk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def get_duration(attributes: list[Attribute]) -> str:


def get_attribute_string(attributes: list[Attribute]) -> str:
"""Returns an attributes list to a string (excludes duration)"""
attr_str = []
for attr in attributes:
if attr.key == 0:
Expand Down
32 changes: 31 additions & 1 deletion tests/unit/protocol/test_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
from typing import ClassVar
import pytest

from aioslsk.protocol.primitives import decode_string, uint32, MessageDataclass
from aioslsk.protocol.primitives import (
decode_string,
Attribute,
AttributeKey,
FileData,
MessageDataclass,
uint32,
)


logger = logging.getLogger()
Expand Down Expand Up @@ -53,3 +60,26 @@ def test_whenDeserialize_fieldWithoutType_shouldRaise(self):
data = bytes.fromhex('04000000010000000100000030')
with pytest.raises(Exception):
FieldWithoutType.deserialize(0, data)


class TestFileData:

def test_getAttributeMap(self):
attrs = [
Attribute(0, 320),
Attribute(1, 120),
Attribute(2, 1),
Attribute(4, 44100),
Attribute(5, 24),
# Unknown value
Attribute(10, 10)
]
file_data = FileData(1, 'test', 2, '', attrs)

assert file_data.get_attribute_map() == {
AttributeKey.BITRATE: 320,
AttributeKey.DURATION: 120,
AttributeKey.VBR: 1,
AttributeKey.SAMPLE_RATE: 44100,
AttributeKey.BIT_DEPTH: 24
}

0 comments on commit 3f94f70

Please sign in to comment.