streamrip/streamrip/artwork.py

107 lines
3.3 KiB
Python

import asyncio
import os
import aiohttp
from PIL import Image
from .config import ArtworkConfig
from .downloadable import BasicDownloadable
from .metadata import Covers
async def download_artwork(
session: aiohttp.ClientSession, folder: str, covers: Covers, config: ArtworkConfig
) -> tuple[str | None, str | None]:
"""Download artwork, which may include a seperate file to keep.
Also updates the passed Covers object with downloaded filepaths.
Because it is a single, we will assume that none of the covers have already been
downloaded, so existing paths in `covers` will be discarded and overwritten.
Args:
covers (Covers): The set of available covers.
Returns:
The path of the cover to embed, or None if there either is no artwork available or
if artwork embedding is turned off.
"""
if (not config.save_artwork and not config.embed) or covers.empty():
# No need to download anything
return None, None
downloadables = []
saved_cover_path = None
if config.save_artwork:
_, l_url, _ = covers.largest()
assert l_url is not None # won't be true unless covers is empty
saved_cover_path = os.path.join(folder, "cover.jpg")
downloadables.append(
BasicDownloadable(session, l_url, "jpg").download(
saved_cover_path, lambda _: None
)
)
embed_cover_path = None
if config.embed:
_, embed_url, _ = covers.get_size(config.embed_size)
assert embed_url is not None
embed_cover_path = os.path.join(folder, "embed_cover.jpg")
downloadables.append(
BasicDownloadable(session, embed_url, "jpg").download(
embed_cover_path, lambda _: None
)
)
await asyncio.gather(*downloadables)
# Update `covers` to reflect the current download state
if config.save_artwork:
assert saved_cover_path is not None
covers.set_largest_path(saved_cover_path)
if config.saved_max_width > 0:
downscale_image(saved_cover_path, config.saved_max_width)
if config.embed:
assert embed_cover_path is not None
covers.set_path(config.embed_size, embed_cover_path)
if config.embed_max_width > 0:
downscale_image(embed_cover_path, config.embed_max_width)
return embed_cover_path, saved_cover_path
def downscale_image(input_image_path: str, max_dimension: int):
"""Downscale an image in place given a maximum allowed dimension.
Args:
input_image_path (str): Path to image
max_dimension (int): Maximum dimension allowed
Returns:
"""
# Open the image
image = Image.open(input_image_path)
# Get the original width and height
width, height = image.size
if max_dimension <= max(width, height):
return
# Calculate the new dimensions while maintaining the aspect ratio
if width > height:
new_width = max_dimension
new_height = int(height * (max_dimension / width))
else:
new_height = max_dimension
new_width = int(width * (max_dimension / height))
# Resize the image with the new dimensions
resized_image = image.resize((new_width, new_height))
# Save the resized image
resized_image.save(input_image_path)