diff --git a/v6d3music/commands.py b/v6d3music/commands.py index 7217874..cb5bce8 100644 --- a/v6d3music/commands.py +++ b/v6d3music/commands.py @@ -8,6 +8,7 @@ from v6d3music.core.yt_audios import yt_audios from v6d3music.utils.assert_admin import assert_admin from v6d3music.utils.catch import catch from v6d3music.utils.effects_for_preset import effects_for_preset +from v6d3music.utils.entries_effects_for_args import default_effects, set_default_effects from v6d3music.utils.options_for_effects import options_for_effects from v6d3music.utils.presets import allowed_presets @@ -110,6 +111,32 @@ async def effects_(ctx: Context, args: list[str]) -> None: yta.set_seconds(seconds) +@at('commands', 'default') +async def default(ctx: Context, args: list[str]) -> None: + await catch( + ctx, args, ''' +`default - effects` +`default + preset` +`default none` +''', 'help' + ) + match args: + case ['-', effects]: + pass + case ['+', preset]: + effects = effects_for_preset(preset) + case ['none']: + effects = None + case []: + await ctx.reply(f'current default effects: {default_effects(ctx.guild.id)}') + return + case _: + raise Explicit('misformatted') + assert_admin(ctx.member) + await set_default_effects(ctx.guild.id, effects) + await ctx.reply(f'effects set to `{effects}`') + + @at('commands', 'queue') async def queue_(ctx: Context, args: list[str]) -> None: await catch( diff --git a/v6d3music/core/queueaudio.py b/v6d3music/core/queueaudio.py index b256579..15240de 100644 --- a/v6d3music/core/queueaudio.py +++ b/v6d3music/core/queueaudio.py @@ -20,6 +20,7 @@ class QueueAudio(discord.AudioSource): for audio in respawned: self.append(audio) self.guild = guild + self.loop = asyncio.get_running_loop() def _update_sources(self): for i in range(PRE_SET_LENGTH): @@ -58,17 +59,24 @@ class QueueAudio(discord.AudioSource): audio.set_source_if_necessary() self.queue.append(audio) - def read(self) -> bytes: - if not self.queue: - return FILL - audio = self.queue[0] - audio.set_source_if_necessary() - frame = audio.read() - if len(frame) != discord.opus.Encoder.FRAME_SIZE: + def _popleft(self, audio: YTAudio): + if self.queue and self.queue[0] is audio: self.queue.popleft().cleanup() self._update_sources() - frame = FILL - return frame + + def read(self) -> bytes: + for i in range(len(self.queue)): + try: + audio = self.queue[i] + except IndexError: + break + audio.set_source_if_necessary() + frame = audio.read() + if len(frame) == discord.opus.Encoder.FRAME_SIZE: + return frame + else: + self.loop.call_soon_threadsafe(self._popleft, audio) + return FILL def skip_at(self, pos: int, member: discord.Member) -> bool: if pos < len(self.queue): diff --git a/v6d3music/core/yt_audios.py b/v6d3music/core/yt_audios.py index 4f4fc89..eb99bdb 100644 --- a/v6d3music/core/yt_audios.py +++ b/v6d3music/core/yt_audios.py @@ -10,7 +10,7 @@ from v6d3music.utils.info_tuple import info_tuple async def yt_audios(ctx: Context, args: list[str]) -> AsyncIterable[YTAudio]: tuples: list[info_tuple] = [] - async for info, effects, already_read, tor in entries_effects_for_args(args): + async for info, effects, already_read, tor in entries_effects_for_args(args, ctx.guild.id): tuples.append((info, effects, already_read, tor)) if len(tuples) >= 5: async for audio in create_ytaudios(ctx, tuples): diff --git a/v6d3music/run-bot.py b/v6d3music/run-bot.py index 42c0dfb..4130dd4 100644 --- a/v6d3music/run-bot.py +++ b/v6d3music/run-bot.py @@ -18,6 +18,7 @@ from v6d3music.core.cache_url import cache_db from v6d3music.core.mainasrc import main_for_raw_vc, mainasrcs from v6d3music.core.mainaudio import volume_db from v6d3music.core.queueaudio import queue_db +from v6d3music.utils.entries_effects_for_args import effects_db loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) @@ -125,7 +126,7 @@ async def setup_tasks(): async def main(): - async with volume_db, queue_db, cache_db, session_db: + async with volume_db, queue_db, cache_db, session_db, effects_db: if 'guerilla' in sys.argv: from pathlib import Path tokenpath = Path('.token.txt') diff --git a/v6d3music/utils/entries_effects_for_args.py b/v6d3music/utils/entries_effects_for_args.py index f943ed1..232dbd3 100644 --- a/v6d3music/utils/entries_effects_for_args.py +++ b/v6d3music/utils/entries_effects_for_args.py @@ -1,13 +1,35 @@ -from typing import AsyncIterable +from typing import AsyncIterable, Optional +from ptvp35 import Db, KVJson +from v6d2ctx.context import Explicit + +from v6d3music.config import myroot from v6d3music.utils.effects_for_preset import effects_for_preset from v6d3music.utils.entries_for_url import entries_for_url from v6d3music.utils.info_tuple import info_tuple from v6d3music.utils.options_for_effects import options_for_effects +from v6d3music.utils.presets import allowed_effects from v6d3music.utils.sparq import sparq -async def entries_effects_for_args(args: list[str]) -> AsyncIterable[info_tuple]: +effects_db = Db(myroot / 'effects.db', kvrequest_type=KVJson) + + +def default_effects(gid: int) -> Optional[str]: + effects = effects_db.get(gid, None) + if effects in allowed_effects: + return effects + else: + return None + + +async def set_default_effects(gid: int, effects: Optional[str]) -> None: + if effects is not None and effects not in allowed_effects: + raise Explicit('these effects are not allowed') + await effects_db.set(gid, effects) + + +async def entries_effects_for_args(args: list[str], gid: int) -> AsyncIterable[info_tuple]: while args: match args: case [url, '-', effects, *args]: @@ -15,7 +37,7 @@ async def entries_effects_for_args(args: list[str]) -> AsyncIterable[info_tuple] case [url, '+', preset, *args]: effects = effects_for_preset(preset) case [url, *args]: - effects = None + effects = default_effects(gid) case _: raise RuntimeError seconds = 0 diff --git a/v6d3music/utils/presets.py b/v6d3music/utils/presets.py index 0887391..ed77cd3 100644 --- a/v6d3music/utils/presets.py +++ b/v6d3music/utils/presets.py @@ -1,13 +1,16 @@ +normal = 'loudnorm=i=-12' +# _prefix = f'{normal},' +_prefix = f'' presets: dict[str, str] = { 'cursed': 'aeval=val(0)*2*sin(440*t)+val(1)*2*cos(622*t)|val(1)*2*sin(622*t)+val(0)*2*cos(440*t)', - 'bassboost': 'bass=g=10', - 'bassbooboost': 'bass=g=30', - 'nightcore': 'asetrate=67882', - 'daycore': 'atempo=.9,aecho=1.0:0.5:20:0.5', + 'bassboost': f'{_prefix}bass=g=10', + 'bassbooboost': f'{_prefix}bass=g=30', + 'nightcore': f'{_prefix}asetrate=67882', + 'daycore': f'{_prefix}atempo=.9,aecho=1.0:0.5:20:0.5', 'пришествие анимешне': 'bass=g=15,asetrate=67882,bass=g=15', 'difference': 'aeval=val(0)-val(1)|val(1)-val(0)', - 'mono': 'aeval=.5*val(0)+.5*val(1)|.5*val(1)+.5*val(0)', - 'normal': 'loudnorm=i=-12', + 'mono': f'{_prefix}aeval=.5*val(0)+.5*val(1)|.5*val(1)+.5*val(0)', + 'normal': f'{normal}', } allowed_presets = ['bassboost', 'bassbooboost', 'nightcore', 'daycore', 'mono', 'normal', ] allowed_effects = {'', *(presets[key] for key in allowed_presets)}