diff --git a/plugins/tagImagesWithPerfTags/manifest b/plugins/tagImagesWithPerfTags/manifest new file mode 100755 index 0000000..68590a8 --- /dev/null +++ b/plugins/tagImagesWithPerfTags/manifest @@ -0,0 +1,12 @@ +id: tagImagesWithPerfTags +name: Tag Images From Performer Tags +metadata: + description: tags images with performer tags. +version: 0.1-private +date: "2025-05-18 19:37:19" +requires: [] +files: +- tagImagesWithPerfTags.yml +- requirements.txt +- README.md +- tagImagesWithPerfTags.py diff --git a/plugins/tagImagesWithPerfTags/requirements.txt b/plugins/tagImagesWithPerfTags/requirements.txt new file mode 100755 index 0000000..e0fcf02 --- /dev/null +++ b/plugins/tagImagesWithPerfTags/requirements.txt @@ -0,0 +1 @@ +stashapp-tools diff --git a/plugins/tagImagesWithPerfTags/tagImagesWithPerfTags.py b/plugins/tagImagesWithPerfTags/tagImagesWithPerfTags.py new file mode 100755 index 0000000..123d540 --- /dev/null +++ b/plugins/tagImagesWithPerfTags/tagImagesWithPerfTags.py @@ -0,0 +1,125 @@ +import stashapi.log as log +from stashapi.stashapp import StashInterface +import sys +import json + +def processAll(): + exclusion_marker_tag_id = None + if settings["excludeImageWithTag"] != "": + exclussion_marker_tag = stash.find_tag(settings["excludeImageWithTag"]) + if exclussion_marker_tag is not None: + exclusion_marker_tag_id = exclussion_marker_tag['id'] + + query = { + "tags": { + "modifier": "NOT_NULL", + }, + "image_count": { + "modifier": "NOT_EQUALS", + "value": 0, + }, + } + performersTotal = stash.find_performers(f=query, filter={"page": 0, "per_page": 0}, get_count=True)[0] + i = 0 + while i < performersTotal: + log.progress((i / performersTotal)) + + perf = stash.find_performers(f=query, filter={"page": i, "per_page": 1}) + + performer_tags_ids = [] + performer_tags_names = [] + for performer_tag in perf[0]["tags"]: + performer_tags_ids.append(performer_tag["id"]) + performer_tags_names.append(performer_tag["name"]) + + image_query = { + "performers": { + "value": [perf[0]["id"]], + "modifier": "INCLUDES_ALL" + } + } + if settings['excludeImageOrganized']: + image_query["organized"] = False + if exclusion_marker_tag_id is not None: + image_query["tags"] = { + "value": [exclusion_marker_tag_id], + "modifier": "EXCLUDES" + } + + performer_image_count = stash.find_images(f=image_query, filter={"page": 0, "per_page": 0}, get_count=True)[0] + + if performer_image_count > 0: + log.info(f"updating {performer_image_count} images of performer \"{ perf[0]['name']}\" with tags {performer_tags_names}") + + performer_image_page_size = 100 + performer_image_page = 0 + while performer_image_page * performer_image_page_size < performer_image_count: + performer_images = stash.find_images(f=image_query, filter={"page": performer_image_page, "per_page": performer_image_page_size}, fragment='id') + performer_image_ids = [performer_image['id'] for performer_image in performer_images] + + stash.update_images( + { + "ids": performer_image_ids, + "tag_ids": {"mode": "ADD", "ids": performer_tags_ids}, + } + ) + performer_image_page += 1 + + i = i + 1 + + +def processImage(image): + tags = [] + performersIds = [] + should_tag = True + if settings["excludeImageWithTag"] != "": + for tag in image["tags"]: + if tag["name"] == settings["excludeImageWithTag"]: + should_tag = False + break + + if settings['excludeImageOrganized']: + if image['organized']: + should_tag = False + + if should_tag: + for perf in image["performers"]: + performersIds.append(perf["id"]) + performers = [] + for perfId in performersIds: + performers.append(stash.find_performer(perfId)) + for perf in performers: + for tag in perf["tags"]: + tags.append(tag["id"]) + stash.update_images({"ids": image["id"], "tag_ids": {"mode": "ADD", "ids": tags}}) + tags = [] + performersIds = [] + performers = [] + + +json_input = json.loads(sys.stdin.read()) +FRAGMENT_SERVER = json_input["server_connection"] +stash = StashInterface(FRAGMENT_SERVER) +config = stash.get_configuration() +settings = { + "excludeImageWithTag": "", + "excludeImageOrganized": False +} +if "tagImagesWithPerfTags" in config["plugins"]: + settings.update(config["plugins"]["tagImagesWithPerfTags"]) + +if "mode" in json_input["args"]: + PLUGIN_ARGS = json_input["args"]["mode"] + if "processAll" in PLUGIN_ARGS: + processAll() +elif "hookContext" in json_input["args"]: + id = json_input["args"]["hookContext"]["id"] + if ( + ( + json_input["args"]["hookContext"]["type"] == "Image.Update.Post" + or "Image.Create.Post" + ) and "inputFields" in json_input["args"]["hookContext"] + and len(json_input["args"]["hookContext"]["inputFields"]) > 2 + ): + image = stash.find_image(id) + processImage(image) diff --git a/plugins/tagImagesWithPerfTags/tagImagesWithPerfTags.yml b/plugins/tagImagesWithPerfTags/tagImagesWithPerfTags.yml new file mode 100755 index 0000000..7ecf6f9 --- /dev/null +++ b/plugins/tagImagesWithPerfTags/tagImagesWithPerfTags.yml @@ -0,0 +1,30 @@ +name: Tag Images From Performer Tags +description: tags images with performer tags. +version: 0.1 +exec: + - python + - "{pluginDir}/tagImagesWithPerfTags.py" +interface: raw + +hooks: + - name: update image + description: Will tag image with selected performers tags + triggeredBy: + - Image.Update.Post + - Image.Create.Post + +settings: + excludeImageOrganized: + displayName: Exclude Images marked as organized + description: Do not automatically tag images with performer tags if the image is marked as organized + type: BOOLEAN + excludeImageWithTag: + displayName: Exclude Images with Tag from Hook + description: Do not automatically tag images with performer tags if the image has this tag + type: STRING + +tasks: + - name: "Tag All Images" + description: Loops through all performers, finds all of their images, then applies the performers tags to each of the images they appear in. Can take a long time on large db's. + defaultArgs: + mode: processAll