diff --git a/pomice/__init__.py b/pomice/__init__.py index afe653a..7d23216 100644 --- a/pomice/__init__.py +++ b/pomice/__init__.py @@ -1,7 +1,7 @@ """Pomice wrapper for Lavalink, made possible by cloudwithax 2021""" import discord -if discord.__version__ != '2.0.0a': +if discord.__version__ != "2.0.0a": class DiscordPyOutdated(Exception): pass @@ -22,4 +22,3 @@ from .filters import * from .objects import * from .player import Player from .pool import * - diff --git a/pomice/enums.py b/pomice/enums.py index b921ef3..f85232f 100644 --- a/pomice/enums.py +++ b/pomice/enums.py @@ -3,14 +3,17 @@ from enum import Enum class SearchType(Enum): """The enum for the different search types for Pomice. - This feature is exclusively for the Spotify search feature of Pomice. - If you are not using this feature, this class is not necessary. + This feature is exclusively for the Spotify search feature of Pomice. + If you are not using this feature, this class is not necessary. - SearchType.ytsearch searches using regular Youtube, which is best for all scenarios. + SearchType.ytsearch searches using regular Youtube, + which is best for all scenarios. - SearchType.ytmsearch searches using YouTube Music, which is best for getting audio-only results. + SearchType.ytmsearch searches using YouTube Music, + which is best for getting audio-only results. - SearchType.scsearch searches using SoundCloud, which is an alternative to YouTube or YouTube Music. + SearchType.scsearch searches using SoundCloud, + which is an alternative to YouTube or YouTube Music. """ ytsearch = "ytsearch" ytmsearch = "ytmsearch" diff --git a/pomice/events.py b/pomice/events.py index 90cd4ed..8f2dcd5 100644 --- a/pomice/events.py +++ b/pomice/events.py @@ -1,6 +1,7 @@ from .pool import NodePool from .utils import ClientType + class PomiceEvent: """The base class for all events dispatched by a node. Every event must be formatted within your bot's code as a listener. @@ -49,12 +50,16 @@ class TrackEndEvent(PomiceEvent): self.handler_args = self.player, self.track, self.reason def __repr__(self) -> str: - return f"" + return ( + f"" + ) class TrackStuckEvent(PomiceEvent): """Fired when a track is stuck and cannot be played. Returns the player - associated with the event along with the pomice.Track object to be further parsed by the end user. + associated with the event along with the pomice.Track object + to be further parsed by the end user. """ name = "track_stuck" @@ -100,6 +105,7 @@ class WebSocketClosedPayload: return f"" + class WebSocketClosedEvent(PomiceEvent): """Fired when a websocket connection to a node has been closed. Returns the reason and the error code. diff --git a/pomice/filters.py b/pomice/filters.py index faa8503..452040a 100644 --- a/pomice/filters.py +++ b/pomice/filters.py @@ -14,14 +14,14 @@ class Equalizer: i.e: Applying a bass boost filter to emphasize the bass in a song. The format for the levels is: List[Tuple[int, float]] """ + def __init__(self, *, levels: list): super().__init__() self.eq = self._factory(self, levels) self.raw = levels - self.payload = {'equalizer': {'bands': self.eq}} - + self.payload = {"equalizer": {"bands": self.eq}} def _factory(self, levels: list): _dict = collections.defaultdict(int) diff --git a/pomice/player.py b/pomice/player.py index fcd40d7..8d9beb1 100644 --- a/pomice/player.py +++ b/pomice/player.py @@ -156,7 +156,7 @@ class Player(VoiceProtocol): self.channel = self.guild.get_channel(int(channel_id)) - if not data.get('token'): + if not data.get("token"): return await self._dispatch_voice_update({**self._voice_state, "event": data}) @@ -274,7 +274,7 @@ class Player(VoiceProtocol): return self._paused async def set_volume(self, volume: int) -> int: - """Sets the volume of the player as an integer. Lavalink accepts an amount from 0 to 500.""" + """Sets the volume of the player as an integer. Lavalink accepts values from 0 to 500.""" await self._node.send(op="volume", guildId=str(self.guild.id), volume=volume) self._volume = volume return self._volume diff --git a/pomice/pool.py b/pomice/pool.py index bca050e..28dfe9b 100644 --- a/pomice/pool.py +++ b/pomice/pool.py @@ -10,7 +10,6 @@ from typing import Dict, Optional, TYPE_CHECKING from urllib.parse import quote import aiohttp -import discord from discord.ext import commands from . import __version__, spotify @@ -21,9 +20,6 @@ from .exceptions import ( NodeCreationError, NodeNotAvailable, NoNodesAvailable, - SpotifyAlbumLoadFailed, - SpotifyPlaylistLoadFailed, - SpotifyTrackLoadFailed, TrackLoadError ) from .objects import Playlist, Track @@ -37,10 +33,12 @@ SPOTIFY_URL_REGEX = re.compile( ) DISCORD_MP3_URL_REGEX = re.compile( - r"https?://cdn.discordapp.com/attachments/(?P[0-9]+)/(?P[0-9]+)/(?P[a-zA-Z0-9_.]+)+" + r"https?://cdn.discordapp.com/attachments/(?P[0-9]+)/" + r"(?P[0-9]+)/(?P[a-zA-Z0-9_.]+)+" ) + URL_REGEX = re.compile( - r'https?://(?:www\.)?.+' + r"https?://(?:www\.)?.+" ) @@ -205,7 +203,8 @@ class Node: async def send(self, **data): if not self._available: raise NodeNotAvailable( - f"The node '{self.identifier}' is not currently available.") + f"The node '{self.identifier}' is unavailable." + ) await self._websocket.send_str(json.dumps(data)) @@ -261,19 +260,19 @@ class Node: Context object on the track it builds. """ - async with self._session.get(f'{self._rest_uri}/decodetrack?', - headers={'Authorization': self._password}, - params={'track': identifier}) as resp: - - data: dict = await resp.json() - + async with self._session.get( + f"{self._rest_uri}/decodetrack?", + headers={"Authorization": self._password}, + params={"track": identifier} + ) as resp: if not resp.status == 200: - raise TrackLoadError(f'Failed to build track. Status: {data["status"]}, Error: {data["error"]}.' - f'Check the identifier is correct and try again.') + raise TrackLoadError( + f"Failed to build track. Check the identifier is correct and try again." + ) + data: dict = await resp.json() return Track(track_id=identifier, ctx=ctx, info=data) - async def get_tracks( self, query: str, @@ -303,70 +302,7 @@ class Node: spotify_results = await self._spotify_client.search(query=query) - if isinstance(spotify_results, spotify.Playlist): - tracks = [ - Track( - track_id=track.id, - ctx=ctx, - search_type=search_type, - spotify=True, - info={ - "title": track.name, - "author": track.artists, - "length": track.length, - "identifier": track.id, - "uri": track.uri, - "isStream": False, - "isSeekable": False, - "position": 0, - "thumbnail": track.image - }, - ) for track in spotify_results.tracks - ] - - return Playlist( - playlist_info={"name": spotify_results.name, "selectedTrack": tracks[0]}, - tracks=tracks, - ctx=ctx, - spotify=True, - thumbnail=spotify_results.image, - uri=spotify_results.uri, - ) - - elif isinstance(spotify_results, spotify.Album): - - tracks = [ - Track( - track_id=track.id, - ctx=ctx, - search_type=search_type, - spotify=True, - info={ - "title": track.name, - "author": track.artists, - "length": track.length, - "identifier": track.id, - "uri": track.uri, - "isStream": False, - "isSeekable": False, - "position": 0, - "thumbnail": track.image - }, - ) for track in spotify_results.tracks - ] - - return Playlist( - playlist_info={"name": spotify_results.name, "selectedTrack": tracks[0]}, - tracks=tracks, - ctx=ctx, - spotify=True, - thumbnail=spotify_results.image, - uri=spotify_results.uri, - ) - - - elif isinstance(spotify_results, spotify.Track): - + if isinstance(spotify_results, spotify.Track): return [ Track( track_id=spotify_results.id, @@ -383,10 +319,38 @@ class Node: "isSeekable": False, "position": 0, "thumbnail": spotify_results.image - }, + } ) ] + tracks = [ + Track( + track_id=track.id, + ctx=ctx, + search_type=search_type, + spotify=True, + info={ + "title": track.name, + "author": track.artists, + "length": track.length, + "identifier": track.id, + "uri": track.uri, + "isStream": False, + "isSeekable": False, + "position": 0, + "thumbnail": track.image + } + ) for track in spotify_results.tracks + ] + + return Playlist( + playlist_info={"name": spotify_results.name, "selectedTrack": tracks[0]}, + tracks=tracks, + ctx=ctx, + spotify=True, + thumbnail=spotify_results.image, + uri=spotify_results.uri + ) elif discord_url := DISCORD_MP3_URL_REGEX.match(query): async with self._session.get( @@ -396,19 +360,22 @@ class Node: data: dict = await response.json() track: dict = data["tracks"][0] - info: dict = track.get('info') + info: dict = track.get("info") - return [Track( - track_id=track['track'], - info={ - "title": discord_url.group('file'), - "author": "Unknown", - "length": info.get('length'), - "uri": info.get('uri'), - "position": info.get('position'), - "identifier": info.get('identifier') - }, - ctx=ctx)] + return [ + Track( + track_id=track["track"], + info={ + "title": discord_url.group("file"), + "author": "Unknown", + "length": info.get("length"), + "uri": info.get("uri"), + "position": info.get("position"), + "identifier": info.get("identifier") + }, + ctx=ctx + ) + ] else: async with self._session.get( @@ -471,9 +438,13 @@ class NodePool: """Fetches a node from the node pool using it's identifier. If no identifier is provided, it will choose a node at random. """ - available_nodes = {identifier: node for identifier, node in cls._nodes.items() if node._available} + available_nodes = { + identifier: node + for identifier, node in cls._nodes.items() if node._available + } + if not available_nodes: - raise NoNodesAvailable('There are no nodes available.') + raise NoNodesAvailable("There are no nodes available.") if identifier is None: return random.choice(list(available_nodes.values())) diff --git a/pomice/utils.py b/pomice/utils.py index a8be0b2..83f7ac4 100644 --- a/pomice/utils.py +++ b/pomice/utils.py @@ -26,9 +26,9 @@ from discord import AutoShardedClient, Client from discord.ext.commands import AutoShardedBot, Bot __all__ = [ - 'ExponentialBackoff', - 'NodeStats', - 'ClientType' + "ClientType", + "ExponentialBackoff", + "NodeStats" ] ClientType = Union[AutoShardedBot, AutoShardedClient, Bot, Client] @@ -64,24 +64,26 @@ class ExponentialBackoff: class NodeStats: - """The base class for the node stats object. Gives critcical information on the node, which is updated every minute.""" + """The base class for the node stats object. + Gives critical information on the node, which is updated every minute. + """ def __init__(self, data: dict) -> None: - memory = data.get('memory') - self.used = memory.get('used') - self.free = memory.get('free') - self.reservable = memory.get('reservable') - self.allocated = memory.get('allocated') + memory = data.get("memory") + self.used = memory.get("used") + self.free = memory.get("free") + self.reservable = memory.get("reservable") + self.allocated = memory.get("allocated") - cpu = data.get('cpu') - self.cpu_cores = cpu.get('cores') - self.cpu_system_load = cpu.get('systemLoad') - self.cpu_process_load = cpu.get('lavalinkLoad') + cpu = data.get("cpu") + self.cpu_cores = cpu.get("cores") + self.cpu_system_load = cpu.get("systemLoad") + self.cpu_process_load = cpu.get("lavalinkLoad") - self.players_active = data.get('playingPlayers') - self.players_total = data.get('players') - self.uptime = data.get('uptime') + self.players_active = data.get("playingPlayers") + self.players_total = data.get("players") + self.uptime = data.get("uptime") def __repr__(self) -> str: - return f'' + return f""