feat: implement public librespot api class, see docs
This commit is contained in:
23
deezspot/models/librespot/__init__.py
Normal file
23
deezspot/models/librespot/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from .types import Image, ExternalUrls, ArtistRef, AlbumRef
|
||||
from .track import Track
|
||||
from .album import Album
|
||||
from .playlist import Playlist, PlaylistItem, TrackStub, TracksPage, Owner, UserMini
|
||||
from .artist import Artist
|
||||
|
||||
__all__ = [
|
||||
"Image",
|
||||
"ExternalUrls",
|
||||
"ArtistRef",
|
||||
"AlbumRef",
|
||||
"Track",
|
||||
"Album",
|
||||
"Playlist",
|
||||
"PlaylistItem",
|
||||
"TrackStub",
|
||||
"TracksPage",
|
||||
"Owner",
|
||||
"UserMini",
|
||||
"Artist",
|
||||
]
|
||||
92
deezspot/models/librespot/album.py
Normal file
92
deezspot/models/librespot/album.py
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, Any, List, Union
|
||||
|
||||
from .types import ExternalUrls, Image, ArtistRef, _str, _int
|
||||
from .track import Track as TrackModel
|
||||
|
||||
|
||||
@dataclass
|
||||
class Album:
|
||||
id: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
uri: Optional[str] = None
|
||||
type: str = "album"
|
||||
album_type: Optional[str] = None
|
||||
release_date: Optional[str] = None
|
||||
release_date_precision: Optional[str] = None
|
||||
total_tracks: Optional[int] = None
|
||||
label: Optional[str] = None
|
||||
popularity: Optional[int] = None
|
||||
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
||||
external_ids: Dict[str, str] = field(default_factory=dict)
|
||||
available_markets: Optional[List[str]] = None
|
||||
images: Optional[List[Image]] = None
|
||||
artists: List[ArtistRef] = field(default_factory=list)
|
||||
tracks: Optional[List[Union[str, TrackModel]]] = None
|
||||
copyrights: Optional[List[Dict[str, Any]]] = None
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> "Album":
|
||||
if not isinstance(obj, dict):
|
||||
return Album()
|
||||
imgs: List[Image] = []
|
||||
for im in obj.get("images", []) or []:
|
||||
im_obj = Image.from_dict(im)
|
||||
if im_obj:
|
||||
imgs.append(im_obj)
|
||||
artists: List[ArtistRef] = []
|
||||
for a in obj.get("artists", []) or []:
|
||||
artists.append(ArtistRef.from_dict(a))
|
||||
# Tracks can be base62 strings or full track dicts
|
||||
tracks_in: List[Union[str, TrackModel]] = []
|
||||
if isinstance(obj.get("tracks"), list):
|
||||
for t in obj.get("tracks"):
|
||||
if isinstance(t, dict):
|
||||
tracks_in.append(TrackModel.from_dict(t))
|
||||
else:
|
||||
ts = _str(t)
|
||||
if ts:
|
||||
tracks_in.append(ts)
|
||||
return Album(
|
||||
id=_str(obj.get("id")),
|
||||
name=_str(obj.get("name")),
|
||||
uri=_str(obj.get("uri")),
|
||||
type=_str(obj.get("type")) or "album",
|
||||
album_type=_str(obj.get("album_type")),
|
||||
release_date=_str(obj.get("release_date")),
|
||||
release_date_precision=_str(obj.get("release_date_precision")),
|
||||
total_tracks=_int(obj.get("total_tracks")),
|
||||
label=_str(obj.get("label")),
|
||||
popularity=_int(obj.get("popularity")),
|
||||
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
||||
external_ids=dict(obj.get("external_ids", {}) or {}),
|
||||
available_markets=list(obj.get("available_markets", []) or []),
|
||||
images=imgs or None,
|
||||
artists=artists,
|
||||
tracks=tracks_in or None,
|
||||
copyrights=list(obj.get("copyrights", []) or []),
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
out = {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"uri": self.uri,
|
||||
"type": self.type,
|
||||
"album_type": self.album_type,
|
||||
"release_date": self.release_date,
|
||||
"release_date_precision": self.release_date_precision,
|
||||
"total_tracks": self.total_tracks,
|
||||
"label": self.label,
|
||||
"popularity": self.popularity,
|
||||
"external_urls": self.external_urls.to_dict(),
|
||||
"external_ids": self.external_ids or {},
|
||||
"available_markets": self.available_markets or [],
|
||||
"images": [im.to_dict() for im in (self.images or [])],
|
||||
"artists": [a.to_dict() for a in (self.artists or [])],
|
||||
"tracks": [t.to_dict() if isinstance(t, TrackModel) else t for t in (self.tracks or [])],
|
||||
"copyrights": self.copyrights or [],
|
||||
}
|
||||
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
||||
63
deezspot/models/librespot/artist.py
Normal file
63
deezspot/models/librespot/artist.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from .types import ExternalUrls, Image, _str, _int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Artist:
|
||||
id: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
uri: Optional[str] = None
|
||||
type: str = "artist"
|
||||
genres: List[str] = field(default_factory=list)
|
||||
images: Optional[List[Image]] = None
|
||||
popularity: Optional[int] = None
|
||||
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
||||
album_group: List[str] = field(default_factory=list)
|
||||
single_group: List[str] = field(default_factory=list)
|
||||
compilation_group: List[str] = field(default_factory=list)
|
||||
appears_on_group: List[str] = field(default_factory=list)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> "Artist":
|
||||
if not isinstance(obj, dict):
|
||||
return Artist()
|
||||
imgs: List[Image] = []
|
||||
for im in obj.get("images", []) or []:
|
||||
im_obj = Image.from_dict(im)
|
||||
if im_obj:
|
||||
imgs.append(im_obj)
|
||||
return Artist(
|
||||
id=_str(obj.get("id")),
|
||||
name=_str(obj.get("name")),
|
||||
uri=_str(obj.get("uri")),
|
||||
type=_str(obj.get("type")) or "artist",
|
||||
genres=list(obj.get("genres", []) or []),
|
||||
images=imgs or None,
|
||||
popularity=_int(obj.get("popularity")),
|
||||
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
||||
album_group=list(obj.get("album_group", []) or []),
|
||||
single_group=list(obj.get("single_group", []) or []),
|
||||
compilation_group=list(obj.get("compilation_group", []) or []),
|
||||
appears_on_group=list(obj.get("appears_on_group", []) or []),
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
out = {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"uri": self.uri,
|
||||
"type": self.type,
|
||||
"genres": self.genres or [],
|
||||
"images": [im.to_dict() for im in (self.images or [])],
|
||||
"popularity": self.popularity,
|
||||
"external_urls": self.external_urls.to_dict(),
|
||||
"album_group": self.album_group or [],
|
||||
"single_group": self.single_group or [],
|
||||
"compilation_group": self.compilation_group or [],
|
||||
"appears_on_group": self.appears_on_group or [],
|
||||
}
|
||||
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
||||
207
deezspot/models/librespot/playlist.py
Normal file
207
deezspot/models/librespot/playlist.py
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/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, {}, [], "")}
|
||||
82
deezspot/models/librespot/track.py
Normal file
82
deezspot/models/librespot/track.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from .types import ExternalUrls, Image, ArtistRef, AlbumRef, _str, _int, _bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class Track:
|
||||
id: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
uri: Optional[str] = None
|
||||
type: str = "track"
|
||||
duration_ms: Optional[int] = None
|
||||
explicit: Optional[bool] = None
|
||||
track_number: Optional[int] = None
|
||||
disc_number: Optional[int] = None
|
||||
popularity: Optional[int] = None
|
||||
preview_url: Optional[str] = None
|
||||
earliest_live_timestamp: Optional[int] = None
|
||||
has_lyrics: Optional[bool] = None
|
||||
licensor_uuid: Optional[str] = None
|
||||
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
||||
external_ids: Dict[str, str] = field(default_factory=dict)
|
||||
available_markets: Optional[List[str]] = None
|
||||
artists: List[ArtistRef] = field(default_factory=list)
|
||||
album: Optional[AlbumRef] = None
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> "Track":
|
||||
if not isinstance(obj, dict):
|
||||
return Track()
|
||||
artists: List[ArtistRef] = []
|
||||
for a in obj.get("artists", []) or []:
|
||||
artists.append(ArtistRef.from_dict(a))
|
||||
album_ref = None
|
||||
if isinstance(obj.get("album"), dict):
|
||||
album_ref = AlbumRef.from_dict(obj.get("album"))
|
||||
return Track(
|
||||
id=_str(obj.get("id")),
|
||||
name=_str(obj.get("name")),
|
||||
uri=_str(obj.get("uri")),
|
||||
type=_str(obj.get("type")) or "track",
|
||||
duration_ms=_int(obj.get("duration_ms")),
|
||||
explicit=_bool(obj.get("explicit")),
|
||||
track_number=_int(obj.get("track_number")),
|
||||
disc_number=_int(obj.get("disc_number")),
|
||||
popularity=_int(obj.get("popularity")),
|
||||
preview_url=_str(obj.get("preview_url")),
|
||||
earliest_live_timestamp=_int(obj.get("earliest_live_timestamp")),
|
||||
has_lyrics=_bool(obj.get("has_lyrics")),
|
||||
licensor_uuid=_str(obj.get("licensor_uuid")),
|
||||
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
||||
external_ids=dict(obj.get("external_ids", {}) or {}),
|
||||
available_markets=list(obj.get("available_markets", []) or []),
|
||||
artists=artists,
|
||||
album=album_ref,
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
out = {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"uri": self.uri,
|
||||
"type": self.type,
|
||||
"duration_ms": self.duration_ms,
|
||||
"explicit": self.explicit,
|
||||
"track_number": self.track_number,
|
||||
"disc_number": self.disc_number,
|
||||
"popularity": self.popularity,
|
||||
"preview_url": self.preview_url,
|
||||
"earliest_live_timestamp": self.earliest_live_timestamp,
|
||||
"has_lyrics": self.has_lyrics,
|
||||
"licensor_uuid": self.licensor_uuid,
|
||||
"external_urls": self.external_urls.to_dict(),
|
||||
"external_ids": self.external_ids or {},
|
||||
"available_markets": self.available_markets or [],
|
||||
"artists": [a.to_dict() for a in (self.artists or [])],
|
||||
"album": self.album.to_dict() if self.album else None,
|
||||
}
|
||||
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
||||
153
deezspot/models/librespot/types.py
Normal file
153
deezspot/models/librespot/types.py
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
|
||||
def _str(v: Any) -> Optional[str]:
|
||||
if v is None:
|
||||
return None
|
||||
try:
|
||||
s = str(v)
|
||||
return s
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _int(v: Any) -> Optional[int]:
|
||||
try:
|
||||
if v is None:
|
||||
return None
|
||||
return int(v)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _bool(v: Any) -> Optional[bool]:
|
||||
if isinstance(v, bool):
|
||||
return v
|
||||
if v in ("true", "True", "1", 1):
|
||||
return True
|
||||
if v in ("false", "False", "0", 0):
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def _list_str(v: Any) -> Optional[List[str]]:
|
||||
if v is None:
|
||||
return []
|
||||
if isinstance(v, list):
|
||||
out: List[str] = []
|
||||
for it in v:
|
||||
s = _str(it)
|
||||
if s is not None:
|
||||
out.append(s)
|
||||
return out
|
||||
return []
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExternalUrls:
|
||||
spotify: Optional[str] = None
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> "ExternalUrls":
|
||||
if not isinstance(obj, dict):
|
||||
return ExternalUrls()
|
||||
return ExternalUrls(
|
||||
spotify=_str(obj.get("spotify"))
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {"spotify": self.spotify} if self.spotify else {}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Image:
|
||||
url: str
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> Optional["Image"]:
|
||||
if not isinstance(obj, dict):
|
||||
return None
|
||||
url = _str(obj.get("url"))
|
||||
if not url:
|
||||
return None
|
||||
w = _int(obj.get("width")) or 0
|
||||
h = _int(obj.get("height")) or 0
|
||||
return Image(url=url, width=w, height=h)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {"url": self.url, "width": self.width, "height": self.height}
|
||||
|
||||
|
||||
@dataclass
|
||||
class ArtistRef:
|
||||
id: Optional[str] = None
|
||||
name: str = ""
|
||||
type: str = "artist"
|
||||
uri: Optional[str] = None
|
||||
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> "ArtistRef":
|
||||
if not isinstance(obj, dict):
|
||||
return ArtistRef()
|
||||
return ArtistRef(
|
||||
id=_str(obj.get("id")),
|
||||
name=_str(obj.get("name")) or "",
|
||||
type=_str(obj.get("type")) or "artist",
|
||||
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,
|
||||
"name": self.name,
|
||||
"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 AlbumRef:
|
||||
id: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
type: str = "album"
|
||||
uri: Optional[str] = None
|
||||
external_urls: ExternalUrls = field(default_factory=ExternalUrls)
|
||||
images: Optional[List[Image]] = None
|
||||
|
||||
@staticmethod
|
||||
def from_dict(obj: Any) -> "AlbumRef":
|
||||
if not isinstance(obj, dict):
|
||||
return AlbumRef()
|
||||
imgs: List[Image] = []
|
||||
for im in obj.get("images", []) or []:
|
||||
im_obj = Image.from_dict(im)
|
||||
if im_obj:
|
||||
imgs.append(im_obj)
|
||||
return AlbumRef(
|
||||
id=_str(obj.get("id")),
|
||||
name=_str(obj.get("name")),
|
||||
type=_str(obj.get("type")) or "album",
|
||||
uri=_str(obj.get("uri")),
|
||||
external_urls=ExternalUrls.from_dict(obj.get("external_urls", {})),
|
||||
images=imgs or None,
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
out = {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"type": self.type,
|
||||
"uri": self.uri,
|
||||
"external_urls": self.external_urls.to_dict(),
|
||||
"images": [im.to_dict() for im in (self.images or [])]
|
||||
}
|
||||
return {k: v for k, v in out.items() if v not in (None, {}, [], "")}
|
||||
Reference in New Issue
Block a user