77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
# Copyright 2023 (c) Anna Schumaker.
|
|
"""A cache to hold Gdk.Textures used by cover art."""
|
|
import pathlib
|
|
import sys
|
|
from gi.repository import GLib
|
|
from gi.repository import Gdk
|
|
|
|
|
|
if "unittest" in sys.modules:
|
|
import tempfile
|
|
TEMP_DIR = tempfile.TemporaryDirectory(prefix="emmental-")
|
|
CACHE_PATH = pathlib.Path(TEMP_DIR.name)
|
|
else:
|
|
from . import gsetup
|
|
CACHE_PATH = gsetup.CACHE_DIR
|
|
|
|
CACHE_PATH.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
class _TextureCache(dict):
|
|
"""A custom dictionary for storing texture files."""
|
|
|
|
def __check_update_cache(self, path: pathlib.Path) -> Gdk.Texture | None:
|
|
if path.is_file() \
|
|
and (cache_path := self.__get_cache_path(path)).exists() \
|
|
and cache_path.stat().st_mtime < path.stat().st_mtime:
|
|
self.__drop(path, cache_path)
|
|
return self.__load_new_item(path, cache_path)
|
|
|
|
def __drop(self, path: pathlib.Path, cache_path: pathlib.Path) -> None:
|
|
self.pop(path, None)
|
|
cache_path.unlink(missing_ok=True)
|
|
|
|
def __get_cache_path(self, path: pathlib.Path) -> pathlib.Path:
|
|
return CACHE_PATH / path.absolute().relative_to("/")
|
|
|
|
def __load_cached_item(self, path: pathlib.Path,
|
|
cache_path: pathlib.Path) -> Gdk.Texture:
|
|
texture = Gdk.Texture.new_from_filename(str(cache_path))
|
|
self.__setitem__(path, texture)
|
|
return texture
|
|
|
|
def __load_new_item(self, path: pathlib.Path,
|
|
cache_path: pathlib.Path) -> Gdk.Texture:
|
|
cache_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with path.open("rb") as f_path:
|
|
bytes = f_path.read()
|
|
with cache_path.open("wb") as f_cache:
|
|
f_cache.write(bytes)
|
|
texture = Gdk.Texture.new_from_bytes(GLib.Bytes.new(bytes))
|
|
self.__setitem__(path, texture)
|
|
return texture
|
|
|
|
def __get_missing_item(self, path: pathlib.Path,
|
|
cache_path: pathlib.Path) -> Gdk.Texture:
|
|
if cache_path.is_file():
|
|
return self.__load_cached_item(path, cache_path)
|
|
elif path.is_file():
|
|
return self.__load_new_item(path, cache_path)
|
|
|
|
def __missing__(self, path: pathlib.Path | None) -> Gdk.Texture:
|
|
"""Load a cache item from disk or add a new item entirely."""
|
|
return self.__get_missing_item(path, self.__get_cache_path(path))
|
|
|
|
def __getitem__(self, path: pathlib.Path | None) -> Gdk.Texture | None:
|
|
"""Get a Gdk.Texture cache item from the cache."""
|
|
if path is not None:
|
|
texture = self.__check_update_cache(path)
|
|
return super().__getitem__(path) if texture is None else texture
|
|
|
|
def drop(self, path: pathlib.Path | None) -> None:
|
|
"""Drop a single cache item from the cache."""
|
|
self.__drop(path, self.__get_cache_path(path))
|
|
|
|
|
|
CACHE = _TextureCache()
|