12
12
from PIL import Image
13
13
14
14
from tagstudio .core .constants import THUMB_CACHE_NAME , TS_FOLDER_NAME
15
- from tagstudio .core .global_settings import DEFAULT_THUMB_CACHE_SIZE
15
+ from tagstudio .core .global_settings import DEFAULT_CACHED_IMAGE_QUALITY , DEFAULT_THUMB_CACHE_SIZE
16
16
17
17
logger = structlog .get_logger (__name__ )
18
18
@@ -24,26 +24,31 @@ def __init__(self, path: Path, size: int):
24
24
25
25
26
26
class CacheManager :
27
- MAX_FOLDER_SIZE = 10 # Number in MiB
27
+ MAX_FOLDER_SIZE = 10 # Absolute maximum size of a folder, number in MiB
28
28
STAT_MULTIPLIER = 1_000_000 # Multiplier to apply to file stats (bytes) to get user units (MiB)
29
29
30
30
def __init__ (
31
31
self ,
32
32
library_dir : Path ,
33
33
max_size : int | float = DEFAULT_THUMB_CACHE_SIZE ,
34
+ img_quality : int = DEFAULT_CACHED_IMAGE_QUALITY ,
34
35
):
35
36
"""A class for managing frontend caches, such as for file thumbnails.
36
37
37
38
Args:
38
39
library_dir(Path): The path of the folder containing the .TagStudio library folder.
39
40
max_size: (int | float) The maximum size of the cache, in MiB.
41
+ img_quality: (int) The image quality value to save PIL images (0-100, default=80)
40
42
"""
41
43
self ._lock = RLock ()
42
44
self .cache_path = library_dir / TS_FOLDER_NAME / THUMB_CACHE_NAME
43
45
self .max_size : int = max (
44
46
math .floor (max_size * CacheManager .STAT_MULTIPLIER ),
45
47
math .floor (CacheManager .MAX_FOLDER_SIZE * CacheManager .STAT_MULTIPLIER ),
46
48
)
49
+ self .img_quality = (
50
+ img_quality if img_quality >= 0 and img_quality <= 100 else DEFAULT_CACHED_IMAGE_QUALITY
51
+ )
47
52
48
53
self .folders : list [CacheFolder ] = []
49
54
self .current_size = 0
@@ -127,12 +132,20 @@ def save_image(self, image: Image.Image, file_name: Path, mode: str = "RGBA"):
127
132
with self ._lock as _lock :
128
133
cache_folder : CacheFolder = self ._get_current_folder ()
129
134
file_path = cache_folder .path / file_name
130
- image .save (file_path , mode = mode )
135
+ try :
136
+ image .save (file_path , mode = mode , quality = self .img_quality )
131
137
132
- size = file_path .stat ().st_size
133
- cache_folder .size += size
134
- self .current_size += size
135
- self ._cull_folders ()
138
+ size = file_path .stat ().st_size
139
+ cache_folder .size += size
140
+ self .current_size += size
141
+ self ._cull_folders ()
142
+ except FileNotFoundError :
143
+ logger .warn (
144
+ "[CacheManager] Failed to save cached image, was the folder deleted on disk?" ,
145
+ folder = file_path ,
146
+ )
147
+ if not cache_folder .path .exists ():
148
+ self .folders .remove (cache_folder )
136
149
137
150
def _create_folder (self ) -> CacheFolder :
138
151
with self ._lock as _lock :
0 commit comments