207 lines
5.6 KiB
Python
207 lines
5.6 KiB
Python
#!/usr/bin/python3
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Optional, Dict, Any, List, Union
|
|
|
|
from .types import ExternalUrls, Image, _str, _int
|
|
from .track import Track as TrackModel
|
|
|
|
|
|
@dataclass
|
|
class UserMini:
|
|
id: Optional[str] = None
|
|
type: str = "user"
|
|
uri: Optional[str] = None
|
|
display_name: Optional[str] = None
|
|
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
|
|
|
@staticmethod
|
|
def from_dict(obj: Any) -> "UserMini":
|
|
if not isinstance(obj, dict):
|
|
return UserMini()
|
|
return UserMini(
|
|
id=_str(obj.get("id")),
|
|
type=_str(obj.get("type")) or "user",
|
|
uri=_str(obj.get("uri")),
|
|
display_name=_str(obj.get("display_name")),
|
|
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
out = {
|
|
"id": self.id,
|
|
"type": self.type,
|
|
"uri": self.uri,
|
|
"display_name": self.display_name,
|
|
"external_urls": self.external_urls.to_dict(),
|
|
}
|
|
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
|
|
|
|
|
@dataclass
|
|
class TrackStub:
|
|
id: Optional[str] = None
|
|
type: str = "track"
|
|
uri: Optional[str] = None
|
|
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
|
|
|
@staticmethod
|
|
def from_dict(obj: Any) -> "TrackStub":
|
|
if not isinstance(obj, dict):
|
|
return TrackStub()
|
|
return TrackStub(
|
|
id=_str(obj.get("id")),
|
|
type=_str(obj.get("type")) or "track",
|
|
uri=_str(obj.get("uri")),
|
|
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
out = {
|
|
"id": self.id,
|
|
"type": self.type,
|
|
"uri": self.uri,
|
|
"external_urls": self.external_urls.to_dict(),
|
|
}
|
|
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
|
|
|
|
|
@dataclass
|
|
class PlaylistItem:
|
|
added_at: Optional[str] = None
|
|
added_by: UserMini = field(default_factory=UserMini)
|
|
is_local: bool = False
|
|
track: Optional[Union[TrackModel, TrackStub]] = None
|
|
item_id: Optional[str] = None
|
|
|
|
@staticmethod
|
|
def from_dict(obj: Any) -> "PlaylistItem":
|
|
if not isinstance(obj, dict):
|
|
return PlaylistItem()
|
|
track_obj = None
|
|
trk = obj.get("track")
|
|
if isinstance(trk, dict):
|
|
if trk.get("duration_ms") is not None:
|
|
track_obj = TrackModel.from_dict(trk)
|
|
else:
|
|
track_obj = TrackStub.from_dict(trk)
|
|
return PlaylistItem(
|
|
added_at=_str(obj.get("added_at")),
|
|
added_by=UserMini.from_dict(obj.get("added_by", {})),
|
|
is_local=bool(obj.get("is_local", False)),
|
|
track=track_obj,
|
|
item_id=_str(obj.get("item_id")),
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
out = {
|
|
"added_at": self.added_at,
|
|
"added_by": self.added_by.to_dict(),
|
|
"is_local": self.is_local,
|
|
"track": self.track.to_dict() if hasattr(self.track, 'to_dict') and self.track else None,
|
|
"item_id": self.item_id,
|
|
}
|
|
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
|
|
|
|
|
@dataclass
|
|
class TracksPage:
|
|
offset: int = 0
|
|
total: int = 0
|
|
items: List[PlaylistItem] = field(default_factory=list)
|
|
|
|
@staticmethod
|
|
def from_dict(obj: Any) -> "TracksPage":
|
|
if not isinstance(obj, dict):
|
|
return TracksPage(items=[])
|
|
items: List[PlaylistItem] = []
|
|
for it in obj.get("items", []) or []:
|
|
items.append(PlaylistItem.from_dict(it))
|
|
return TracksPage(
|
|
offset=_int(obj.get("offset")) or 0,
|
|
total=_int(obj.get("total")) or len(items),
|
|
items=items,
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
return {
|
|
"offset": self.offset,
|
|
"total": self.total,
|
|
"items": [it.to_dict() for it in (self.items or [])]
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class Owner:
|
|
id: Optional[str] = None
|
|
type: str = "user"
|
|
uri: Optional[str] = None
|
|
display_name: Optional[str] = None
|
|
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
|
|
|
@staticmethod
|
|
def from_dict(obj: Any) -> "Owner":
|
|
if not isinstance(obj, dict):
|
|
return Owner()
|
|
return Owner(
|
|
id=_str(obj.get("id")),
|
|
type=_str(obj.get("type")) or "user",
|
|
uri=_str(obj.get("uri")),
|
|
display_name=_str(obj.get("display_name")),
|
|
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
out = {
|
|
"id": self.id,
|
|
"type": self.type,
|
|
"uri": self.uri,
|
|
"display_name": self.display_name,
|
|
"external_urls": self.external_urls.to_dict(),
|
|
}
|
|
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
|
|
|
|
|
@dataclass
|
|
class Playlist:
|
|
name: Optional[str] = None
|
|
description: Optional[str] = None
|
|
collaborative: Optional[bool] = None
|
|
images: Optional[List[Image]] = None
|
|
owner: Owner = field(default_factory=Owner)
|
|
snapshot_id: Optional[str] = None
|
|
tracks: TracksPage = field(default_factory=lambda: TracksPage(items=[]))
|
|
type: str = "playlist"
|
|
|
|
@staticmethod
|
|
def from_dict(obj: Any) -> "Playlist":
|
|
if not isinstance(obj, dict):
|
|
return Playlist(tracks=TracksPage(items=[]))
|
|
imgs: List[Image] = []
|
|
for im in obj.get("images", []) or []:
|
|
im_obj = Image.from_dict(im)
|
|
if im_obj:
|
|
imgs.append(im_obj)
|
|
return Playlist(
|
|
name=_str(obj.get("name")),
|
|
description=_str(obj.get("description")),
|
|
collaborative=bool(obj.get("collaborative")) if obj.get("collaborative") is not None else None,
|
|
images=imgs or None,
|
|
owner=Owner.from_dict(obj.get("owner", {})),
|
|
snapshot_id=_str(obj.get("snapshot_id")),
|
|
tracks=TracksPage.from_dict(obj.get("tracks", {})),
|
|
type=_str(obj.get("type")) or "playlist",
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
out = {
|
|
"name": self.name,
|
|
"description": self.description,
|
|
"collaborative": self.collaborative,
|
|
"images": [im.to_dict() for im in (self.images or [])],
|
|
"owner": self.owner.to_dict(),
|
|
"snapshot_id": self.snapshot_id,
|
|
"tracks": self.tracks.to_dict(),
|
|
"type": self.type,
|
|
}
|
|
return {k: v for k, v in out.items() if v not in (None, {}, [], "")} |