diff --git a/pomice/__init__.py b/pomice/__init__.py index afe9d4e..58b951a 100644 --- a/pomice/__init__.py +++ b/pomice/__init__.py @@ -4,10 +4,17 @@ __version__ = "1.0.5" __title__ = "pomice" __author__ = "cloudwithax" +import discord + +if discord.__version__ != '2.0.0a': + raise exit("You must have discord.py 2.0 to use this library. Uninstall your current version and install discord.py 2.0 using 'pip install git+https://github.com/Rapptz/discord.py'") + +from .enums import SearchType from .events import * from .exceptions import * from .filters import * -from .node import Node, NodePool -from .objects import Track, Playlist +from .pool import * +from .objects import * from .player import Player -from .enums import SearchType + + diff --git a/pomice/enums.py b/pomice/enums.py index 9aef2e0..0ac9c66 100644 --- a/pomice/enums.py +++ b/pomice/enums.py @@ -11,9 +11,12 @@ class SearchType(Enum): SearchType.SCSEARCH searches for a Spotify track using SoundCloud, which is an alternative to YouTube or YouTube Music. """ - YTSEARCH = f'ytsearch:{track.artist} - {track.title}' - YTMSEARCH = f'ytmsearch:{track.artist} - {track.title}' - SCSEARCH = f'scsearch:{track.artist} - {track.title}' + YTSEARCH = 'ytsearch:' + YTMSEARCH = 'ytmsearch:' + SCSEARCH = 'scsearch:' + + def __str__(self) -> str: + return self.value diff --git a/pomice/events.py b/pomice/events.py index 1ceef7f..209e59c 100644 --- a/pomice/events.py +++ b/pomice/events.py @@ -1,4 +1,4 @@ -from .node import NodePool +from .pool import NodePool class PomiceEvent: diff --git a/pomice/objects.py b/pomice/objects.py index e883b1c..6acdbd2 100644 --- a/pomice/objects.py +++ b/pomice/objects.py @@ -1,3 +1,4 @@ +from re import S from typing import Optional from . import SearchType @@ -13,17 +14,14 @@ class Track: self, track_id: str, info: dict, - ctx: Optional[commands.Context] = None, + ctx: Optional[commands.Context], + search_type: SearchType = None, spotify: bool = False ): self.track_id = track_id self.info = info self.spotify = spotify - if self.spotify: - self.youtube_result = None - self.search_type: SearchType = None - self.title = info.get("title") self.author = info.get("author") self.length = info.get("length") @@ -35,6 +33,11 @@ class Track: self.is_seekable = info.get("isSeekable") self.position = info.get("position") + if self.spotify: + self.youtube_result = None + if search_type: + self.search_type = search_type + def __eq__(self, other): if not isinstance(other, Track): return False diff --git a/pomice/player.py b/pomice/player.py index e2ec24a..fc906dd 100644 --- a/pomice/player.py +++ b/pomice/player.py @@ -2,10 +2,10 @@ import time from typing import Any, Dict, Type, Union import discord -from discord import VoiceChannel, VoiceProtocol, Guild, Member +from discord import VoiceChannel, VoiceProtocol, Guild from discord.ext import commands -from . import events, filters, NodePool, objects, Node +from . import events, filters, NodePool, objects, Node from .exceptions import TrackInvalidPosition @@ -24,7 +24,6 @@ class Player(VoiceProtocol): self._bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]] = client self.channel = channel self._guild: discord.Guild = self.channel.guild - self._dj: discord.Member = None self._node = NodePool.get_node() self._current: objects.Track = None @@ -93,10 +92,6 @@ class Player(VoiceProtocol): """Property which returns the players current volume""" return self._volume - @property - def dj(self) -> Member: - """Property which returns the DJ for the player session""" - return self._dj @property def filter(self) -> filters.Filter: @@ -182,10 +177,7 @@ class Player(VoiceProtocol): async def play(self, track: objects.Track, start_position: int = 0) -> objects.Track: """Plays a track. If a Spotify track is passed in, it will be handled accordingly.""" if track.spotify: - search_type = track.search_type or f"ytmsearch:{track.author} - {track.title}" - spotify_track: objects.Track = (await self._node.get_tracks( - search_type - ))[0] + spotify_track: objects.Track = (await self._node.get_tracks(f"{track.search_type}"))[0] track.youtube_result = spotify_track await self._node.send( op="play", diff --git a/pomice/node.py b/pomice/pool.py similarity index 91% rename from pomice/node.py rename to pomice/pool.py index a680383..4bf989b 100644 --- a/pomice/node.py +++ b/pomice/pool.py @@ -4,15 +4,17 @@ import random import re import socket import time -from typing import Optional, Type, Union +from typing import Optional, Union from urllib.parse import quote import aiohttp import discord from discord.ext import commands +from typing import Union, Optional -from . import __version__, spotify, Player, SearchType + +from . import __version__, spotify, SearchType from .exceptions import ( InvalidSpotifyClientAuthorization, NodeConnectionFailure, @@ -42,16 +44,17 @@ class Node: def __init__( self, pool, - bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]], + bot: Union[discord.Client, commands.Bot, commands.AutoShardedBot], host: str, port: int, password: str, identifier: str, + session: Optional[aiohttp.ClientSession], spotify_client_id: Optional[str], spotify_client_secret: Optional[str], - session: Optional[aiohttp.ClientSession] + ): - self._bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]] = bot + self._bot: Union[discord.Client, commands.Bot, commands.AutoShardedBot] = bot self._host: str = host self._port: int = port self._pool: NodePool = pool @@ -122,7 +125,7 @@ class Node: return self._players @property - def bot(self) -> Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]]: + def bot(self) -> Union[discord.Client, commands.Bot, commands.AutoShardedBot]: """Property which returns the discord.py client linked to this node""" return self._bot @@ -193,13 +196,13 @@ class Node: await player._update_state(data) async def send(self, **data): - if not self.available: + if not self._available: raise NodeNotAvailable( f"The node '{self.identifier}' is not currently available.") await self._websocket.send_str(json.dumps(data)) - def get_player(self, guild_id: int) -> Player: + def get_player(self, guild_id: int): """Takes a guild ID as a parameter. Returns a pomice Player object.""" return self._players.get(guild_id, None) @@ -256,10 +259,10 @@ class Node: "please obtain Spotify API credentials here: https://developer.spotify.com/" ) - search_type = spotify_url_check.group("type") + spotify_search_type = spotify_url_check.group("type") spotify_id = spotify_url_check.group("id") - if search_type == "playlist": + if spotify_search_type == "playlist": results = spotify.Playlist( client=self._spotify_client, data=await self._spotify_http_client.get_playlist(spotify_id) @@ -271,7 +274,7 @@ class Node: Track( track_id=track.id, ctx=ctx, - search_type=search_type, + search_type=f"{search_type}{track.artists[0].name} - {track.name}" if search_type else f"ytmsearch:{track.artists[0].name} - {track.name}", spotify=True, info={ "title": track.name or "Unknown", @@ -303,7 +306,7 @@ class Node: f"Unable to find results for {query}" ) - elif search_type == "album": + elif spotify_search_type == "album": results = await self._spotify_client.get_album(spotify_id=spotify_id) try: @@ -312,7 +315,7 @@ class Node: Track( track_id=track.id, ctx=ctx, - search_type=search_type, + search_type=f"{search_type}{track.artists[0].name} - {track.name}" if search_type else f"ytmsearch:{track.artists[0].name} - {track.name}", spotify=True, info={ "title": track.name or "Unknown", @@ -342,7 +345,7 @@ class Node: except SpotifyException: raise SpotifyAlbumLoadFailed(f"Unable to find results for {query}") - elif search_type == 'track': + elif spotify_search_type == 'track': try: results = await self._spotify_client.get_track(spotify_id=spotify_id) @@ -350,7 +353,7 @@ class Node: Track( track_id=results.id, ctx=ctx, - search_type=search_type, + search_type=f"{search_type}{results.artists[0].name} - {results.name}" if search_type else f"ytmsearch:{results.artists[0].name} - {results.name}", spotify=True, info={ "title": results.name or "Unknown", @@ -409,6 +412,8 @@ class Node: for track in data["tracks"] ] + + class NodePool: """The base class for the node pool. This holds all the nodes that are to be used by the bot. @@ -444,14 +449,16 @@ class NodePool: @classmethod async def create_node( - bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]], cls, + bot: Union[discord.Client, commands.Bot, commands.AutoShardedBot], host: str, port: str, password: str, identifier: str, - spotify_client_id: Optional[str] = None, - spotify_client_secret: Optional[str] = None + spotify_client_id: Optional[str], + spotify_client_secret: Optional[str], + session: Optional[aiohttp.ClientSession] = None, + ) -> Node: """Creates a Node object to be then added into the node pool. For Spotify searching capabilites, pass in valid Spotify API credentials. @@ -460,9 +467,9 @@ class NodePool: raise NodeCreationError(f"A node with identifier '{identifier}' already exists.") node = Node( - bot=bot, pool=cls, host=host, port=port, password=password, + pool=cls, bot=bot, host=host, port=port, password=password, identifier=identifier, spotify_client_id=spotify_client_id, - spotify_client_secret=spotify_client_secret + session=session, spotify_client_secret=spotify_client_secret ) await node.connect() diff --git a/pomice/utils.py b/pomice/utils.py index b382b2a..708e14f 100644 --- a/pomice/utils.py +++ b/pomice/utils.py @@ -20,7 +20,6 @@ DEALINGS IN THE SOFTWARE. import random import time -from typing import Any __all__ = [ 'ExponentialBackoff',