-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
578 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
# Stash Performer Custom Fields | ||
|
||
Adds custom fields to performers that are stored in performer details as JSON. | ||
|
||
**Note: Make sure you fully understand how this plugin will affect your performer details data before attempting to use it.** | ||
|
||
## Overview | ||
|
||
This plugin provides the following: | ||
|
||
* A task for migrating existing performer detail data to JSON format | ||
* A performer creation hook that adds custom fields to performer details data | ||
* UI updates to performer pages for viewing and editing performer details and custom fields | ||
|
||
## Consequences | ||
|
||
Since this plugin combines existing performer details data and custom field data in JSON format for storage as performer details in the stash database, this has some consequences and limitations to consider: | ||
|
||
* Custom fields cannot be filtered on directly | ||
|
||
* Filtering on performer details will include custom fields data. | ||
|
||
* Direct editing of performer details is discouraged | ||
* However, an alternative is provided by the updated UI. | ||
|
||
* The raw performer details data is less human-readable due to it being JSON instead of just unformatted text. | ||
* This shouldn't matter if you just use the updated UI for editing details and custom fields data. | ||
|
||
## Performer Details Migration Task | ||
|
||
The first thing the task does is run the backup task. Then it goes through all performers and converts details data to JSON with custom fields. Existing details data is preserved within the JSON. | ||
|
||
A performer without any existing details will end up with `{"custom": {"notes": null, "paths": null, "urls": null}}` | ||
|
||
A performer with existing details of `"This is a performer bio"` will have their details changed to `{"custom": {"notes": null, "paths": null, "urls": null}, "details": "This is a performer bio"}`. | ||
|
||
No existing details data is lost, because it is still embedded within the JSON. | ||
|
||
*Examples assume the default fields setting `notes,paths,urls`* | ||
|
||
## Performer Creation Hook | ||
|
||
Whenever a new performer is created, the plugin hook with the default field setting `notes,paths,urls` will set the performer details to `{"custom": {"notes": null, "paths": null, "urls": null}}`. | ||
|
||
## Performer Page UI Changes | ||
|
||
The plugin displays custom fields just as the normal performer fields are displayed. Data in the `urls` and `paths` custom fields will display as links. Clicking a url link will open the link in a new tab and clicking a path will open File Explorer at that location. | ||
|
||
A toggle button is added to the Details section that allows you to switch to the editing mode. The editing mode allows adding and remove custom field data entries. | ||
|
||
The editing mode also provides a textbox for editing the normal Details section. This is a substitute for editing performer details the normal way. | ||
|
||
Manually editing performer details data the normal way is no longer recommended unless you are familiar with JSON and understand the data format used by the plugin. | ||
|
||
## Plugin Settings | ||
|
||
### Fields | ||
|
||
The fields setting defines the custom fields that will be used. The value should be a comma-separated list of custom field names. The default value is `notes,paths,urls`. Only the `paths` and `urls` custom field names have special UI behavior. | ||
|
||
Field names should not contain spaces. You can use underscores instead and they will be replaced with spaces in the field name labels on the performers page. | ||
|
||
### Show Edit | ||
|
||
This setting is tied to the toggle button that is added to the performer page details that switches between view and edit mode. | ||
|
||
## JSON Format | ||
|
||
Custom field data along with performer details data is saved to the existing performer details field as JSON. | ||
|
||
The performer details JSON is an object with a `custom` key and an optional `details` key. The `custom` value is an object and the `details` value is a string. | ||
|
||
The field names in the field setting are used as keys in the `custom` object. The key values are either null or an array of strings. | ||
|
||
*Examples assume the default fields setting `notes,paths,urls`* | ||
|
||
Without performer details and no urls, paths, or notes: | ||
``` | ||
{ | ||
"custom": { | ||
"notes": null, | ||
"paths": null, | ||
"urls": null | ||
} | ||
} | ||
``` | ||
|
||
With performer details and no urls, paths, or notes: | ||
``` | ||
{ | ||
"custom": { | ||
"notes": null, | ||
"paths": null, | ||
"urls": null | ||
}, | ||
"details": "Performer details go here" | ||
} | ||
``` | ||
|
||
With performer details, urls, paths, and notes: | ||
``` | ||
{ | ||
"custom": { | ||
"notes": ["Note 1","Note 2"], | ||
"paths": ["C:\Videos\Alice","C:\Videos\Alice 2"], | ||
"urls": ["https://github.com/stashapp/stash","https://github.com/7dJx1qP/stash-plugins"] | ||
}, | ||
"details": "Performer details go here" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import json | ||
import math | ||
import yaml | ||
from tqdm import tqdm | ||
from stashlib.logger import logger as log | ||
from stashlib.stash_database import StashDatabase | ||
from stashlib.stash_models import PerformersRow | ||
|
||
def update_performer_details(db: StashDatabase, performer_id: int, details, commit=True): | ||
encoded_details = json.dumps(details, ensure_ascii=False) | ||
db.performers.update_details_by_id(performer_id, encoded_details, commit) | ||
|
||
def fields_to_dict(fields: list[str]): | ||
result = {} | ||
for field in fields: | ||
result[field] = None | ||
return result | ||
|
||
def init_performer_details(db: StashDatabase, fields: list[str], performer: PerformersRow, commit=True): | ||
log.LogDebug(f"Initializing performer... {performer.id} {performer.name}") | ||
if not performer.details: | ||
log.LogTrace(f"No details. Updating performer...") | ||
details = { | ||
'custom': fields_to_dict(fields) | ||
} | ||
encoded_details = json.dumps(details, ensure_ascii=False) | ||
db.performers.update_details_by_id(performer.id, encoded_details, commit) | ||
else: | ||
log.LogTrace(f"Checking for performer details JSON...") | ||
details = { | ||
'custom': fields_to_dict(fields) | ||
} | ||
needs_update = False | ||
try: | ||
docs = json.loads(performer.details) | ||
if type(docs) is dict: | ||
details = docs | ||
log.LogTrace(f"JSON is dict, details: {'details' in details}, custom: {'custom' in details}") | ||
if 'details' in details and type(details['details']) is not str: | ||
log.LogWarning(f"Malformed details key value. Expected str, got {type(details['details']).__name__}. Skipping... {performer.id} {performer.name}") | ||
return | ||
if 'custom' not in details: | ||
details['custom'] = fields_to_dict(fields) | ||
needs_update = True | ||
log.LogTrace(f"Added missing custom dict") | ||
elif type(details['custom']) is not dict: | ||
log.LogWarning(f"Malformed custom key value. Expected dict, got {type(details['custom']).__name__}. Skipping... {performer.id} {performer.name}") | ||
return | ||
else: | ||
log.LogTrace(f"Has custom dict") | ||
for field in fields: | ||
if field not in details['custom']: | ||
details['custom'][field] = None | ||
needs_update = True | ||
log.LogTrace(f"Added missing {field} field to custom dict") | ||
else: | ||
log.LogWarning(f"JSON detected but expected dict, got {type(docs).__name__}... {performer.id} {performer.name}") | ||
details['details'] = performer.details | ||
needs_update = True | ||
except: | ||
log.LogTrace(f"Invalid JSON") | ||
details['details'] = performer.details | ||
needs_update = True | ||
|
||
if needs_update: | ||
log.LogTrace(f"Updating performer details... {performer.id} {performer.name}") | ||
encoded_details = json.dumps(details, ensure_ascii=False) | ||
db.performers.update_details_by_id(performer.id, encoded_details, commit) | ||
else: | ||
log.LogTrace(f"No update needed... {performer.id} {performer.name}") | ||
|
||
def init_performer_details_by_id(db: StashDatabase, fields: list[str], performer_id, commit=True): | ||
performer = db.performers.selectone_id(performer_id) | ||
if performer: | ||
init_performer_details(db, fields, performer, commit) | ||
|
||
def init_all_performer_details(db: StashDatabase, fields: list[str]): | ||
performers = [PerformersRow().from_sqliterow(row) for row in db.performers.select()] | ||
log.LogInfo(f"Migrating {len(performers)} performer details...") | ||
for performer in performers: | ||
init_performer_details(db, fields, performer, commit=False) | ||
db.commit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pystashlib==0.4.2 |
Oops, something went wrong.