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

93 lines
2.5 KiB
Python

from io import BytesIO
from attrs import define
from . import track_formats
from .driver import DeezerDriver
from .song import FullSongItem
from .util import ChunkDecrypter, UrlDecrypter
@define
class DeezerBytestream:
file: bytes
filename: str
song: FullSongItem
@classmethod
def from_bytestream(
cls, bytestream: BytesIO, filename: str, full_song: FullSongItem
):
bytestream.seek(0)
return cls(
file=bytestream.read(),
filename=filename,
song=full_song,
)
@define
class Downloader:
driver: DeezerDriver
song_id: str
track: dict
song: FullSongItem
@classmethod
async def build(cls, song_id: str, driver: DeezerDriver):
track = await driver.reverse_get_track(song_id)
try:
return cls(
song_id=str(song_id),
driver=driver,
track=track["results"],
song=await FullSongItem.from_deezer(track),
)
except KeyError:
from icecream import ic
ic(track)
await driver.renew_engine()
return await cls.build(song_id, driver)
async def to_bytestream(self) -> DeezerBytestream:
quality = track_formats.MP3_128
decrypter = ChunkDecrypter.from_track_id(self.song_id)
i = 0
audio = BytesIO()
async for chunk in self.driver.engine.get_data_iter(
await self._get_download_url(quality=quality)
):
if i % 3 > 0 or len(chunk) < 2 * 1024:
audio.write(chunk)
else:
audio.write(decrypter.decrypt_chunk(chunk))
i += 1
return DeezerBytestream.from_bytestream(
filename=self.song.full_name + track_formats.TRACK_FORMAT_MAP[quality].ext,
bytestream=audio,
full_song=self.song,
)
async def _get_download_url(self, quality: str = "MP3_128"):
md5_origin = self.track["MD5_ORIGIN"]
track_id = self.track["SNG_ID"]
media_version = self.track["MEDIA_VERSION"]
url_decrypter = UrlDecrypter(
md5_origin=md5_origin, track_id=track_id, media_version=media_version
)
return url_decrypter.get_url_for(track_formats.TRACK_FORMAT_MAP[quality])
@define
class DownloaderBuilder:
driver: DeezerDriver
async def from_id(self, song_id: str):
return await Downloader.build(song_id=song_id, driver=self.driver)