help catch + effects command + time fix + allowed presets
This commit is contained in:
parent
dbce057615
commit
dc86f70c40
@ -9,7 +9,7 @@ import subprocess
|
|||||||
import time
|
import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from typing import Optional, AsyncIterable, Any
|
from typing import Optional, AsyncIterable, Any, Iterable
|
||||||
|
|
||||||
# noinspection PyPackageRequirements
|
# noinspection PyPackageRequirements
|
||||||
import discord
|
import discord
|
||||||
@ -17,7 +17,7 @@ import nacl.hash
|
|||||||
import youtube_dl
|
import youtube_dl
|
||||||
from ptvp35 import Db, KVJson
|
from ptvp35 import Db, KVJson
|
||||||
from v6d1tokens.client import request_token
|
from v6d1tokens.client import request_token
|
||||||
from v6d2ctx.context import Context, at, escape, monitor, Benchmark, Explicit
|
from v6d2ctx.context import Context, at, escape, monitor, Benchmark, Explicit, Implicit
|
||||||
from v6d2ctx.handle_content import handle_content
|
from v6d2ctx.handle_content import handle_content
|
||||||
from v6d2ctx.lock_for import lock_for
|
from v6d2ctx.lock_for import lock_for
|
||||||
from v6d2ctx.serve import serve
|
from v6d2ctx.serve import serve
|
||||||
@ -75,7 +75,7 @@ async def restore_vcs():
|
|||||||
|
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
print("ready")
|
print('ready')
|
||||||
await client.change_presence(activity=discord.Game(
|
await client.change_presence(activity=discord.Game(
|
||||||
name='феноменально',
|
name='феноменально',
|
||||||
))
|
))
|
||||||
@ -92,6 +92,31 @@ async def help_(ctx: Context, args: list[str]) -> None:
|
|||||||
await ctx.reply(f'help for {name}: `{name} help`')
|
await ctx.reply(f'help for {name}: `{name} help`')
|
||||||
|
|
||||||
|
|
||||||
|
def speed_quotient(options: str) -> float:
|
||||||
|
options = options or ''
|
||||||
|
options = ''.join(c for c in options if not c.isspace())
|
||||||
|
options += ','
|
||||||
|
quotient: float = 1.0
|
||||||
|
asetrate: str
|
||||||
|
for asetrate in re.findall(r'asetrate=([0-9.]+?),', options):
|
||||||
|
try:
|
||||||
|
quotient *= float(asetrate) / discord.opus.Encoder.SAMPLING_RATE
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
atempo: str
|
||||||
|
for atempo in re.findall(r'atempo=([0-9.]+?),', options):
|
||||||
|
try:
|
||||||
|
quotient *= float(atempo)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
quotient = max(0.1, min(10.0, quotient))
|
||||||
|
return quotient
|
||||||
|
|
||||||
|
|
||||||
|
def sparq(options: str) -> float:
|
||||||
|
return speed_quotient(options) * discord.opus.Encoder.FRAME_LENGTH / 1000
|
||||||
|
|
||||||
|
|
||||||
class YTAudio(discord.AudioSource):
|
class YTAudio(discord.AudioSource):
|
||||||
source: discord.FFmpegPCMAudio
|
source: discord.FFmpegPCMAudio
|
||||||
|
|
||||||
@ -127,30 +152,11 @@ class YTAudio(discord.AudioSource):
|
|||||||
self.already_read = already_read
|
self.already_read = already_read
|
||||||
self.set_source()
|
self.set_source()
|
||||||
|
|
||||||
def _speed_quotient(self) -> float:
|
def set_seconds(self, seconds: float):
|
||||||
options = self.options or ''
|
self.set_already_read(round(seconds / sparq(self.options)))
|
||||||
options = ''.join(c for c in options if not c.isspace())
|
|
||||||
options += ','
|
|
||||||
quotient: float = 1.0
|
|
||||||
asetrate: str
|
|
||||||
for asetrate in re.findall(r'asetrate=([0-9.]+?),', options):
|
|
||||||
try:
|
|
||||||
quotient *= float(asetrate) / discord.opus.Encoder.SAMPLING_RATE
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
atempo: str
|
|
||||||
for atempo in re.findall(r'atempo=([0-9.]+?),', options):
|
|
||||||
try:
|
|
||||||
quotient *= float(atempo)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return quotient
|
|
||||||
|
|
||||||
def speed_quotient(self) -> float:
|
|
||||||
return max(0.5, min(2.0, self._speed_quotient()))
|
|
||||||
|
|
||||||
def source_seconds(self) -> float:
|
def source_seconds(self) -> float:
|
||||||
return self.already_read * self.speed_quotient() * discord.opus.Encoder.FRAME_LENGTH / 1000
|
return self.already_read * sparq(self.options)
|
||||||
|
|
||||||
def source_timecode(self) -> str:
|
def source_timecode(self) -> str:
|
||||||
seconds = round(self.source_seconds())
|
seconds = round(self.source_seconds())
|
||||||
@ -266,6 +272,12 @@ class YTAudio(discord.AudioSource):
|
|||||||
FILL = b'\x00' * discord.opus.Encoder.FRAME_SIZE
|
FILL = b'\x00' * discord.opus.Encoder.FRAME_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
def assert_admin(member: discord.Member):
|
||||||
|
permissions: discord.Permissions = member.guild_permissions
|
||||||
|
if not permissions.administrator:
|
||||||
|
raise Explicit('not an administrator')
|
||||||
|
|
||||||
|
|
||||||
class QueueAudio(discord.AudioSource):
|
class QueueAudio(discord.AudioSource):
|
||||||
def __init__(self, guild: discord.Guild, respawned: list[YTAudio]):
|
def __init__(self, guild: discord.Guild, respawned: list[YTAudio]):
|
||||||
self.queue: deque[YTAudio] = deque()
|
self.queue: deque[YTAudio] = deque()
|
||||||
@ -328,31 +340,22 @@ class QueueAudio(discord.AudioSource):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def clear(self, member: discord.Member) -> None:
|
def clear(self, member: discord.Member) -> None:
|
||||||
permissions: discord.Permissions = member.guild_permissions
|
assert_admin(member)
|
||||||
if permissions.administrator:
|
self.cleanup()
|
||||||
self.cleanup()
|
|
||||||
else:
|
|
||||||
raise Explicit('not an administrator')
|
|
||||||
|
|
||||||
def swap(self, member: discord.Member, a: int, b: int) -> None:
|
def swap(self, member: discord.Member, a: int, b: int) -> None:
|
||||||
permissions: discord.Permissions = member.guild_permissions
|
assert_admin(member)
|
||||||
if permissions.administrator:
|
if max(a, b) >= len(self.queue):
|
||||||
if max(a, b) >= len(self.queue):
|
return
|
||||||
return
|
self.queue[a], self.queue[b] = self.queue[b], self.queue[a]
|
||||||
self.queue[a], self.queue[b] = self.queue[b], self.queue[a]
|
|
||||||
else:
|
|
||||||
raise Explicit('not an administrator')
|
|
||||||
|
|
||||||
def move(self, member: discord.Member, a: int, b: int) -> None:
|
def move(self, member: discord.Member, a: int, b: int) -> None:
|
||||||
permissions: discord.Permissions = member.guild_permissions
|
assert_admin(member)
|
||||||
if permissions.administrator:
|
if max(a, b) >= len(self.queue):
|
||||||
if max(a, b) >= len(self.queue):
|
return
|
||||||
return
|
audio = self.queue[a]
|
||||||
audio = self.queue[a]
|
self.queue.remove(audio)
|
||||||
self.queue.remove(audio)
|
self.queue.insert(b, audio)
|
||||||
self.queue.insert(b, audio)
|
|
||||||
else:
|
|
||||||
raise Explicit('not an administrator')
|
|
||||||
|
|
||||||
async def format(self) -> str:
|
async def format(self) -> str:
|
||||||
stream = StringIO()
|
stream = StringIO()
|
||||||
@ -375,13 +378,11 @@ class MainAudio(discord.PCMVolumeTransformer):
|
|||||||
super().__init__(self.queue, volume=volume)
|
super().__init__(self.queue, volume=volume)
|
||||||
|
|
||||||
async def set(self, volume: float, member: discord.Member):
|
async def set(self, volume: float, member: discord.Member):
|
||||||
|
assert_admin(member)
|
||||||
if volume < 0.01:
|
if volume < 0.01:
|
||||||
raise Explicit('volume too small')
|
raise Explicit('volume too small')
|
||||||
if volume > 1:
|
if volume > 1:
|
||||||
raise Explicit('volume too big')
|
raise Explicit('volume too big')
|
||||||
permissions: discord.Permissions = member.guild_permissions
|
|
||||||
if not permissions.administrator:
|
|
||||||
raise Explicit('not an administrator')
|
|
||||||
self.volume = volume
|
self.volume = volume
|
||||||
await volume_db.set(member.guild.id, volume)
|
await volume_db.set(member.guild.id, volume)
|
||||||
|
|
||||||
@ -469,14 +470,17 @@ async def real_url(url: str, override: bool) -> str:
|
|||||||
return rurl
|
return rurl
|
||||||
|
|
||||||
|
|
||||||
|
def options_for_effects(effects: str) -> Optional[str]:
|
||||||
|
return f'-af {shlex.quote(effects)}' if effects else None
|
||||||
|
|
||||||
|
|
||||||
async def create_ytaudio(ctx: Context, info: dict[str, Any], effects: Optional[str], already_read: int) -> YTAudio:
|
async def create_ytaudio(ctx: Context, info: dict[str, Any], effects: Optional[str], already_read: int) -> YTAudio:
|
||||||
if effects:
|
if effects:
|
||||||
permissions: discord.Permissions = ctx.member.guild_permissions
|
if effects not in allowed_effects:
|
||||||
if not permissions.administrator:
|
assert_admin(ctx.member)
|
||||||
raise Explicit("not an administrator")
|
|
||||||
if not set(effects) <= set(string.ascii_letters + string.digits + '*,=+-/()|.^:_'):
|
if not set(effects) <= set(string.ascii_letters + string.digits + '*,=+-/()|.^:_'):
|
||||||
raise Explicit('malformed effects')
|
raise Explicit('malformed effects')
|
||||||
options = f'-af {shlex.quote(effects)}'
|
options = options_for_effects(effects)
|
||||||
else:
|
else:
|
||||||
options = None
|
options = None
|
||||||
return YTAudio(
|
return YTAudio(
|
||||||
@ -494,8 +498,8 @@ async def entries_for_url(url: str) -> AsyncIterable[
|
|||||||
]:
|
]:
|
||||||
info = await aextract(
|
info = await aextract(
|
||||||
{
|
{
|
||||||
"playlistend": 128,
|
'playlistend': 128,
|
||||||
"logtostderr": True
|
'logtostderr': True
|
||||||
},
|
},
|
||||||
url,
|
url,
|
||||||
download=False,
|
download=False,
|
||||||
@ -530,6 +534,8 @@ presets: dict[str, str] = {
|
|||||||
'difference': 'aeval=val(0)-val(1)|val(1)-val(0)',
|
'difference': 'aeval=val(0)-val(1)|val(1)-val(0)',
|
||||||
'mono': 'aeval=.5*val(0)+.5*val(1)|.5*val(1)+.5*val(0)',
|
'mono': 'aeval=.5*val(0)+.5*val(1)|.5*val(1)+.5*val(0)',
|
||||||
}
|
}
|
||||||
|
allowed_presets = ['bassboost', 'bassbooboost', 'nightcore', 'mono']
|
||||||
|
allowed_effects = {'', *(presets[key] for key in allowed_presets)}
|
||||||
|
|
||||||
|
|
||||||
async def entries_effects_for_args(args: list[str]) -> AsyncIterable[tuple[dict[str, Any], str, int]]:
|
async def entries_effects_for_args(args: list[str]) -> AsyncIterable[tuple[dict[str, Any], str, int]]:
|
||||||
@ -543,17 +549,17 @@ async def entries_effects_for_args(args: list[str]) -> AsyncIterable[tuple[dict[
|
|||||||
effects = None
|
effects = None
|
||||||
case _:
|
case _:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
timestamp = 0
|
seconds = 0
|
||||||
match args:
|
match args:
|
||||||
case [h, m, s, *args] if h.isdecimal() and m.isdecimal() and s.isdecimal():
|
case [h, m, s, *args] if h.isdecimal() and m.isdecimal() and s.isdecimal():
|
||||||
timestamp = 3600 * int(h) + 60 * int(m) + int(s)
|
seconds = 3600 * int(h) + 60 * int(m) + int(s)
|
||||||
case [m, s, *args] if m.isdecimal() and s.isdecimal():
|
case [m, s, *args] if m.isdecimal() and s.isdecimal():
|
||||||
timestamp = 60 * int(m) + int(s)
|
seconds = 60 * int(m) + int(s)
|
||||||
case [s, *args] if s.isdecimal():
|
case [s, *args] if s.isdecimal():
|
||||||
timestamp = int(s)
|
seconds = int(s)
|
||||||
case [*args]:
|
case [*args]:
|
||||||
pass
|
pass
|
||||||
already_read = timestamp * 1000 / discord.opus.Encoder.FRAME_LENGTH
|
already_read = round(seconds / sparq(options_for_effects(effects)))
|
||||||
async for info in entries_for_url(url):
|
async for info in entries_for_url(url):
|
||||||
yield info, effects, already_read
|
yield info, effects, already_read
|
||||||
|
|
||||||
@ -573,39 +579,49 @@ async def yt_audios(ctx: Context, args: list[str]) -> AsyncIterable[YTAudio]:
|
|||||||
mainasrcs: dict[discord.Guild, MainAudio] = {}
|
mainasrcs: dict[discord.Guild, MainAudio] = {}
|
||||||
|
|
||||||
|
|
||||||
|
async def catch(ctx: Context, args: list[str], reply: str, *catched: (Iterable[str] | str)):
|
||||||
|
catched = {(case,) if isinstance(case, str) else tuple(case) for case in catched}
|
||||||
|
if tuple(args) in catched:
|
||||||
|
await ctx.reply(reply.strip())
|
||||||
|
raise Implicit
|
||||||
|
|
||||||
|
|
||||||
@at('commands', '/')
|
@at('commands', '/')
|
||||||
@at('commands', 'play')
|
@at('commands', 'play')
|
||||||
async def play(ctx: Context, args: list[str]) -> None:
|
async def play(ctx: Context, args: list[str]) -> None:
|
||||||
match args:
|
await catch(
|
||||||
case [] | ['help']:
|
ctx, args,
|
||||||
await ctx.reply('''
|
f'''
|
||||||
`play ...args`
|
`play ...args`
|
||||||
`play url [- effects] ...args`
|
`play url [- effects] ...args`
|
||||||
'''.strip())
|
`play url [+ preset] ...args`
|
||||||
case _:
|
presets: {shlex.join(allowed_presets)}
|
||||||
async with lock_for(ctx.guild, 'not in a guild'):
|
''',
|
||||||
queue = await queue_for(ctx, create=True)
|
(), 'help'
|
||||||
async for audio in yt_audios(ctx, args):
|
)
|
||||||
queue.append(audio)
|
async with lock_for(ctx.guild, 'not in a guild'):
|
||||||
await ctx.reply('done')
|
queue = await queue_for(ctx, create=True)
|
||||||
|
async for audio in yt_audios(ctx, args):
|
||||||
|
queue.append(audio)
|
||||||
|
await ctx.reply('done')
|
||||||
|
|
||||||
|
|
||||||
async def raw_vc_for(ctx: Context) -> discord.VoiceClient:
|
async def raw_vc_for(ctx: Context) -> discord.VoiceClient:
|
||||||
if ctx.guild is None:
|
if ctx.guild is None:
|
||||||
raise Explicit("not in a guild")
|
raise Explicit('not in a guild')
|
||||||
vc: discord.VoiceProtocol = ctx.guild.voice_client
|
vc: discord.VoiceProtocol = ctx.guild.voice_client
|
||||||
if vc is None or isinstance(vc, discord.VoiceClient) and not vc.is_connected():
|
if vc is None or isinstance(vc, discord.VoiceClient) and not vc.is_connected():
|
||||||
vs: discord.VoiceState = ctx.member.voice
|
vs: discord.VoiceState = ctx.member.voice
|
||||||
if vs is None:
|
if vs is None:
|
||||||
raise Explicit("not connected")
|
raise Explicit('not connected')
|
||||||
vch: discord.VoiceChannel = vs.channel
|
vch: discord.VoiceChannel = vs.channel
|
||||||
if vch is None:
|
if vch is None:
|
||||||
raise Explicit("not connected")
|
raise Explicit('not connected')
|
||||||
try:
|
try:
|
||||||
vc: discord.VoiceProtocol = await vch.connect()
|
vc: discord.VoiceProtocol = await vch.connect()
|
||||||
except discord.ClientException:
|
except discord.ClientException:
|
||||||
await ctx.guild.fetch_channels()
|
await ctx.guild.fetch_channels()
|
||||||
raise Explicit("try again later")
|
raise Explicit('try again later')
|
||||||
assert isinstance(vc, discord.VoiceClient)
|
assert isinstance(vc, discord.VoiceClient)
|
||||||
return vc
|
return vc
|
||||||
|
|
||||||
@ -620,7 +636,7 @@ async def main_for_raw_vc(vc: discord.VoiceClient, *, create: bool) -> MainAudio
|
|||||||
MainAudio(await QueueAudio.create(vc.guild), volume=volume_db.get(vc.guild.id, 0.2))
|
MainAudio(await QueueAudio.create(vc.guild), volume=volume_db.get(vc.guild.id, 0.2))
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise Explicit("not playing")
|
raise Explicit('not playing')
|
||||||
if vc.source != source or create and not vc.is_playing():
|
if vc.source != source or create and not vc.is_playing():
|
||||||
vc.play(source)
|
vc.play(source)
|
||||||
return source
|
return source
|
||||||
@ -647,12 +663,10 @@ async def queue_for(ctx: Context, *, create: bool) -> QueueAudio:
|
|||||||
|
|
||||||
@at('commands', 'skip')
|
@at('commands', 'skip')
|
||||||
async def skip(ctx: Context, args: list[str]) -> None:
|
async def skip(ctx: Context, args: list[str]) -> None:
|
||||||
match args:
|
await catch(ctx, args, '''
|
||||||
case ['help']:
|
|
||||||
await ctx.reply('''
|
|
||||||
`skip [first] [last]`
|
`skip [first] [last]`
|
||||||
'''.strip())
|
''', 'help')
|
||||||
return
|
match args:
|
||||||
case []:
|
case []:
|
||||||
queue = await queue_for(ctx, create=False)
|
queue = await queue_for(ctx, create=False)
|
||||||
queue.skip_at(0, ctx.member)
|
queue.skip_at(0, ctx.member)
|
||||||
@ -667,34 +681,58 @@ async def skip(ctx: Context, args: list[str]) -> None:
|
|||||||
if not queue.skip_at(pos0, ctx.member):
|
if not queue.skip_at(pos0, ctx.member):
|
||||||
pos0 += 1
|
pos0 += 1
|
||||||
case _:
|
case _:
|
||||||
raise Explicit("misformatted")
|
raise Explicit('misformatted')
|
||||||
await ctx.reply('done')
|
await ctx.reply('done')
|
||||||
|
|
||||||
|
|
||||||
@at('commands', 'to')
|
@at('commands', 'to')
|
||||||
async def skip_to(ctx: Context, args: list[str]) -> None:
|
async def skip_to(ctx: Context, args: list[str]) -> None:
|
||||||
|
await catch(ctx, args, '''
|
||||||
|
`to [[h]] [m] s`
|
||||||
|
''', 'help')
|
||||||
match args:
|
match args:
|
||||||
case ['help']:
|
|
||||||
await ctx.reply('`to [[h]] [m] s`')
|
|
||||||
return
|
|
||||||
case [h, m, s] if h.isdecimal() and m.isdecimal() and s.isdecimal():
|
case [h, m, s] if h.isdecimal() and m.isdecimal() and s.isdecimal():
|
||||||
timestamp = 3600 * int(h) + 60 * int(m) + int(s)
|
seconds = 3600 * int(h) + 60 * int(m) + int(s)
|
||||||
case [m, s] if m.isdecimal() and s.isdecimal():
|
case [m, s] if m.isdecimal() and s.isdecimal():
|
||||||
timestamp = 60 * int(m) + int(s)
|
seconds = 60 * int(m) + int(s)
|
||||||
case [s] if s.isdecimal():
|
case [s] if s.isdecimal():
|
||||||
timestamp = int(s)
|
seconds = int(s)
|
||||||
case _:
|
case _:
|
||||||
raise Explicit("misformatted")
|
raise Explicit('misformatted')
|
||||||
already_read = timestamp * 1000 / discord.opus.Encoder.FRAME_LENGTH
|
|
||||||
queue = await queue_for(ctx, create=False)
|
queue = await queue_for(ctx, create=False)
|
||||||
queue.queue[0].set_already_read(already_read)
|
queue.queue[0].set_seconds(seconds)
|
||||||
|
|
||||||
|
|
||||||
|
@at('commands', 'effects')
|
||||||
|
async def effects_(ctx: Context, args: list[str]) -> None:
|
||||||
|
await catch(ctx, args, '''
|
||||||
|
`effects - effects`
|
||||||
|
`effects + preset`
|
||||||
|
''', 'help')
|
||||||
|
match args:
|
||||||
|
case ['-', effects]:
|
||||||
|
pass
|
||||||
|
case ['+', preset]:
|
||||||
|
effects = presets[preset]
|
||||||
|
case _:
|
||||||
|
raise Explicit('misformatted')
|
||||||
|
assert_admin(ctx.member)
|
||||||
|
queue = await queue_for(ctx, create=False)
|
||||||
|
yta = queue.queue[0]
|
||||||
|
seconds = yta.source_seconds()
|
||||||
|
yta.options = options_for_effects(effects)
|
||||||
|
yta.set_seconds(seconds)
|
||||||
|
|
||||||
|
|
||||||
@at('commands', 'queue')
|
@at('commands', 'queue')
|
||||||
async def queue_(ctx: Context, args: list[str]) -> None:
|
async def queue_(ctx: Context, args: list[str]) -> None:
|
||||||
|
await catch(ctx, args, '''
|
||||||
|
`queue`
|
||||||
|
`queue clear`
|
||||||
|
`queue resume`
|
||||||
|
`queue pause`
|
||||||
|
''', 'help')
|
||||||
match args:
|
match args:
|
||||||
case ['help']:
|
|
||||||
await ctx.reply('current queue')
|
|
||||||
case []:
|
case []:
|
||||||
await ctx.long((await (await queue_for(ctx, create=False)).format()).strip() or 'no queue')
|
await ctx.long((await (await queue_for(ctx, create=False)).format()).strip() or 'no queue')
|
||||||
case ['clear']:
|
case ['clear']:
|
||||||
@ -710,43 +748,46 @@ async def queue_(ctx: Context, args: list[str]) -> None:
|
|||||||
vc.pause()
|
vc.pause()
|
||||||
await ctx.reply('done')
|
await ctx.reply('done')
|
||||||
case _:
|
case _:
|
||||||
raise Explicit("misformatted")
|
raise Explicit('misformatted')
|
||||||
|
|
||||||
|
|
||||||
@at('commands', 'swap')
|
@at('commands', 'swap')
|
||||||
async def swap(ctx: Context, args: list[str]) -> None:
|
async def swap(ctx: Context, args: list[str]) -> None:
|
||||||
|
await catch(ctx, args, '''
|
||||||
|
`swap a b`
|
||||||
|
''', 'help')
|
||||||
match args:
|
match args:
|
||||||
case ['help']:
|
|
||||||
await ctx.reply('`swap a b`')
|
|
||||||
case [a, b] if a.isdecimal() and b.isdecimal():
|
case [a, b] if a.isdecimal() and b.isdecimal():
|
||||||
a, b = int(a), int(b)
|
a, b = int(a), int(b)
|
||||||
(await queue_for(ctx, create=False)).swap(ctx.member, a, b)
|
(await queue_for(ctx, create=False)).swap(ctx.member, a, b)
|
||||||
case _:
|
case _:
|
||||||
raise Explicit("misformatted")
|
raise Explicit('misformatted')
|
||||||
|
|
||||||
|
|
||||||
@at('commands', 'move')
|
@at('commands', 'move')
|
||||||
async def move(ctx: Context, args: list[str]) -> None:
|
async def move(ctx: Context, args: list[str]) -> None:
|
||||||
|
await catch(ctx, args, '''
|
||||||
|
`move a b`
|
||||||
|
''', 'help')
|
||||||
match args:
|
match args:
|
||||||
case ['help']:
|
|
||||||
await ctx.reply('`move a b`')
|
|
||||||
case [a, b] if a.isdecimal() and b.isdecimal():
|
case [a, b] if a.isdecimal() and b.isdecimal():
|
||||||
a, b = int(a), int(b)
|
a, b = int(a), int(b)
|
||||||
(await queue_for(ctx, create=False)).move(ctx.member, a, b)
|
(await queue_for(ctx, create=False)).move(ctx.member, a, b)
|
||||||
case _:
|
case _:
|
||||||
raise Explicit("misformatted")
|
raise Explicit('misformatted')
|
||||||
|
|
||||||
|
|
||||||
@at('commands', 'volume')
|
@at('commands', 'volume')
|
||||||
async def volume_(ctx: Context, args: list[str]) -> None:
|
async def volume_(ctx: Context, args: list[str]) -> None:
|
||||||
|
await catch(ctx, args, '''
|
||||||
|
`volume volume`
|
||||||
|
''', 'help')
|
||||||
match args:
|
match args:
|
||||||
case ['help']:
|
|
||||||
await ctx.reply('`volume 0.2`')
|
|
||||||
case [volume]:
|
case [volume]:
|
||||||
volume = float(volume)
|
volume = float(volume)
|
||||||
await (await main_for(ctx, create=False)).set(volume, ctx.member)
|
await (await main_for(ctx, create=False)).set(volume, ctx.member)
|
||||||
case _:
|
case _:
|
||||||
raise Explicit("misformatted")
|
raise Explicit('misformatted')
|
||||||
|
|
||||||
|
|
||||||
@at('commands', 'pause')
|
@at('commands', 'pause')
|
||||||
|
Loading…
Reference in New Issue
Block a user