css content type + doctype html + repeat + branch

This commit is contained in:
AF 2022-12-01 03:07:11 +00:00
parent 5d54f08c2b
commit 14aedca8b4
7 changed files with 144 additions and 33 deletions

View File

@ -223,7 +223,8 @@ class MusicAppFactory(AppFactory):
@routes.get('/main.css') @routes.get('/main.css')
async def maincss(_request: web.Request) -> web.Response: async def maincss(_request: web.Request) -> web.Response:
return web.Response( return web.Response(
text=await self.file('main.css') text=await self.file('main.css'),
content_type='text/css'
) )
@routes.post('/api/') @routes.post('/api/')

View File

@ -144,6 +144,53 @@ async def default(ctx: Context, args: list[str]) -> None:
await ctx.reply(f'effects set to `{effects}`') await ctx.reply(f'effects set to `{effects}`')
@at('commands', 'repeat')
async def repeat(ctx: Context, args: list[str]):
match args:
case []:
n = 1
case [n_] if n_.isdecimal():
n = int(n_)
case _:
raise Explicit('misformatted')
assert_admin(ctx.member)
queue = await queue_for(ctx, create=False, force_play=False)
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())
@at('commands', 'branch')
async def branch(ctx: Context, args: list[str]):
match args:
case ['-', effects]:
pass
case ['+', preset]:
effects = effects_for_preset(preset)
case ['none']:
effects = ''
case []:
effects = None
case _:
raise Explicit('misformatted')
assert_admin(ctx.member)
queue = await queue_for(ctx, create=False, force_play=False)
if not queue.queue:
raise Explicit('empty queue')
audio = queue.queue[0].branch()
if effects is not None:
seconds = audio.source_seconds()
audio.options = options_for_effects(effects or None)
audio.set_seconds(seconds)
else:
audio.set_source()
queue.queue.insert(1, audio)
@at('commands', '//') @at('commands', '//')
@at('commands', 'queue') @at('commands', 'queue')
async def queue_(ctx: Context, args: list[str]) -> None: async def queue_(ctx: Context, args: list[str]) -> None:

View File

@ -45,7 +45,7 @@ class QueueAudio(discord.AudioSource):
@classmethod @classmethod
async def create(cls, guild: discord.Guild): async def create(cls, guild: discord.Guild):
return cls(guild, await QueueAudio.respawned(guild)) return cls(guild, await cls.respawned(guild))
async def save(self, delay: bool): async def save(self, delay: bool):
hybernated = [] hybernated = []

View File

@ -1,9 +1,10 @@
import asyncio import asyncio
import functools
import random import random
from typing import Optional from typing import Optional
import discord import discord
from v6d2ctx.context import Benchmark from v6d2ctx.context import Explicit
from v6d3music.core.ffmpegnormalaudio import FFmpegNormalAudio from v6d3music.core.ffmpegnormalaudio import FFmpegNormalAudio
from v6d3music.core.real_url import real_url from v6d3music.core.real_url import real_url
@ -12,6 +13,9 @@ from v6d3music.utils.sparq import sparq
from v6d3music.utils.tor_prefix import tor_prefix from v6d3music.utils.tor_prefix import tor_prefix
__all__ = ('YTAudio',)
class YTAudio(discord.AudioSource): class YTAudio(discord.AudioSource):
source: FFmpegNormalAudio source: FFmpegNormalAudio
@ -24,6 +28,9 @@ class YTAudio(discord.AudioSource):
rby: discord.Member, rby: discord.Member,
already_read: int, already_read: int,
tor: bool, tor: bool,
/,
*,
stop_at: int | None = None
): ):
self.url = url self.url = url
self.origin = origin self.origin = origin
@ -36,6 +43,7 @@ class YTAudio(discord.AudioSource):
# self.set_source() # self.set_source()
self._durations: dict[str, str] = {} self._durations: dict[str, str] = {}
self.loop = asyncio.get_running_loop() self.loop = asyncio.get_running_loop()
self.stop_at: int | None = stop_at
def set_source_if_necessary(self): def set_source_if_necessary(self):
if not hasattr(self, 'source'): if not hasattr(self, 'source'):
@ -117,6 +125,8 @@ class YTAudio(discord.AudioSource):
def read(self) -> bytes: def read(self) -> bytes:
if self.regenerating: if self.regenerating:
return FILL return FILL
if self.stop_at is not None and self.already_read >= self.stop_at - 1:
return b''
self.already_read += 1 self.already_read += 1
ret: bytes = self.source.read() ret: bytes = self.source.read()
if not ret and not self.source.droppable(): if not ret and not self.source.droppable():
@ -156,6 +166,7 @@ class YTAudio(discord.AudioSource):
'rby': self.rby.id, 'rby': self.rby.id,
'already_read': self.already_read, 'already_read': self.already_read,
'tor': self.tor, 'tor': self.tor,
'stop_at': self.stop_at,
} }
@classmethod @classmethod
@ -167,7 +178,8 @@ class YTAudio(discord.AudioSource):
respawn['options'], respawn['options'],
guild.get_member(respawn['rby']) or await guild.fetch_member(respawn['rby']), guild.get_member(respawn['rby']) or await guild.fetch_member(respawn['rby']),
respawn['already_read'], respawn['already_read'],
respawn.get('tor', False) respawn.get('tor', False),
stop_at=respawn.get('stop_at', None),
) )
async def regenerate(self): async def regenerate(self):
@ -189,3 +201,29 @@ class YTAudio(discord.AudioSource):
'description': self.description, 'description': self.description,
'canbeskipped': self.can_be_skipped_by(member), 'canbeskipped': self.can_be_skipped_by(member),
} }
def copy(self) -> 'YTAudio':
return YTAudio(
self.url,
self.origin,
self.description,
self.options,
self.rby,
0,
self.tor,
)
def branch(self) -> 'YTAudio':
if self.stop_at is not None:
raise Explicit('already branched')
self.stop_at = stop_at = self.already_read + 50
audio = YTAudio(
self.url,
self.origin,
self.description,
self.options,
self.rby,
stop_at,
self.tor,
)
return audio

View File

@ -1,4 +1,8 @@
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="/main.css" /> <link rel="stylesheet" href="/main.css" />
</head>
<body>
<div id="root"></div> <div id="root"></div>
<script src="/main.js"></script> <script src="/main.js"></script>
<script> <script>
@ -6,3 +10,4 @@
root.append(await pageHome()); root.append(await pageHome());
})(); })();
</script> </script>
</body>

View File

@ -1,5 +1,23 @@
html, body { html,
body,
input {
color: white; color: white;
background: black; background: black;
margin: 0; margin: 0;
} }
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #111;
}
::-webkit-scrollbar-thumb {
background: #444;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}

View File

@ -147,38 +147,40 @@ const aQueue = async () => {
const sleep = (s) => { const sleep = (s) => {
return new Promise((resolve) => setTimeout(resolve, 1000 * s)); return new Promise((resolve) => setTimeout(resolve, 1000 * s));
}; };
const aUpdateAudioSchedule = async (timecode, audio, i, current_i) => { const audioWidget = (audio) => {
while (i == current_i()) {
timecode.innerText = audio.ts();
await sleep(0.5);
}
};
const audioWidget = (audio, i, current_i) => {
const description = baseEl("span", audio.description); const description = baseEl("span", audio.description);
const timecode = baseEl("span", audio.timecode); const timecode = baseEl("span", audio.timecode);
const duration = baseEl("span", audio.duration); const duration = baseEl("span", audio.duration);
aUpdateAudioSchedule(timecode, audio, i, current_i); audio.tce = timecode;
return baseEl("div", "audio", " ", timecode, "/", duration, " ", description); return baseEl("div", "audio", " ", timecode, "/", duration, " ", description);
}; };
const aUpdateQueueOnce = async (queue, el, i, current_i) => { const aUpdateQueueOnce = async (queue, el) => {
console.log(queue);
console.log(JSON.stringify(queue));
el.innerHTML = ""; el.innerHTML = "";
if (queue !== null) { if (queue !== null) {
for (const audio of queue.queuejson) { for (const audio of queue.queuejson) {
el.append(audioWidget(audio, i, current_i)); el.append(audioWidget(audio));
} }
} }
}; };
const aUpdateQueueSetup = async (el) => { const aUpdateQueueSetup = async (el) => {
let i = 0; let queue = await aQueue();
await aUpdateQueueOnce(await aQueue(), el, i, () => i); await aUpdateQueueOnce(queue, el);
(async () => { (async () => {
while (true) { while (true) {
const queue = await aQueue();
i += 1;
await aUpdateQueueOnce(queue, el, i, () => i);
await sleep(2); await sleep(2);
const newQueue = await aQueue();
await aUpdateQueueOnce(newQueue, el);
queue = newQueue;
}
})();
(async () => {
while (true) {
await sleep(.25);
if (queue !== null) {
for (const audio of queue.queuejson) {
audio.tce.innerText = audio.ts();
}
}
} }
})(); })();
}; };