From b0a04ae4bc6589e6f446545ac36dec5338c032f8 Mon Sep 17 00:00:00 2001 From: Peter Levi Date: Fri, 17 Jun 2022 01:54:34 +0300 Subject: [PATCH] Fix #480: Improve image searching: Avoid deep/huge folders causing Variety to ignore the other folders --- variety/PreferencesVarietyDialog.py | 60 ++++++++++++----------------- variety/Util.py | 58 +++++++++++++++++----------- variety/VarietyWindow.py | 15 +++----- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/variety/PreferencesVarietyDialog.py b/variety/PreferencesVarietyDialog.py index d40cfd14..2c6885a2 100644 --- a/variety/PreferencesVarietyDialog.py +++ b/variety/PreferencesVarietyDialog.py @@ -848,7 +848,6 @@ def show_thumbs(self, source_rows, pin=False, thumbs_type=None): images = [] folders = [] - image_count = 0 for row in source_rows: if not row: @@ -856,46 +855,35 @@ def show_thumbs(self, source_rows, pin=False, thumbs_type=None): type = row[1] if type == Options.SourceType.IMAGE: - image_count += 1 images.append(row[2]) else: folder = self.parent.get_folder_of_source(self.model_row_to_source(row)) - image_count += sum( - 1 - for f in Util.list_files( - folders=(folder,), - filter_func=Util.is_image, - max_files=1, - randomize=False, - ) - ) folders.append(folder) - if image_count > -1: - folder_images = list( - Util.list_files(folders=folders, filter_func=Util.is_image, max_files=1000) - ) - if len(source_rows) == 1 and source_rows[0][1] == Options.SourceType.ALBUM_FILENAME: - folder_images = sorted(folder_images) - elif len(source_rows) == 1 and source_rows[0][1] == Options.SourceType.ALBUM_DATE: - folder_images = sorted(folder_images, key=os.path.getmtime) - else: - random.shuffle(folder_images) - to_show = images + folder_images - if hasattr(self, "focused_image") and self.focused_image is not None: - try: - to_show.remove(self.focused_image) - except Exception: - pass - to_show.insert(0, self.focused_image) - self.focused_image = None - self.parent.thumbs_manager.show( - to_show, screen=self.get_screen(), folders=folders, type=thumbs_type - ) - if pin: - self.parent.thumbs_manager.pin() - if thumbs_type: - self.parent.update_indicator(auto_changed=False) + folder_images = list( + Util.list_files(folders=folders, filter_func=Util.is_image, max_files=10000) + ) + if len(source_rows) == 1 and source_rows[0][1] == Options.SourceType.ALBUM_FILENAME: + folder_images = sorted(folder_images) + elif len(source_rows) == 1 and source_rows[0][1] == Options.SourceType.ALBUM_DATE: + folder_images = sorted(folder_images, key=os.path.getmtime) + else: + random.shuffle(folder_images) + to_show = images + folder_images + if hasattr(self, "focused_image") and self.focused_image is not None: + try: + to_show.remove(self.focused_image) + except Exception: + pass + to_show.insert(0, self.focused_image) + self.focused_image = None + self.parent.thumbs_manager.show( + to_show, screen=self.get_screen(), folders=folders, type=thumbs_type + ) + if pin: + self.parent.thumbs_manager.pin() + if thumbs_type: + self.parent.update_indicator(auto_changed=False) except Exception: logger.exception(lambda: "Could not create thumbs window:") diff --git a/variety/Util.py b/variety/Util.py index ff0cb541..021c8a1d 100644 --- a/variety/Util.py +++ b/variety/Util.py @@ -397,6 +397,9 @@ def is_animated_gif(filename): def list_files( files=(), folders=(), filter_func=(lambda f: True), max_files=10000, randomize=True ): + class NextFolderException(Exception): + pass + count = 0 for filepath in files: logger.debug( @@ -411,29 +414,38 @@ def list_files( random.shuffle(folders) for folder in folders: - if os.path.isdir(folder): - try: - for root, subFolders, files in os.walk(folder, followlinks=True): - if randomize: - random.shuffle(files) - random.shuffle(subFolders) - for filename in files: - logger.debug( - lambda: "checking file %s against filter_func %s (root=%s)" - % (filename, filter_func, root) - ) - path = os.path.join(root, filename) - if filter_func(path): - count += 1 - if count > max_files: - logger.info( - lambda: "More than %d files in the folders, stop listing" - % max_files - ) - return - yield path - except Exception: - logger.exception(lambda: "Could not walk folder " + folder) + folder_quota = max(20, int(max_files / len(folders))) + if not os.path.isdir(folder): + continue + try: + count_in_folder = 0 + for root, subfolders, files in os.walk(folder, followlinks=True): + subfolder_quota = max(10, int(folder_quota / (1 + len(subfolders)))) + if randomize: + random.shuffle(files) + random.shuffle(subfolders) + for filename in files[:subfolder_quota]: + logger.debug( + lambda: "checking file %s against filter_func %s (root=%s)" + % (filename, filter_func, root) + ) + path = os.path.join(root, filename) + if filter_func(path): + count += 1 + if count > max_files: + logger.info( + lambda: "More than %d files in the folders, stop listing" + % max_files + ) + return + yield path + count_in_folder += 1 + if count_in_folder > folder_quota: + raise NextFolderException + except NextFolderException: + continue + except Exception: + logger.exception(lambda: "Could not walk folder " + folder) @staticmethod def start_force_exit_thread(delay): diff --git a/variety/VarietyWindow.py b/variety/VarietyWindow.py index 395a4699..114cc906 100644 --- a/variety/VarietyWindow.py +++ b/variety/VarietyWindow.py @@ -67,7 +67,7 @@ import gi # isort:skip gi.require_version("Notify", "0.7") -from gi.repository import Gdk, GdkPixbuf, Gio, GObject, Gtk, Notify # isort:skip +from gi.repository import Gdk, Gio, GObject, Gtk, Notify # isort:skip Notify.init("Variety") # fmt: on @@ -1579,11 +1579,10 @@ def _set_icon_to_current(): except Exception: logger.exception(lambda: "Error while setting wallpaper") - def list_images(self): - return Util.list_files(self.individual_images, self.folders, Util.is_image, max_files=10000) - def select_random_images(self, count): - all_images = list(self.list_images()) + all_images = list( + Util.list_files(self.individual_images, self.folders, Util.is_image, max_files=10000) + ) self.image_count = len(all_images) # add just the first image of each album to the selection, @@ -1847,9 +1846,7 @@ def image_ok(self, img, fuzziness): width = self.image_colors_cache[img][3] height = self.image_colors_cache[img][4] else: - i = PILImage.open(img) - width = i.size[0] - height = i.size[1] + width, height = Util.get_size(img) if not self.size_ok(width, height, fuzziness): return False @@ -1899,7 +1896,7 @@ def image_ok(self, img, fuzziness): return True except Exception: - logger.exception(lambda: "Error in image_ok for file %s" % img) + logger.warning(lambda: "Error in image_ok for file %s" % img) return False def size_ok(self, width, height, fuzziness=0):