97 lines
2.6 KiB
Python
97 lines
2.6 KiB
Python
import shlex
|
|
import subprocess
|
|
import time
|
|
from threading import Thread
|
|
from typing import Optional
|
|
|
|
import discord
|
|
|
|
from v6d3music.utils.fill import *
|
|
from v6d3music.utils.tor_prefix import *
|
|
|
|
__all__ = ('FFmpegNormalAudio',)
|
|
|
|
|
|
class FFmpegNormalAudio(discord.FFmpegAudio):
|
|
def __init__(
|
|
self, source, *, executable='ffmpeg', pipe=False, stderr=None, before_options=None, options=None,
|
|
tor: bool
|
|
):
|
|
self.source = source
|
|
args = []
|
|
if tor:
|
|
_tor_prefix = tor_prefix()
|
|
args.extend([*_tor_prefix[1:], executable])
|
|
executable = _tor_prefix[0]
|
|
|
|
subprocess_kwargs = {'stdin': source if pipe else subprocess.DEVNULL, 'stderr': stderr}
|
|
|
|
if isinstance(before_options, str):
|
|
args.extend(shlex.split(before_options))
|
|
|
|
args.append('-i')
|
|
args.append('-' if pipe else source)
|
|
args.extend(('-f', 's16le', '-ar', '48000', '-ac', '2', '-loglevel', 'warning'))
|
|
|
|
if isinstance(options, str):
|
|
args.extend(shlex.split(options))
|
|
|
|
args.append('pipe:1')
|
|
|
|
super().__init__(source, executable=executable, args=args, **subprocess_kwargs)
|
|
|
|
self._chunk: Optional[bytes] = None
|
|
self._generating = False
|
|
self._started = False
|
|
self._loaded = False
|
|
self.loaded_at: Optional[float] = None
|
|
|
|
def _raw_read(self):
|
|
return self._stdout.read(discord.opus.Encoder.FRAME_SIZE)
|
|
|
|
def _set_chunk(self):
|
|
self._chunk = self._raw_read()
|
|
|
|
def _thread_step(self):
|
|
if self._chunk is None:
|
|
self._set_chunk()
|
|
self._generating = False
|
|
|
|
def _generate(self):
|
|
if not self._generating:
|
|
self._generating = True
|
|
Thread(target=self._thread_step).start()
|
|
|
|
def _read(self):
|
|
if not self._started:
|
|
self._set_chunk()
|
|
self._started = True
|
|
if self._chunk is None:
|
|
self._generate()
|
|
return FILL
|
|
else:
|
|
chunk = self._chunk
|
|
self._chunk = None
|
|
self._generate()
|
|
return chunk
|
|
|
|
def droppable(self) -> bool:
|
|
if self.loaded_at is None:
|
|
return False
|
|
else:
|
|
return self._loaded and time.time() - self.loaded_at < 600
|
|
|
|
def read(self):
|
|
ret = self._raw_read()
|
|
if len(ret) != discord.opus.Encoder.FRAME_SIZE:
|
|
if self._process.poll() is None:
|
|
print('poll')
|
|
return FILL
|
|
return b''
|
|
self.loaded_at = time.time()
|
|
self._loaded = True
|
|
return ret
|
|
|
|
def is_opus(self):
|
|
return False
|