feat: add data models for search results

This commit is contained in:
Xoconoch
2025-08-26 22:15:01 -06:00
parent 6c795d8d92
commit e55b15db2c
3 changed files with 186 additions and 0 deletions

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ deezspot_test.log
spotify_downloads spotify_downloads
deezer_spo_downloads deezer_spo_downloads
__pycache__ __pycache__
test_librespot.py

View File

@@ -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",
] ]

View 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