Files
AnyMusicBot/bot/modules/youtube/downloader.py
2024-11-02 00:10:44 +02:00

78 lines
1.9 KiB
Python

import asyncio
from concurrent.futures import ThreadPoolExecutor
from io import BytesIO
from attrs import define
from pydub import AudioSegment
from pytubefix import Stream, YouTube
@define
class YouTubeBytestream:
file: bytes
filename: str
duration: int
@classmethod
def from_bytestream(cls, bytestream: BytesIO, filename: str, duration: float):
bytestream.seek(0)
return cls(
file=bytestream.read(),
filename=filename,
duration=int(duration),
)
def __rerender(self):
segment = AudioSegment.from_file(file=BytesIO(self.file))
self.file = segment.export(BytesIO(), format="mp3", codec="libmp3lame").read()
return self
async def rerender(self):
with ThreadPoolExecutor() as executor:
return await asyncio.get_running_loop().run_in_executor(
executor, self.__rerender
)
@define
class Downloader:
audio_stream: Stream
filename: str
duration: int
@classmethod
def from_id(cls, yt_id: str):
video = YouTube.from_id(yt_id)
audio_stream = (
video.streams.filter(
only_audio=True,
)
.order_by("abr")
.desc()
.first()
)
return cls(
audio_stream=audio_stream,
filename=f"{audio_stream.default_filename}.mp3",
duration=int(video.length),
)
def __to_bytestream(self):
audio_io = BytesIO()
self.audio_stream.stream_to_buffer(audio_io)
audio_io.seek(0)
return YouTubeBytestream.from_bytestream(
audio_io,
self.filename,
self.duration,
)
async def to_bytestream(self):
return await asyncio.get_event_loop().run_in_executor(
None, self.__to_bytestream
)