From 464f9123e58ff33e9eae58fe9cef4963830b043b Mon Sep 17 00:00:00 2001 From: Choco <94597336+ChocoMeow@users.noreply.github.com> Date: Sat, 17 Feb 2024 13:04:20 +0800 Subject: [PATCH] Optimized code --- cogs/listeners.py | 10 ++-- cogs/playlist.py | 57 +++++++++++++--------- cogs/task.py | 2 +- function.py | 38 +++++++-------- langs/CH.json | 4 +- langs/DE.json | 4 +- langs/EN.json | 4 +- langs/ES.json | 4 +- langs/JA.json | 4 +- langs/KO.json | 4 +- langs/RU.json | 4 +- langs/UA.json | 4 +- main.py | 3 +- update.py | 2 +- views/controller.py | 8 +-- views/playlist.py | 22 ++++++--- voicelink/enums.py | 5 +- voicelink/filters.py | 113 ++++++++++++++++++++++++------------------- voicelink/objects.py | 18 ++++--- voicelink/player.py | 2 +- web/ipc/methods.py | 21 ++++---- 21 files changed, 177 insertions(+), 156 deletions(-) diff --git a/cogs/listeners.py b/cogs/listeners.py index e1a5d7e..51957cf 100644 --- a/cogs/listeners.py +++ b/cogs/listeners.py @@ -42,10 +42,12 @@ class Listeners(commands.Cog): await self.bot.wait_until_ready() for n in func.settings.nodes.values(): try: - await self.voicelink.create_node(bot=self.bot, - spotify_client_id=func.tokens.spotify_client_id, - spotify_client_secret=func.tokens.spotify_client_secret, - **n) + await self.voicelink.create_node( + bot=self.bot, + spotify_client_id=func.tokens.spotify_client_id, + spotify_client_secret=func.tokens.spotify_client_secret, + **n + ) except Exception as e: print(f'Node {n["identifier"]} is not able to connect! - Reason: {e}') diff --git a/cogs/playlist.py b/cogs/playlist.py index ef61162..665e397 100644 --- a/cogs/playlist.py +++ b/cogs/playlist.py @@ -28,9 +28,9 @@ from discord import app_commands from discord.ext import commands from function import ( time as ctime, - get_playlist, + get_user, + update_user, check_roles, - update_playlist, get_lang, settings, get_aliases, @@ -46,13 +46,14 @@ def assign_playlistId(existed: list) -> str: return str(i) async def check_playlist_perms(user_id: int, author_id: int, d_id: str) -> dict: - playlist = await get_playlist(author_id, 'playlist', d_id) + playlist = await get_user(author_id, 'playlist') + playlist = playlist.get(d_id) if not playlist or user_id not in playlist['perms']['read']: return {} return playlist async def check_playlist(ctx: commands.Context, name: str = None, full: bool = False, share: bool = True) -> dict: - user = await get_playlist(ctx.author.id, 'playlist') + user = await get_user(ctx.author.id, 'playlist') await ctx.defer() if full: @@ -91,7 +92,7 @@ class Playlists(commands.Cog, name="playlist"): self.description = "This is the Vocard playlist system. You can save your favorites and use Vocard to play on any server." async def playlist_autocomplete(self, interaction: discord.Interaction, current: str) -> list: - playlists_raw: dict[str, dict] = await get_playlist(interaction.user.id, 'playlist') + playlists_raw: dict[str, dict] = await get_user(interaction.user.id, 'playlist') playlists = [value['name'] for value in playlists_raw.values()] if playlists_raw else [] if current: return [app_commands.Choice(name=p, value=p) for p in playlists if current in p] @@ -171,7 +172,7 @@ class Playlists(commands.Cog, name="playlist"): if share := playlist['type'] == 'share': playlist = await check_playlist_perms(ctx.author.id, playlist['user'], playlist['referId']) if not playlist: - await update_playlist(ctx.author.id, {"$unset": {f"playlist.{data}": 1}}) + await update_user(ctx.author.id, {"$unset": {f"playlist.{data}": 1}}) continue if playlist['type'] == 'link': @@ -188,18 +189,26 @@ class Playlists(commands.Cog, name="playlist"): results.append({'emoji': ('🔒' if max_p < index else ('🤝' if share else '❤️')), 'id': data, 'time': ctime(time), 'name': user[data]['name'], 'tracks': playlist['tracks'], 'perms': playlist['perms'], 'owner': user[data].get('user', None), 'type': user[data]['type']}) except: - results.append({'emoji': '⛔', 'id': data, 'time': '00:00', 'name': 'Error', 'tracks': [], 'type': 'error'}) + results.append({'emoji': '⛔', 'id': data, 'time': '--:--', 'name': 'Error', 'tracks': [], 'type': 'error'}) - title = get_lang(ctx.guild.id, 'playlistViewHeaders') + title = get_lang(ctx.guild.id, 'playlistViewHeaders').split(",") embed = discord.Embed( title=get_lang(ctx.guild.id, 'playlistViewTitle').format(ctx.author.display_name), - description=f'```{title[0]:>0} {title[1]:>4} {title[2]:>10} {title[3]:>10} {title[4]:>10}\n' + '\n'.join(f"""{info['emoji']} {info['id']:>4}. {f'''[{info["time"]}]''':>10} {info['name']:>10} {f'''{len(info['tracks'])}/{max_t}''':>10}""" for info in results) + '```', + description='```prolog\n %4s %10s %10s %10s\n' % tuple(title), color=settings.embed_color ) - embed.add_field(name=get_lang(ctx.guild.id, 'playlistMaxP'), value=f"➥ {len(user)}/{max_p}", inline=True) - embed.add_field(name=get_lang(ctx.guild.id, 'playlistMaxT'), value=f"➥ {max_t}", inline=True) + for index in range(max_p): + try: + info = results[index] + track_info = (info['emoji'], info['id'], f"[{info['time']}]", info['name'], f"{len(info['tracks'])}/{max_t}") + except IndexError: + track_info = ("🎵", "-"*3, "[--:--]", "-"*6, f"-/{max_t}") + + embed.description += '%0s %3s. %10s %10s %10s\n' % track_info + + embed.description += "```" embed.set_footer(text=get_lang(ctx.guild.id, 'playlistFooter')) view = PlaylistView(embed, results, ctx.author) @@ -231,7 +240,7 @@ class Playlists(commands.Cog, name="playlist"): return await ctx.send(get_lang(ctx.guild.id, 'playlistNotInvaildUrl'), ephemeral=True) data = {'uri': link, 'perms': {'read': []}, 'name': name, 'type': 'link'} if link else {'tracks': [], 'perms': {'read': [], 'write': [], 'remove': []}, 'name': name, 'type': 'playlist'} - await update_playlist(ctx.author.id, {"$set": {f"playlist.{assign_playlistId([data for data in user])}": data}}) + await update_user(ctx.author.id, {"$set": {f"playlist.{assign_playlistId([data for data in user])}": data}}) await ctx.send(get_lang(ctx.guild.id, 'playlistCreated').format(name)) @playlist.command(name="delete", aliases=get_aliases("delete")) @@ -247,9 +256,9 @@ class Playlists(commands.Cog, name="playlist"): return await ctx.send(get_lang(ctx.guild.id, 'playlistDeleteError'), ephemeral=True) if result['playlist']['type'] == 'share': - await update_playlist(result['playlist']['user'], {"$pull": {f"playlist.{result['playlist']['referId']}.perms.read": ctx.author.id}}) + await update_user(result['playlist']['user'], {"$pull": {f"playlist.{result['playlist']['referId']}.perms.read": ctx.author.id}}) - await update_playlist(ctx.author.id, {"$unset": {f"playlist.{result['id']}": 1}}) + await update_user(ctx.author.id, {"$unset": {f"playlist.{result['id']}": 1}}) return await ctx.send(get_lang(ctx.guild.id, 'playlistRemove').format(result['playlist']['name'])) @playlist.command(name="share", aliases=get_aliases("share")) @@ -274,7 +283,7 @@ class Playlists(commands.Cog, name="playlist"): if member.id in result['playlist']['perms']['read']: return await ctx.send(get_lang(ctx.guild.id, 'playlistShare').format(member), ephemeral=True) - receiver = await get_playlist(member.id) + receiver = await get_user(member.id) if not receiver: return await ctx.send(get_lang(ctx.guild.id, 'noPlaylistAcc').format(member)) for mail in receiver['inbox']: @@ -283,7 +292,7 @@ class Playlists(commands.Cog, name="playlist"): if len(receiver['inbox']) >= 10: return await ctx.send(get_lang(ctx.guild.id, 'inboxFull').format(member), ephemeral=True) - await update_playlist( + await update_user( member.id, {"$push": {"inbox": { 'sender': ctx.author.id, @@ -320,14 +329,14 @@ class Playlists(commands.Cog, name="playlist"): if not found: return await ctx.send(get_lang(ctx.guild.id, 'playlistNotFound').format(name), ephemeral=True) - await update_playlist(ctx.author.id, {"$set": {f'playlist.{id}.name': newname}}) + await update_user(ctx.author.id, {"$set": {f'playlist.{id}.name': newname}}) await ctx.send(get_lang(ctx.guild.id, 'playlistRenamed').format(name, newname)) @playlist.command(name="inbox", aliases=get_aliases("inbox")) @commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild) async def inbox(self, ctx: commands.Context) -> None: "Show your playlist invitation." - user = await get_playlist(ctx.author.id) + user = await get_user(ctx.author.id) rank, max_p, max_t = check_roles() if not user['inbox']: @@ -344,7 +353,7 @@ class Playlists(commands.Cog, name="playlist"): update_data, dId = {}, {dId for dId in user["playlist"]} for data in view.newplaylist[:(max_p - len(user['playlist']))]: addId = assign_playlistId(dId) - await update_playlist(data['sender'], {"$push": {f"playlist.{data['referId']}.perms.read": ctx.author.id}}) + await update_user(data['sender'], {"$push": {f"playlist.{data['referId']}.perms.read": ctx.author.id}}) update_data[f'playlist.{addId}'] = { 'user': data['sender'], 'referId': data['referId'], 'name': f"Share{data['time'].strftime('%M%S')}", 'type': 'share' @@ -353,7 +362,7 @@ class Playlists(commands.Cog, name="playlist"): dId.add(addId) if update_data: - await update_playlist(ctx.author.id, {"$set": update_data}) + await update_user(ctx.author.id, {"$set": update_data}) @playlist.command(name="add", aliases=get_aliases("add")) @commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild) @@ -384,7 +393,7 @@ class Playlists(commands.Cog, name="playlist"): if results[0].is_stream: return await ctx.send(get_lang(ctx.guild.id, 'playlistStream'), ephemeral=True) - await update_playlist(ctx.author.id, {"$push": {f'playlist.{result["id"]}.tracks': results[0].track_id}}) + await update_user(ctx.author.id, {"$push": {f'playlist.{result["id"]}.tracks': results[0].track_id}}) await ctx.send(get_lang(ctx.guild.id, 'playlistAdded').format(results[0].title, ctx.author, result['playlist']['name'])) @playlist.command(name="remove", aliases=get_aliases("remove")) @@ -404,7 +413,7 @@ class Playlists(commands.Cog, name="playlist"): if not 0 < position <= len(result['playlist']['tracks']): return await ctx.send(get_lang(ctx.guild.id, 'playlistPositionNotFound').format(position, name)) - await update_playlist(ctx.author.id, {"$pull": {f'playlist.{result["id"]}.tracks': result['playlist']['tracks'][position - 1]}}) + await update_user(ctx.author.id, {"$pull": {f'playlist.{result["id"]}.tracks': result['playlist']['tracks'][position - 1]}}) track = voicelink.decode(result['playlist']['tracks'][position - 1]) await ctx.send(get_lang(ctx.guild.id, 'playlistRemoved').format(track.get("title"), ctx.author, name)) @@ -421,7 +430,7 @@ class Playlists(commands.Cog, name="playlist"): if result['playlist']['type'] in ['link', 'share']: return await ctx.send(get_lang(ctx.guild.id, 'playlistNotAllow'), ephemeral=True) - await update_playlist(ctx.author.id, {"$set": {f'playlist.{result["id"]}.tracks': []}}) + await update_user(ctx.author.id, {"$set": {f'playlist.{result["id"]}.tracks': []}}) await ctx.send(get_lang(ctx.guild.id, 'playlistClear').format(name)) @playlist.command(name="export", aliases=get_aliases("export")) @@ -492,7 +501,7 @@ class Playlists(commands.Cog, name="playlist"): track_ids = track_ids.decode().split(",") data = {'tracks': track_ids, 'perms': {'read': [], 'write': [], 'remove': []}, 'name': name, 'type': 'playlist'} - await update_playlist(ctx.author.id, {"$set": {f"playlist.{assign_playlistId([data for data in user])}": data}}) + await update_user(ctx.author.id, {"$set": {f"playlist.{assign_playlistId([data for data in user])}": data}}) await ctx.send(get_lang(ctx.guild.id, 'playlistCreated').format(name)) except: diff --git a/cogs/task.py b/cogs/task.py index 97324f0..8ee4dac 100644 --- a/cogs/task.py +++ b/cogs/task.py @@ -111,7 +111,7 @@ class Task(commands.Cog): @tasks.loop(hours=12.0) async def cache_cleaner(self): func.SETTINGS_BUFFER.clear() - func.PLAYLISTS_BUFFER.clear() + func.USERS_BUFFER.clear() errorFile = func.gen_report() if errorFile: diff --git a/function.py b/function.py index ee6fb02..e8b331f 100644 --- a/function.py +++ b/function.py @@ -23,15 +23,15 @@ settings: Settings MONGO_DB: AsyncIOMotorClient SETTINGS_DB: AsyncIOMotorCollection -PLAYLISTS_DB: AsyncIOMotorCollection +USERS_DB: AsyncIOMotorCollection ERROR_LOGS: dict[int, dict[int, str]] = {} #Stores error that not a Voicelink Exception LANGS: dict[str, dict[str, str]] = {} #Stores all the languages in ./langs +LOCAL_LANGS: dict[str, dict[str, str]] = {} #Stores all the localization languages in ./local_langs SETTINGS_BUFFER: dict[int, dict[str, Any]] = {} #Cache guild language -LOCAL_LANGS: dict[str, dict[str, str]] = {} #Stores all the localization languages in ./local_langs -PLAYLISTS_BUFFER: dict[str, dict] = {} +USERS_BUFFER: dict[str, dict] = {} -PLAYLIST_BASE: dict[str, Any] = { +USERS_BASE: dict[str, Any] = { 'playlist': { '200': { 'tracks':[], @@ -40,6 +40,7 @@ PLAYLIST_BASE: dict[str, Any] = { 'type':'playlist' } }, + 'history': [], 'inbox':[] } @@ -183,24 +184,21 @@ async def update_settings(guild_id: int, data: dict[str, dict[str, Any]]) -> boo settings = await get_settings(guild_id) return await update_db(SETTINGS_DB, settings, {"_id": guild_id}, data) -async def get_playlist(user_id: int, d_type: Optional[str] = None, d_id: Optional[str] = None, need_copy: bool = True) -> Dict[str, Any]: - playlist = PLAYLISTS_BUFFER.get(user_id) - if not playlist: - playlist = await PLAYLISTS_DB.find_one({"_id": user_id}) - if not playlist: - playlist = {"_id": user_id, **PLAYLIST_BASE} - await PLAYLISTS_DB.insert_one(playlist) +async def get_user(user_id: int, d_type: Optional[str] = None, need_copy: bool = True) -> Dict[str, Any]: + user = USERS_BUFFER.get(user_id) + if not user: + user = await USERS_DB.find_one({"_id": user_id}) + if not user: + user = {"_id": user_id, **USERS_BASE} + await USERS_DB.insert_one(user) - PLAYLISTS_BUFFER[user_id] = playlist + USERS_BUFFER[user_id] = user if d_type: - if d_id and d_type == "playlist": - playlist = playlist[d_type].get(d_id) - else: - playlist = playlist.get(d_type) + user = user.setdefault(d_type, copy.deepcopy(USERS_BASE.get(d_type))) - return copy.deepcopy(playlist) if need_copy else playlist + return copy.deepcopy(user) if need_copy else user -async def update_playlist(user_id:int, data:dict) -> None: - playlist = await get_playlist(user_id, need_copy=False) - return await update_db(PLAYLISTS_DB, playlist, {"_id": user_id}, data) \ No newline at end of file +async def update_user(user_id:int, data:dict) -> bool: + playlist = await get_user(user_id, need_copy=False) + return await update_db(USERS_DB, playlist, {"_id": user_id}, data) \ No newline at end of file diff --git a/langs/CH.json b/langs/CH.json index 256a226..057d840 100644 --- a/langs/CH.json +++ b/langs/CH.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "此聲音效果已在使用中!請使用 /cleareffect 移除它。", "playlistViewTitle": "📜 所有 {0} 的播放清單", - "playlistViewHeaders": [" ", "ID:", "時間:", "名稱:", "曲目數:"], - "playlistMaxP": "最大播放清單:", - "playlistMaxT": "最大曲目數:", + "playlistViewHeaders": "ID:,時間:,名稱:,曲目數:", "playlistFooter": "輸入 /playlist play [播放清單] 加入此播放清單至隊列中。", "playlistNotFound": "找不到播放清單 [`{0}`]。輸入 /playlist view 查看所有播放清單。", "playlistNotAccess": "抱歉!你無權訪問此播放清單!", diff --git a/langs/DE.json b/langs/DE.json index 2d6cf28..b5602da 100644 --- a/langs/DE.json +++ b/langs/DE.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "Diese Soundeffekte sind bereits im Einsatz! Bitte verwenden Sie /cleareffect , um sie zu entfernen.", "playlistViewTitle": "📜 Alle Playlists von {0}", - "playlistViewHeaders": [" ", "ID:", "Zeit:", "Name:", "Spuren:"], - "playlistMaxP": "Maximale Wiedergabeliste:", - "playlistMaxT": "Max. Spuren:", + "playlistViewHeaders": "ID:,Zeit:,Name:,Spuren:", "playlistFooter": "Geben Sie /playlist play [playlist] ein, um die Playlist in die Warteschlange einzufügen.", "playlistNotFound": "Wiedergabeliste [`{0}`] nicht gefunden. Geben Sie /playlist view ein, um Ihre gesamte Wiedergabeliste anzuzeigen.", "playlistNotAccess": "Es tut uns leid! Du bist nicht berechtigt, auf diese Playlist zuzugreifen!", diff --git a/langs/EN.json b/langs/EN.json index 2ebd9ca..ef0b595 100644 --- a/langs/EN.json +++ b/langs/EN.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "This sound effects has already in use! Please use /cleareffect to remove it.", "playlistViewTitle": "📜 All {0}'s Playlists", - "playlistViewHeaders": [" ", "ID:", "Time:", "Name:", "Tracks:"], - "playlistMaxP": "Max Playlist:", - "playlistMaxT": "Max Tracks:", + "playlistViewHeaders": "ID:,Time:,Name:,Tracks:", "playlistFooter": "Type /playlist play [playlist] to add the playlist the into queue.", "playlistNotFound": "Playlist [`{0}`] not found. Type /playlist view to view all your playlist.", "playlistNotAccess": "Sorry! You are not allowed to access this playlist!", diff --git a/langs/ES.json b/langs/ES.json index 3efe57e..f9a81e9 100644 --- a/langs/ES.json +++ b/langs/ES.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "¡Este efecto de sonido ya está en uso! Utilice /cleareffect para eliminarlo.", "playlistViewTitle": "📜 Todas las listas de reproducción de {0}", - "playlistViewHeaders": [" ", "ID:", "Tiempo:", "Nombre:", "Pistas:"], - "playlistMaxP": "Máximo de lista de reproducción:", - "playlistMaxT": "Máximo de pistas:", + "playlistViewHeaders": "ID:,Tiempo:,Nombre:,Pistas:", "playlistFooter": "Escriba /playlist play [playlist] para agregar la lista de reproducción a la cola.", "playlistNotFound": "Lista de reproducción [`{0}`] no encontrada. Escriba /playlist view para ver todas sus listas de reproducción.", "playlistNotAccess": "¡Lo siento! No está autorizado para acceder a esta lista de reproducción.", diff --git a/langs/JA.json b/langs/JA.json index 11214a1..d718e91 100644 --- a/langs/JA.json +++ b/langs/JA.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "このサウンドエフェクトはすでに使用されています!削除するには/cleareffect を使用してください。", "playlistViewTitle": "📜 {0}のすべてのプレイリスト", - "playlistViewHeaders": [" ", "ID:", "時間:", "名前:", "トラック:"], - "playlistMaxP": "最大プレイリスト:", - "playlistMaxT": "最大トラック:", + "playlistViewHeaders": "ID:,時間:,名前:,トラック:", "playlistFooter": "プレイリストをキューに追加するには、/playlist play [playlist]を入力してください。", "playlistNotFound": "プレイリスト[{0}]が見つかりません。すべてのプレイリストを表示するには、/playlist viewを入力してください。", "playlistNotAccess": "申し訳ありません!このプレイリストにアクセスすることはできません!", diff --git a/langs/KO.json b/langs/KO.json index b5e010b..170b717 100644 --- a/langs/KO.json +++ b/langs/KO.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "이 필터는 이미 사용 중입니다! 삭제하려면 /cleareffect 를 사용하십시오.", "playlistViewTitle": "📜 {0}의 모든 재생 목록", - "playlistViewHeaders": [" ", "ID:", "시간:", "이름:", "트랙:"], - "playlistMaxP": "최대 재생 목록:", - "playlistMaxT": "최대 트랙:", + "playlistViewHeaders": "ID:,시간:,이름:,트랙:", "playlistFooter": "/playlist play [재생 목록]을 입력하여 재생 목록을 대기열에 추가하세요.", "playlistNotFound": "재생 목록 [{0}]을(를) 찾을 수 없습니다. 모든 재생 목록을 보려면 /playlist view를 입력하세요.", "playlistNotAccess": "죄송합니다! 이 재생 목록에 액세스할 수 없습니다!", diff --git a/langs/RU.json b/langs/RU.json index 661f326..c06ccfa 100644 --- a/langs/RU.json +++ b/langs/RU.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "Этот звуковой эффект уже используется! Пожалуйста, используйте /cleareffect <Тег>, чтобы удалить его.", "playlistViewTitle": "📜 Все плейлисты пользователя {0}", - "playlistViewHeaders": [" ", "ID:", "Время:", "Название:", "Треки:"], - "playlistMaxP": "Максимальное количество плейлистов:", - "playlistMaxT": "Максимальное количество треков:", + "playlistViewHeaders": "ID:,Время:,Название:,Треки:", "playlistFooter": "Введите /playlist play [плейлист], чтобы добавить плейлист в очередь.", "playlistNotFound": "Плейлист [`{0}`] не найден. Введите /playlist view, чтобы посмотреть все ваши плейлисты.", "playlistNotAccess": "Извините! У вас нет доступа к этому плейлисту!", diff --git a/langs/UA.json b/langs/UA.json index 134ce7e..8cc2e69 100644 --- a/langs/UA.json +++ b/langs/UA.json @@ -45,9 +45,7 @@ "FilterTagAlreadyInUse": "Цей звуковий ефект уже використовується! Будь ласка, використовуйте /cleareffect <Тег>, щоб видалити його.", "playlistViewTitle": "📜 Усі плейлисти користувача {0}", - "playlistViewHeaders": [" ", "ID:", "Час:", "Назва:", "Треки:"], - "playlistMaxP": "Максимальна кількість плейлистів:", - "playlistMaxT": "Максимальное количество треков:", + "playlistViewHeaders": "ID:,Час:,Назва:,Треки:", "playlistFooter": "Введите /playlist play [плейлист], чтобы добавить плейлист в очередь.", "playlistNotFound": "Плейлист [`{0}`] не знайдено. Введіть /playlist view, щоб подивитися всі ваші плейлисти.", "playlistNotAccess": "Вибачте! У вас немає доступу до цього плейлиста!", diff --git a/main.py b/main.py index 66dc0c1..ddc7afb 100644 --- a/main.py +++ b/main.py @@ -61,7 +61,7 @@ class Vocard(commands.Bot): raise Exception("Not able to connect MongoDB! Reason:", e) func.SETTINGS_DB = func.MONGO_DB[db_name]["Settings"] - func.PLAYLISTS_DB = func.MONGO_DB[db_name]["Playlist"] + func.USERS_DB = func.MONGO_DB[db_name]["Users"] async def setup_hook(self) -> None: func.langs_setup() @@ -150,6 +150,7 @@ func.settings = Settings(func.open_json("settings.json")) # Setup the bot object intents = discord.Intents.default() intents.message_content = True if func.settings.bot_prefix else False +intents.members = True member_cache = discord.MemberCacheFlags( voice=True, joined=False diff --git a/update.py b/update.py index 71995a2..5655184 100644 --- a/update.py +++ b/update.py @@ -2,7 +2,7 @@ import requests, zipfile, os, shutil, argparse from io import BytesIO ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -__version__ = "v2.6.8b2" +__version__ = "v2.6.8b3" GITHUB_API_URL = "https://api.github.com/repos/ChocoMeow/Vocard/releases/latest" VOCARD_URL = "https://github.com/ChocoMeow/Vocard/archive/" diff --git a/views/controller.py b/views/controller.py index 613efbf..a504c74 100644 --- a/views/controller.py +++ b/views/controller.py @@ -28,8 +28,8 @@ import function as func from discord.ext import commands from . import ButtonOnCooldown from function import ( - get_playlist, - update_playlist, + get_user, + update_user, check_roles ) @@ -198,14 +198,14 @@ class Add(ControlButton): return await self.send(interaction, self.player.get_msg("noTrackPlaying")) if track.is_stream: return await self.send(interaction, self.player.get_msg("playlistAddError")) - user = await get_playlist(interaction.user.id, 'playlist') + user = await get_user(interaction.user.id, 'playlist') rank, max_p, max_t = check_roles() if len(user['200']['tracks']) >= max_t: return await self.send(interaction, self.player.get_msg("playlistlimited").format(max_t), ephemeral=True) if track.track_id in user['200']['tracks']: return await self.send(interaction, self.player.get_msg("playlistrepeated"), ephemeral=True) - respond = await update_playlist(interaction.user.id, {'playlist.200.tracks': track.track_id}, mode="push") + respond = await update_user(interaction.user.id, {"$push": {'playlist.200.tracks': track.track_id}}) if respond: await self.send(interaction, self.player.get_msg("playlistAdded").format(track.title, interaction.user.mention, user['200']['name']), ephemeral=True) else: diff --git a/views/playlist.py b/views/playlist.py index 873b16f..0068420 100644 --- a/views/playlist.py +++ b/views/playlist.py @@ -37,6 +37,7 @@ class Select_playlist(discord.ui.Select): super().__init__( placeholder="Select a playlist to view ..", + custom_id="selector", options=[discord.SelectOption(emoji='🌎', label='All Playlist')] + [ discord.SelectOption(emoji=playlist['emoji'], label=f'{index}. {playlist["name"]}', description=f"{playlist['time']} · {playlist['type']}") @@ -47,12 +48,14 @@ class Select_playlist(discord.ui.Select): async def callback(self, interaction: discord.Interaction) -> None: if self.values[0] == 'All Playlist': self.view.current = None - return await interaction.response.edit_message(embed=self.view.viewEmbed) + self.view.toggle_btn(True) + return await interaction.response.edit_message(embed=self.view.viewEmbed, view=self.view) self.view.current = self.view.results[int(self.values[0].split(". ")[0]) - 1] self.view.page = ceil(len(self.view.current['tracks']) / 7) self.view.current_page = 1 - await interaction.response.edit_message(embed=self.view.build_embed()) + self.view.toggle_btn(False) + await interaction.response.edit_message(embed=self.view.build_embed(), view=self.view) class PlaylistView(discord.ui.View): def __init__( @@ -80,6 +83,11 @@ class PlaylistView(discord.ui.View): async def on_error(self, error, item, interaction) -> None: return + def toggle_btn(self, action: bool) -> None: + for child in self.children: + if child.custom_id not in ("delete", "selector"): + child.disabled = action + def build_embed(self) -> discord.Embed: offset: int = self.current_page * 7 tracks: list[Track] = self.current['tracks'][(offset-7):offset] @@ -117,7 +125,7 @@ class PlaylistView(discord.ui.View): except: pass - @discord.ui.button(label='<<', style=discord.ButtonStyle.grey) + @discord.ui.button(label='<<', style=discord.ButtonStyle.grey, disabled=True) async def fast_back_button(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: if not self.current: return @@ -126,7 +134,7 @@ class PlaylistView(discord.ui.View): return await interaction.response.edit_message(embed=self.build_embed()) await interaction.response.defer() - @discord.ui.button(label='Back', style=discord.ButtonStyle.blurple) + @discord.ui.button(label='Back', style=discord.ButtonStyle.blurple, disabled=True) async def back_button(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: if not self.current: return @@ -135,7 +143,7 @@ class PlaylistView(discord.ui.View): return await interaction.response.edit_message(embed=self.build_embed()) await interaction.response.defer() - @discord.ui.button(label='Next', style=discord.ButtonStyle.blurple) + @discord.ui.button(label='Next', style=discord.ButtonStyle.blurple, disabled=True) async def next_button(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: if not self.current: return @@ -144,7 +152,7 @@ class PlaylistView(discord.ui.View): return await interaction.response.edit_message(embed=self.build_embed()) await interaction.response.defer() - @discord.ui.button(label='>>', style=discord.ButtonStyle.grey) + @discord.ui.button(label='>>', style=discord.ButtonStyle.grey, disabled=True) async def fast_next_button(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: if not self.current: return @@ -153,7 +161,7 @@ class PlaylistView(discord.ui.View): return await interaction.response.edit_message(embed=self.build_embed()) await interaction.response.defer() - @discord.ui.button(emoji='🗑️', style=discord.ButtonStyle.red) + @discord.ui.button(emoji='🗑️', custom_id="delete", style=discord.ButtonStyle.red) async def stop_button(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: await self.response.delete() self.stop() \ No newline at end of file diff --git a/voicelink/enums.py b/voicelink/enums.py index e459243..205f016 100644 --- a/voicelink/enums.py +++ b/voicelink/enums.py @@ -31,11 +31,11 @@ class LoopType(Enum): LoopType.queue: 3 """ - + 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. @@ -50,6 +50,7 @@ class SearchType(Enum): SearchType.scsearch searches using SoundCloud, which is an alternative to YouTube or YouTube Music. """ + ytsearch = "ytsearch" ytmsearch = "ytmsearch" scsearch = "scsearch" diff --git a/voicelink/filters.py b/voicelink/filters.py index 3ac9bc5..7751793 100644 --- a/voicelink/filters.py +++ b/voicelink/filters.py @@ -25,6 +25,7 @@ import collections from .exceptions import FilterInvalidArgument, FilterTagAlreadyInUse, FilterTagInvalid from typing import ( + Dict, List ) @@ -36,7 +37,7 @@ class Filter: these filters will not work. """ def __init__(self): - self.payload = None + self.payload: Dict[str, List] = None self.tag: str = None class Filters: @@ -68,7 +69,7 @@ class Filters: payload.update(filter.payload) return payload - def get_filters(self) -> list: + def get_filters(self) -> List[Filter]: return self._filters class Equalizer(Filter): @@ -185,9 +186,13 @@ class Timescale(Filter): self.rate = rate self.tag = tag - self.payload = {"timescale": {"speed": self.speed, - "pitch": self.pitch, - "rate": self.rate}} + self.payload = { + "timescale": { + "speed": self.speed, + "pitch": self.pitch, + "rate": self.rate + } + } @classmethod def vaporwave(cls): @@ -235,10 +240,14 @@ class Karaoke(Filter): self.filter_width = filter_width self.tag = tag - self.payload = {"karaoke": {"level": self.level, - "monoLevel": self.mono_level, - "filterBand": self.filter_band, - "filterWidth": self.filter_width}} + self.payload = { + "karaoke": { + "level": self.level, + "monoLevel": self.mono_level, + "filterBand": self.filter_band, + "filterWidth": self.filter_width + } + } def __repr__(self): return ( @@ -262,18 +271,20 @@ class Tremolo(Filter): super().__init__() if frequency < 0: - raise FilterInvalidArgument( - "Tremolo frequency must be more than 0.") + raise FilterInvalidArgument("Tremolo frequency must be more than 0.") if depth < 0 or depth > 1: - raise FilterInvalidArgument( - "Tremolo depth must be between 0 and 1.") + raise FilterInvalidArgument("Tremolo depth must be between 0 and 1.") self.frequency = frequency self.depth = depth self.tag = tag - self.payload = {"tremolo": {"frequency": self.frequency, - "depth": self.depth}} + self.payload = { + "tremolo": { + "frequency": self.frequency, + "depth": self.depth + } + } def __repr__(self): return f"" @@ -294,18 +305,20 @@ class Vibrato(Filter): super().__init__() if frequency < 0 or frequency > 14: - raise FilterInvalidArgument( - "Vibrato frequency must be between 0 and 14.") + raise FilterInvalidArgument("Vibrato frequency must be between 0 and 14.") if depth < 0 or depth > 1: - raise FilterInvalidArgument( - "Vibrato depth must be between 0 and 1.") + raise FilterInvalidArgument("Vibrato depth must be between 0 and 1.") self.frequency = frequency self.depth = depth self.tag = tag - self.payload = {"vibrato": {"frequency": self.frequency, - "depth": self.depth}} + self.payload = { + "vibrato": { + "frequency": self.frequency, + "depth": self.depth + } + } def __repr__(self): return f"" @@ -348,17 +361,13 @@ class ChannelMix(Filter): super().__init__() if 0 > left_to_left > 1: - raise ValueError( - "'left_to_left' value must be more than or equal to 0 or less than or equal to 1.") + raise ValueError("'left_to_left' value must be more than or equal to 0 or less than or equal to 1.") if 0 > right_to_right > 1: - raise ValueError( - "'right_to_right' value must be more than or equal to 0 or less than or equal to 1.") + raise ValueError("'right_to_right' value must be more than or equal to 0 or less than or equal to 1.") if 0 > left_to_right > 1: - raise ValueError( - "'left_to_right' value must be more than or equal to 0 or less than or equal to 1.") + raise ValueError("'left_to_right' value must be more than or equal to 0 or less than or equal to 1.") if 0 > right_to_left > 1: - raise ValueError( - "'right_to_left' value must be more than or equal to 0 or less than or equal to 1.") + raise ValueError("'right_to_left' value must be more than or equal to 0 or less than or equal to 1.") self.left_to_left = left_to_left self.left_to_right = left_to_right @@ -366,17 +375,19 @@ class ChannelMix(Filter): self.right_to_right = right_to_right self.tag = tag - self.payload = {"channelMix": {"leftToLeft": self.left_to_left, - "leftToRight": self.left_to_right, - "rightToLeft": self.right_to_left, - "rightToRight": self.right_to_right} - } - + self.payload = { + "channelMix": { + "leftToLeft": self.left_to_left, + "leftToRight": self.left_to_right, + "rightToLeft": self.right_to_left, + "rightToRight": self.right_to_right + } + } def __repr__(self) -> str: return ( - f"" + f"" ) class Distortion(Filter): @@ -409,22 +420,24 @@ class Distortion(Filter): self.scale = scale self.tag = tag - self.payload = {"distortion": { - "sinOffset": self.sin_offset, - "sinScale": self.sin_scale, - "cosOffset": self.cos_offset, - "cosScale": self.cos_scale, - "tanOffset": self.tan_offset, - "tanScale": self.tan_scale, - "offset": self.offset, - "scale": self.scale - }} + self.payload = { + "distortion": { + "sinOffset": self.sin_offset, + "sinScale": self.sin_scale, + "cosOffset": self.cos_offset, + "cosScale": self.cos_scale, + "tanOffset": self.tan_offset, + "tanScale": self.tan_scale, + "offset": self.offset, + "scale": self.scale + } + } def __repr__(self) -> str: return ( - f" " - f"cos_offset={self.cos_offset} cos_scale={self.cos_scale} tan_offset={self.tan_offset} " - f"tan_scale={self.tan_scale} offset={self.offset} scale={self.scale}" + f" " + f"cos_offset={self.cos_offset} cos_scale={self.cos_scale} tan_offset={self.tan_offset} " + f"tan_scale={self.tan_scale} offset={self.offset} scale={self.scale}" ) diff --git a/voicelink/objects.py b/voicelink/objects.py index 8032fe9..e0a00e4 100644 --- a/voicelink/objects.py +++ b/voicelink/objects.py @@ -33,9 +33,11 @@ from function import ( time as ctime ) +from .spotify import Playlist as spPlaylist from .formatter import encode YOUTUBE_REGEX = re.compile(r'(https?://)?(www\.)?youtube\.(com|nl)/watch\?v=([-\w]+)') + class Track: """The base track object. Returns critical track information needed for parsing by Lavalink. You can also pass in commands.Context to get a discord.py Context object in your track. @@ -154,16 +156,16 @@ class Playlist: tracks: list, requester: Member = None, spotify: bool = False, - spotify_playlist = None + spotify_playlist: Optional[spPlaylist] = None ): - self.playlist_info = playlist_info - self.tracks_raw = tracks - self.spotify = spotify - self.name = playlist_info.get("name") - self.spotify_playlist = spotify_playlist + self.playlist_info: dict = playlist_info + self.tracks_raw: list[Track] = tracks + self.spotify: bool = spotify + self.name: str = playlist_info.get("name") + self.spotify_playlist: Optional[spPlaylist] = spotify_playlist - self._thumbnail = None - self._uri = None + self._thumbnail: str = None + self._uri: str = None if self.spotify: self.tracks = tracks diff --git a/voicelink/player.py b/voicelink/player.py index 1482b32..c261d61 100644 --- a/voicelink/player.py +++ b/voicelink/player.py @@ -201,7 +201,7 @@ class Player(VoiceProtocol): return self._volume @property - def filters(self) -> Filter: + def filters(self) -> Filters: """Property which returns the helper class for interacting with filters""" return self._filters diff --git a/web/ipc/methods.py b/web/ipc/methods.py index 74fcc6d..9fab211 100644 --- a/web/ipc/methods.py +++ b/web/ipc/methods.py @@ -30,7 +30,8 @@ async def connect_channel(member: Member, bot: commands.Bot): channel = member.voice.channel try: - player: Player = await channel.connect(cls=Player(bot, channel, TempCtx(member, channel))) + settings = await func.get_settings(channel.guild.id) + player: Player = await channel.connect(cls=Player(bot, channel, TempCtx(member, channel), settings)) await player.send_ws({"op": "createPlayer", "members_id": [member.id for member in channel.members]}) return player except: @@ -264,7 +265,7 @@ async def closeConnection(player: Player, member: Member, data: dict): player._ipc_connection = False async def getPlaylists(member: Member, data: dict): - playlists: dict = await func.get_playlist(member.id, "playlist") + playlists: dict = await func.get_user(member.id, "playlist") if not playlists: return @@ -276,10 +277,11 @@ async def getPlaylists(member: Member, data: dict): playlists[pId]["tracks"] = [ track.track_id for track in tracks.tracks ] elif pList["type"] == "share": - playlist = await func.get_playlist(pList["user"], "playlist", pList["referId"]) + playlist = await func.get_user(pList["user"], "playlist") + playlist = playlist.get(pList["referId"]) if playlist: if member.id not in playlist["perms"]["read"]: - await func.update_playlist(member.id, {f"playlist.{pId}": 1}, mode="unset") + await func.update_user(member.id, {"$unset": {f"playlist.{pId}": 1}}) del playlists[pId] continue @@ -304,9 +306,9 @@ async def removePlaylist(member: Member, data:dict): if isShare: refer_user = data.get("refer_user") - await func.update_playlist(refer_user, {f"playlist.{pId}.perms.read": member.id}, mode="pull") + await func.update_user(refer_user, {"$pull": {f"playlist.{pId}.perms.read": member.id}}) - await func.update_playlist(member.id, {f'playlist.{pId}': 1}, mode="unset") + await func.update_user(member.id, {"$unset": {f'playlist.{pId}': 1}}) async def addPlaylistTrack(member: Member, data: dict): track_id = data.get("track_id") @@ -314,7 +316,8 @@ async def addPlaylistTrack(member: Member, data: dict): if not track_id or not pId: return - playlist: dict = await func.get_playlist(member.id, 'playlist', pId) + playlist: dict = await func.get_user(member.id, 'playlist') + playlist = playlist.get(pId) if not playlist: return @@ -328,7 +331,7 @@ async def addPlaylistTrack(member: Member, data: dict): if track_id in playlist['tracks']: return error_msg(func.get_lang(member.guild.id, "playlistrepeated"), user_id=member.id) - await func.update_playlist(member.id, {f'playlist.{pId}.tracks': track_id}, mode="push") + await func.update_user(member.id, {"$push": {f'playlist.{pId}.tracks': track_id}}) async def removePlaylistTrack(member: Member, data: dict): track_id = data.get("track_id") @@ -336,7 +339,7 @@ async def removePlaylistTrack(member: Member, data: dict): if not track_id or not pId: return - await func.update_playlist(member.id, {f'playlist.{pId}.tracks': track_id }, mode="pull") + await func.update_user(member.id, {"$pull": {f'playlist.{pId}.tracks': track_id }}) methods = { "initPlayer": [initPlayer, False],