Optimize code for improved cleanliness and enhanced performance.
This commit is contained in:
@@ -13,42 +13,9 @@ class Settings:
|
||||
self.emoji_source_raw = settings.get("emoji_source_raw", {})
|
||||
self.cooldowns_settings = settings.get("cooldowns", {})
|
||||
self.aliases_settings = settings.get("aliases", {})
|
||||
self.controller = settings.get("default_controller",
|
||||
{
|
||||
"embeds": {
|
||||
"active": {
|
||||
"description": "**Now Playing: ```[@@track_name@@]```\nLink: [Click Me](@@track_url@@) | Requester: @@requester@@ | DJ: @@dj@@**",
|
||||
"footer": {
|
||||
"text": "Queue Length: @@queue_length@@ | Duration: @@duration@@ | Volume: @@volume@@% {{loop_mode!=Off ?? | Repeat: @@loop_mode@@}}",
|
||||
},
|
||||
"image": "@@track_thumbnail@@",
|
||||
"author": {
|
||||
"name": "Music Controller | @@channel_name@@",
|
||||
"icon_url": "@@bot_icon@@"
|
||||
},
|
||||
"color": "@@default_embed_color@@"
|
||||
},
|
||||
"inactive": {
|
||||
"title": {
|
||||
"name": "There are no songs playing right now"
|
||||
},
|
||||
"description": "[Support](@@server_invite_link@@) | [Invite](@@invite_link@@) | [Questionnaire](https://forms.gle/Qm8vjBfg2kp13YGD7)",
|
||||
"image": "https://i.imgur.com/dIFBwU7.png",
|
||||
"color": "@@default_embed_color@@"
|
||||
}
|
||||
},
|
||||
"default_buttons": [
|
||||
["back", "resume", "skip", {"stop": "red"}, "add"],
|
||||
["tracks"]
|
||||
]
|
||||
})
|
||||
self.controller = settings.get("default_controller", {})
|
||||
self.lyrics_platform = settings.get("lyrics_platform", "A_ZLyrics").lower()
|
||||
self.ipc_server = settings.get("ipc_server", {
|
||||
"host": "127.0.0.1",
|
||||
"port": 8000,
|
||||
"enable": False
|
||||
}
|
||||
)
|
||||
self.ipc_server = settings.get("ipc_server", {})
|
||||
self.version = settings.get("version", "")
|
||||
|
||||
class TOKENS:
|
||||
|
||||
@@ -33,7 +33,7 @@ async def nowplay(ctx: commands.Context, player: voicelink.Player):
|
||||
if not track:
|
||||
return await ctx.send(player.get_msg('noTrackPlaying'), ephemeral=True)
|
||||
|
||||
upnext = "\n".join(f"`{index}.` `[{track.formatLength}]` [{track.title[:30]}]({track.uri})" for index, track in enumerate(
|
||||
upnext = "\n".join(f"`{index}.` `[{track.formatted_length}]` [{track.title[:30]}]({track.uri})" for index, track in enumerate(
|
||||
player.queue.tracks()[:2], start=2))
|
||||
embed = discord.Embed(description=player.get_msg(
|
||||
'nowplayingDesc').format(track.title), color=settings.embed_color)
|
||||
@@ -48,7 +48,7 @@ async def nowplay(ctx: commands.Context, player: voicelink.Player):
|
||||
":pause_button:" if player.is_paused else ":arrow_forward:")
|
||||
|
||||
embed.add_field(
|
||||
name="\u2800", value=f"{icon} {pbar} **[{ctime(player.position)}/{track.formatLength}]**", inline=False)
|
||||
name="\u2800", value=f"{icon} {pbar} **[{ctime(player.position)}/{track.formatted_length}]**", inline=False)
|
||||
|
||||
return await ctx.send(embed=embed, view=LinkView(player.get_msg('nowplayingLink').format(track.source), track.emoji, track.uri))
|
||||
|
||||
@@ -103,7 +103,7 @@ class Basic(commands.Cog):
|
||||
await ctx.send(player.get_msg('playlistLoad').format(tracks.name, index))
|
||||
else:
|
||||
position = await player.add_track(tracks[0])
|
||||
await ctx.send((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + (player.get_msg('trackLoad_pos').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength, position) if position >= 1 and player.is_playing else player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength)), allowed_mentions=False)
|
||||
await ctx.send((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + (player.get_msg('trackLoad_pos').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length, position) if position >= 1 and player.is_playing else player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length)), allowed_mentions=False)
|
||||
except voicelink.QueueFull as e:
|
||||
await ctx.send(e)
|
||||
finally:
|
||||
@@ -143,7 +143,7 @@ class Basic(commands.Cog):
|
||||
await interaction.response.send_message(player.get_msg('playlistLoad').format(tracks.name, index))
|
||||
else:
|
||||
position = await player.add_track(tracks[0])
|
||||
await interaction.response.send_message((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + (player.get_msg('trackLoad_pos').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength, position) if position >= 1 and player.is_playing else player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength)), allowed_mentions=False)
|
||||
await interaction.response.send_message((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + (player.get_msg('trackLoad_pos').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length, position) if position >= 1 and player.is_playing else player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length)), allowed_mentions=False)
|
||||
except voicelink.QueueFull as e:
|
||||
await interaction.response.send_message(e)
|
||||
|
||||
@@ -190,7 +190,7 @@ class Basic(commands.Cog):
|
||||
return await ctx.send(player.get_msg('noTrackFound'))
|
||||
|
||||
query_track = "\n".join(
|
||||
f"`{index}.` `[{track.formatLength}]` **{track.title[:35]}**" for index, track in enumerate(tracks[0:10], start=1))
|
||||
f"`{index}.` `[{track.formatted_length}]` **{track.title[:35]}**" for index, track in enumerate(tracks[0:10], start=1))
|
||||
embed = discord.Embed(title=player.get_msg('searchTitle').format(query), description=player.get_msg(
|
||||
'searchDesc').format(emoji_source(platform), platform, len(tracks[0:10]), query_track), color=settings.embed_color)
|
||||
view = SearchView(tracks=tracks[0:10], lang=player.lang)
|
||||
@@ -202,8 +202,8 @@ class Basic(commands.Cog):
|
||||
for value in view.values:
|
||||
track = tracks[int(value.split(". ")[0]) - 1]
|
||||
position = await player.add_track(track)
|
||||
msg += ((f"`{player.get_msg('live')}`" if track.is_stream else "") + (player.get_msg('trackLoad_pos').format(track.title, track.uri, track.author, track.formatLength,
|
||||
position) if position >= 1 else player.get_msg('trackLoad').format(track.title, track.uri, track.author, track.formatLength)))
|
||||
msg += ((f"`{player.get_msg('live')}`" if track.is_stream else "") + (player.get_msg('trackLoad_pos').format(track.title, track.uri, track.author, track.formatted_length,
|
||||
position) if position >= 1 else player.get_msg('trackLoad').format(track.title, track.uri, track.author, track.formatted_length)))
|
||||
await ctx.send(msg, allowed_mentions=False)
|
||||
|
||||
if not player.is_playing:
|
||||
@@ -231,7 +231,7 @@ class Basic(commands.Cog):
|
||||
await ctx.send(player.get_msg('playlistLoad').format(tracks.name, index))
|
||||
else:
|
||||
position = await player.add_track(tracks[0], at_font=True)
|
||||
await ctx.send((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + (player.get_msg('trackLoad_pos').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength, position) if position >= 1 and player.is_playing else player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength)), allowed_mentions=False)
|
||||
await ctx.send((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + (player.get_msg('trackLoad_pos').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length, position) if position >= 1 and player.is_playing else player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length)), allowed_mentions=False)
|
||||
|
||||
except voicelink.QueueFull as e:
|
||||
await ctx.send(e)
|
||||
@@ -262,7 +262,7 @@ class Basic(commands.Cog):
|
||||
await ctx.send(player.get_msg('playlistLoad').format(tracks.name, index))
|
||||
else:
|
||||
await player.add_track(tracks[0], at_font=True)
|
||||
await ctx.send((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatLength), allowed_mentions=False)
|
||||
await ctx.send((f"`{player.get_msg('live')}`" if tracks[0].is_stream else "") + player.get_msg('trackLoad').format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length), allowed_mentions=False)
|
||||
|
||||
except voicelink.QueueFull as e:
|
||||
await ctx.send(e)
|
||||
|
||||
@@ -17,7 +17,7 @@ if not os.path.exists(os.path.join(root_dir, "settings.json")):
|
||||
raise Exception("Settings file not set!")
|
||||
|
||||
#-------------- API Clients --------------
|
||||
tokens: TOKENS = TOKENS();
|
||||
tokens: TOKENS = TOKENS()
|
||||
|
||||
if not (tokens.mongodb_name and tokens.mongodb_url):
|
||||
raise Exception("MONGODB_NAME and MONGODB_URL can't not be empty in .env")
|
||||
@@ -133,7 +133,7 @@ def formatTime(number:str) -> Optional[int]:
|
||||
|
||||
return (int(num.tm_hour) * 3600 + int(num.tm_min) * 60 + int(num.tm_sec)) * 1000
|
||||
|
||||
def emoji_source(emoji:str):
|
||||
def emoji_source(emoji:str) -> str:
|
||||
return settings.emoji_source_raw.get(emoji.lower(), "🔗")
|
||||
|
||||
def gen_report() -> Optional[discord.File]:
|
||||
|
||||
@@ -376,7 +376,7 @@ class Tracks(discord.ui.Select):
|
||||
for index, track in enumerate(self.player.queue.tracks(), start=1):
|
||||
if index > 10:
|
||||
break
|
||||
options.append(discord.SelectOption(label=f"{index}. {track.title[:40]}", description=f"{track.author[:30]} · " + ("Live" if track.is_stream else track.formatLength), emoji=track.emoji))
|
||||
options.append(discord.SelectOption(label=f"{index}. {track.title[:40]}", description=f"{track.author[:30]} · " + ("Live" if track.is_stream else track.formatted_length), emoji=track.emoji))
|
||||
|
||||
super().__init__(
|
||||
placeholder=player.get_msg("playerDropdown"),
|
||||
|
||||
@@ -31,7 +31,7 @@ class SearchDropdown(discord.ui.Select):
|
||||
self.lang = lang
|
||||
options = []
|
||||
for index, track in enumerate(self.tracks, start=1):
|
||||
options.append(discord.SelectOption(label=f"{index}. {track.title[:50]}", description=f"{track.author[:50]} · {track.formatLength}"))
|
||||
options.append(discord.SelectOption(label=f"{index}. {track.title[:50]}", description=f"{track.author[:50]} · {track.formatted_length}"))
|
||||
|
||||
super().__init__(placeholder=langs[lang]['searchWait'],
|
||||
min_values=1, max_values=len(tracks),
|
||||
|
||||
@@ -41,6 +41,28 @@ class Track:
|
||||
You can also pass in commands.Context to get a discord.py Context object in your track.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"track_id",
|
||||
"info",
|
||||
"identifier",
|
||||
"title",
|
||||
"author",
|
||||
"uri",
|
||||
"source",
|
||||
"spotify",
|
||||
"artist_id",
|
||||
"original",
|
||||
"_search_type",
|
||||
"spotify_track",
|
||||
"thumbnail",
|
||||
"emoji",
|
||||
"length",
|
||||
"requester",
|
||||
"is_stream",
|
||||
"is_seekable",
|
||||
"position"
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -50,73 +72,83 @@ class Track:
|
||||
search_type: SearchType = SearchType.ytsearch,
|
||||
spotify_track = None,
|
||||
):
|
||||
self.track_id = track_id
|
||||
self.info = info
|
||||
self.track_id: str = track_id
|
||||
self.info: dict = info
|
||||
|
||||
self.identifier = info.get("identifier")
|
||||
self.title = info.get("title", "Unknown")
|
||||
self.author = info.get("author", "Unknown")
|
||||
self.uri = info.get("uri", "https://discord.com/application-directory/605618911471468554")
|
||||
self.source = info.get("sourceName", extract(self.uri).domain)
|
||||
self.spotify = True if self.source == "spotify" else False
|
||||
self.identifier: str = info.get("identifier")
|
||||
self.title: str = info.get("title", "Unknown")
|
||||
self.author: str = info.get("author", "Unknown")
|
||||
self.uri: str = info.get("uri", "https://discord.com/application-directory/605618911471468554")
|
||||
self.source: str = info.get("sourceName", extract(self.uri).domain)
|
||||
self.spotify: bool = True if self.source == "spotify" else False
|
||||
if self.spotify:
|
||||
self.artistId: Optional[list] = info.get("artistId")
|
||||
self.artist_id: Optional[list] = info.get("artist_id")
|
||||
|
||||
self.original: Optional[Track] = None if self.spotify else self
|
||||
self._search_type = SearchType.ytmsearch if self.spotify else search_type
|
||||
self.spotify_track = spotify_track
|
||||
self._search_type: SearchType = SearchType.ytmsearch if self.spotify else search_type
|
||||
self.spotify_track: Track = spotify_track
|
||||
|
||||
self.thumbnail = None
|
||||
|
||||
self.emoji = emoji_source(self.source)
|
||||
self.thumbnail: str = None
|
||||
self.emoji: str = emoji_source(self.source)
|
||||
|
||||
if info.get("thumbnail"):
|
||||
self.thumbnail = info.get("thumbnail")
|
||||
elif YOUTUBE_REGEX.match(self.uri):
|
||||
self.thumbnail = f"https://img.youtube.com/vi/{self.identifier}/hqdefault.jpg"
|
||||
|
||||
if self.source == "soundcloud" and "/preview/" in self.identifier:
|
||||
self.length = 30000
|
||||
else:
|
||||
self.length = info.get("length")
|
||||
self.length: float = 3000 if self.source == "soundcloud" and "/preview/" in self.identifier else info.get("length")
|
||||
|
||||
self.formatLength = ctime(self.length)
|
||||
self.requester = requester
|
||||
self.is_stream = info.get("isStream", False)
|
||||
self.is_seekable = info.get("isSeekable", True)
|
||||
self.position = info.get("position", 0)
|
||||
self.requester: Member = requester
|
||||
self.is_stream: bool = info.get("isStream", False)
|
||||
self.is_seekable: bool = info.get("isSeekable", True)
|
||||
self.position: int = info.get("position", 0)
|
||||
|
||||
if not track_id:
|
||||
self.track_id = encode(self)
|
||||
|
||||
def toDict(self):
|
||||
def __eq__(self, other) -> bool:
|
||||
if not isinstance(other, Track):
|
||||
return False
|
||||
|
||||
return other.track_id == self.track_id
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.title
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Voicelink.track title={self.title!r} uri=<{self.uri!r}> length={self.length}>"
|
||||
|
||||
def toDict(self) -> dict:
|
||||
return {
|
||||
"track_id": self.track_id,
|
||||
"info": self.info,
|
||||
"thumbnail": self.thumbnail
|
||||
}
|
||||
|
||||
def encode(self):
|
||||
def encode(self) -> bytes:
|
||||
return encode(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Track):
|
||||
return False
|
||||
|
||||
return other.track_id == self.track_id
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Voicelink.track title={self.title!r} uri=<{self.uri!r}> length={self.length}>"
|
||||
|
||||
@property
|
||||
def formatted_length(self) -> str:
|
||||
return ctime(self.length)
|
||||
|
||||
class Playlist:
|
||||
"""The base playlist object.
|
||||
Returns critical playlist information needed for parsing by Lavalink.
|
||||
You can also pass in commands.Context to get a discord.py Context object in your tracks.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"playlist_info",
|
||||
"tracks_raw",
|
||||
"spotify",
|
||||
"name",
|
||||
"spotify_playlist",
|
||||
"_thumbnail",
|
||||
"_uri",
|
||||
"tracks"
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -147,12 +179,10 @@ class Playlist:
|
||||
self._thumbnail = None
|
||||
self._uri = None
|
||||
|
||||
self.track_count = len(self.tracks)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return f"<Voicelink.playlist name={self.name!r} track_count={len(self.tracks)}>"
|
||||
|
||||
@property
|
||||
@@ -164,3 +194,7 @@ class Playlist:
|
||||
def thumbnail(self) -> Optional[str]:
|
||||
"""Spotify album/playlist thumbnail, or None if not a Spotify object."""
|
||||
return self._thumbnail
|
||||
|
||||
@property
|
||||
def track_count(self) -> int:
|
||||
return len(self.tracks)
|
||||
|
||||
@@ -441,7 +441,7 @@ class Player(VoiceProtocol):
|
||||
|
||||
try:
|
||||
tracks = await self._node._spotify_client.trackSearch(query=query)
|
||||
except:
|
||||
except Exception as _:
|
||||
raise TrackLoadError("Not able to find the provided Spotify entity, is it private?")
|
||||
|
||||
return [ Track(
|
||||
|
||||
@@ -394,7 +394,7 @@ class Node:
|
||||
|
||||
try:
|
||||
spotify_results = await self._spotify_client.search(query=query)
|
||||
except:
|
||||
except Exception as _:
|
||||
raise TrackLoadError("Not able to find the provided Spotify entity, is it private?")
|
||||
|
||||
if isinstance(spotify_results, spotify.Track):
|
||||
|
||||
@@ -53,12 +53,12 @@ class LoopTypeCycle:
|
||||
|
||||
class Queue:
|
||||
def __init__(self, size: int, allow_duplicate: bool, get_msg: Callable[[str], str]) -> None:
|
||||
self._queue = []
|
||||
self._position = 0
|
||||
self._size = size
|
||||
self._repeat = LoopTypeCycle()
|
||||
self._repeat_position = 0
|
||||
self._allow_duplicate = allow_duplicate
|
||||
self._queue: List[Track] = []
|
||||
self._position: int = 0
|
||||
self._size: int = size
|
||||
self._repeat: LoopTypeCycle = LoopTypeCycle()
|
||||
self._repeat_position: int = 0
|
||||
self._allow_duplicate: bool = allow_duplicate
|
||||
|
||||
self.get_msg = get_msg
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ SOFTWARE.
|
||||
|
||||
import re
|
||||
import time
|
||||
from base64 import b64encode
|
||||
|
||||
import aiohttp
|
||||
|
||||
from base64 import b64encode
|
||||
from typing import List, Union
|
||||
from .objects import Track, Album, Artist, Playlist
|
||||
from .exceptions import InvalidSpotifyURL, SpotifyRequestException
|
||||
from .exceptions import InvalidSpotifyURL, SpotifyRequestException
|
||||
|
||||
GRANT_URL = "https://accounts.spotify.com/api/token"
|
||||
REQUEST_URL = "https://api.spotify.com/v1/{type}s/{id}"
|
||||
@@ -71,7 +71,7 @@ class Client:
|
||||
self._expiry = time.time() + (int(data["expires_in"]) - 10)
|
||||
self._bearer_headers = {"Authorization": f"Bearer {self._bearer_token}"}
|
||||
|
||||
async def trackSearch(self, query: str, track: str = "track", limit: int = 10) -> list:
|
||||
async def trackSearch(self, query: str, track: str = "track", limit: int = 10) -> List[Track]:
|
||||
if not self._bearer_token or time.time() >= self._expiry:
|
||||
await self._fetch_bearer_token()
|
||||
|
||||
@@ -87,7 +87,7 @@ class Client:
|
||||
|
||||
return [ Track(track) for track in data['tracks']['items'] ]
|
||||
|
||||
async def similar_track(self, seed_tracks: str, *, limit: int = 5) -> list:
|
||||
async def similar_track(self, seed_tracks: str, *, limit: int = 5) -> List[Track]:
|
||||
if not self._bearer_token or time.time() >= self._expiry:
|
||||
await self._fetch_bearer_token()
|
||||
|
||||
@@ -103,7 +103,7 @@ class Client:
|
||||
|
||||
return [ Track(track) for track in data['tracks'] ]
|
||||
|
||||
async def search(self, *, query: str):
|
||||
async def search(self, *, query: str) -> Union(Track, Album, Playlist):
|
||||
if not self._bearer_token or time.time() >= self._expiry:
|
||||
await self._fetch_bearer_token()
|
||||
|
||||
|
||||
@@ -3,22 +3,24 @@ from typing import List
|
||||
class Track:
|
||||
"""The base class for a Spotify Track"""
|
||||
|
||||
__slots__ = (
|
||||
"name",
|
||||
"artists",
|
||||
"artist_id",
|
||||
"length",
|
||||
"id",
|
||||
"image",
|
||||
"uri"
|
||||
)
|
||||
|
||||
def __init__(self, data: dict, image=None) -> None:
|
||||
self.name = data.get('name', 'Unknown')
|
||||
self.artists = ", ".join(artist["name"] for artist in data.get('artists'))
|
||||
self.artistId = [artist['id'] for artist in data.get('artists')]
|
||||
self.length = data.get('duration_ms')
|
||||
self.id = data.get('id')
|
||||
|
||||
if data.get("album") and data["album"].get("images"):
|
||||
self.image = data["album"]["images"][0]["url"]
|
||||
else:
|
||||
self.image = image
|
||||
|
||||
if data["is_local"]:
|
||||
self.uri = None
|
||||
else:
|
||||
self.uri = data["external_urls"]["spotify"]
|
||||
self.name: str = data.get('name', 'Unknown')
|
||||
self.artists: str = ", ".join(artist["name"] for artist in data.get('artists'))
|
||||
self.artist_id: list = [artist['id'] for artist in data.get('artists')]
|
||||
self.length: int = data.get('duration_ms')
|
||||
self.id: str = data.get('id')
|
||||
self.image: str = images[0]["url"] if (images := data.get("album", {}).get("images")) else image
|
||||
self.uri: str = None if data["is_local"] else data["external_urls"]["spotify"]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
@@ -26,7 +28,7 @@ class Track:
|
||||
"author": self.artists,
|
||||
"length": self.length,
|
||||
"identifier": self.id,
|
||||
"artistId": self.artistId,
|
||||
"artist_id": self.artist_id,
|
||||
"uri": self.uri,
|
||||
"isStream": False,
|
||||
"isSeekable": True,
|
||||
@@ -43,14 +45,24 @@ class Track:
|
||||
class Album:
|
||||
"""The base class for a Spotify album"""
|
||||
|
||||
__slots__ = (
|
||||
"name",
|
||||
"artists",
|
||||
"image",
|
||||
"tracks",
|
||||
"total_tracks",
|
||||
"id",
|
||||
"uri"
|
||||
)
|
||||
|
||||
def __init__(self, data: dict) -> None:
|
||||
self.name = data.get('name', 'Unknown')
|
||||
self.artists = ", ".join(artist["name"] for artist in data.get('artists'))
|
||||
self.image = data["images"][0]["url"]
|
||||
self.tracks = [Track(track, image=self.image) for track in data["tracks"]["items"]]
|
||||
self.total_tracks = data["total_tracks"]
|
||||
self.id = data.get('id')
|
||||
self.uri = data["external_urls"]["spotify"]
|
||||
self.name: str = data.get('name', 'Unknown')
|
||||
self.artists: str = ", ".join(artist["name"] for artist in data.get('artists'))
|
||||
self.image: str = data["images"][0]["url"]
|
||||
self.tracks: list = [Track(track, image=self.image) for track in data["tracks"]["items"]]
|
||||
self.total_tracks: int = data["total_tracks"]
|
||||
self.id: str = data.get('id')
|
||||
self.uri: str = data["external_urls"]["spotify"]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
@@ -61,15 +73,24 @@ class Album:
|
||||
class Artist:
|
||||
"""The base class for a Spotify playlist"""
|
||||
|
||||
__slots__ = (
|
||||
"tracks",
|
||||
"image",
|
||||
"total_tracks",
|
||||
"owner",
|
||||
"id",
|
||||
"uri",
|
||||
"name"
|
||||
)
|
||||
def __init__(self, data: dict) -> None:
|
||||
self.tracks = [Track(track) for track in data['tracks']]
|
||||
self.tracks: List[Track] = [Track(track) for track in data['tracks']]
|
||||
if self.tracks:
|
||||
self.image = self.tracks[0].image
|
||||
self.total_tracks = len(self.tracks)
|
||||
self.owner = self.tracks[0].artists
|
||||
self.id = self.tracks[0].artistId
|
||||
self.uri = data['tracks'][0]['album']['artists'][0]['external_urls']['spotify']
|
||||
self.name = f"Top tracks - {self.owner}"
|
||||
self.image: str = self.tracks[0].image
|
||||
self.total_tracks: int = len(self.tracks)
|
||||
self.owner: str = self.tracks[0].artists
|
||||
self.id: str = self.tracks[0].artist_id
|
||||
self.uri: str = data['tracks'][0]['album']['artists'][0]['external_urls']['spotify']
|
||||
self.name: str = f"Top tracks - {self.owner}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
@@ -80,17 +101,24 @@ class Artist:
|
||||
class Playlist:
|
||||
"""The base class for a Spotify playlist"""
|
||||
|
||||
__slots__ = (
|
||||
"name",
|
||||
"tracks",
|
||||
"owner",
|
||||
"total_tracks",
|
||||
"id",
|
||||
"image",
|
||||
"uri"
|
||||
)
|
||||
|
||||
def __init__(self, data: dict, tracks: List[Track]) -> None:
|
||||
self.name = data.get('name', 'Unknown')
|
||||
self.tracks = tracks
|
||||
self.owner = data["owner"]["display_name"]
|
||||
self.total_tracks = data["tracks"]["total"]
|
||||
self.id = data.get('id')
|
||||
if data.get("images") and len(data["images"]):
|
||||
self.image = data["images"][0]["url"]
|
||||
else:
|
||||
self.image = None
|
||||
self.uri = data["external_urls"]["spotify"]
|
||||
self.name: str = data.get('name', 'Unknown')
|
||||
self.tracks: List[Track] = tracks
|
||||
self.owner: str = data["owner"]["display_name"]
|
||||
self.total_tracks: int = data["tracks"]["total"]
|
||||
self.id: str = data.get('id')
|
||||
self.image: str = data["images"][0]["url"] if len(data.get("images", [])) else None
|
||||
self.uri: str = data["external_urls"]["spotify"]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user