Source code for flexget.utils.cache

from __future__ import annotations

import hashlib
import os
from typing import TYPE_CHECKING

import requests
from loguru import logger

if TYPE_CHECKING:
    from pathlib import Path

logger = logger.bind(name='utils.cache')


# TODO: refactor this to use lru_cache
[docs] def cached_resource( url: str, base_dir: Path, force: bool = False, max_size: int = 250, directory: str = 'cached_resources', ) -> tuple[Path, str]: """Cache a remote resource to local filesystem. Return a tuple of local file name and mime type, use primarily for API/WebUI. :param url: Resource URL :param force: Does not check for existence of cached resource, fetches the remote URL, ignores directory size limit :param max_size: Maximum allowed size of directory, in MB. :param directory: Name of directory to use. Default is `cached_resources` :return: Tuple of file path and mime type """ mime_type = None hashed_name = hashlib.md5(url.encode('utf-8')).hexdigest() file_path = base_dir / directory / hashed_name directory = file_path.parent if not file_path.exists() or force: logger.debug('caching {}', url) response = requests.get(url) response.raise_for_status() mime_type = response.headers.get('content-type') content = response.content if not directory.exists(): directory.mkdir(parents=True) # Checks directory size and trims if necessary. size = dir_size(directory) / (1024 * 1024.0) if not force: while size >= max_size: logger.debug( 'directory {} size is over the allowed limit of {}, trimming', size, max_size ) trim_dir(directory) size = dir_size(directory) / (1024 * 1024.0) with file_path.open('wb') as file: file.write(content) return file_path, mime_type
[docs] def dir_size(directory: Path) -> int: """Sum the size of all files in a given dir. Not recursive. :param directory: Directory to check :return: Summed size of all files in Bytes. """ size = 0 for file in os.listdir(directory): filename = directory / file size += filename.stat().st_size return size
[docs] def trim_dir(directory: Path) -> None: """Remove the least accessed file on a given dir. :param directory: Directory to check """ def access_time(f: str) -> float: return (directory / f).stat().st_atime files = sorted(os.listdir(directory), key=access_time) file_name = directory / files[0] logger.debug('removing least accessed file: {}', file_name) file_name.unlink()