servicing
This commit is contained in:
parent
b2dc8c5edb
commit
872271fc6f
@ -280,6 +280,10 @@ class MusicAppFactory(AppFactory):
|
||||
except Api.MisusedApi as e:
|
||||
return web.json_response(e.json(), status=404)
|
||||
|
||||
@routes.get('/whaturl/')
|
||||
async def whaturl(request: web.Request) -> web.StreamResponse:
|
||||
return web.json_response(str(request.url))
|
||||
|
||||
|
||||
class AppContext:
|
||||
def __init__(self, mainservice: MainService) -> None:
|
||||
|
@ -3,19 +3,20 @@ from typing import Callable
|
||||
|
||||
from v6d3music.core.default_effects import *
|
||||
from v6d3music.core.mainservice import MainService
|
||||
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.options_for_effects import options_for_effects
|
||||
from v6d3music.utils.catch import *
|
||||
from v6d3music.utils.effects_for_preset import *
|
||||
from v6d3music.utils.options_for_effects import *
|
||||
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
|
||||
|
||||
__all__ = ('get_of',)
|
||||
|
||||
def get_of(mainservice: MainService, defaulteffects: DefaultEffects) -> Callable[[str], command_type]:
|
||||
|
||||
def get_of(mainservice: MainService) -> Callable[[str], command_type]:
|
||||
at_of: AtOf[str, command_type] = AtOf()
|
||||
at, of = at_of()
|
||||
|
||||
@ -47,7 +48,7 @@ def get_of(mainservice: MainService, defaulteffects: DefaultEffects) -> Callable
|
||||
if len(ctx.message.attachments) > 1:
|
||||
raise Explicit('no more than one attachment')
|
||||
args = [ctx.message.attachments[0].url] + args
|
||||
async for audio in yt_audios(mainservice.caching, defaulteffects, ctx, args):
|
||||
async for audio in mainservice.yt_audios(ctx, args):
|
||||
queue.append(audio)
|
||||
await ctx.reply('done')
|
||||
|
||||
@ -136,12 +137,12 @@ def get_of(mainservice: MainService, defaulteffects: DefaultEffects) -> Callable
|
||||
case ['none']:
|
||||
effects = None
|
||||
case []:
|
||||
await ctx.reply(f'current default effects: {defaulteffects.get(ctx.guild.id)}')
|
||||
await ctx.reply(f'current default effects: {mainservice.defaulteffects.get(ctx.guild.id)}')
|
||||
return
|
||||
case _:
|
||||
raise Explicit('misformatted')
|
||||
assert_admin(ctx.member)
|
||||
await defaulteffects.set(ctx.guild.id, effects)
|
||||
await mainservice.defaulteffects.set(ctx.guild.id, effects)
|
||||
await ctx.reply(f'effects set to `{effects}`')
|
||||
|
||||
@at('repeat')
|
||||
@ -155,14 +156,13 @@ def get_of(mainservice: MainService, defaulteffects: DefaultEffects) -> Callable
|
||||
raise Explicit('misformatted')
|
||||
assert_admin(ctx.member)
|
||||
queue = await mainservice.context(ctx, create=False, force_play=False).queue()
|
||||
if not queue.queue:
|
||||
raise Explicit('empty queue')
|
||||
if n > 99:
|
||||
raise Explicit('too long')
|
||||
audio = queue.queue[0]
|
||||
for _ in range(n):
|
||||
queue.queue.insert(1, audio.copy())
|
||||
queue.update_sources()
|
||||
queue.repeat(n)
|
||||
|
||||
@at('shuffle')
|
||||
async def shuffle(ctx: Context, args: list[str]):
|
||||
assert_admin(ctx.member)
|
||||
queue = await mainservice.context(ctx, create=False, force_play=False).queue()
|
||||
queue.shuffle()
|
||||
|
||||
@at('branch')
|
||||
async def branch(ctx: Context, args: list[str]):
|
||||
|
@ -1,19 +1,18 @@
|
||||
import string
|
||||
from typing import Any, Optional
|
||||
|
||||
from v6d2ctx.context import Context, Explicit, escape
|
||||
|
||||
from v6d3music.core.real_url import real_url
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d3music.core.ytaservicing import *
|
||||
from v6d3music.core.ytaudio import YTAudio
|
||||
from v6d3music.utils.argctx import InfoCtx
|
||||
from v6d3music.utils.assert_admin import assert_admin
|
||||
from v6d3music.utils.options_for_effects import options_for_effects
|
||||
from v6d3music.utils.presets import allowed_effects
|
||||
from v6d3music.utils.argctx import InfoCtx
|
||||
|
||||
from v6d2ctx.context import Context, Explicit, escape
|
||||
|
||||
|
||||
async def create_ytaudio(
|
||||
caching: Caching, ctx: Context, it: InfoCtx
|
||||
servicing: YTAServicing, ctx: Context, it: InfoCtx
|
||||
) -> YTAudio:
|
||||
assert ctx.member is not None
|
||||
if it.effects:
|
||||
@ -25,8 +24,8 @@ async def create_ytaudio(
|
||||
else:
|
||||
options = None
|
||||
return YTAudio(
|
||||
caching,
|
||||
await real_url(caching, it.info['url'], False, it.tor),
|
||||
servicing,
|
||||
await real_url(servicing.caching, it.info['url'], False, it.tor),
|
||||
it.info['url'],
|
||||
f'{escape(it.info.get("title", "unknown"))} `Rby` {ctx.member}',
|
||||
options,
|
||||
|
@ -1,11 +1,13 @@
|
||||
import discord
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d3music.core.queueaudio import QueueAudio
|
||||
from v6d3music.core.ytaservicing import *
|
||||
from v6d3music.core.queueaudio import *
|
||||
from v6d3music.utils.assert_admin import assert_admin
|
||||
|
||||
from ptvp35 import *
|
||||
from v6d2ctx.context import Explicit
|
||||
|
||||
__all__ = ('MainAudio',)
|
||||
|
||||
|
||||
class MainAudio(discord.PCMVolumeTransformer):
|
||||
def __init__(self, db: DbConnection, queue: QueueAudio, volume: float):
|
||||
@ -23,5 +25,5 @@ class MainAudio(discord.PCMVolumeTransformer):
|
||||
await self.db.set(member.guild.id, volume)
|
||||
|
||||
@classmethod
|
||||
async def create(cls, caching: Caching, db: DbConnection, queues: DbConnection, guild: discord.Guild) -> 'MainAudio':
|
||||
return cls(db, await QueueAudio.create(caching, queues, guild), volume=db.get(guild.id, 0.2))
|
||||
async def create(cls, servicing: YTAServicing, db: DbConnection, queues: DbConnection, guild: discord.Guild) -> 'MainAudio':
|
||||
return cls(db, await QueueAudio.create(servicing, queues, guild), volume=db.get(guild.id, 0.2))
|
||||
|
@ -1,22 +1,33 @@
|
||||
import asyncio
|
||||
import traceback
|
||||
from contextlib import AsyncExitStack
|
||||
from typing import AsyncIterable, TypeVar
|
||||
|
||||
import discord
|
||||
from v6d3music.config import myroot
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d3music.core.mainaudio import MainAudio
|
||||
from v6d3music.core.queueaudio import QueueAudio
|
||||
from v6d3music.core.caching import *
|
||||
from v6d3music.core.default_effects import *
|
||||
from v6d3music.core.mainaudio import *
|
||||
from v6d3music.core.queueaudio import *
|
||||
from v6d3music.core.ystate import *
|
||||
from v6d3music.core.ytaservicing import *
|
||||
from v6d3music.core.ytaudio import *
|
||||
from v6d3music.processing.pool import *
|
||||
from v6d3music.utils.argctx import *
|
||||
|
||||
from ptvp35 import *
|
||||
from v6d2ctx.context import Context, Explicit
|
||||
from v6d2ctx.lock_for import lock_for
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class MainService:
|
||||
def __init__(self, client: discord.Client) -> None:
|
||||
def __init__(self, defaulteffects: DefaultEffects, client: discord.Client) -> None:
|
||||
self.defaulteffects = defaulteffects
|
||||
self.client = client
|
||||
self.mains: dict[discord.Guild, MainAudio] = {}
|
||||
self.restore_lock = asyncio.Lock()
|
||||
|
||||
@staticmethod
|
||||
async def raw_vc_for_member(member: discord.Member) -> discord.VoiceClient:
|
||||
@ -51,16 +62,18 @@ class MainService:
|
||||
return self.descriptor(create=create, force_play=force_play).context(ctx)
|
||||
|
||||
async def create(self, guild: discord.Guild) -> MainAudio:
|
||||
return await MainAudio.create(self.caching, self.__volumes, self.queues, guild)
|
||||
return await MainAudio.create(self.__servicing, self.__volumes, self.__queues, guild)
|
||||
|
||||
async def __aenter__(self) -> 'MainService':
|
||||
async with AsyncExitStack() as es:
|
||||
self.__volumes = await es.enter_async_context(DbFactory(myroot / 'volume.db', kvfactory=KVJson()))
|
||||
self.queues = await es.enter_async_context(DbFactory(myroot / 'queue.db', kvfactory=KVJson()))
|
||||
self.caching = await es.enter_async_context(Caching())
|
||||
self.__queues = await es.enter_async_context(DbFactory(myroot / 'queue.db', kvfactory=KVJson()))
|
||||
self.__caching = await es.enter_async_context(Caching())
|
||||
self.__pool = await es.enter_async_context(Pool(5))
|
||||
self.__servicing = YTAServicing(self.__caching, self.__pool)
|
||||
self.__vcs_restored: asyncio.Future[None] = asyncio.Future()
|
||||
self.__es = es.pop_all()
|
||||
self.__save_task = asyncio.create_task(self.save_daemon())
|
||||
self.__es = es.pop_all()
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
@ -83,10 +96,10 @@ class MainService:
|
||||
if vc.is_playing():
|
||||
if vc.guild is not None and vc.channel is not None:
|
||||
vcs.append((vc.guild.id, vc.channel.id, vc.is_paused()))
|
||||
self.queues.set_nowait('vcs', vcs)
|
||||
self.__queues.set_nowait('vcs', vcs)
|
||||
|
||||
async def save_commit(self) -> None:
|
||||
await self.queues.commit()
|
||||
await self.__queues.commit()
|
||||
|
||||
async def _save_all(self, delay: bool, save_playing: bool) -> None:
|
||||
await self.save_queues(delay)
|
||||
@ -152,7 +165,7 @@ class MainService:
|
||||
print(f'vc restored {vcgid} {vccid}')
|
||||
|
||||
async def restore_vcs(self) -> None:
|
||||
vcs: list[tuple[int, int, bool]] = self.queues.get('vcs', [])
|
||||
vcs: list[tuple[int, int, bool]] = self.__queues.get('vcs', [])
|
||||
try:
|
||||
tasks = []
|
||||
for vcgid, vccid, vc_is_paused in vcs:
|
||||
@ -163,10 +176,16 @@ class MainService:
|
||||
self.__vcs_restored.set_result(None)
|
||||
|
||||
async def restore(self) -> None:
|
||||
async with lock_for('vcs_restored', '...'):
|
||||
async with self.restore_lock:
|
||||
if not self.__vcs_restored.done():
|
||||
await self.restore_vcs()
|
||||
|
||||
async def yt_audios(self, ctx: Context, args: list[str]) -> AsyncIterable[YTAudio]:
|
||||
assert ctx.guild is not None
|
||||
argctx = ArgCtx(self.defaulteffects.get(ctx.guild.id), args)
|
||||
async for audio in YState(self.__servicing, self.__pool, ctx, argctx.sources).iterate():
|
||||
yield audio
|
||||
|
||||
|
||||
class MainDescriptor:
|
||||
def __init__(self, service: MainService, *, create: bool, force_play: bool) -> None:
|
||||
|
@ -1,15 +1,21 @@
|
||||
import asyncio
|
||||
import random
|
||||
from collections import deque
|
||||
from io import StringIO
|
||||
from typing import MutableSequence
|
||||
|
||||
import discord
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d2ctx.context import Explicit
|
||||
from v6d3music.core.ytaservicing import *
|
||||
from v6d3music.core.ytaudio import YTAudio
|
||||
from v6d3music.utils.assert_admin import assert_admin
|
||||
from v6d3music.utils.fill import FILL
|
||||
|
||||
from ptvp35 import *
|
||||
|
||||
__all__ = ('QueueAudio',)
|
||||
|
||||
|
||||
PRE_SET_LENGTH = 24
|
||||
|
||||
|
||||
@ -30,12 +36,12 @@ class QueueAudio(discord.AudioSource):
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
async def respawned(caching: Caching, db: DbConnection, guild: discord.Guild) -> list[YTAudio]:
|
||||
async def respawned(servicing: YTAServicing, db: DbConnection, guild: discord.Guild) -> list[YTAudio]:
|
||||
respawned = []
|
||||
try:
|
||||
for audio_respawn in db.get(guild.id, []):
|
||||
try:
|
||||
respawned.append(await YTAudio.respawn(caching, guild, audio_respawn))
|
||||
respawned.append(await YTAudio.respawn(servicing, guild, audio_respawn))
|
||||
except Exception as e:
|
||||
print('audio respawn failed', e)
|
||||
raise
|
||||
@ -44,8 +50,8 @@ class QueueAudio(discord.AudioSource):
|
||||
return respawned
|
||||
|
||||
@classmethod
|
||||
async def create(cls, caching: Caching, db: DbConnection, guild: discord.Guild) -> 'QueueAudio':
|
||||
return cls(db, guild, await cls.respawned(caching, db, guild))
|
||||
async def create(cls, servicing: YTAServicing, db: DbConnection, guild: discord.Guild) -> 'QueueAudio':
|
||||
return cls(db, guild, await cls.respawned(servicing, db, guild))
|
||||
|
||||
async def save(self, delay: bool) -> None:
|
||||
hybernated = []
|
||||
@ -143,3 +149,41 @@ class QueueAudio(discord.AudioSource):
|
||||
import random
|
||||
audios = list(self.queue)
|
||||
return [await audio.pubjson(member) for audio, _ in zip(audios, range(limit))]
|
||||
|
||||
def repeat(self, n: int) -> None:
|
||||
if not self.queue:
|
||||
raise Explicit('empty queue')
|
||||
if n > 99:
|
||||
raise Explicit('too long')
|
||||
audio = self.queue[0]
|
||||
for _ in range(n):
|
||||
self.queue.insert(1, audio.copy())
|
||||
self.update_sources()
|
||||
|
||||
def shuffle(self) -> None:
|
||||
try:
|
||||
random.shuffle(ForwardView(self.queue))
|
||||
except:
|
||||
from traceback import print_exc
|
||||
print_exc()
|
||||
self.update_sources()
|
||||
|
||||
|
||||
class ForwardView(MutableSequence[YTAudio]):
|
||||
def __init__(self, sequence: MutableSequence[YTAudio]) -> None:
|
||||
self.sequence = sequence
|
||||
|
||||
def __len__(self) -> int:
|
||||
return max(0, self.sequence.__len__() - 1)
|
||||
|
||||
def __setitem__(self, index: int, value: YTAudio) -> None:
|
||||
self.sequence.__setitem__(index + 1, value)
|
||||
|
||||
def __getitem__(self, index: int) -> YTAudio:
|
||||
return self.sequence.__getitem__(index + 1)
|
||||
|
||||
def __delitem__(self, index: int | slice) -> None:
|
||||
self.sequence.__delitem__(index)
|
||||
|
||||
def insert(self, index: int, value: YTAudio) -> None:
|
||||
self.sequence.insert(index, value)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d3music.core.caching import *
|
||||
from v6d3music.utils.bytes_hash import bytes_hash
|
||||
from v6d3music.utils.tor_prefix import tor_prefix
|
||||
|
||||
|
@ -3,6 +3,7 @@ from collections import deque
|
||||
from contextlib import AsyncExitStack
|
||||
from typing import AsyncIterable, Iterable
|
||||
|
||||
from v6d3music.core.ytaservicing import *
|
||||
from v6d3music.core.create_ytaudio import *
|
||||
from v6d3music.core.ytaudio import *
|
||||
from v6d3music.processing.pool import *
|
||||
@ -14,8 +15,8 @@ __all__ = ('YState',)
|
||||
|
||||
|
||||
class YState:
|
||||
def __init__(self, caching: Caching, pool: Pool, ctx: Context, sources: Iterable[UrlCtx]) -> None:
|
||||
self.caching = caching
|
||||
def __init__(self, servicing: YTAServicing, pool: Pool, ctx: Context, sources: Iterable[UrlCtx]) -> None:
|
||||
self.servicing = servicing
|
||||
self.pool = pool
|
||||
self.ctx = ctx
|
||||
self.sources: deque[UrlCtx] = deque(sources)
|
||||
@ -53,7 +54,7 @@ class YState:
|
||||
|
||||
async def result(self, entry: InfoCtx) -> YTAudio | None:
|
||||
try:
|
||||
return await create_ytaudio(self.caching, self.ctx, entry)
|
||||
return await create_ytaudio(self.servicing, self.ctx, entry)
|
||||
except Exception:
|
||||
if not entry.ignore:
|
||||
raise
|
||||
|
@ -1,18 +0,0 @@
|
||||
from typing import AsyncIterable
|
||||
|
||||
from v6d3music.core.default_effects import *
|
||||
from v6d3music.core.ystate import *
|
||||
from v6d3music.core.ytaudio import *
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d3music.processing.pool import *
|
||||
from v6d3music.utils.argctx import *
|
||||
|
||||
from v6d2ctx.context import Context
|
||||
|
||||
|
||||
async def yt_audios(caching: Caching, defaulteffects: DefaultEffects, ctx: Context, args: list[str]) -> AsyncIterable[YTAudio]:
|
||||
assert ctx.guild is not None
|
||||
argctx = ArgCtx(defaulteffects.get(ctx.guild.id), args)
|
||||
async with Pool(5) as pool:
|
||||
async for audio in YState(caching, pool, ctx, argctx.sources).iterate():
|
||||
yield audio
|
11
v6d3music/core/ytaservicing.py
Normal file
11
v6d3music/core/ytaservicing.py
Normal file
@ -0,0 +1,11 @@
|
||||
from v6d3music.core.caching import *
|
||||
from v6d3music.processing.abstractrunner import *
|
||||
|
||||
|
||||
__all__ = ('YTAServicing',)
|
||||
|
||||
|
||||
class YTAServicing:
|
||||
def __init__(self, caching: Caching, runner: AbstractRunner) -> None:
|
||||
self.caching = caching
|
||||
self.runner = runner
|
@ -5,25 +5,22 @@ from typing import Optional
|
||||
import discord
|
||||
from v6d3music.core.ffmpegnormalaudio import FFmpegNormalAudio
|
||||
from v6d3music.core.real_url import real_url
|
||||
from v6d3music.core.caching import Caching
|
||||
from v6d3music.utils.fill import FILL
|
||||
from v6d3music.utils.sparq import sparq
|
||||
from v6d3music.utils.tor_prefix import tor_prefix
|
||||
from v6d3music.core.ytaservicing import *
|
||||
|
||||
from v6d2ctx.context import Explicit
|
||||
|
||||
__all__ = ('YTAudio',)
|
||||
|
||||
|
||||
semaphore = asyncio.BoundedSemaphore(5)
|
||||
|
||||
|
||||
class YTAudio(discord.AudioSource):
|
||||
source: FFmpegNormalAudio
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
caching: Caching,
|
||||
servicing: YTAServicing,
|
||||
url: str,
|
||||
origin: str,
|
||||
description: str,
|
||||
@ -35,7 +32,7 @@ class YTAudio(discord.AudioSource):
|
||||
*,
|
||||
stop_at: int | None = None
|
||||
):
|
||||
self.caching = caching
|
||||
self.servicing = servicing
|
||||
self.url = url
|
||||
self.origin = origin
|
||||
self.description = description
|
||||
@ -112,8 +109,7 @@ class YTAudio(discord.AudioSource):
|
||||
self._durations[url] = (await ap.stdout.read()).decode().strip().split('.')[0]
|
||||
|
||||
async def update_duration(self):
|
||||
async with semaphore:
|
||||
await self._update_duration()
|
||||
await self.servicing.runner.run(self._update_duration())
|
||||
|
||||
def duration(self) -> str:
|
||||
duration = self._durations.get(self.url)
|
||||
@ -184,7 +180,7 @@ class YTAudio(discord.AudioSource):
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def respawn(cls, caching: Caching, guild: discord.Guild, respawn: dict) -> 'YTAudio':
|
||||
async def respawn(cls, servicing: YTAServicing, guild: discord.Guild, respawn: dict) -> 'YTAudio':
|
||||
member_id: int | None = respawn['rby']
|
||||
if member_id is None:
|
||||
member = None
|
||||
@ -197,7 +193,7 @@ class YTAudio(discord.AudioSource):
|
||||
except discord.NotFound:
|
||||
member = None
|
||||
audio = YTAudio(
|
||||
caching,
|
||||
servicing,
|
||||
respawn['url'],
|
||||
respawn['origin'],
|
||||
respawn['description'],
|
||||
@ -213,7 +209,7 @@ class YTAudio(discord.AudioSource):
|
||||
async def regenerate(self):
|
||||
try:
|
||||
print(f'regenerating {self.origin}')
|
||||
self.url = await real_url(self.caching, self.origin, True, self.tor)
|
||||
self.url = await real_url(self.servicing.caching, self.origin, True, self.tor)
|
||||
if hasattr(self, 'source'):
|
||||
self.source.cleanup()
|
||||
self.set_source()
|
||||
@ -232,7 +228,7 @@ class YTAudio(discord.AudioSource):
|
||||
|
||||
def copy(self) -> 'YTAudio':
|
||||
return YTAudio(
|
||||
self.caching,
|
||||
self.servicing,
|
||||
self.url,
|
||||
self.origin,
|
||||
self.description,
|
||||
@ -247,7 +243,7 @@ class YTAudio(discord.AudioSource):
|
||||
raise Explicit('already branched')
|
||||
self.stop_at = stop_at = self.already_read + 50
|
||||
audio = YTAudio(
|
||||
self.caching,
|
||||
self.servicing,
|
||||
self.url,
|
||||
self.origin,
|
||||
self.description,
|
||||
|
@ -166,7 +166,7 @@ const aUpdateQueueSetup = async (el) => {
|
||||
while (true) {
|
||||
await sleep(2);
|
||||
if (queue !== null && queue.queuejson.length > 100) {
|
||||
await sleep(queue.queuejson.length / 100);
|
||||
await sleep((queue.queuejson.length - 100) / 200);
|
||||
}
|
||||
const newQueue = await aQueue();
|
||||
await aUpdateQueueOnce(newQueue, el);
|
||||
|
13
v6d3music/processing/abstractrunner.py
Normal file
13
v6d3music/processing/abstractrunner.py
Normal file
@ -0,0 +1,13 @@
|
||||
from typing import Any, Coroutine, TypeVar
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
__all__ = ('AbstractRunner',)
|
||||
|
||||
|
||||
class AbstractRunner(ABC):
|
||||
@abstractmethod
|
||||
async def run(self, coro: Coroutine[Any, Any, T]) -> T:
|
||||
raise NotImplementedError
|
@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
from typing import Union
|
||||
from typing import Any, Coroutine, Generic, TypeVar, Union
|
||||
|
||||
from v6d3music.processing.yprocess import *
|
||||
from .abstractrunner import AbstractRunner
|
||||
|
||||
__all__ = ('Job', 'Pool', 'JobDescriptor',)
|
||||
|
||||
@ -164,7 +164,23 @@ class Working:
|
||||
return self.__worker.busy()
|
||||
|
||||
|
||||
class Pool:
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class CoroJD(JobDescriptor, Generic[T]):
|
||||
def __init__(self, coro: Coroutine[Any, Any, T]) -> None:
|
||||
self.future = asyncio.Future()
|
||||
self.coro = coro
|
||||
|
||||
async def run(self) -> JobDescriptor | None:
|
||||
try:
|
||||
self.future.set_result(await self.coro)
|
||||
except BaseException as e:
|
||||
self.future.set_exception(e)
|
||||
return None
|
||||
|
||||
|
||||
class Pool(AbstractRunner):
|
||||
def __init__(self, workers: int) -> None:
|
||||
if workers < 1:
|
||||
raise ValueError('non-positive number of workers')
|
||||
@ -203,6 +219,11 @@ class Pool:
|
||||
def workers(self) -> int:
|
||||
return self.__workers
|
||||
|
||||
async def run(self, coro: Coroutine[Any, Any, T]) -> T:
|
||||
job = CoroJD(coro)
|
||||
self.submit(job.wrap())
|
||||
return await job.future
|
||||
|
||||
|
||||
class JDC:
|
||||
def __init__(self, descriptor: JobDescriptor, pool: Pool) -> None:
|
||||
|
@ -6,7 +6,7 @@ import time
|
||||
|
||||
import discord
|
||||
from v6d3music.app import AppContext
|
||||
from v6d3music.commands import get_of
|
||||
from v6d3music.commands import *
|
||||
from v6d3music.config import prefix
|
||||
from v6d3music.core.caching import *
|
||||
from v6d3music.core.default_effects import *
|
||||
@ -54,8 +54,8 @@ def message_allowed(message: discord.Message) -> bool:
|
||||
return guild_allowed(message.guild)
|
||||
|
||||
|
||||
def register_handlers(mainservice: MainService, defaulteffects: DefaultEffects):
|
||||
of = get_of(mainservice, defaulteffects)
|
||||
def register_handlers(mainservice: MainService):
|
||||
of = get_of(mainservice)
|
||||
|
||||
@client.event
|
||||
async def on_message(message: discord.Message) -> None:
|
||||
@ -138,11 +138,11 @@ def _db_ee() -> contextlib.ExitStack:
|
||||
async def main():
|
||||
async with (
|
||||
DefaultEffects() as defaulteffects,
|
||||
MainService(client) as mainservice,
|
||||
MainService(defaulteffects, client) as mainservice,
|
||||
AppContext(mainservice),
|
||||
ABlockMonitor(delta=0.5)
|
||||
):
|
||||
register_handlers(mainservice, defaulteffects)
|
||||
register_handlers(mainservice)
|
||||
if 'guerilla' in sys.argv:
|
||||
from pathlib import Path
|
||||
tokenpath = Path('.token.txt')
|
||||
|
@ -4,6 +4,7 @@ from v6d3music.utils.effects_for_preset import effects_for_preset
|
||||
from v6d3music.utils.entries_for_url import entries_for_url
|
||||
from v6d3music.utils.options_for_effects import options_for_effects
|
||||
from v6d3music.utils.sparq import sparq
|
||||
from v6d2ctx.context import Explicit
|
||||
|
||||
__all__ = ('InfoCtx', 'UrlCtx', 'ArgCtx',)
|
||||
|
||||
@ -61,14 +62,16 @@ class ArgCtx:
|
||||
case [*args]:
|
||||
pass
|
||||
ctx.already_read = round(seconds / sparq(options_for_effects(effects)))
|
||||
match args:
|
||||
case ['tor', *args]:
|
||||
ctx.tor = True
|
||||
case [*args]:
|
||||
pass
|
||||
match args:
|
||||
case ['ignore', *args]:
|
||||
ctx.ignore = True
|
||||
case [*args]:
|
||||
pass
|
||||
while True:
|
||||
match args:
|
||||
case ['tor', *args]:
|
||||
if ctx.tor:
|
||||
raise Explicit('duplicate tor')
|
||||
ctx.tor = True
|
||||
case ['ignore', *args]:
|
||||
if ctx.ignore:
|
||||
raise Explicit('duplicate ignore')
|
||||
ctx.ignore = True
|
||||
case [*args]:
|
||||
break
|
||||
self.sources.append(ctx)
|
||||
|
@ -2,6 +2,8 @@ from typing import Iterable
|
||||
|
||||
from v6d2ctx.context import Context, Implicit
|
||||
|
||||
__all__ = ('catch',)
|
||||
|
||||
|
||||
async def catch(ctx: Context, args: list[str], reply: str, *catched: (Iterable[str] | str), attachments_ok=True):
|
||||
if ctx.message.attachments and attachments_ok:
|
||||
|
@ -3,6 +3,9 @@ from v6d2ctx.context import Explicit
|
||||
from v6d3music.utils.presets import presets
|
||||
|
||||
|
||||
__all__ = ('effects_for_preset',)
|
||||
|
||||
|
||||
def effects_for_preset(preset: str) -> str:
|
||||
if preset in presets:
|
||||
return presets[preset]
|
||||
|
@ -1,6 +1,8 @@
|
||||
import shlex
|
||||
from typing import Optional
|
||||
|
||||
__all__ = ('options_for_effects',)
|
||||
|
||||
|
||||
def options_for_effects(effects: str | None) -> Optional[str]:
|
||||
return f'-af {shlex.quote(effects)}' if effects else None
|
||||
|
Loading…
Reference in New Issue
Block a user