Files
sublime-music/libremsonic/server/api_objects.py
Sumner Evans 0177b3ade2 Added todo
2019-06-04 18:45:13 -06:00

247 lines
5.2 KiB
Python

import typing
from typing import Dict, List, Any, Type
from datetime import datetime
from dateutil import parser
def _from_json(cls, data):
"""
Approach for deserialization here:
https://stackoverflow.com/a/40639688/2319844
"""
# If it's a forward reference, evaluate it to figure out the actual
# type.
if isinstance(cls, typing.ForwardRef):
cls = cls._evaluate(globals(), locals())
annotations: Dict[str, Type] = getattr(cls, '__annotations__', {})
# Handle primitive of objects
if data is None:
instance = None
elif cls == str:
instance = data
elif cls == int:
instance = int(data)
elif cls == bool:
instance = bool(data)
elif cls == datetime:
instance = parser.parse(data)
# Handle generics. List[*], Dict[*, *] in particular.
elif type(cls) == typing._GenericAlias:
# Having to use this because things changed in Python 3.7.
class_name = cls._name
# TODO: this is not very elegant since it doesn't allow things which
# sublass from List or Dict.
if class_name == 'List':
list_type = cls.__args__[0]
instance: List[list_type] = list()
for value in data:
instance.append(_from_json(list_type, value))
elif class_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.
else:
instance: cls = cls()
for field, field_type in annotations.items():
value = data.get(field)
setattr(instance, field, _from_json(field_type, value))
return instance
class APIObject:
@classmethod
def from_json(cls, data):
return _from_json(cls, data)
def get(self, field, default=None):
return getattr(self, field, default)
def __repr__(self):
annotations: Dict[str, Any] = self.get('__annotations__', {})
typename = type(self).__name__
fieldstr = ' '.join([
f'{field}={getattr(self, field)!r}'
for field in annotations.keys() if hasattr(self, field)
])
return f'<{typename} {fieldstr}>'
class SubsonicError(APIObject):
code: int
message: str
def as_exception(self):
return Exception(f'{self.code}: {self.message}')
class License(APIObject):
valid: bool
email: str
licenseExpires: datetime
trialExpires: datetime
class MusicFolder(APIObject):
id: int
name: str
class File(APIObject):
id: int
parent: int
title: str
isDir: bool
album: str
artist: str
track: str
year: str
genre: str
coverArt: int
size: int
contentType: str
isVideo: bool
transcodedSuffix: str
transcodedContentType: str
suffix: str
duration: int
bitRate: int
path: str
playCount: int
created: datetime
class Album(APIObject):
id: int
name: str
artist: str
artistId: int
coverArt: str
songCount: int
duration: int
created: datetime
year: str
genre: str
song: List[File]
class Artist(APIObject):
id: int
name: str
coverArt: str
albumCount: int
album: List[Album]
class Shortcut(APIObject):
id: int
name: str
class Index(APIObject):
name: str
artist: List[Artist]
class Indexes(APIObject):
lastModified: int
ignoredArticles: str
index: List[Index]
shortcut: List[Shortcut]
child: List[File]
class Directory(APIObject):
id: int
parent: str
name: str
playCount: int
child: List[File]
class Genre(APIObject):
songCount: int
albumCount: int
vvalue: str
class MusicFolders(APIObject):
musicFolder: List[MusicFolder]
class Genres(APIObject):
genre: List[Genre]
class Artists(APIObject):
index: List[Index]
class Videos(APIObject):
video: List[File]
class VideoInfo(APIObject):
# TODO implement when I have videos
pass
class ArtistInfo(APIObject):
biography: str
musicBrainzId: str
lastFmUrl: str
smallImageUrl: str
mediumImageUrl: str
largeImageUrl: str
similarArtist: List[Artist]
class AlbumInfo(APIObject):
notes: str
musicBrainzId: str
lastFmUrl: str
smallImageUrl: str
mediumImageUrl: str
largeImageUrl: str
class SimilarSongs(APIObject):
song: List[File]
class SubsonicResponse(APIObject):
status: str
version: str
license: License
error: SubsonicError
musicFolders: MusicFolders
indexes: Indexes
directory: Directory
genres: Genres
artists: Artists
artist: Artist
album: Album
song: File
videos: Videos
videoInfo: VideoInfo
artistInfo: ArtistInfo
artistInfo2: ArtistInfo
albumInfo: AlbumInfo
albumInfo2: AlbumInfo
similarSongs: SimilarSongs