Fixed bugs and optimized code
This commit is contained in:
@@ -824,9 +824,6 @@ class Player(VoiceProtocol):
|
|||||||
|
|
||||||
if self.is_paused:
|
if self.is_paused:
|
||||||
await self.set_pause(True)
|
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:
|
async def get_recommendations(self, *, track: Optional[Track] = None) -> bool:
|
||||||
"""Get recommendations from Youtube or Spotify."""
|
"""Get recommendations from Youtube or Spotify."""
|
||||||
|
|||||||
@@ -566,12 +566,12 @@ class NodePool:
|
|||||||
This option is preferred if you want to choose the best node
|
This option is preferred if you want to choose the best node
|
||||||
from a multi-node setup using either the node's latency
|
from a multi-node setup using either the node's latency
|
||||||
or the node's voice region.
|
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.
|
based on the node's latency.
|
||||||
Use NodeAlgorithm.by_region if you want to get the best node
|
Use NodeAlgorithm.by_region if you want to get the best node
|
||||||
based on the node's voice region. This method will only work
|
based on the node's voice region. This method will only work
|
||||||
if you set a voice region when you create a node.
|
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
|
based on how players it has. This method will return a node with
|
||||||
the least amount of players
|
the least amount of players
|
||||||
"""
|
"""
|
||||||
@@ -580,11 +580,11 @@ class NodePool:
|
|||||||
if not available_nodes:
|
if not available_nodes:
|
||||||
raise NoNodesAvailable("There are no nodes available.")
|
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}
|
tested_nodes = {node: node.latency for node in available_nodes}
|
||||||
return min(tested_nodes, key=tested_nodes.get)
|
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}
|
tested_nodes = {node: len(node.players.keys()) for node in available_nodes}
|
||||||
return min(tested_nodes, key=tested_nodes.get)
|
return min(tested_nodes, key=tested_nodes.get)
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class Client:
|
|||||||
self._categories: List[Category] = []
|
self._categories: List[Category] = []
|
||||||
|
|
||||||
async def _fetch_bearer_token(self) -> None:
|
async def _fetch_bearer_token(self) -> None:
|
||||||
|
"""Fetches and stores a bearer token for API authentication."""
|
||||||
if self._client_id and self._client_secret:
|
if self._client_id and self._client_secret:
|
||||||
url, data = GRANT_URL, {"grant_type": "client_credentials"}
|
url, data = GRANT_URL, {"grant_type": "client_credentials"}
|
||||||
else:
|
else:
|
||||||
@@ -90,6 +91,7 @@ class Client:
|
|||||||
self._bearer_headers = {"Authorization": f"Bearer {self._bearer_token}"}
|
self._bearer_headers = {"Authorization": f"Bearer {self._bearer_token}"}
|
||||||
|
|
||||||
async def get_request(self, url: str) -> Dict:
|
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:
|
if not self._bearer_token or time.time() >= self._expiry:
|
||||||
await self._fetch_bearer_token()
|
await self._fetch_bearer_token()
|
||||||
|
|
||||||
@@ -102,68 +104,72 @@ class Client:
|
|||||||
return await resp.json()
|
return await resp.json()
|
||||||
|
|
||||||
async def track_search(self, query: str, track: str = "track", limit: int = 10) -> List[Track]:
|
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)
|
request_url = SEARCH_URL.format(query=query, type=track, limit=limit)
|
||||||
data = await self.get_request(request_url)
|
data = await self.get_request(request_url)
|
||||||
return [ Track(track) for track in data['tracks']['items'] ]
|
return [ Track(track) for track in data['tracks']['items'] ]
|
||||||
|
|
||||||
async def similar_track(self, seed_tracks: str, *, limit: int = 10) -> List[Track]:
|
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)
|
request_url = SUGGESTION_URL.format(limit=limit, seed_tracks=seed_tracks)
|
||||||
data = await self.get_request(request_url)
|
data = await self.get_request(request_url)
|
||||||
return [ Track(track) for track in data['tracks'] ]
|
return [ Track(track) for track in data['tracks'] ]
|
||||||
|
|
||||||
async def search(self, *, query: str) -> Union[Track, Album, Playlist]:
|
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)
|
result = SPOTIFY_URL_REGEX.match(query)
|
||||||
spotify_type = result.group("type")
|
|
||||||
spotify_id = result.group("id")
|
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise InvalidSpotifyURL("The Spotify link provided is not valid.")
|
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)
|
request_url = REQUEST_URL.format(type=spotify_type, id=spotify_id)
|
||||||
|
|
||||||
if isArtist := (spotify_type == "artist"):
|
if isArtist := (spotify_type == "artist"):
|
||||||
request_url += "/top-tracks?market=US"
|
request_url += "/top-tracks?market=US"
|
||||||
|
|
||||||
data = await self.get_request(request_url)
|
data = await self.get_request(request_url)
|
||||||
|
|
||||||
if spotify_type == "track":
|
if spotify_type == "track":
|
||||||
return Track(data)
|
return Track(data)
|
||||||
elif spotify_type == "album":
|
elif spotify_type == "album":
|
||||||
return Album(data)
|
return Album(data)
|
||||||
elif isArtist:
|
elif isArtist:
|
||||||
return Artist(data)
|
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"])
|
Track(track["track"])
|
||||||
for track in data["tracks"]["items"] if track["track"] is not None
|
for track in next_data.get("items", []) if track.get("track") is not None
|
||||||
]
|
])
|
||||||
if not tracks:
|
next_page_url = next_data.get("next")
|
||||||
raise SpotifyRequestException("This playlist is empty and therefore cannot be queued.")
|
|
||||||
|
|
||||||
next_page_url = data["tracks"]["next"]
|
|
||||||
|
|
||||||
while next_page_url is not None:
|
return Playlist(data, tracks)
|
||||||
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)
|
|
||||||
|
|
||||||
async def get_categories(self) -> List[Category]:
|
async def get_categories(self) -> List[Category]:
|
||||||
|
"""Fetches and returns available music categories from the Spotify API."""
|
||||||
if not self._categories:
|
if not self._categories:
|
||||||
request_url = f"{BASE_URL}browse/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
|
return self._categories
|
||||||
|
|
||||||
async def close(self) -> None:
|
async def close(self) -> None:
|
||||||
|
"""Closes the HTTP session used for making API requests."""
|
||||||
await self.session.close()
|
await self.session.close()
|
||||||
@@ -129,7 +129,7 @@ class Category:
|
|||||||
self.href: str = data.get("href")
|
self.href: str = data.get("href")
|
||||||
self.id: str = data.get("id")
|
self.id: str = data.get("id")
|
||||||
self.name: str = data.get("name")
|
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:
|
def __repr__(self) -> str:
|
||||||
return (f"<Voicelink.spotify.Category name={self.name} id={self.id}")
|
return (f"<Voicelink.spotify.Category name={self.name} id={self.id}")
|
||||||
Reference in New Issue
Block a user