feat: add data models for search results
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,3 +19,4 @@ deezspot_test.log
|
|||||||
spotify_downloads
|
spotify_downloads
|
||||||
deezer_spo_downloads
|
deezer_spo_downloads
|
||||||
__pycache__
|
__pycache__
|
||||||
|
test_librespot.py
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from .track import Track
|
|||||||
from .album import Album
|
from .album import Album
|
||||||
from .playlist import Playlist, PlaylistItem, TrackStub, TracksPage, Owner, UserMini
|
from .playlist import Playlist, PlaylistItem, TrackStub, TracksPage, Owner, UserMini
|
||||||
from .artist import Artist
|
from .artist import Artist
|
||||||
|
from .search import SearchResult, SearchTracksPage, SearchAlbumsPage, SearchArtistsPage, SearchPlaylistsPage
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Image",
|
"Image",
|
||||||
@@ -20,4 +21,9 @@ __all__ = [
|
|||||||
"Owner",
|
"Owner",
|
||||||
"UserMini",
|
"UserMini",
|
||||||
"Artist",
|
"Artist",
|
||||||
|
"SearchResult",
|
||||||
|
"SearchTracksPage",
|
||||||
|
"SearchAlbumsPage",
|
||||||
|
"SearchArtistsPage",
|
||||||
|
"SearchPlaylistsPage",
|
||||||
]
|
]
|
||||||
179
deezspot/models/librespot/search.py
Normal file
179
deezspot/models/librespot/search.py
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Optional, Dict, Any, List
|
||||||
|
|
||||||
|
from .track import Track
|
||||||
|
from .album import Album
|
||||||
|
from .artist import Artist
|
||||||
|
from .playlist import Playlist
|
||||||
|
from .types import _int
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SearchTracksPage:
|
||||||
|
limit: int = 0
|
||||||
|
offset: int = 0
|
||||||
|
total: int = 0
|
||||||
|
items: List[Track] = field(default_factory=list)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(obj: Any) -> "SearchTracksPage":
|
||||||
|
if not isinstance(obj, dict):
|
||||||
|
return SearchTracksPage()
|
||||||
|
items: List[Track] = []
|
||||||
|
for it in obj.get("items", []) or []:
|
||||||
|
if isinstance(it, dict):
|
||||||
|
items.append(Track.from_dict(it))
|
||||||
|
return SearchTracksPage(
|
||||||
|
limit=_int(obj.get("limit")) or 0,
|
||||||
|
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 {
|
||||||
|
"limit": self.limit,
|
||||||
|
"offset": self.offset,
|
||||||
|
"total": self.total,
|
||||||
|
"items": [it.to_dict() for it in (self.items or [])]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SearchAlbumsPage:
|
||||||
|
limit: int = 0
|
||||||
|
offset: int = 0
|
||||||
|
total: int = 0
|
||||||
|
items: List[Album] = field(default_factory=list)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(obj: Any) -> "SearchAlbumsPage":
|
||||||
|
if not isinstance(obj, dict):
|
||||||
|
return SearchAlbumsPage()
|
||||||
|
items: List[Album] = []
|
||||||
|
for it in obj.get("items", []) or []:
|
||||||
|
if isinstance(it, dict):
|
||||||
|
items.append(Album.from_dict(it))
|
||||||
|
return SearchAlbumsPage(
|
||||||
|
limit=_int(obj.get("limit")) or 0,
|
||||||
|
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 {
|
||||||
|
"limit": self.limit,
|
||||||
|
"offset": self.offset,
|
||||||
|
"total": self.total,
|
||||||
|
"items": [it.to_dict() for it in (self.items or [])]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SearchArtistsPage:
|
||||||
|
limit: int = 0
|
||||||
|
offset: int = 0
|
||||||
|
total: int = 0
|
||||||
|
items: List[Artist] = field(default_factory=list)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(obj: Any) -> "SearchArtistsPage":
|
||||||
|
if not isinstance(obj, dict):
|
||||||
|
return SearchArtistsPage()
|
||||||
|
items: List[Artist] = []
|
||||||
|
for it in obj.get("items", []) or []:
|
||||||
|
if isinstance(it, dict):
|
||||||
|
items.append(Artist.from_dict(it))
|
||||||
|
return SearchArtistsPage(
|
||||||
|
limit=_int(obj.get("limit")) or 0,
|
||||||
|
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 {
|
||||||
|
"limit": self.limit,
|
||||||
|
"offset": self.offset,
|
||||||
|
"total": self.total,
|
||||||
|
"items": [it.to_dict() for it in (self.items or [])]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SearchPlaylistsPage:
|
||||||
|
limit: int = 0
|
||||||
|
offset: int = 0
|
||||||
|
total: int = 0
|
||||||
|
items: List[Playlist] = field(default_factory=list)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(obj: Any) -> "SearchPlaylistsPage":
|
||||||
|
if not isinstance(obj, dict):
|
||||||
|
return SearchPlaylistsPage()
|
||||||
|
items: List[Playlist] = []
|
||||||
|
for it in obj.get("items", []) or []:
|
||||||
|
if isinstance(it, dict):
|
||||||
|
items.append(Playlist.from_dict(it))
|
||||||
|
return SearchPlaylistsPage(
|
||||||
|
limit=_int(obj.get("limit")) or 0,
|
||||||
|
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 {
|
||||||
|
"limit": self.limit,
|
||||||
|
"offset": self.offset,
|
||||||
|
"total": self.total,
|
||||||
|
"items": [it.to_dict() for it in (self.items or [])]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SearchResult:
|
||||||
|
query: Optional[str] = None
|
||||||
|
tracks: Optional[SearchTracksPage] = None
|
||||||
|
albums: Optional[SearchAlbumsPage] = None
|
||||||
|
artists: Optional[SearchArtistsPage] = None
|
||||||
|
playlists: Optional[SearchPlaylistsPage] = None
|
||||||
|
# raw passthrough for unsupported sections (e.g., shows, episodes)
|
||||||
|
other: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(obj: Any) -> "SearchResult":
|
||||||
|
if not isinstance(obj, dict):
|
||||||
|
return SearchResult()
|
||||||
|
tracks = SearchTracksPage.from_dict(obj.get("tracks", {})) if isinstance(obj.get("tracks"), dict) else None
|
||||||
|
albums = SearchAlbumsPage.from_dict(obj.get("albums", {})) if isinstance(obj.get("albums"), dict) else None
|
||||||
|
artists = SearchArtistsPage.from_dict(obj.get("artists", {})) if isinstance(obj.get("artists"), dict) else None
|
||||||
|
playlists = SearchPlaylistsPage.from_dict(obj.get("playlists", {})) if isinstance(obj.get("playlists"), dict) else None
|
||||||
|
known = {k for k in ("query", "tracks", "albums", "artists", "playlists")}
|
||||||
|
other = {k: v for k, v in obj.items() if k not in known}
|
||||||
|
return SearchResult(
|
||||||
|
query=obj.get("query"),
|
||||||
|
tracks=tracks,
|
||||||
|
albums=albums,
|
||||||
|
artists=artists,
|
||||||
|
playlists=playlists,
|
||||||
|
other=other,
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
out: Dict[str, Any] = {}
|
||||||
|
if self.query is not None:
|
||||||
|
out["query"] = self.query
|
||||||
|
if self.tracks is not None:
|
||||||
|
out["tracks"] = self.tracks.to_dict()
|
||||||
|
if self.albums is not None:
|
||||||
|
out["albums"] = self.albums.to_dict()
|
||||||
|
if self.artists is not None:
|
||||||
|
out["artists"] = self.artists.to_dict()
|
||||||
|
if self.playlists is not None:
|
||||||
|
out["playlists"] = self.playlists.to_dict()
|
||||||
|
out.update(self.other or {})
|
||||||
|
return out
|
||||||
Reference in New Issue
Block a user