From 6ace97ff83bea1393f7a76f0842c5a711d96f0d0 Mon Sep 17 00:00:00 2001 From: restitux Date: Tue, 13 Sep 2022 22:57:43 -0600 Subject: [PATCH] Add image caching logic for show posters --- ikinuki_client/__main__.py | 62 +++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/ikinuki_client/__main__.py b/ikinuki_client/__main__.py index 7b78514..2f1e51d 100644 --- a/ikinuki_client/__main__.py +++ b/ikinuki_client/__main__.py @@ -1,8 +1,9 @@ from typing import Type import os +import shutil import sys -from urllib import parse +import urllib.parse from collections import defaultdict @@ -14,7 +15,6 @@ from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot from PyQt5.QtGui import QImage - from .qtmpv import MpvObject import requests @@ -92,13 +92,13 @@ class ProviderImageProvider(QQuickImageProvider): def getUrl(base: str, path: str) -> dict: - url: str = parse.urljoin(base, path) + url: str = urllib.parse.urljoin(base, path) r: requests.Response = requests.get(url) return r.json() class Provider(QObject): - def __init__(self, url: str, parent=None): + def __init__(self, url: str, data_dir: str, parent=None): super().__init__(parent) self.url: str = url @@ -108,17 +108,44 @@ class Provider(QObject): describe["icon"] ) - def default_val(): - return [] - + # Create dictionary of show episodes episodes: dict = getUrl(self.url, "episodes") - _episodes: defaultdict[str, list[Episode]] = defaultdict(default_val) + _episodes: defaultdict[str, list[Episode]] = defaultdict(lambda: []) for e in episodes["episodes"]: _episodes[e["ShowTitle"]].append(Episode(e)) shows: dict = getUrl(self.url, "shows") + # Create image_cache directory + provider_data_dir: str = os.path.join( + data_dir, "image_cache", "providers", self._name + ) + os.makedirs(provider_data_dir, exist_ok=True) + + # Cache show posters + for s in shows["data"]: + # Get local cache path + poster_url: str = s["poster"] + poster_path: str = urllib.parse.urlparse(poster_url).path + poster_ext: str = os.path.splitext(poster_path)[1] + download_path: str = os.path.join( + provider_data_dir, str(s["id"]) + poster_ext + ) + + # Download poster + try: + with open(download_path, "xb") as f: + r = requests.get(poster_url, stream=True) + if r.status_code == 200: + r.raw.decode_content = True + shutil.copyfileobj(r.raw, f) + except FileExistsError: + pass + + # Overwrite poster URL with local path + s["poster"] = download_path + self._shows: dict[int, Show] = { e["id"]: Show(e, _episodes[e["title"]]) for e in shows["data"] } @@ -161,8 +188,8 @@ class Provider(QObject): class DataSource: - def __init__(self, providers=[]): - self.providers: list[Provider] = [Provider(url) for url in providers] + def __init__(self, providers: list[str], data_dir: str): + self.providers: list[Provider] = [Provider(url, data_dir) for url in providers] def DatabaseType(data_source) -> Type: @@ -204,6 +231,17 @@ def load_config() -> list[str]: return [f'http://{b["address"]}:{b["port"]}/' for b in config["backends"]] +def get_data_dir() -> str: + try: + data_dir: str = os.path.join(os.environ["XDG_DATA_HOME"], "ikinuki") + except: + data_dir: str = os.path.join(os.environ["HOME"], ".local", "share", "ikinuki") + + os.makedirs(data_dir, exist_ok=True) + + return data_dir + + def main(): app = QApplication(sys.argv) @@ -218,7 +256,9 @@ def main(): print(f"ERROR: Could not load config file: {repr(e)}") sys.exit(-1) - data_source = DataSource(backends) + data_dir: str = get_data_dir() + + data_source = DataSource(backends, data_dir) qmlRegisterType(DatabaseType(data_source), "Ikinuki.Client", 1, 0, "Database")