Merge branch 'dev'

This commit is contained in:
Nathan Thomas 2024-01-24 16:06:38 -08:00
commit d00e6e2f48
5 changed files with 45 additions and 27 deletions

View file

@ -133,29 +133,23 @@ class DeezerDownloadable(Downloadable):
blowfish_key, blowfish_key,
) )
assert self.chunk_size == 2048 * 3 buf = bytearray()
async for data, _ in resp.content.iter_chunks():
buf += data
callback(len(data))
# Write data from server to tempfile because there's no async with aiofiles.open(path, "wb") as audio:
# efficient way to guarantee a fixed chunk size for all iterations buflen = len(buf)
# in async for i in range(0, buflen, self.chunk_size):
async with aiofiles.tempfile.TemporaryFile("wb+") as tmp: data = buf[i : min(i + self.chunk_size, buflen - 1)]
async for chunk in resp.content.iter_chunks(): if len(data) >= 2048:
data, _ = chunk decrypted_chunk = (
await tmp.write(data) self._decrypt_chunk(blowfish_key, data[:2048])
callback(len(data)) + data[2048:]
)
await tmp.seek(0) else:
async with aiofiles.open(path, "wb") as audio: decrypted_chunk = data
while chunk := await tmp.read(self.chunk_size): await audio.write(decrypted_chunk)
if len(chunk) >= 2048:
decrypted_chunk = (
self._decrypt_chunk(blowfish_key, chunk[:2048])
+ chunk[2048:]
)
else:
decrypted_chunk = chunk
await audio.write(decrypted_chunk)
@staticmethod @staticmethod
def _decrypt_chunk(key, data): def _decrypt_chunk(key, data):

View file

@ -161,7 +161,7 @@ add_singles_to_folder = false
folder_format = "{albumartist} - {title} ({year}) [{container}] [{bit_depth}B-{sampling_rate}kHz]" folder_format = "{albumartist} - {title} ({year}) [{container}] [{bit_depth}B-{sampling_rate}kHz]"
# Available keys: "tracknumber", "artist", "albumartist", "composer", "title", # Available keys: "tracknumber", "artist", "albumartist", "composer", "title",
# and "albumcomposer", "explicit" # and "albumcomposer", "explicit"
track_format = "{tracknumber}. {artist} - {title}{explicit}" track_format = "{tracknumber:02}. {artist} - {title}{explicit}"
# Only allow printable ASCII characters in filenames. # Only allow printable ASCII characters in filenames.
restrict_characters = false restrict_characters = false
# Truncate the filename if it is greater than this number of characters # Truncate the filename if it is greater than this number of characters

View file

@ -7,6 +7,7 @@ from .. import progress
from ..client import Client from ..client import Client
from ..config import Config from ..config import Config
from ..db import Database from ..db import Database
from ..exceptions import NonStreamableError
from ..filepath_utils import clean_filepath from ..filepath_utils import clean_filepath
from ..metadata import AlbumMetadata from ..metadata import AlbumMetadata
from ..metadata.util import get_album_track_ids from ..metadata.util import get_album_track_ids
@ -50,7 +51,14 @@ class PendingAlbum(Pending):
db: Database db: Database
async def resolve(self) -> Album | None: async def resolve(self) -> Album | None:
resp = await self.client.get_metadata(self.id, "album") try:
resp = await self.client.get_metadata(self.id, "album")
except NonStreamableError as e:
logger.error(
f"Album {self.id} not available to stream on {self.client.source} ({e})",
)
return None
meta = AlbumMetadata.from_album_resp(resp, self.client.source) meta = AlbumMetadata.from_album_resp(resp, self.client.source)
if meta is None: if meta is None:
logger.error( logger.error(

View file

@ -7,6 +7,7 @@ from ..client import Client
from ..config import Config, QobuzDiscographyFilterConfig from ..config import Config, QobuzDiscographyFilterConfig
from ..console import console from ..console import console
from ..db import Database from ..db import Database
from ..exceptions import NonStreamableError
from ..metadata import ArtistMetadata from ..metadata import ArtistMetadata
from .album import Album, PendingAlbum from .album import Album, PendingAlbum
from .media import Media, Pending from .media import Media, Pending
@ -180,8 +181,15 @@ class PendingArtist(Pending):
config: Config config: Config
db: Database db: Database
async def resolve(self) -> Artist: async def resolve(self) -> Artist | None:
resp = await self.client.get_metadata(self.id, "artist") try:
resp = await self.client.get_metadata(self.id, "artist")
except NonStreamableError as e:
logger.error(
f"Artist {self.id} not available to stream on {self.client.source} ({e})",
)
return None
meta = ArtistMetadata.from_resp(resp, self.client.source) meta = ArtistMetadata.from_resp(resp, self.client.source)
albums = [ albums = [
PendingAlbum(album_id, self.client, self.config, self.db) PendingAlbum(album_id, self.client, self.config, self.db)

View file

@ -147,7 +147,14 @@ class PendingPlaylist(Pending):
db: Database db: Database
async def resolve(self) -> Playlist | None: async def resolve(self) -> Playlist | None:
resp = await self.client.get_metadata(self.id, "playlist") try:
resp = await self.client.get_metadata(self.id, "playlist")
except NonStreamableError as e:
logger.error(
f"Playlist {self.id} not available to stream on {self.client.source} ({e})",
)
return None
meta = PlaylistMetadata.from_resp(resp, self.client.source) meta = PlaylistMetadata.from_resp(resp, self.client.source)
name = meta.name name = meta.name
parent = self.config.session.downloads.folder parent = self.config.session.downloads.folder
@ -261,6 +268,7 @@ class PendingLastfmPlaylist(Pending):
if that fails. if that fails.
Args: Args:
----
query (str): Query to search query (str): Query to search
s (Status): s (Status):
callback: function to call after each query completes callback: function to call after each query completes