Initial commit

This commit is contained in:
sarah committed 2026-10-09 15:33:43 +02:00
commit 0eeff23589
25 files changed
+3328

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
"""Small versions of cover art. Embedded covers can be several megabytes,
and everything shown goes through Flet's connection, so the album grid and
play bar get thumbnails, cached in ~/.cache/SaraSuite/SaraTune/Covers/."""
import hashlib
import io
from pathlib import Path
from typing import Optional
from PIL import Image, UnidentifiedImageError
from Core import CacheDir
from Metadata import ReadCover
CoversDir = CacheDir / "Covers"
_NoCover = b"" # remembered in the memory cache so a coverless album isn't read again
def Thumbnail(Data: bytes, Size: int) -> Optional[bytes]:
try:
with Image.open(io.BytesIO(Data)) as Picture:
Picture = Picture.convert("RGB")
Picture.thumbnail((Size, Size), Image.LANCZOS)
Output = io.BytesIO()
Picture.save(Output, "JPEG", quality=88)
return Output.getvalue()
except (UnidentifiedImageError, OSError, ValueError, Image.DecompressionBombError):
return None
_Memory: dict[tuple[str, int], bytes] = {}
def CoverFor(FilePath: str, Size: int) -> Optional[bytes]:
"""FilePath's cover at most Size pixels wide. Blocking (run it in a
thread). Cached on disk by path, size and the file's mtime."""
Key = (FilePath, Size)
if Key in _Memory:
return _Memory[Key] or None
try:
Stamp = Path(FilePath).stat().st_mtime_ns
except OSError:
return None
Name = hashlib.sha1(f"{FilePath}|{Size}|{Stamp}".encode("utf-8", "surrogateescape")).hexdigest()
CachePath = CoversDir / f"{Name}.jpg"
if CachePath.exists():
Data = CachePath.read_bytes()
else:
Original = ReadCover(FilePath)
Data = Thumbnail(Original, Size) if Original else None
if Data:
try:
CoversDir.mkdir(parents=True, exist_ok=True)
CachePath.write_bytes(Data)
except OSError:
pass
_Memory[Key] = Data or _NoCover
return Data