Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions plugins/javstashAutofill/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

## v1.3
- Initial release.
- Fill a newly-created performer's empty fields from a scraper (default javstash) on `Performer.Create.Post`.
- Best name-match selection with a configurable threshold; skip when no match.
- Per-origin (Identify / manual) source and primary-name policy.
- Duplicate merge when the scraper name becomes primary and a same-named performer already exists.
- Per-field overwrite toggles (default off = fill empty only).
- Measurements normalisation and asynchronous image setting.
52 changes: 52 additions & 0 deletions plugins/javstashAutofill/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Javstash Autofill

Automatically fills in a newly-created performer's empty fields from a scraper
(default: the [javstash](https://javstash.org) stash-box) the moment the
performer is created (`Performer.Create.Post` hook).

It searches the configured source by the performer's name, takes the
best name-matching candidate, and fills the empty fields. Existing values and
existing images are protected by default; you can opt into overwriting on a
per-field basis.

## Behaviour

- **Best name match, or skip.** The candidate with the highest name-match score
(exact = 1.0, otherwise fuzzy) is used. If the best score is below the
configurable threshold, nothing is done.
- **Fill empty only (default).** Only empty fields are written, so manual edits
and other scrapers' data are preserved. Each field can be switched to
"overwrite existing" individually.
- **Primary name policy.** For each origin (Identify vs. manual creation) you can
choose whether the created name stays primary (scraper name goes to aliases)
or the scraper's canonical name becomes primary (created name goes to aliases).
- **Duplicate merge.** When the scraper name would become primary but a performer
with that name already exists, the newly-created one is merged into the
existing performer (`performerMerge`) — scenes are re-linked, the created name
and the stash-box id are carried over, and the duplicate is removed.
- **Measurements normalisation.** `91H-56-88` → `91(H)-56-88`.
- **Asynchronous image.** The image is downloaded and set in a detached
background process, so the hook returns immediately and Stash never blocks on a
slow remote image fetch.

## Requirements

- Python 3 available to Stash's plugin runner.
- The chosen source configured in Stash. For a stash-box source (e.g. javstash),
add it under **Settings → Metadata Providers → Stash-box Endpoints**.

## Settings

| Setting | Description |
| --- | --- |
| Scraper (Identify) / Scraper (manual) | Source per origin: a stash-box endpoint URL or a `scraper_id`. Empty = javstash. |
| Use scraper name (Identify) / (manual) | Make the scraper's canonical name the primary name for that origin. Default: Identify ON, manual OFF. |
| Name-match threshold | Skip if the best match score is below this (default 0.9). |
| Overwrite: *field* | Per-field toggle. OFF = fill only when empty (default); ON = overwrite even if a value already exists. For URLs / aliases, ON replaces and OFF appends; for the image, ON replaces an existing image. |

## Notes

- The source scrape is proxied through Stash's own `scrapeSinglePerformer`, so no
API keys are needed in the plugin itself.
- Identify-origin creations are detected by the presence of `stash_ids` in the
create input.
105 changes: 105 additions & 0 deletions plugins/javstashAutofill/javstashAutofill.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: Javstash Autofill
description: On performer create, fill empty fields from a scraper (best name match, skip if none). Existing values/images are protected; per-field overwrite is optional. Primary name can be the created one or the scraper's, chosen separately for Identify and manual; when the scraper name would collide, the new performer is merged into the existing one.
version: 1.3
exec:
- python3
- "{pluginDir}/javstash_autofill.py"
interface: raw
settings:
identifySource:
displayName: Scraper (Identify)
description: Source for performers auto-created by Identify. A stash-box endpoint URL (e.g. https://javstash.org/graphql) or a scraper_id (e.g. Minnano-AV-JP). Empty = javstash.
type: STRING
identifyUseScraperName:
displayName: Identify - use scraper name as primary
description: When ON, Identify-created performers get the scraper's canonical name as primary (created name -> alias; merged if a same-named performer exists). When OFF, keep the created name. Default ON.
type: BOOLEAN
manualSource:
displayName: Scraper (manual)
description: Source for manually-created performers. Endpoint URL or scraper_id. Empty = javstash.
type: STRING
manualUseScraperName:
displayName: Manual - use scraper name as primary
description: When ON, manually-created performers also get the scraper's canonical name as primary. When OFF, keep the created name. Default OFF.
type: BOOLEAN
threshold:
displayName: Name-match threshold (0-1)
description: Skip when the best name-match score is below this. Default 0.9.
type: NUMBER
owBirthdate:
displayName: "Overwrite: birthdate"
description: Overwrite even if a value already exists. OFF = fill only when empty.
type: BOOLEAN
owDeathDate:
displayName: "Overwrite: death date"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owMeasurements:
displayName: "Overwrite: measurements"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owHeight:
displayName: "Overwrite: height"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owWeight:
displayName: "Overwrite: weight"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owCountry:
displayName: "Overwrite: country"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owEthnicity:
displayName: "Overwrite: ethnicity"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owHairColor:
displayName: "Overwrite: hair color"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owEyeColor:
displayName: "Overwrite: eye color"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owGender:
displayName: "Overwrite: gender"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owFakeTits:
displayName: "Overwrite: fake tits (Natural/Fake)"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owCareerLength:
displayName: "Overwrite: career length"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owTattoos:
displayName: "Overwrite: tattoos"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owPiercings:
displayName: "Overwrite: piercings"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owDetails:
displayName: "Overwrite: details"
description: Overwrite even if set. OFF = empty only.
type: BOOLEAN
owUrls:
displayName: "Overwrite: URLs"
description: When ON, replace urls with the scraper's. OFF = keep existing and append missing.
type: BOOLEAN
owAliasList:
displayName: "Overwrite: aliases"
description: When ON, replace alias_list from the scraper. OFF = keep existing and append missing (recommended).
type: BOOLEAN
owImage:
displayName: "Overwrite: image"
description: When ON, replace an existing image with the scraper's. OFF = set only when there is no image.
type: BOOLEAN
hooks:
- name: performer_create_autofill
description: Fill fields when a performer is created
triggeredBy:
- Performer.Create.Post
Loading
Loading