From 8b585c827be4bf5a52cbce2a811b97b21ef6fe15 Mon Sep 17 00:00:00 2001 From: DogmaDragon <103123951+DogmaDragon@users.noreply.github.com> Date: Wed, 2 Sep 2026 20:25:24 +0300 Subject: [PATCH] Fix scene delete task --- plugins/additionalFilesDeleter/README.md | 20 ++++++------- plugins/additionalFilesDeleter/deleter.py | 28 +++++++++++-------- plugins/additionalFilesDeleter/deleter.yml | 2 +- .../additionalFilesDeleter/requirements.txt | 2 +- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/plugins/additionalFilesDeleter/README.md b/plugins/additionalFilesDeleter/README.md index 0429309d..6e011ded 100644 --- a/plugins/additionalFilesDeleter/README.md +++ b/plugins/additionalFilesDeleter/README.md @@ -1,20 +1,20 @@ # Addtional Files Deleter - https://discourse.stashapp.cc/t/addtional-files-deleter/1337 +https://discourse.stashapp.cc/t/addtional-files-deleter/1337 -This is a plugin that will scan your Stash for either scenes or images where the file count is above 1. It will then skip over the primary file for each scene or image object and delete these extra files. Usually scene that contain multiple files are identical Phash matches (Unless you have manually merged unidentical Phashed files). Image objects that contain multiple files are grouped together under identical checksums, not Phashes. (You can't manually merge images as of yet.) +This plugin scans your Stash library for scenes or images where the file count is greater than 1\. It skips the primary file for each object and deletes the additional files. In most cases, duplicate scene files are identical phash matches unless a scene was manually merged. Image objects with multiple files are typically grouped by identical checksums. ## Usage -Copy repository into Stash plugins folder or add via the new plugins system and refresh your plugins from the Settings. +Copy the repository into your Stash plugins folder or add it through the plugin system and refresh plugins from the Settings screen. -If on first run you may want to run the Create Tag task, which creates an ignore tag that you can apply to Scenes or Images, so that they are bypassed when any of the other tasks are run. +If this is your first run, use the Create Tag task to create an ignore tag that can be applied to Scenes or Images so they are skipped when the other tasks run. -Other than Create Tag task you can run the following tasks. +Other than the Create Tag task, you can run the following tasks: -Images - Delete -Images - Delete & Record -Scenes - Delete -Scenes - Delete & Record +- Images - Delete +- Images - Delete & Record +- Scenes - Delete +- Scenes - Delete & Record -Tasks that just specify delete will just delete addtional files from their respective objects and Delete & Record will take the file paths of the files to be deleted, prefix them with "File: " (For latter easy searching) and it will append them to the current list of urls the object has and update the object. This is just a precaution to record perhaps usefull metadata an additional file path may hold for later use. +Tasks that just specify Delete remove the additional files from the object. Delete & Record saves the deleted file paths with a "File: " prefix, appends them to the object's current URL list, and updates the object. This is a precaution to preserve metadata that may be useful later. diff --git a/plugins/additionalFilesDeleter/deleter.py b/plugins/additionalFilesDeleter/deleter.py index 50165b87..2914bfe1 100644 --- a/plugins/additionalFilesDeleter/deleter.py +++ b/plugins/additionalFilesDeleter/deleter.py @@ -1,7 +1,11 @@ import sys, json -import stashapi.log as log -from stashapi.stashapp import StashInterface +try: + import stashapi.log as log + from stashapi.stashapp import StashInterface +except ModuleNotFoundError: + print("stashapi not found", file=sys.stderr) + sys.exit(1) SVG_IMAGE = ( "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIi" @@ -49,12 +53,12 @@ def main(): def update_image(image_id, paths): update = stash.update_image( - {'id': image_id, 'urls': paths}) + {'id': image_id, 'urls': list(paths or [])}) return update def update_scene(scene_id, paths): update = stash.update_scene( - {'id': scene_id, 'urls': paths}) + {'id': scene_id, 'urls': list(paths or [])}) return update def find_images(find_images_tag): @@ -64,7 +68,7 @@ def find_images(find_images_tag): "tags": {"modifier": "EXCLUDES", "value": find_images_tag}, }, filter={ - "per_page": "-1" + "per_page": -1 }, get_count=True, @@ -78,7 +82,7 @@ def find_scenes(find_scenes_tag): "tags": {"modifier": "EXCLUDES", "value": find_scenes_tag}, }, filter={ - "per_page": "-1" + "per_page": -1 }, get_count=True, ) @@ -122,7 +126,7 @@ def images_delete(): for i, file in enumerate(image["visual_files"]): if i == 0: # skip first ID continue - delete = stash.destroy_files(file["id"]) + delete = stash.destroy_files([file["id"]]) if delete is True: log.info(f"Image ID:{image['id']} - File ID:{file['id']} - Deleted: {file['path']}") else: @@ -139,14 +143,14 @@ def images_delete_record_paths(): for j, image in enumerate(images): image_id = image["id"] - paths = image["urls"] + paths = list(image.get("urls") or []) log.progress(j / image_count) for i, file in enumerate(image["visual_files"]): if i == 0: # skip first ID continue path = file["path"] - delete = stash.destroy_files(file["id"]) + delete = stash.destroy_files([file["id"]]) if delete is True: log.info(f"Image ID:{image['id']} - File ID:{file['id']} - Deleted: {path}") paths.append("File: " + path) @@ -173,7 +177,7 @@ def scenes_delete(): for i, file in enumerate(scene["files"]): if i == 0: # skip first ID continue - delete = stash.destroy_files(file["id"]) + delete = stash.destroy_files([file["id"]]) if delete is True: log.info(f"Scene ID:{scene['id']} - File ID:{file['id']} - Deleted: {file['path']}") else: @@ -192,13 +196,13 @@ def scenes_delete_record_paths(): log.progress(j / scene_count) scene_id = scene["id"] - paths = scene["urls"] + paths = list(scene.get("urls") or []) for i, file in enumerate(scene["files"]): if i == 0: # skip first ID continue path = file["path"] - delete = stash.destroy_files(file["id"]) + delete = stash.destroy_files([file["id"]]) if delete is True: log.info(f"Scene ID:{scene['id']} - File ID:{file['id']} - Deleted: {path}") paths.append("File: " + path) diff --git a/plugins/additionalFilesDeleter/deleter.yml b/plugins/additionalFilesDeleter/deleter.yml index 7cb27746..5cf9c676 100644 --- a/plugins/additionalFilesDeleter/deleter.yml +++ b/plugins/additionalFilesDeleter/deleter.yml @@ -1,6 +1,6 @@ name: Addtional Files Deleter description: Deletes addtional files assosiated with an image or scene object. Which will usually have identical PHashes for scenes or Checksum for images. Unless is a scene manually merged. Apply ignore tag to scene/image object for plugin to bypass. -version: 0.1 +version: 0.2 url: https://discourse.stashapp.cc/t/addtional-files-deleter/1337 exec: - python diff --git a/plugins/additionalFilesDeleter/requirements.txt b/plugins/additionalFilesDeleter/requirements.txt index eeba91d4..5ffea202 100644 --- a/plugins/additionalFilesDeleter/requirements.txt +++ b/plugins/additionalFilesDeleter/requirements.txt @@ -1 +1 @@ -stashapp-tools==0.2.40 \ No newline at end of file +stashapi \ No newline at end of file