diff --git a/cogs/admin.py b/cogs/admin.py index 895f930..d1e5321 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -6,6 +6,7 @@ import textwrap import traceback import function as func +from typing import Tuple from discord import app_commands from discord.ext import commands from function import ( @@ -25,7 +26,7 @@ class Admin(commands.Cog, name="settings"): self.bot = bot self.description = "This category is only available to admin permissions on the server." - def get_settings(self, ctx: commands.Context) -> dict: + def get_settings(self, ctx: commands.Context) -> Tuple[voicelink.Player, dict]: player: voicelink.Player = ctx.guild.voice_client if not player: settings = get_settings(ctx.guild.id) @@ -34,9 +35,11 @@ class Admin(commands.Cog, name="settings"): return player, settings - @commands.hybrid_group(name="settings", - aliases=get_aliases("settings"), - invoke_without_command=True) + @commands.hybrid_group( + name="settings", + aliases=get_aliases("settings"), + invoke_without_command=True + ) async def settings(self, ctx: commands.Context): view = HelpView(self.bot, ctx.author) embed = view.build_embed(self.qualified_name) @@ -102,7 +105,7 @@ class Admin(commands.Cog, name="settings"): "Change to another type of queue mode." player, settings = self.get_settings(ctx) - mode = "FairQueue" if mode.lower() == "fairqueue" else "queue" + mode = "FairQueue" if mode.lower() == "fairqueue" else "Queue" settings["queueType"] = mode update_settings(ctx.guild.id, {"queueType": mode}) await ctx.send(get_lang(ctx.guild.id, "setqueue").format(mode)) @@ -211,10 +214,10 @@ class Admin(commands.Cog, name="settings"): player, settings = self.get_settings(ctx) toggle = settings.get('duplicateTrack', False) if player: - player.queue._duplicateTrack = not toggle + player.queue._allow_duplicate = not toggle update_settings(ctx.guild.id, {'duplicateTrack': not toggle}) - toggle = get_lang(ctx.guild.id, "enabled" if not toggle else "disabled") + toggle = get_lang(ctx.guild.id, "enabled" if toggle else "disabled") return await ctx.send(get_lang(ctx.guild.id, "toggleDuplicateTrack").format(toggle)) @settings.command(name="customcontroller", aliases=get_aliases("customcontroller")) @@ -234,7 +237,7 @@ class Admin(commands.Cog, name="settings"): if interaction.user.id not in func.settings.bot_access_user: return await interaction.response.send_message("You are not able to use this command!") - def clear_code(content): + def clear_code(content: str): if content.startswith("```") and content.endswith("```"): return "\n".join(content.split("\n")[1:])[:-3] else: diff --git a/cogs/basic.py b/cogs/basic.py index 4cdebd8..ab802d6 100644 --- a/cogs/basic.py +++ b/cogs/basic.py @@ -322,8 +322,9 @@ class Basic(commands.Cog): await ctx.send(player.get_msg('skipped').format(ctx.author)) - if player.queue._repeat == 1: - await player.queue.set_repeat("off") + if player.queue._repeat.mode == voicelink.LoopType.track: + await player.set_repeat(voicelink.LoopType.off.name) + await player.stop() @commands.hybrid_command(name="back", aliases=get_aliases("back")) @@ -357,8 +358,8 @@ class Basic(commands.Cog): await ctx.send(player.get_msg('backed').format(ctx.author)) - if player.queue._repeat == 1: - await player.queue.set_repeat("off") + if player.queue._repeat.mode == voicelink.LoopType.track: + await player.set_repeat(voicelink.LoopType.off.name) @commands.hybrid_command(name="seek", aliases=get_aliases("seek")) @app_commands.describe(position="Input position. Exmaple: 1:20.") diff --git a/views/controller.py b/views/controller.py index b436c09..52edf74 100644 --- a/views/controller.py +++ b/views/controller.py @@ -22,6 +22,7 @@ SOFTWARE. """ import discord +import voicelink import function as func from discord.ext import commands @@ -40,7 +41,7 @@ def key(interaction: discord.Interaction): class Back(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="⏮️", label=player.get_msg('buttonBack'), style=style, disabled=False if self.player.queue.history() or not self.player.current else True, row=row) async def callback(self, interaction: discord.Interaction): @@ -63,12 +64,12 @@ class Back(discord.ui.Button): await interaction.response.send_message(self.player.get_msg("backed").format(interaction.user)) - if self.player.queue._repeat == 1: - await self.player.set_repeat("off") + if self.player.queue._repeat.mode == voicelink.LoopType.track: + await self.player.set_repeat(voicelink.LoopType.off.name) class Resume(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="⏸️", label=player.get_msg('buttonPause'), style=style, disabled=False if self.player.current else True, row=row) async def callback(self, interaction: discord.Interaction): @@ -107,7 +108,7 @@ class Resume(discord.ui.Button): class Skip(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="⏭️", label=player.get_msg('buttonSkip'), style=style, row=row) async def callback(self, interaction: discord.Interaction): @@ -127,13 +128,13 @@ class Skip(discord.ui.Button): await interaction.response.send_message(self.player.get_msg("skipped").format(interaction.user)) - if self.player.queue._repeat == 1: - await self.player.set_repeat("off") + if self.player.queue._repeat.mode == voicelink.LoopType.track: + await self.player.set_repeat(voicelink.LoopType.off.name) await self.player.stop() class Stop(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="⏹️", label=player.get_msg('buttonLeave'), style=style, row=row) async def callback(self, interaction: discord.Interaction): if not self.player.is_privileged(interaction.user): @@ -151,7 +152,7 @@ class Stop(discord.ui.Button): class Add(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="❤️", style=style, disabled=False if self.player.current else True, row=row) async def callback(self, interaction: discord.Interaction): @@ -177,7 +178,7 @@ class Add(discord.ui.Button): class Loop(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="🔁", label=player.get_msg('buttonLoop'), style=style, row=row) async def callback(self, interaction: discord.Interaction): @@ -189,7 +190,7 @@ class Loop(discord.ui.Button): class VolumeUp(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="🔊", label=player.get_msg('buttonVolumeUp'), style=style, row=row) async def callback(self, interaction: discord.Interaction): @@ -203,7 +204,7 @@ class VolumeUp(discord.ui.Button): class VolumeDown(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="🔉", label=player.get_msg('buttonVolumeDown'), style=style, row=row) async def callback(self, interaction: discord.Interaction): @@ -217,7 +218,7 @@ class VolumeDown(discord.ui.Button): class VolumeMute(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="🔇" if player.volume else "🔈", label=player.get_msg('buttonVolumeMute' if player.volume else "buttonVolumeUnmute"), style=style, row=row) @@ -241,7 +242,7 @@ class VolumeMute(discord.ui.Button): class AutoPlay(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="💡", label=player.get_msg('buttonAutoPlay'), style=style, row=row) @@ -259,7 +260,7 @@ class AutoPlay(discord.ui.Button): class Shuffle(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="🔀", label=player.get_msg('buttonShuffle'), style=style, row=row) @@ -280,7 +281,7 @@ class Shuffle(discord.ui.Button): class Forward(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="⏩", label=player.get_msg('buttonForward'), disabled=False if self.player.current else True, @@ -298,7 +299,7 @@ class Forward(discord.ui.Button): class Rewind(discord.ui.Button): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player super().__init__(emoji="⏪", label=player.get_msg('buttonRewind'), disabled=False if self.player.current else True, @@ -319,7 +320,7 @@ class Rewind(discord.ui.Button): class Tracks(discord.ui.Select): def __init__(self, player, style, row): - self.player = player + self.player: voicelink.Player = player options = [] for index, track in enumerate(self.player.queue.tracks(), start=1): @@ -370,7 +371,7 @@ class InteractiveController(discord.ui.View): def __init__(self, player): super().__init__(timeout=None) - self.player = player + self.player: voicelink.Player = player for row, btnRow in enumerate(func.settings.controller.get("default_buttons")): for btn in btnRow: color = "" @@ -385,7 +386,7 @@ class InteractiveController(discord.ui.View): self.cooldown = commands.CooldownMapping.from_cooldown(2.0, 10.0, key) - async def interaction_check(self, interaction): + async def interaction_check(self, interaction: discord.Interaction): if not self.player.node._available: await interaction.response.send_message(self.player.get_msg("nodeReconnect"), ephemeral=True) return False diff --git a/voicelink/__init__.py b/voicelink/__init__.py index c7753ba..f82f387 100644 --- a/voicelink/__init__.py +++ b/voicelink/__init__.py @@ -26,7 +26,7 @@ __author__ = 'Vocard Development, Choco' __license__ = "MIT" __copyright__ = "Copyright 2023 (c) Vocard Development, Choco" -from .enums import SearchType +from .enums import SearchType, LoopType from .events import * from .exceptions import * from .filters import * diff --git a/voicelink/enums.py b/voicelink/enums.py index 8d16f4c..d9e4a00 100644 --- a/voicelink/enums.py +++ b/voicelink/enums.py @@ -23,6 +23,18 @@ SOFTWARE. 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 + + """ + + off = auto() + track = auto() + queue = auto() class SearchType(Enum): """The enum for the different search types for Voicelink. diff --git a/voicelink/queue.py b/voicelink/queue.py index c705577..efa7bad 100644 --- a/voicelink/queue.py +++ b/voicelink/queue.py @@ -23,39 +23,58 @@ SOFTWARE. from .exceptions import QueueFull, OutofList, DuplicateTrack from .objects import Track +from .enums import LoopType + +from typing import Optional, Tuple, List, Callable +from itertools import cycle from discord import Member +class LoopTypeCycle: + def __init__(self) -> None: + self._cycle = cycle(LoopType) + self.current = next(self._cycle) + + def next(self) -> LoopType: + self.current = next(self._cycle) + return self.current + + def set_mode(self, value: LoopType) -> LoopType: + while next(self._cycle) != value: + pass + self.current = value + return value + + @property + def mode(self) -> LoopType: + return self.current + + def __str__(self) -> str: + return self.current.name.capitalize() + class Queue: - def __init__(self, size: int, duplicate_track: bool, get_msg): + def __init__(self, size: int, allow_duplicate: bool, get_msg: Callable[[str], str]) -> None: self._queue = [] self._position = 0 self._size = size - self._repeat = 0 + self._repeat = LoopTypeCycle() self._repeat_position = 0 - self._duplicate_track = duplicate_track - - self._repeat_mode = { - 0: "off", - 1: "track", - 2: "queue", - } + self._allow_duplicate = allow_duplicate self.get_msg = get_msg - def get(self): + def get(self) -> Optional[Track]: track = None try: - track = self._queue[self._position - - 1 if self._repeat == 1 else self._position] - if self._repeat != 1: + 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 == 2: + if self._repeat.mode == LoopType.queue: try: track = self._queue[self._repeat_position] self._position = self._repeat_position + 1 except IndexError: - self._repeat = 0 + self._repeat.set_mode(LoopType.off) return track @@ -70,7 +89,7 @@ class Queue: self._queue.append(item) return self.count - def put_at_front(self, item: Track): + def put_at_front(self, item: Track) -> int: if self.count >= self._size: raise QueueFull(self.get_msg("voicelinkQueueFull").format(self._size)) @@ -81,7 +100,7 @@ class Queue: self._queue.insert(self._position, item) return 1 - def put_at_index(self, index: int, item: Track): + def put_at_index(self, index: int, item: Track) -> None: if self.count >= self._size: raise QueueFull(self.get_msg("voicelinkQueueFull").format(self._size)) @@ -91,33 +110,33 @@ class Queue: return self._queue.insert(self._position - 1 + index, item) - def skipto(self, index: int): + def skipto(self, index: int) -> None: if not 0 < index <= self.count: raise OutofList(self.get_msg("voicelinkOutofList")) else: self._position += index - 1 - def backto(self, index: int): + def backto(self, index: int) -> None: if not self._position - index >= 0: raise OutofList(self.get_msg("voicelinkOutofList")) else: self._position -= index - def history_clear(self, is_playing: bool): + def history_clear(self, is_playing: bool) -> None: self._queue[:self._position - 1 if is_playing else self._position] = [] self._position = 1 if is_playing else 0 - def clear(self): + def clear(self) -> None: del self._queue[self._position:] - def replace(self, queue_type: str, replacement: list): + def replace(self, queue_type: str, replacement: list) -> None: if queue_type == "queue": self.clear() self._queue += replacement elif queue_type == "history": self._queue[:self._position] = replacement - def swap(self, num1: int, num2: int): + def swap(self, num1: int, num2: int) -> Tuple[Track, Track]: try: pos = self._position - 1 self._queue[pos + num1], self._queue[pos + num2] = self._queue[pos + num2], self._queue[pos + num1] @@ -125,7 +144,7 @@ class Queue: except IndexError: raise OutofList(self.get_msg("voicelinkOutofList")) - def move(self, target: int, to: int): + def move(self, target: int, to: int) -> Optional[Track]: if not 0 < target <= self.count or not 0 < to: raise OutofList(self.get_msg("voicelinkOutofList")) @@ -137,7 +156,7 @@ class Queue: except: raise OutofList(self.get_msg("voicelinkOutofList")) - def remove(self, index: int, index2: int = None, member: Member = None): + def remove(self, index: int, index2: int = None, member: Member = None) -> Optional[List[Track]]: pos = self._position - 1 if index2 is None: @@ -160,36 +179,35 @@ class Queue: except: raise OutofList(self.get_msg("voicelinkOutofList")) - def history(self, incTrack: bool = False) -> list: + def history(self, incTrack: bool = False) -> List[Track]: if incTrack: return self._queue[:self._position] return self._queue[:self._position - 1] - def tracks(self, incTrack: bool = False): + def tracks(self, incTrack: bool = False) -> List[Track]: if incTrack: return self._queue[self._position - 1:] return self._queue[self._position:] @property - def count(self): + def count(self) -> int: return len(self._queue[self._position:]) + + @property + def repeat(self) -> str: + return self._repeat.mode.name.capitalize() @property - def repeat(self): - return self._repeat_mode.get(self._repeat, "Off").capitalize() - - @property - def is_empty(self): + def is_empty(self) -> bool: try: self._queue[self._position] except: return True return False - class FairQueue(Queue): - def __init__(self, size: int, duplicate_track: bool, get_msg): - super().__init__(size, duplicate_track, get_msg) + def __init__(self, size: int, allow_duplicate: bool, get_msg) -> None: + super().__init__(size, allow_duplicate, get_msg) self._set = set() def put(self, item: Track) -> int: diff --git a/web/ipc/methods.py b/web/ipc/methods.py index 9a4cfab..3f598da 100644 --- a/web/ipc/methods.py +++ b/web/ipc/methods.py @@ -2,7 +2,7 @@ import json, function as func from discord import Member, VoiceChannel from discord.ext import commands -from voicelink import Player, Track, Playlist, NodePool, connect_channel, decode +from voicelink import Player, Track, Playlist, NodePool, connect_channel, decode, LoopType class TempCtx(): def __init__(self, author: Member, channel: VoiceChannel) -> None: @@ -76,8 +76,8 @@ async def skipTo(player: Player, member: Member, data: dict): if index > 1: player.queue.skipto(index) - if player.queue._repeat == 1: - await player.set_repeat("off") + if player.queue._repeat.mode == LoopType.track: + await player.set_repeat(LoopType.off.name) await player.stop() async def backTo(player: Player, member: Member, data: dict):