diff --git a/voicelink/player.py b/voicelink/player.py index ac166a3..d8a6f52 100644 --- a/voicelink/player.py +++ b/voicelink/player.py @@ -824,9 +824,6 @@ class Player(VoiceProtocol): if self.is_paused: await self.set_pause(True) - - if self.volume != 100: - await self.set_volume(self.volume) async def get_recommendations(self, *, track: Optional[Track] = None) -> bool: """Get recommendations from Youtube or Spotify.""" diff --git a/voicelink/pool.py b/voicelink/pool.py index 3902025..997a079 100644 --- a/voicelink/pool.py +++ b/voicelink/pool.py @@ -566,12 +566,12 @@ class NodePool: This option is preferred if you want to choose the best node from a multi-node setup using either the node's latency or the node's voice region. - Use NodeAlgorithm.by_ping if you want to get the best node + Use NodeAlgorithm.BY_PING if you want to get the best node based on the node's latency. Use NodeAlgorithm.by_region if you want to get the best node based on the node's voice region. This method will only work if you set a voice region when you create a node. - Use NodeAlgorithm.by_players if you want to get the best node + Use NodeAlgorithm.BY_PLAYERS if you want to get the best node based on how players it has. This method will return a node with the least amount of players """ @@ -580,11 +580,11 @@ class NodePool: if not available_nodes: raise NoNodesAvailable("There are no nodes available.") - if algorithm == NodeAlgorithm.by_ping: + if algorithm == NodeAlgorithm.BY_PING: tested_nodes = {node: node.latency for node in available_nodes} return min(tested_nodes, key=tested_nodes.get) - elif algorithm == NodeAlgorithm.by_players: + elif algorithm == NodeAlgorithm.BY_PLAYERS: tested_nodes = {node: len(node.players.keys()) for node in available_nodes} return min(tested_nodes, key=tested_nodes.get) diff --git a/voicelink/spotify/client.py b/voicelink/spotify/client.py index c880e2f..c247b9c 100644 --- a/voicelink/spotify/client.py +++ b/voicelink/spotify/client.py @@ -67,6 +67,7 @@ class Client: self._categories: List[Category] = [] async def _fetch_bearer_token(self) -> None: + """Fetches and stores a bearer token for API authentication.""" if self._client_id and self._client_secret: url, data = GRANT_URL, {"grant_type": "client_credentials"} else: @@ -90,6 +91,7 @@ class Client: self._bearer_headers = {"Authorization": f"Bearer {self._bearer_token}"} async def get_request(self, url: str) -> Dict: + """Performs a GET request to the specified URL with authorization headers.""" if not self._bearer_token or time.time() >= self._expiry: await self._fetch_bearer_token() @@ -102,68 +104,72 @@ class Client: return await resp.json() async def track_search(self, query: str, track: str = "track", limit: int = 10) -> List[Track]: + """Searches for tracks based on the provided query and returns a list of Track objects.""" request_url = SEARCH_URL.format(query=query, type=track, limit=limit) data = await self.get_request(request_url) return [ Track(track) for track in data['tracks']['items'] ] async def similar_track(self, seed_tracks: str, *, limit: int = 10) -> List[Track]: + """Retrieves tracks similar to the provided seed tracks and returns them as Track objects.""" request_url = SUGGESTION_URL.format(limit=limit, seed_tracks=seed_tracks) data = await self.get_request(request_url) return [ Track(track) for track in data['tracks'] ] async def search(self, *, query: str) -> Union[Track, Album, Playlist]: + """Searches for an item (track, album, artist, or playlist) by query and returns the corresponding object.""" result = SPOTIFY_URL_REGEX.match(query) - spotify_type = result.group("type") - spotify_id = result.group("id") - if not result: raise InvalidSpotifyURL("The Spotify link provided is not valid.") + spotify_type = result.group("type") + spotify_id = result.group("id") request_url = REQUEST_URL.format(type=spotify_type, id=spotify_id) + if isArtist := (spotify_type == "artist"): request_url += "/top-tracks?market=US" data = await self.get_request(request_url) + if spotify_type == "track": return Track(data) elif spotify_type == "album": return Album(data) elif isArtist: return Artist(data) - else: - tracks = [ + + tracks = [ + Track(track["track"]) + for track in data["tracks"]["items"] if track.get("track") is not None + ] + + if not tracks: + raise SpotifyRequestException("This playlist is empty and therefore cannot be queued.") + + next_page_url = data["tracks"].get("next") + + while next_page_url: + next_data = await self.get_request(next_page_url) + tracks.extend([ Track(track["track"]) - for track in data["tracks"]["items"] if track["track"] is not None - ] - if not tracks: - raise SpotifyRequestException("This playlist is empty and therefore cannot be queued.") - - next_page_url = data["tracks"]["next"] + for track in next_data.get("items", []) if track.get("track") is not None + ]) + next_page_url = next_data.get("next") - while next_page_url is not None: - async with self.session.get(next_page_url, headers=self._bearer_headers) as resp: - if resp.status != 200: - raise SpotifyRequestException( - f"Error while fetching results: {resp.status} {resp.reason}" - ) - - next_data: Dict = await resp.json() - - tracks += [ - Track(track["track"]) - for track in next_data["items"] if track["track"] is not None - ] - next_page_url = next_data["next"] - - return Playlist(data, tracks) + return Playlist(data, tracks) async def get_categories(self) -> List[Category]: + """Fetches and returns available music categories from the Spotify API.""" if not self._categories: request_url = f"{BASE_URL}browse/categories" - data = await self.get_request(request_url) - self._categories = [Category(item) for item in data.get("items", [])] + + while request_url: + data = await self.get_request(request_url) + items = data.get("categories", {}).get("items", []) + self._categories.extend(Category(item) for item in items) + request_url = data.get("categories", {}).get("next") return self._categories async def close(self) -> None: + """Closes the HTTP session used for making API requests.""" await self.session.close() \ No newline at end of file diff --git a/voicelink/spotify/objects.py b/voicelink/spotify/objects.py index 9a26062..59a645d 100644 --- a/voicelink/spotify/objects.py +++ b/voicelink/spotify/objects.py @@ -129,7 +129,7 @@ class Category: self.href: str = data.get("href") self.id: str = data.get("id") self.name: str = data.get("name") - self.icon: str = data.get("icon", [])[0].get("url") + self.icon: str = data.get("icons", [{}])[0].get("url") def __repr__(self) -> str: return (f"