From 9d505caf7f28a5490c563009d49b54ac76ed6ff4 Mon Sep 17 00:00:00 2001 From: Choco <94597336+ChocoMeow@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:32:02 +0800 Subject: [PATCH] Updated voicelink enum --- cogs/basic.py | 66 +++++++++++++++++--------------------------- ipc/methods.py | 4 +-- views/controller.py | 10 +++---- voicelink/enums.py | 47 +++++++++++++++++-------------- voicelink/objects.py | 4 +-- voicelink/player.py | 45 ++++++++++++++---------------- voicelink/pool.py | 18 +++++++----- voicelink/queue.py | 10 +++---- 8 files changed, 97 insertions(+), 107 deletions(-) diff --git a/cogs/basic.py b/cogs/basic.py index f25b39d..80b07a2 100644 --- a/cogs/basic.py +++ b/cogs/basic.py @@ -40,17 +40,11 @@ from function import ( logger ) +from voicelink import SearchType, LoopType from addons import lyricsPlatform from views import SearchView, ListView, LinkView, LyricsView, HelpView from validators import url -searchPlatform = { - "youtube": "ytsearch", - "youtubemusic": "ytmsearch", - "soundcloud": "scsearch", - "apple": "amsearch", -} - async def nowplay(ctx: commands.Context, player: voicelink.Player): track = player.current if not track: @@ -94,22 +88,22 @@ class Basic(commands.Cog): async def play_autocomplete(self, interaction: discord.Interaction, current: str) -> list: if voicelink.pool.URL_REGEX.match(current): return [app_commands.Choice(name=current, value=current)] + if current: + node = voicelink.NodePool.get_node() + if node and node.spotify_client: + try: + tracks: list[voicelink.Track] = await node.spotifySearch(current, requester=interaction.user) + return [app_commands.Choice(name=truncate_string(f"🎵 {track.author} - {track.title}", 100), value=truncate_string(f"{track.author} - {track.title}", 100)) for track in tracks] + except voicelink.TrackLoadError: + return [] + history: dict[str, str] = {} for track_id in reversed(await get_user(interaction.user.id, "history")): track_dict = voicelink.decode(track_id) history[track_dict["identifier"]] = track_dict history_tracks = [app_commands.Choice(name=truncate_string(f"🕒 {track['author']} - {track['title']}", 100), value=track['uri']) for track in history.values() if len(track['uri']) <= 100][:25] - if not current: - return history_tracks - - node = voicelink.NodePool.get_node() - if node and node.spotify_client: - try: - tracks: list[voicelink.Track] = await node.spotifySearch(current, requester=interaction.user) - return [app_commands.Choice(name=truncate_string(f"🎵 {track.author} - {track.title}", 100), value=truncate_string(f"{track.author} - {track.title}", 100)) for track in tracks] - except voicelink.TrackLoadError: - return [] + return history_tracks @commands.hybrid_command(name="connect", aliases=get_aliases("connect")) @app_commands.describe(channel="Provide a channel to connect.") @@ -209,14 +203,11 @@ class Basic(commands.Cog): platform="Select the platform you want to search." ) @app_commands.choices(platform=[ - app_commands.Choice(name="Youtube", value="Youtube"), - app_commands.Choice(name="Youtube Music", value="YoutubeMusic"), - app_commands.Choice(name="Spotify", value="Spotify"), - app_commands.Choice(name="SoundCloud", value="SoundCloud"), - app_commands.Choice(name="Apple Music", value="Apple") + app_commands.Choice(name=search_type.name.replace("_", " ").title(), value=search_type.name) + for search_type in SearchType ]) @commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild) - async def search(self, ctx: commands.Context, *, query: str, platform: str = "Youtube"): + async def search(self, ctx: commands.Context, *, query: str, platform: str = SearchType.YOUTUBE.name): "Loads your input and added it to the queue." player: voicelink.Player = ctx.guild.voice_client if not player: @@ -227,14 +218,8 @@ class Basic(commands.Cog): if url(query): return await send(ctx, "noLinkSupport", ephemeral=True) - - platform = platform.lower() - if platform != 'spotify': - query_platform = searchPlatform.get(platform, 'ytsearch') + f":{query}" - tracks = await player.get_tracks(query=query_platform, requester=ctx.author) - else: - tracks = await player.node.spotifySearch(query=query, requester=ctx.author) - + + tracks = await player.get_tracks(query=query, requester=ctx.author, search_type=SearchType[platform] if platform in SearchType.__members__ else SearchType.YOUTUBE) if not tracks: return await send(ctx, "noTrackFound") @@ -332,8 +317,8 @@ class Basic(commands.Cog): await ctx.send(e) finally: - if player.queue._repeat.mode == voicelink.LoopType.track: - await player.set_repeat(voicelink.LoopType.off.name) + if player.queue._repeat.mode == voicelink.LoopType.TRACK: + await player.set_repeat(voicelink.LoopType.OFF) await player.stop() if player.is_playing else await player.do_next() @@ -410,8 +395,8 @@ class Basic(commands.Cog): player.queue.skipto(index) await send(ctx, "skipped", ctx.author) - if player.queue._repeat.mode == voicelink.LoopType.track: - await player.set_repeat(voicelink.LoopType.off.name) + if player.queue._repeat.mode == voicelink.LoopType.TRACK: + await player.set_repeat(voicelink.LoopType.OFF) await player.stop() @@ -443,8 +428,8 @@ class Basic(commands.Cog): await player.stop() await send(ctx, "backed", ctx.author) - if player.queue._repeat.mode == voicelink.LoopType.track: - await player.set_repeat(voicelink.LoopType.off.name) + if player.queue._repeat.mode == voicelink.LoopType.TRACK: + await player.set_repeat(voicelink.LoopType.OFF) @commands.hybrid_command(name="seek", aliases=get_aliases("seek")) @app_commands.describe(position="Input position. Exmaple: 1:20.") @@ -613,9 +598,8 @@ class Basic(commands.Cog): @commands.hybrid_command(name="loop", aliases=get_aliases("loop")) @app_commands.describe(mode="Choose a looping mode.") @app_commands.choices(mode=[ - app_commands.Choice(name='Off', value='off'), - app_commands.Choice(name='Track', value='track'), - app_commands.Choice(name='Queue', value='queue') + app_commands.Choice(name=loop_type.name.title(), value=loop_type.name) + for loop_type in LoopType ]) @commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild) async def loop(self, ctx: commands.Context, mode: str): @@ -627,7 +611,7 @@ class Basic(commands.Cog): if not player.is_privileged(ctx.author): return await send(ctx, "missingPerms_mode", ephemeral=True) - await player.set_repeat(mode, ctx.author) + await player.set_repeat(LoopType[mode] if mode in LoopType.__members__ else LoopType.OFF, ctx.author) await send(ctx, "repeat", mode.capitalize()) @commands.hybrid_command(name="clear", aliases=get_aliases("clear")) diff --git a/ipc/methods.py b/ipc/methods.py index 9522d5e..22493eb 100644 --- a/ipc/methods.py +++ b/ipc/methods.py @@ -178,8 +178,8 @@ async def skipTo(player: Player, member: Member, data: Dict) -> None: if index > 1: player.queue.skipto(index) - if player.queue._repeat.mode == LoopType.track: - await player.set_repeat(LoopType.off.name) + if player.queue._repeat.mode == LoopType.TRACK: + await player.set_repeat(LoopType.OFF) await player.stop() async def backTo(player: Player, member: Member, data: Dict) -> None: diff --git a/views/controller.py b/views/controller.py index 3c75aa5..7a9c409 100644 --- a/views/controller.py +++ b/views/controller.py @@ -82,8 +82,8 @@ class Back(ControlButton): await self.send(interaction, "backed", interaction.user) - if self.player.queue._repeat.mode == voicelink.LoopType.track: - await self.player.set_repeat(voicelink.LoopType.off.name) + if self.player.queue._repeat.mode == voicelink.LoopType.TRACK: + await self.player.set_repeat(voicelink.LoopType.OFF) class Resume(ControlButton): def __init__(self, **kwargs): @@ -140,8 +140,8 @@ class Skip(ControlButton): await self.send(interaction, "skipped", interaction.user) - if self.player.queue._repeat.mode == voicelink.LoopType.track: - await self.player.set_repeat(voicelink.LoopType.off.name) + if self.player.queue._repeat.mode == voicelink.LoopType.TRACK: + await self.player.set_repeat(voicelink.LoopType.OFF) await self.player.stop() class Stop(ControlButton): @@ -222,7 +222,7 @@ class Loop(ControlButton): self.emoji = self.get_next_loop_emoji(self.player) await interaction.response.edit_message(view=self.view) - await self.send(interaction, 'repeat', mode.capitalize()) + await self.send(interaction, 'repeat', mode.name.capitalize()) class VolumeUp(ControlButton): def __init__(self, **kwargs): diff --git a/voicelink/enums.py b/voicelink/enums.py index c8c53fa..9fb9578 100644 --- a/voicelink/enums.py +++ b/voicelink/enums.py @@ -26,35 +26,42 @@ from enum import Enum, auto class LoopType(Enum): """The enum for the different loop types for Voicelink - LoopType.off: 1 - LoopType.track: 2 - LoopType.queue: 3 + LoopType.OFF: 1 + LoopType.TRACK: 2 + LoopType.QUEUE: 3 """ - off = auto() - track = auto() - queue = auto() + OFF = auto() + TRACK = auto() + QUEUE = auto() class SearchType(Enum): """The enum for the different search types for Voicelink. This feature is exclusively for the Spotify search feature of Voicelink. If you are not using this feature, this class is not necessary. - SearchType.ytsearch searches using regular Youtube, + SearchType.YOUTUBE searches using regular Youtube, which is best for all scenarios. - SearchType.ytmsearch searches using YouTube Music, + SearchType.YOUTUBE_MUSIC searches using YouTube Music, which is best for getting audio-only results. + + SearchType.SPOTIFY searches using Spotify, + which is an alternative to YouTube or YouTube Music. - SearchType.scsearch searches using SoundCloud, + SearchType.SOUNDCLOUD searches using SoundCloud, + which is an alternative to YouTube or YouTube Music. + + SearchType.APPLE_MUSIC searches using Apple Music, which is an alternative to YouTube or YouTube Music. """ - ytsearch = "ytsearch" - ytmsearch = "ytmsearch" - scsearch = "scsearch" - amsearch = "amsearch" + YOUTUBE = "ytsearch" + YOUTUBE_MUSIC = "ytmsearch" + SPOTIFY = "spsearch" + SOUNDCLOUD = "scsearch" + APPLE_MUSIC = "amsearch" def __str__(self) -> str: return self.value @@ -62,10 +69,10 @@ class SearchType(Enum): class RequestMethod(Enum): """The enum for the different request methods in Voicelink """ - get = "get" - patch = "patch" - delete = "delete" - post = "post" + GET = "get" + PATCH = "patch" + DELETE = "delete" + POST = "post" def __str__(self) -> str: return self.value @@ -86,9 +93,9 @@ class NodeAlgorithm(Enum): """ # We don't have to define anything special for these, since these just serve as flags - by_ping = auto() - by_region = auto() - by_players = auto() + BY_PING = auto() + BY_REGION = auto() + BY_PLAYERS = auto() def __str__(self) -> str: return self.value \ No newline at end of file diff --git a/voicelink/objects.py b/voicelink/objects.py index de5e1bd..baa9927 100644 --- a/voicelink/objects.py +++ b/voicelink/objects.py @@ -72,7 +72,7 @@ class Track: track_id: str = None, info: dict, requester: Member, - search_type: SearchType = SearchType.ytsearch, + search_type: SearchType = SearchType.YOUTUBE, spotify_track = None, ): self._track_id: Optional[str] = track_id @@ -88,7 +88,7 @@ class Track: self.artist_id: Optional[list] = info.get("artist_id") self.original: Optional[Track] = None if self.spotify else self - self._search_type: SearchType = SearchType.ytsearch if self.spotify else search_type + self._search_type: SearchType = SearchType.YOUTUBE if self.spotify else search_type self.spotify_track: Track = spotify_track self.thumbnail: str = info.get("artworkUrl") diff --git a/voicelink/player.py b/voicelink/player.py index 48fc399..1671e15 100644 --- a/voicelink/player.py +++ b/voicelink/player.py @@ -289,7 +289,7 @@ class Player(VoiceProtocol): "sessionId": state['sessionId'], } - await self.send(method=RequestMethod.patch, data={"voice": data}) + await self.send(method=RequestMethod.PATCH, data={"voice": data}) self._logger.debug(f"Player in {self.guild.name}({self.guild.id}) dispatched voice update to {state['event']['endpoint']} with data {data}") async def on_voice_server_update(self, data: dict): @@ -450,7 +450,7 @@ class Player(VoiceProtocol): query: str, *, requester: Member, - search_type: SearchType = SearchType.ytsearch + search_type: SearchType = SearchType.YOUTUBE ) -> Union[List[Track], Playlist]: """Fetches tracks from the node's REST api to parse into Lavalink. @@ -474,7 +474,7 @@ class Player(VoiceProtocol): async def stop(self): """Stops the currently playing track.""" self._current = None - await self.send(method=RequestMethod.patch, data={'encodedTrack': None}) + await self.send(method=RequestMethod.PATCH, data={'encodedTrack': None}) async def disconnect(self, *, force: bool = False): """Disconnects the player from voice.""" @@ -498,7 +498,7 @@ class Player(VoiceProtocol): assert self.channel is None and not self.is_connected self._node._players.pop(self.guild.id) - await self.send(method=RequestMethod.delete) + await self.send(method=RequestMethod.DELETE) async def play( self, @@ -514,7 +514,7 @@ class Player(VoiceProtocol): if track.spotify: if not track.original: - search_results = await self._node.get_tracks(f"ytsearch:{track.author} - {track.title}", requester=track.requester) + search_results = await self._node.get_tracks(f"{track.author} - {track.title}", requester=track.requester) if not search_results: raise TrackLoadError("Can't find a playable source!") track.original = search_results[0] @@ -527,7 +527,7 @@ class Player(VoiceProtocol): if end or track.end_time: data["endTime"] = str(end if end else track.end_time) - await self.send(method=RequestMethod.patch, query=f"noReplace={ignore_if_playing}", data=data) + await self.send(method=RequestMethod.PATCH, query=f"noReplace={ignore_if_playing}", data=data) self._current = track @@ -601,7 +601,7 @@ class Player(VoiceProtocol): if position < 0 or position > self._current.original.length: raise TrackInvalidPosition("Seek position must be between 0 and the track length") - await self.send(method=RequestMethod.patch, data={"position": position}) + await self.send(method=RequestMethod.PATCH, data={"position": position}) if self.is_ipc_connected: await self.send_ws({"op": "updatePosition", "position": position}, requester) @@ -613,7 +613,7 @@ class Player(VoiceProtocol): self._paused = pause self.pause_votes.clear() if pause else self.resume_votes.clear() - await self.send(method=RequestMethod.patch, data={"paused": pause}) + await self.send(method=RequestMethod.PATCH, data={"paused": pause}) if self.is_ipc_connected: await self.send_ws({"op": "updatePause", "pause": pause}, requester) @@ -623,7 +623,7 @@ class Player(VoiceProtocol): async def set_volume(self, volume: int, requester: Member = None) -> int: """Sets the volume of the player as an integer. Lavalink accepts values from 0 to 500.""" - await self.send(method=RequestMethod.patch, data={"volume": volume}) + await self.send(method=RequestMethod.PATCH, data={"volume": volume}) self._volume = volume if self.is_ipc_connected: @@ -668,24 +668,19 @@ class Player(VoiceProtocol): return moved_track - async def set_repeat(self, mode: str = None, requester: Member = None) -> str: + async def set_repeat(self, mode: LoopType = None, requester: Member = None) -> LoopType: if not mode: - mode = self.queue._repeat.next().name - - is_found = False - for type in LoopType: - if type.name.lower() == mode.lower(): - self.queue._repeat.set_mode(type) - is_found = True - break - - if not is_found: + mode = self.queue._repeat.next() + + if not isinstance(mode, LoopType): raise VoicelinkException("Invalid repeat mode.") + self.queue._repeat.set_mode(mode) + if self.is_ipc_connected: - await self.send_ws({"op": "repeatTrack", "repeatMode": mode}, requester) + await self.send_ws({"op": "repeatTrack", "repeatMode": mode.name.lower()}, requester) - self._logger.debug(f"Player in {self.guild.name}({self.guild.id}) has been update the repeat mode to {mode}.") + self._logger.debug(f"Player in {self.guild.name}({self.guild.id}) has been update the repeat mode to {mode.name.lower()}.") return mode async def add_filter(self, filter: Filter, requester: Member = None, fast_apply: bool = False) -> Filters: @@ -695,7 +690,7 @@ class Player(VoiceProtocol): raise FilterTagAlreadyInUse(self.get_msg("FilterTagAlreadyInUse")) payload = self._filters.get_all_payloads() - await self.send(method=RequestMethod.patch, data={"filters": payload}) + await self.send(method=RequestMethod.PATCH, data={"filters": payload}) if fast_apply: await self.seek(self.position) @@ -725,7 +720,7 @@ class Player(VoiceProtocol): async def remove_filter(self, filter_tag: str, requester: Member = None, fast_apply: bool = False) -> Filters: self._filters.remove_filter(filter_tag=filter_tag) payload = self._filters.get_all_payloads() - await self.send(method=RequestMethod.patch, data={"filters": payload}) + await self.send(method=RequestMethod.PATCH, data={"filters": payload}) if fast_apply: await self.seek(self.position) @@ -744,7 +739,7 @@ class Player(VoiceProtocol): raise FilterInvalidArgument("You must have filters applied first in order to use this method.") self._filters.reset_filters() - await self.send(method=RequestMethod.patch, data={"filters": {}}) + await self.send(method=RequestMethod.PATCH, data={"filters": {}}) if fast_apply: await self.seek(self.position) diff --git a/voicelink/pool.py b/voicelink/pool.py index 5b258f8..518750e 100644 --- a/voicelink/pool.py +++ b/voicelink/pool.py @@ -271,7 +271,7 @@ class Node: if resp.status >= 300: raise NodeException(f"Getting errors from Lavalink REST api") - if method == RequestMethod.delete: + if method == RequestMethod.DELETE: return await resp.json(content_type=None) return await resp.json() @@ -286,7 +286,7 @@ class Node: self._task = self._bot.loop.create_task(self._listen()) self._available = True - self._info = NodeInfo(await self.send(RequestMethod.get, query="info")) + self._info = NodeInfo(await self.send(RequestMethod.GET, query="info")) self._logger.info(f"Node [{self._identifier}] is connected!") @@ -369,7 +369,7 @@ class Node: query: str, *, requester: Member, - search_type: SearchType = SearchType.ytsearch + search_type: SearchType = SearchType.YOUTUBE ) -> Union[List[Track], Playlist]: """Fetches tracks from the node's REST api to parse into Lavalink. @@ -380,8 +380,12 @@ class Node: Context object on any track you search. """ - if not URL_REGEX.match(query) and not re.match(r"(?:ytm?|sc)search:.", query): - query = f"{search_type}:{query}" + if not URL_REGEX.match(query): + if search_type == SearchType.SPOTIFY: + return await self.spotifySearch(query=query, requester=requester) + + else: + query = f"{search_type}:{query}" if SPOTIFY_URL_REGEX.match(query): try: @@ -509,7 +513,7 @@ class Node: Track( track_id=None, requester=requester, - search_type=SearchType.ytsearch, + search_type=SearchType.YOUTUBE, spotify_track=track, info=track.to_dict() ) @@ -525,7 +529,7 @@ class Node: tracks = [ Track( track_id=None, - search_type=SearchType.ytsearch, + search_type=SearchType.YOUTUBE, spotify_track=track, info=track.to_dict(), requester=self.bot.user diff --git a/voicelink/queue.py b/voicelink/queue.py index 79bd41a..10beee0 100644 --- a/voicelink/queue.py +++ b/voicelink/queue.py @@ -25,7 +25,7 @@ from .exceptions import QueueFull, OutofList from .objects import Track from .enums import LoopType -from typing import Optional, Tuple, List, Callable, Dict +from typing import Optional, Tuple, Callable, Dict, List from itertools import cycle from discord import Member @@ -65,16 +65,16 @@ class Queue: def get(self) -> Optional[Track]: track = None try: - track = self._queue[self._position - 1 if self._repeat.mode == LoopType.track else self._position] - if self._repeat.mode != LoopType.track: + track = self._queue[self._position - 1 if self._repeat.mode == LoopType.TRACK else self._position] + if self._repeat.mode != LoopType.TRACK: self._position += 1 except: - if self._repeat.mode == LoopType.queue: + if self._repeat.mode == LoopType.QUEUE: try: track = self._queue[self._repeat_position] self._position = self._repeat_position + 1 except IndexError: - self._repeat.set_mode(LoopType.off) + self._repeat.set_mode(LoopType.OFF) return track