my discord.py bot has a music function and today i wanted to add seek
command which would allow to skip back or forward x
amt of seconds, although i keep running into issues and cant find much abt it, i tried ai and stuff, but im just confused lol, this is pretty much my first time working with audio stuff in discord so yeah, im sorry if this is a well known question
anyway, this is the audio source i use :
class YTDLSource(discord.PCMVolumeTransformer):
def __init__(
self,
source: discord.AudioSource,
*,
data: dict[typing.Any, typing.Any],
volume: float = const.MUSIC_DEFAULT_VOL,
) -> None:
super().__init__(source, volume) # type: ignore
self.data: dict[typing.Any, typing.Any] = data
@classmethod
async def from_url(
cls,
url: str,
ytdl: yt_dlp.YoutubeDL,
*,
loop: typing.Optional[asyncio.AbstractEventLoop] = None,
) -> typing.Any:
loop = loop or asyncio.get_event_loop()
data: typing.Any = await loop.run_in_executor(
None, lambda: ytdl.extract_info(url, download=False) # type: ignore
)
if data is None:
return
if "entries" in data:
data: typing.Any = data["entries"][0]
return cls(
discord.PCMVolumeTransformer(
discord.FFmpegPCMAudio(data["url"], **const.FFMPEG_OPTIONS) # type: ignore
),
data=data,
)
my ffmpeg and ytdl options :
FFMPEG_OPTIONS: Final[dict[str, str]] = {
"before_options": "-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -nostdin",
"options": "-vn",
}
YTDL_OPTIONS: Final[dict[str, Any]] = {
"format": "bestaudio/best",
"extract_flat": "in_playlist",
"ignoreerrors": True,
"logtostderr": False,
"quiet": True,
"no_warnings": True,
"default_search": "auto",
"source_address": "0.0.0.0",
"noprogress": True,
"socket_timeout": 5,
"socket_io_timeout": 10,
"sleep_interval": 1,
"max_sleep_interval": 5,
"retries": 10,
"fragment_retries": 10,
"threads": 6,
"nocheckcertificate": True,
"geo_bypass": True,
}
how would i skip forward for example 5 seconds ( seek 5
) and how would i skip backward 5 seconds ( seek -5
) using this source ?
thanks for answers in advance
First, you need to keep track of the length of the music that has been played. You can do this by subclassing the FFmpegPCMAudio
class and add a counter under read()
function. (Each read()
will take 20ms
of audio data)
# some subclassing like this
class myAudioSubclass(discord.FFmpegPCMAudio):
def __init__(self, pass_time, ...):
# initialization
# also initialize counter
# pass_time means the seeked time
self.counter : int = 0
def read(self) -> bytes:
# add the time here
self.counter += 20
return super().read()
# custom method to return the current play-time
def check_time(self) -> float:
return self.counter / 1000 + pass_time
Then, after you keep track of time, you could do some calculation and use FFmpeg (before option) -ss {time_you_want_to_seek}
to start playing at the point you want.
P.S: why we need sth like pass_time
? because you need to correctly keep track of the time if voice.play()
a audio-source that is not started in the beginning.