diff --git a/libremsonic/__main__.py b/libremsonic/__main__.py index db15ec5..c3ee2eb 100644 --- a/libremsonic/__main__.py +++ b/libremsonic/__main__.py @@ -17,7 +17,7 @@ def main(): password=sys.argv[2]) # print(server.ping()) - # print(server.get_license()) + print(server.get_license()) print(server.get_music_folders()) # print(server.get_indexes()) # print() diff --git a/libremsonic/server/api_objects.py b/libremsonic/server/api_objects.py index b22dbbf..6019f4a 100644 --- a/libremsonic/server/api_objects.py +++ b/libremsonic/server/api_objects.py @@ -1,5 +1,6 @@ import inspect -from typing import Dict, List, Any +import typing +from typing import Dict, List, Any, Type from datetime import datetime from dateutil import parser @@ -9,25 +10,37 @@ def _from_json(cls, data): Approach for deserialization here: https://stackoverflow.com/a/40639688/2319844 """ - print(cls, data) - annotations: Dict[str, Any] = getattr(cls, '__annotations__', {}) + annotations: Dict[str, Type] = getattr(cls, '__annotations__', {}) # Handle lists of objects. if cls == str: - return data - if issubclass(cls, List): - list_type = cls.__args__[0] - instance: List[list_type] = list() - for value in data: - instance.append(_from_json(list_type, value)) + instance = data + elif cls == int: + instance = int(data) + elif cls == bool: + instance = bool(data) + elif cls == datetime: + instance = parser.parse(data) + elif type(cls) == typing._GenericAlias: + # Having to use this because things changed in Python 3.7. - # Handle dictionaries of objects. - elif issubclass(cls, Dict): - key_type, val_type = cls.__args__ - instance: Dict[key_type, val_type] = dict() - for key, value in data.items(): - instance.update(_from_json(key_type, key), - _from_json(val_type, value)) + # No idea what the heck this is, but let's go with it. + if cls._name == 'List': + list_type = cls.__args__[0] + instance: List[list_type] = list() + for value in data: + instance.append(_from_json(list_type, value)) + + elif cls._name == 'Dict': + key_type, val_type = cls.__args__ + instance: Dict[key_type, val_type] = dict() + for key, value in data.items(): + key = _from_json(key_type, key) + value = _from_json(val_type, value) + instance[key] = value + else: + raise Exception( + 'Trying to deserialize an unsupported type: {cls._name}') # Handle everything else by first instantiating the class, then adding # all of the sub-elements, recursively calling from_json on them. @@ -35,11 +48,10 @@ def _from_json(cls, data): instance: cls = cls() for name, value in data.items(): field_type = annotations.get(name) - print('ohea', field_type, value) - if inspect.isclass(field_type): + + # Sometimes there are extraneous values, ignore them. + if field_type: setattr(instance, name, _from_json(field_type, value)) - else: - setattr(instance, name, value) return instance @@ -74,6 +86,7 @@ class License(APIObject): valid: bool email: str licenseExpires: datetime + trialExpires: datetime class MusicFolder(APIObject): @@ -86,4 +99,4 @@ class SubsonicResponse(APIObject): version: str license: License error: SubsonicError - musicFolders: List[MusicFolder] + musicFolders: Dict[str, List[MusicFolder]] diff --git a/libremsonic/server/server.py b/libremsonic/server/server.py index f9eab5c..3f2b1f1 100644 --- a/libremsonic/server/server.py +++ b/libremsonic/server/server.py @@ -51,7 +51,9 @@ class Server: def get_music_folders(self): result = self._post(self._make_url('getMusicFolders')) - return result.musicFolders + # The Airsonic API implementation of this is dumb. It gives totally the + # wrong answer so we have to go in to the 'musicFolder' key here. + return result.musicFolders['musicFolder'] def get_indexes(self): result = self._post(self._make_url('getIndexes'))