v6d3music/v6d3music/core/ffmpegnormalaudio.py
timofey 9ad6126838 docs + raise from + new locks + extended repeat
+ _Stop + maybe better connection handling
2023-01-01 05:54:11 +00:00

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