Files
compose-projects-arr/stash/config/plugins/community/stashdb-performer-gallery/stashdb-performer-gallery.py
Christoph Califice 0a5f88d75a stash
2025-10-10 09:50:30 -03:00

471 lines
19 KiB
Python

import stashapi.log as log
from stashapi.stashapp import StashInterface
from stashapi.stashbox import StashBoxInterface
import os
import sys
import requests
import json
import requests
from pathlib import Path
import base64
per_page = 100
request_s = requests.Session()
stash_boxes = {}
scrapers = {}
def processImages(img):
log.debug("image: %s" % (img,))
image_data = None
for file in [x["path"] for x in img["visual_files"]]:
if settings["path"] in file:
index_file = Path(Path(file).parent) / (Path(file).stem + ".json")
log.debug(index_file)
if index_file.exists():
log.debug("loading index file %s" % (index_file,))
with open(index_file) as f:
index = json.load(f)
index["id"] = img["id"]
if image_data:
image_data["gallery_ids"].extend(index["gallery_ids"])
else:
image_data = index
if image_data:
# log.debug(image_data)
stash.update_image(image_data)
def processPerformers():
query = {
"tags": {
"depth": 0,
"excludes": [],
"modifier": "INCLUDES_ALL",
"value": [tag_stashbox_performer_gallery],
}
}
performers = stash.find_performers(f=query)
for performer in performers:
processPerformer(performer)
def processPerformer(performer):
dir = Path(settings["path"]) / performer["id"]
dir.mkdir(parents=True, exist_ok=True)
nogallery = dir / ".nogallery"
nogallery.touch()
for sid in performer["stash_ids"]:
log.debug(sid)
processPerformerStashid(sid["endpoint"], sid["stash_id"], performer)
def get_stashbox(endpoint):
for sbx_config in stash.get_configuration()["general"]["stashBoxes"]:
if sbx_config["endpoint"] == endpoint:
stashbox = StashBoxInterface(
{"endpoint": sbx_config["endpoint"], "api_key": sbx_config["api_key"]}
)
stash_boxes[endpoint] = stashbox
return stashbox
def processPerformerStashid(endpoint, stashid, p):
log.info(
"processing performer %s, %s endpoint: %s, stash id: %s"
% (
p["name"],
p["id"],
endpoint,
stashid,
)
)
index_file = os.path.join(settings["path"], p["id"], "index.json")
if os.path.exists(index_file):
with open(os.path.join(settings["path"], p["id"], "index.json")) as f:
index = json.load(f)
else:
index = {"files": {}, "galleries": {}, "performer_id": p["id"]}
modified = False
stashbox = get_stashbox(endpoint)
if stashbox:
query = """id
name
images {
id
url
}
urls{
url
type
}
"""
perf = stashbox.find_performer(stashid, fragment=query)
log.debug(perf)
if endpoint not in index["galleries"]:
gallery_input = {
"title": "%s - %s "
% (
p["name"],
endpoint[8:-8],
),
"urls": [
"%s/performers/%s"
% (
endpoint[:-8],
stashid,
)
],
"tag_ids": [tag_stashbox_performer_gallery],
"performer_ids": [p["id"]],
}
gal = stash.create_gallery(gallery_input)
log.info("Created gallery %s" % (gal,))
index["galleries"][endpoint] = gal
modified = True
# check if the gallery still exists and has not been deleted
current_gal = stash.find_gallery(index["galleries"][endpoint])
log.debug("current: %s" % (current_gal,))
if current_gal is None:
log.debug("deleted?")
gallery_input = {
"title": "%s - %s "
% (
p["name"],
endpoint[:-8],
),
"urls": [
"%s/performers/%s"
% (
endpoint[:-8],
stashid,
)
],
"tag_ids": [tag_stashbox_performer_gallery],
"performer_ids": [p["id"]],
}
gal = stash.create_gallery(gallery_input)
log.info("Created gallery %s" % (gal,))
index["galleries"][endpoint] = gal
modified = True
if modified:
with open(index_file, "w") as f:
json.dump(index, f)
for img in perf["images"]:
image_index = Path(settings["path"]) / p["id"] / (img["id"] + ".json")
if not image_index.exists():
with open(image_index, "w") as f:
image_data = {
"title": img["id"],
"urls": [img["url"]],
"performer_ids": [p["id"]],
"tag_ids": [tag_stashbox_performer_gallery],
"gallery_ids": [index["galleries"][endpoint]],
}
json.dump(image_data, f)
filename = Path(settings["path"]) / p["id"] / (img["id"] + ".jpg")
if not os.path.exists(filename):
log.info(
"Downloading image %s to %s"
% (
img["url"],
filename,
)
)
r = requests.get(img["url"])
with open(filename, "wb") as f:
f.write(r.content)
f.close()
# modified=True
else:
log.debug("image already downloaded")
# scrape urls on the performer using the url scrapers in stash
if settings["runPerformerScraper"] and len(perf["urls"]) > 0:
# we need to determine what scrapers we have and what url patterns they accept, query what url patterns are supported, should only need to check once
if len(scrapers) == 0:
scrapers_graphql = """query ListPerformerScrapers {
listScrapers(types: [PERFORMER]) {
id
name
performer {
urls
supported_scrapes
}
}
}"""
res = stash.callGQL(scrapers_graphql)
for r in res["listScrapers"]:
if r["performer"]["urls"]:
for url in r["performer"]["urls"]:
scrapers[url] = r
for u in perf["urls"]:
for url in scrapers.keys():
if url in u["url"]:
log.info(
"Running stash scraper on performer url: %s" % (u["url"],)
)
res = stash.scrape_performer_url(u["url"])
# Check if the scraper returned a result
if res is not None:
log.debug(res)
# it's possible for multiple images to be returned by a scraper so incriment a number each image
image_id = 1
if res["images"]:
for image in res["images"]:
image_index = (
Path(settings["path"])
/ p["id"]
/ (
"%s-%s.json"
% (
scrapers[url]["id"],
image_id,
)
)
)
if not image_index.exists():
with open(image_index, "w") as f:
image_data = {
"title": "%s - %s "
% (
scrapers[url]["id"],
image_id,
),
"details": "name: %s\ngender: %s\nurl: %s\ntwitter: %s\ninstagram: %s\nbirthdate: %s\nethnicity: %s\ncountry: %s\neye_color: %s\nheight: %s\nmeasurements: %s\nfake tits: %s\npenis_length: %s\n career length: %s\ntattoos: %s\npiercings: %s\nhair_color: %s\nweight: %s\n description: %s\n"
% (
res["name"],
res["gender"],
res["url"],
res["twitter"],
res["instagram"],
res["birthdate"],
res["ethnicity"],
res["country"],
res["eye_color"],
res["height"],
res["measurements"],
res["fake_tits"],
res["penis_length"],
res["career_length"],
res["tattoos"],
res["piercings"],
res["hair_color"],
res["weight"],
res["details"],
),
"urls": [
u["url"],
],
"performer_ids": [p["id"]],
"tag_ids": [
tag_stashbox_performer_gallery
],
"gallery_ids": [
index["galleries"][endpoint]
],
}
json.dump(image_data, f)
filename = (
Path(settings["path"])
/ p["id"]
/ (
"%s-%s.jpg"
% (
scrapers[url]["id"],
image_id,
)
)
)
if not filename.exists():
if image.startswith("data:"):
with open(filename, "wb") as f:
f.write(
base64.b64decode(
image.split("base64,")[1]
)
)
f.close()
else:
with open(image_index, "w") as f:
image_data = {
"title": "%s - %s "
% (
scrapers[url]["id"],
image_id,
),
"details": "%s" % (res,),
"urls": [u["url"], image],
"performer_ids": [p["id"]],
"tag_ids": [
tag_stashbox_performer_gallery
],
"gallery_ids": [
index["galleries"][endpoint]
],
}
json.dump(image_data, f)
filename = (
Path(settings["path"])
/ p["id"]
/ ("%s.jpg" % (image_id,))
)
r = requests.get(img["url"])
if r.status_code == 200:
with open(filename, "wb") as f:
f.write(r.content)
f.close()
image_id = image_id + 1
# log.debug('%s %s' % (url['url'],url['type'],))
# stash.scraper
# scrape=stash.scrape_performer_url(ur)
else:
log.error("endpoint %s not configured, skipping" % (endpoint,))
def setPerformerPicture(img):
if len(img["performers"]) == 1:
log.debug(img["paths"]["image"])
res = request_s.get(img["paths"]["image"])
log.debug(res.headers["Content-Type"])
if res.status_code == 200:
encoded = base64.b64encode(res.content).decode()
new_performer = {
"id": img["performers"][0]["id"],
"image": "data:{0};base64,{1}".format(
res.headers["Content-Type"], encoded
),
}
log.info("updating performer with tagged image %s" % (new_performer["id"],))
stash.update_performer(new_performer)
def processQueue():
for id in settings["queue"].split(","):
if len(id) > 0:
p = stash.find_performer(id)
processPerformer(p)
# queue has not changed since we started, clear setting
if (
stash.get_configuration()["plugins"]["stashdb-performer-gallery"]
== settings["queue"]
):
stash.configure_plugin("stashdb-performer-gallery", {"queue": ""})
stash.metadata_scan(paths=[settings["path"]])
stash.run_plugin_task("stashdb-performer-gallery", "relink missing images")
else:
# update remove the completed entries from the queue string leaving the unprocessed and schedule the task again
log.debug("updating queue")
stash.configure_plugin(
"stashdb-performer-gallery",
{
"queue": stash.get_configuration()["plugins"][
"stashdb-performer-gallery"
]["queue"].removeprefix(settings["queue"])
},
)
stash.run_plugin_task(
"stashdb-performer-gallery", "Process Performers", args={"full": False}
)
def relink_images(performer_id=None):
query = {
"path": {"modifier": "INCLUDES", "value": settings["path"]},
}
if performer_id == None:
query["is_missing"] = "galleries"
query["path"] = {"modifier": "INCLUDES", "value": settings["path"]}
else:
query["path"] = {
"modifier": "INCLUDES",
"value": str(Path(settings["path"]) / performer_id / ""),
}
# else:
# query["file_count"] = {"modifier": "NOT_EQUALS", "value": 1}
total = stash.find_images(f=query, get_count=True)[0]
i = 0
images = []
while i < total:
images = stash.find_images(f=query, filter={"page": i, "per_page": per_page})
for img in images:
log.debug("image: %s" % (img,))
processImages(img)
i = i + 1
log.progress((i / total))
json_input = json.loads(sys.stdin.read())
FRAGMENT_SERVER = json_input["server_connection"]
stash = StashInterface(FRAGMENT_SERVER)
config = stash.get_configuration()["plugins"]
settings = {
"path": "/download_dir",
"runPerformerScraper": False,
}
if "stashdb-performer-gallery" in config:
settings.update(config["stashdb-performer-gallery"])
# log.info('config: %s ' % (settings,))
tag_stashbox_performer_gallery = stash.find_tag(
"[Stashbox Performer Gallery]", create=True
).get("id")
tag_performer_image = stash.find_tag("[Set Profile Image]", create=True).get("id")
if "stasdb-performer-gallery" in config:
settings.update(config["stasdb-performer-gallery"])
if "mode" in json_input["args"]:
PLUGIN_ARGS = json_input["args"]["mode"]
if "performer" in json_input["args"]:
p = stash.find_performer(json_input["args"]["performer"])
if tag_stashbox_performer_gallery in [x["id"] for x in p["tags"]]:
processPerformer(p)
stash.metadata_scan(paths=[settings["path"]])
stash.run_plugin_task(
"stashdb-performer-gallery",
"relink missing images",
args={"performer_id": p["id"]},
)
elif "processPerformers" in PLUGIN_ARGS:
processPerformers()
stash.metadata_scan([settings["path"]])
stash.run_plugin_task(
"stashdb-performer-gallery", "relink missing images", args={}
)
elif "processImages" in PLUGIN_ARGS:
if "performer_id" in json_input["args"]:
relink_images(performer_id=json_input["args"]["performer_id"])
else:
relink_images()
elif "hookContext" in json_input["args"]:
id = json_input["args"]["hookContext"]["id"]
if json_input["args"]["hookContext"]["type"] == "Image.Create.Post":
img = stash.find_image(image_in=id)
processImages(img)
if json_input["args"]["hookContext"]["type"] == "Image.Update.Post":
img = stash.find_image(image_in=id)
if tag_performer_image in [x["id"] for x in img["tags"]]:
setPerformerPicture(img)
if json_input["args"]["hookContext"]["type"] == "Performer.Update.Post":
stash.run_plugin_task(
"stashdb-performer-gallery", "Process Performers", args={"performer": id}
)