commands revised + optimisations
This commit is contained in:
parent
2e45ccc591
commit
45fee6d593
@ -1,6 +1,6 @@
|
||||
ptvp35 @ git+https://gitea.parrrate.ru/PTV/ptvp35.git@87ba808c2af1be87f4fbb9d9b3b97ba748cb9fae
|
||||
v6d0auth @ git+https://gitea.parrrate.ru/PTV/v6d0auth.git@324236f435c92756aefe22877a97a906c462ef2c
|
||||
v6d1tokens @ git+https://gitea.parrrate.ru/PTV/v6d1tokens.git@96567a0cb0c3cb60f20647518df5370df6dc6664
|
||||
v6d2ctx @ git+https://gitea.parrrate.ru/PTV/v6d2ctx.git@4a821aa168a83924934b2ab833d283226eb307bb
|
||||
v6d2ctx @ git+https://gitea.parrrate.ru/PTV/v6d2ctx.git@d6d3b873de4e67cf41c6ce22c99f962c66e59f91
|
||||
rainbowadn @ git+https://gitea.parrrate.ru/PTV/rainbowadn.git@e9fba7b064902ceedee0dd5578cb47030665a6aa
|
||||
adaas @ git+https://gitea.parrrate.ru/PTV/adaas.git@5e407a73be3fc52e66a91725996087d4d11522f2
|
||||
|
@ -1,19 +1,24 @@
|
||||
import shlex
|
||||
from typing import Callable
|
||||
|
||||
from v6d2ctx.context import Context, Explicit, at
|
||||
from v6d2ctx.lock_for import lock_for
|
||||
|
||||
from v6d3music.core.entries_effects_for_args import *
|
||||
from v6d3music.core.mainasrc import main_for, queue_for, vc_for
|
||||
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.core.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
|
||||
|
||||
from v6d2ctx.at_of import AtOf
|
||||
from v6d2ctx.context import Context, Explicit, command_type
|
||||
from v6d2ctx.lock_for import lock_for
|
||||
|
||||
@at('commands', 'help')
|
||||
at_of: AtOf[str, command_type] = AtOf()
|
||||
at, of = at_of()
|
||||
|
||||
|
||||
@at('help')
|
||||
async def help_(ctx: Context, args: list[str]) -> None:
|
||||
match args:
|
||||
case []:
|
||||
@ -22,8 +27,8 @@ async def help_(ctx: Context, args: list[str]) -> None:
|
||||
await ctx.reply(f'help for {name}: `{name} help`')
|
||||
|
||||
|
||||
@at('commands', '/')
|
||||
@at('commands', 'play')
|
||||
@at('/')
|
||||
@at('play')
|
||||
async def play(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args,
|
||||
@ -47,7 +52,7 @@ presets: {shlex.join(allowed_presets)}
|
||||
await ctx.reply('done')
|
||||
|
||||
|
||||
@at('commands', 'skip')
|
||||
@at('skip')
|
||||
async def skip(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -74,7 +79,7 @@ async def skip(ctx: Context, args: list[str]) -> None:
|
||||
await ctx.reply('done')
|
||||
|
||||
|
||||
@at('commands', 'to')
|
||||
@at('to')
|
||||
async def skip_to(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -94,7 +99,7 @@ async def skip_to(ctx: Context, args: list[str]) -> None:
|
||||
queue.queue[0].set_seconds(seconds)
|
||||
|
||||
|
||||
@at('commands', 'effects')
|
||||
@at('effects')
|
||||
async def effects_(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -117,7 +122,7 @@ async def effects_(ctx: Context, args: list[str]) -> None:
|
||||
yta.set_seconds(seconds)
|
||||
|
||||
|
||||
@at('commands', 'default')
|
||||
@at('default')
|
||||
async def default(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -144,7 +149,7 @@ async def default(ctx: Context, args: list[str]) -> None:
|
||||
await ctx.reply(f'effects set to `{effects}`')
|
||||
|
||||
|
||||
@at('commands', 'repeat')
|
||||
@at('repeat')
|
||||
async def repeat(ctx: Context, args: list[str]):
|
||||
match args:
|
||||
case []:
|
||||
@ -164,7 +169,7 @@ async def repeat(ctx: Context, args: list[str]):
|
||||
queue.queue.insert(1, audio.copy())
|
||||
|
||||
|
||||
@at('commands', 'branch')
|
||||
@at('branch')
|
||||
async def branch(ctx: Context, args: list[str]):
|
||||
match args:
|
||||
case ['-', effects]:
|
||||
@ -191,8 +196,8 @@ async def branch(ctx: Context, args: list[str]):
|
||||
queue.queue.insert(1, audio)
|
||||
|
||||
|
||||
@at('commands', '//')
|
||||
@at('commands', 'queue')
|
||||
@at('//')
|
||||
@at('queue')
|
||||
async def queue_(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -224,7 +229,7 @@ async def queue_(ctx: Context, args: list[str]) -> None:
|
||||
raise Explicit('misformatted')
|
||||
|
||||
|
||||
@at('commands', 'swap')
|
||||
@at('swap')
|
||||
async def swap(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -240,7 +245,7 @@ async def swap(ctx: Context, args: list[str]) -> None:
|
||||
raise Explicit('misformatted')
|
||||
|
||||
|
||||
@at('commands', 'move')
|
||||
@at('move')
|
||||
async def move(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -256,7 +261,7 @@ async def move(ctx: Context, args: list[str]) -> None:
|
||||
raise Explicit('misformatted')
|
||||
|
||||
|
||||
@at('commands', 'volume')
|
||||
@at('volume')
|
||||
async def volume_(ctx: Context, args: list[str]) -> None:
|
||||
await catch(
|
||||
ctx, args, '''
|
||||
@ -272,17 +277,13 @@ async def volume_(ctx: Context, args: list[str]) -> None:
|
||||
raise Explicit('misformatted')
|
||||
|
||||
|
||||
@at('commands', 'pause')
|
||||
@at('pause')
|
||||
async def pause(ctx: Context, _args: list[str]) -> None:
|
||||
vc = await vc_for(ctx, create=False, force_play=False)
|
||||
vc.pause()
|
||||
|
||||
|
||||
@at('commands', 'resume')
|
||||
@at('resume')
|
||||
async def resume(ctx: Context, _args: list[str]) -> None:
|
||||
vc = await vc_for(ctx, create=False, force_play=True)
|
||||
vc.resume()
|
||||
|
||||
|
||||
def register_commands():
|
||||
pass
|
||||
|
@ -125,7 +125,10 @@ class QueueAudio(discord.AudioSource):
|
||||
|
||||
async def format(self) -> str:
|
||||
stream = StringIO()
|
||||
for i, audio in enumerate(list(self.queue)):
|
||||
for i, audio in enumerate(lst := list(self.queue)):
|
||||
if i >= (n := 100):
|
||||
stream.write(f'cutting queue at {n} results, {len(lst) - n} remaining.\n')
|
||||
break
|
||||
stream.write(f'`[{i}]` `{audio.source_timecode()} / {audio.duration()}` {audio.description}\n')
|
||||
return stream.getvalue()
|
||||
|
||||
|
@ -53,7 +53,7 @@ class YState:
|
||||
async def result(self, entry: InfoCtx) -> YTAudio | None:
|
||||
try:
|
||||
return await create_ytaudio(self.ctx, entry)
|
||||
except:
|
||||
except Exception:
|
||||
if not entry.ignore:
|
||||
raise
|
||||
else:
|
||||
|
@ -1,21 +1,22 @@
|
||||
import asyncio
|
||||
import functools
|
||||
import random
|
||||
from typing import Optional
|
||||
|
||||
import discord
|
||||
from v6d2ctx.context import Explicit
|
||||
|
||||
from v6d3music.core.ffmpegnormalaudio import FFmpegNormalAudio
|
||||
from v6d3music.core.real_url import real_url
|
||||
from v6d3music.utils.fill import FILL
|
||||
from v6d3music.utils.sparq import sparq
|
||||
from v6d3music.utils.tor_prefix import tor_prefix
|
||||
|
||||
from v6d2ctx.context import Explicit
|
||||
|
||||
__all__ = ('YTAudio',)
|
||||
|
||||
|
||||
semaphore = asyncio.BoundedSemaphore(5)
|
||||
|
||||
|
||||
class YTAudio(discord.AudioSource):
|
||||
source: FFmpegNormalAudio
|
||||
|
||||
@ -25,7 +26,7 @@ class YTAudio(discord.AudioSource):
|
||||
origin: str,
|
||||
description: str,
|
||||
options: Optional[str],
|
||||
rby: discord.Member,
|
||||
rby: discord.Member | None,
|
||||
already_read: int,
|
||||
tor: bool,
|
||||
/,
|
||||
@ -45,6 +46,9 @@ class YTAudio(discord.AudioSource):
|
||||
self.loop = asyncio.get_running_loop()
|
||||
self.stop_at: int | None = stop_at
|
||||
|
||||
def _reduced_durations(self) -> dict[str, str]:
|
||||
return {url: duration for url, duration in self._durations.items() if url == self.url}
|
||||
|
||||
def set_source_if_necessary(self):
|
||||
if not hasattr(self, 'source'):
|
||||
self.set_source()
|
||||
@ -80,7 +84,7 @@ class YTAudio(discord.AudioSource):
|
||||
def schedule_duration_update(self):
|
||||
self.loop.call_soon_threadsafe(self._schedule_duration_update)
|
||||
|
||||
async def update_duration(self):
|
||||
async def _update_duration(self):
|
||||
url: str = self.url
|
||||
if url in self._durations:
|
||||
return
|
||||
@ -104,6 +108,10 @@ class YTAudio(discord.AudioSource):
|
||||
assert ap.stdout is not None
|
||||
self._durations[url] = (await ap.stdout.read()).decode().strip().split('.')[0]
|
||||
|
||||
async def update_duration(self):
|
||||
async with semaphore:
|
||||
await self._update_duration()
|
||||
|
||||
def duration(self) -> str:
|
||||
duration = self._durations.get(self.url)
|
||||
if duration is None:
|
||||
@ -114,7 +122,7 @@ class YTAudio(discord.AudioSource):
|
||||
before_options = ''
|
||||
if 'https' in self.url:
|
||||
before_options += (
|
||||
'-reconnect 1 -reconnect_at_eof 0 -reconnect_streamed 1 -reconnect_delay_max 10 -copy_unknown'
|
||||
'-reconnect 1 -reconnect_at_eof 0 -reconnect_streamed 1 -reconnect_delay_max 60 -copy_unknown'
|
||||
)
|
||||
if self.already_read:
|
||||
before_options += (
|
||||
@ -154,33 +162,49 @@ class YTAudio(discord.AudioSource):
|
||||
return True
|
||||
elif permissions.manage_messages:
|
||||
return True
|
||||
elif self.rby is None:
|
||||
return False
|
||||
else:
|
||||
return self.rby == member
|
||||
|
||||
def hybernate(self):
|
||||
def hybernate(self) -> dict:
|
||||
return {
|
||||
'url': self.url,
|
||||
'origin': self.origin,
|
||||
'description': self.description,
|
||||
'options': self.options,
|
||||
'rby': self.rby.id,
|
||||
'rby': None if self.rby is None else self.rby.id,
|
||||
'already_read': self.already_read,
|
||||
'tor': self.tor,
|
||||
'stop_at': self.stop_at,
|
||||
'durations': self._reduced_durations(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def respawn(cls, guild: discord.Guild, respawn) -> 'YTAudio':
|
||||
return YTAudio(
|
||||
async def respawn(cls, guild: discord.Guild, respawn: dict) -> 'YTAudio':
|
||||
member_id: int | None = respawn['rby']
|
||||
if member_id is None:
|
||||
member = None
|
||||
else:
|
||||
member = guild.get_member(member_id)
|
||||
if member is None:
|
||||
try:
|
||||
member = await guild.fetch_member(respawn['rby'])
|
||||
guild._add_member(member)
|
||||
except discord.NotFound:
|
||||
member = None
|
||||
audio = YTAudio(
|
||||
respawn['url'],
|
||||
respawn['origin'],
|
||||
respawn['description'],
|
||||
respawn['options'],
|
||||
guild.get_member(respawn['rby']) or await guild.fetch_member(respawn['rby']),
|
||||
member,
|
||||
respawn['already_read'],
|
||||
respawn.get('tor', False),
|
||||
stop_at=respawn.get('stop_at', None),
|
||||
)
|
||||
audio._durations |= respawn.get('durations', {})
|
||||
return audio
|
||||
|
||||
async def regenerate(self):
|
||||
try:
|
||||
|
@ -165,6 +165,9 @@ const aUpdateQueueSetup = async (el) => {
|
||||
(async () => {
|
||||
while (true) {
|
||||
await sleep(2);
|
||||
if (queue !== null && queue.queuejson.length > 100) {
|
||||
await sleep(queue.queuejson.length / 100);
|
||||
}
|
||||
const newQueue = await aQueue();
|
||||
await aUpdateQueueOnce(newQueue, el);
|
||||
queue = newQueue;
|
||||
@ -176,6 +179,7 @@ const aUpdateQueueSetup = async (el) => {
|
||||
if (queue !== null) {
|
||||
for (const audio of queue.queuejson) {
|
||||
audio.tce.innerText = audio.ts();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
import time
|
||||
import contextlib
|
||||
import asyncio
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
import discord
|
||||
from v6d3music.app import MusicAppFactory, session_db
|
||||
from v6d3music.commands import register_commands
|
||||
from v6d3music.commands import of
|
||||
from v6d3music.config import prefix
|
||||
from v6d3music.core.cache_url import cache_db
|
||||
from v6d3music.core.entries_effects_for_args import effects_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.core.entries_effects_for_args import effects_db
|
||||
|
||||
from rainbowadn.instrument import Instrumentation
|
||||
from v6d1tokens.client import request_token
|
||||
@ -24,7 +24,6 @@ from v6d2ctx.serve import serve
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
register_commands()
|
||||
|
||||
|
||||
class MusicClient(discord.Client):
|
||||
@ -56,35 +55,47 @@ client = MusicClient(
|
||||
vcs_restored = False
|
||||
|
||||
|
||||
async def _restore_vc(guild: discord.Guild, vccid: int, vc_is_paused: bool) -> None:
|
||||
channels = await guild.fetch_channels()
|
||||
channel: discord.VoiceChannel
|
||||
channel, = [
|
||||
ch for ch in
|
||||
(
|
||||
chc for chc in channels
|
||||
if
|
||||
isinstance(chc, discord.VoiceChannel)
|
||||
)
|
||||
if ch.id == vccid
|
||||
]
|
||||
vp: discord.VoiceProtocol = await channel.connect()
|
||||
assert isinstance(vp, discord.VoiceClient)
|
||||
vc = vp
|
||||
await main_for_raw_vc(vc, create=True, force_play=True)
|
||||
if vc_is_paused:
|
||||
vc.pause()
|
||||
|
||||
|
||||
async def restore_vc(vcgid: int, vccid: int, vc_is_paused: bool) -> None:
|
||||
try:
|
||||
print(f'vc restoring {vcgid}')
|
||||
guild: discord.Guild = await client.fetch_guild(vcgid)
|
||||
async with lock_for(guild, 'not in a guild'):
|
||||
await _restore_vc(guild, vccid, vc_is_paused)
|
||||
except Exception as e:
|
||||
print(f'vc {vcgid} {vccid} {vc_is_paused} failed', e)
|
||||
else:
|
||||
print(f'vc restored {vcgid} {vccid}')
|
||||
|
||||
|
||||
async def restore_vcs():
|
||||
global vcs_restored
|
||||
vcs: list[tuple[int, int, bool]] = queue_db.get('vcs', [])
|
||||
try:
|
||||
tasks = []
|
||||
for vcgid, vccid, vc_is_paused in vcs:
|
||||
try:
|
||||
guild: discord.Guild = await client.fetch_guild(vcgid)
|
||||
async with lock_for(guild, 'not in a guild'):
|
||||
channels = await guild.fetch_channels()
|
||||
channel: discord.VoiceChannel
|
||||
channel, = [
|
||||
ch for ch in
|
||||
(
|
||||
chc for chc in channels
|
||||
if
|
||||
isinstance(chc, discord.VoiceChannel)
|
||||
)
|
||||
if ch.id == vccid
|
||||
]
|
||||
vp: discord.VoiceProtocol = await channel.connect()
|
||||
assert isinstance(vp, discord.VoiceClient)
|
||||
vc = vp
|
||||
await main_for_raw_vc(vc, create=True, force_play=True)
|
||||
if vc_is_paused:
|
||||
vc.pause()
|
||||
except Exception as e:
|
||||
print(f'vc {vcgid} {vccid} {vc_is_paused} failed', e)
|
||||
else:
|
||||
print(f'vc restored {vcgid} {vccid}')
|
||||
tasks.append(asyncio.create_task(restore_vc(vcgid, vccid, vc_is_paused)))
|
||||
for task in tasks:
|
||||
await task
|
||||
finally:
|
||||
vcs_restored = True
|
||||
|
||||
@ -116,7 +127,7 @@ def message_allowed(message: discord.Message) -> bool:
|
||||
@client.event
|
||||
async def on_message(message: discord.Message) -> None:
|
||||
if message_allowed(message):
|
||||
await handle_content(message, message.content, prefix, client)
|
||||
await handle_content(of, message, message.content, prefix, client)
|
||||
|
||||
|
||||
async def save_queues(delay: bool):
|
||||
|
@ -31,7 +31,7 @@ class UrlCtx:
|
||||
try:
|
||||
async for info in entries_for_url(self.url, self.tor):
|
||||
yield InfoCtx(info, self.effects, self.already_read, self.tor, self.ignore)
|
||||
except:
|
||||
except Exception:
|
||||
if not self.ignore:
|
||||
raise
|
||||
|
||||
|
@ -7,7 +7,7 @@ if (address := os.getenv('v6tor', None)) is not None:
|
||||
try:
|
||||
import socket
|
||||
address = socket.gethostbyname_ex(address)[2][0]
|
||||
except:
|
||||
except Exception:
|
||||
print('failed tor resolution')
|
||||
_tor_prefix = None
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user