from attrs import define from ..common.song import BaseSongItem from .driver import DeezerDriver @define class SongItem(BaseSongItem): @classmethod def from_deezer(cls, song_item: dict): return cls( name=song_item["title"], id=str(song_item["id"]), artists=[song_item["artist"]["name"]], preview_url=song_item.get("preview"), thumbnail=song_item["album"]["cover_medium"], ) @define class FullSongItem(BaseSongItem): duration: int track_dict: dict @classmethod async def from_deezer(cls, song_item: dict): if song_item.get("results"): song_item = song_item["results"] return cls( name=song_item["SNG_TITLE"], id=song_item["SNG_ID"], artists=[artist["ART_NAME"] for artist in song_item["ARTISTS"]], preview_url=( song_item.get("MEDIA").get("HREF") if type(song_item.get("MEDIA")) is dict and song_item.get("MEDIA").get("TYPE") == "preview" else None ), thumbnail=f"https://e-cdns-images.dzcdn.net/images/cover/" f'{song_item["ALB_PICTURE"]}/320x320.jpg', duration=int(song_item["DURATION"]), track_dict=song_item, ) @define class Songs(object): driver: DeezerDriver async def search(self, query: str, limit: int = 30) -> list[SongItem] | None: r = await self.driver.search(query, limit=limit) if r is None: return None return [SongItem.from_deezer(item) for item in r] async def search_one(self, query: str) -> SongItem | None: return (await self.search(query, limit=1) or [None])[0] async def from_id(self, song_id: str) -> FullSongItem | None: r = await self.driver.reverse_get_track(song_id) if r is None: return None return await FullSongItem.from_deezer(r)