Add PlexSync

This commit is contained in:
Harry Strongburg
2025-05-31 00:20:10 +02:00
parent c1d1bc1538
commit e19a8d07c4
5 changed files with 246 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
import stashapi.log as log
import re
from stashapi.stashapp import StashInterface
import sys
import json
import unidecode
import requests
def processScene(scene):
tags = []
if settings["skipUnorganized"] and not scene['organized']: # don't process scenes that aren't marked organized.
log.info("Not organized, bye!")
sys.exit()
if settings["tagStashIDs"]:
if not scene["stash_ids"]: # Tagging empty Stash ID
tags.append(empty_stashid)
for stashbox in scene["stash_ids"]: # Add all the stashbox ID tags
url = stashbox['endpoint']
if (url == "https://stashdb.org/graphql"):
tags.append(int(settings["tagID_stashdb"]))
if (url == "https://pmvstash.org/graphql"):
tags.append(int(settings["tagID_pmvstash"]))
if (url == "https://theporndb.net/graphql"):
tags.append(int(settings["tagID_porndb"]))
if (url == "https://fansdb.cc/graphql"):
tags.append(int(settings["tagID_fansdb"]))
if (url == "https://javstash.org/graphql"):
tags.append(int(settings["tagID_javstash"]))
if (len(tags) != 0):
for x in scene['tags']:
if (int(x['id']) in tags):
log.debug(f"We already have the tag {x['id']} from {tags}")
tags.remove(int(x['id']))
if tags: # Just a double check that we still have pending tags to add
log.info(f"Adding the stashbox tags {tags} to scene {scene['title']}")
stash.update_scenes({"ids": scene["id"], "tag_ids": {"mode": "ADD", "ids": tags}})
if settings["cleanTitles"]:
if scene['title']: # Lots of title fixing. It's messy, but works good to remove weird characters and other improvements.
new_title = unidecode.unidecode(scene['title'], errors='ignore') # NB!!: Cyrillic and such gets changed to "normal" characters.
new_title = re.sub('^( | |@|\')+', "", new_title)
new_title = re.sub(' +$', "", new_title)
new_title = re.sub('^!+', "", new_title)
new_title = re.sub("^\\?+", "", new_title)
new_title = re.sub("^\\*+", "", new_title)
new_title = re.sub('^The ("|\')', 'The ', new_title)
new_title = re.sub('^A ("|\')', 'A ', new_title)
new_title = re.sub(' (Wmv|Mp4|Mov|Qt|HD)$', '', new_title)
new_title = re.sub('^[^A-Za-z0-9]', '', new_title)
new_title = re.sub('^( )', '', new_title)
if not (new_title == scene['title']):
log.info(f"New title: {new_title} from {scene['title']}")
if (new_title == ""):
new_title = "ZZZ Invalid Title"
stash.update_scenes({"ids": scene["id"], "title": new_title})
if scene["urls"]: # If scene contains Plex URL, refresh Plex metadata
for urls in reversed(scene["urls"]): # todo: remove reversed(); this was a quickfix for when a scene somehow got two plex urls - the most recent url is most likely the most "valid"
if ("/library/metadata/" in urls):
plexurl = urls.replace("plex", "https://" + settings["plexHost"] + ":" + settings["plexPort"])
plexurl += "/refresh?X-Plex-Token=" + settings["plexToken"]
log.info(f"Refreshing scene on Plex via {plexurl}")
try:
requests.packages.urllib3.disable_warnings() # TLS errors are irrelevant when I'm on localhost...
r = requests.put(plexurl, verify=False)
r.raise_for_status()
except requests.exceptions.HTTPError as e:
log.error(f"Plex API failed: {e.response.text}")
return
json_input = json.loads(sys.stdin.read())
FRAGMENT_SERVER = json_input["server_connection"]
stash = StashInterface(FRAGMENT_SERVER)
config = stash.get_configuration()
settings = {
"plexToken": "YOUR_PLEX_TOKEN_HERE",
"plexHost": "localhost",
"plexPort": "32400",
"tagStashIDs": False,
"skipUnorganized": True,
"cleanTitles": True,
"tagID_emptystashid": "1",
"tagID_stashdb": "2",
"tagID_pmvstash": "3",
"tagID_porndb": "4",
"tagID_fansdb": "5",
"tagID_javstash": "6"
}
if "PlexSync" in config["plugins"]:
settings.update(config["plugins"]["PlexSync"])
if "hookContext" in json_input["args"]:
id = json_input["args"]["hookContext"]["id"]
if (
json_input["args"]["hookContext"]["type"] == "Scene.Update.Post"
or "Scene.Create.Post"
):
#log.info(f"We run with {json_input}") # Uncomment for debugging what's sent to Stash
exit = False
request_tags = []
stashbox_tags = []
stashbox_tags.append(frozenset(
{
int(settings["tagID_stashdb"]),
int(settings["tagID_pmvstash"]),
int(settings["tagID_porndb"]),
int(settings["tagID_fansdb"]),
int(settings["tagID_javstash"])
}))
if "tag_ids" in json_input["args"]["hookContext"]["inputFields"]:
request_tags = json_input["args"]["hookContext"]["input"]["tag_ids"]
if set(request_tags) & set(stashbox_tags): # prevent rerunning tag addition, when the update is simply adding the tags
log.info("Already have correct tags.")
exit = True
else:
exit = False
if "urls" in json_input["args"]["hookContext"]["inputFields"]:
if len(json_input["args"]["hookContext"]["inputFields"]) == 2: # Hacky fix; Plex agent sends only two fields, so in this case we won't update metadata there again. Stash UI etc usually sends all fields in update, so no worries.
log.info("Got new Plex URL, will not refresh.")
exit = True
else:
exit = False
if exit == True:
log.info("Nothing to do, exiting.")
sys.exit()
scene = stash.find_scene(id)
processScene(scene)

View File

@@ -0,0 +1,57 @@
name: Plex Sync
description: Refresh Plex metadata when scene updated in Stash.
version: 0.1
url: https://github.com/stashapp/CommunityScripts/
exec:
- python3
- "{pluginDir}/PlexSync.py"
interface: raw
settings:
plexToken:
displayName: Plex server token
description: The X-Plex-Token for your connected Plex server.
type: STRING
plexHost:
displayName: Plex server address
description: Address to your Plex server; only hostname (do NOT add "https" or similar). "localhost" should work if Stash is on the same machine.
type: STRING
plexPort:
displayName: Plex server port
description: Port to your Plex server. Usually "32400"
type: STRING
tagStashIDs:
displayName: Set tags on scenes based on their Stashbox source. Suggested default False.
description: If enabled, you MUST manually create each tag, and set all the following tagID configs.
type: BOOLEAN
skipUnorganized:
displayName: Do not process scenes that are not marked as "organized". Suggested default True.
type: BOOLEAN
cleanTitles:
displayName: Convert away non-ASCII characters in titles. Suggested default True.
description: This is useful especially for "new Plex experience", but it will remove non-ASCII characters such as Cyrillic script.
type: BOOLEAN
tagID_emptystashid:
displayName: Tag ID for scenes not containing any Stashbox URL
type: STRING
tagID_stashdb:
displayName: Tag ID for scenes from StashDB
type: STRING
tagID_pmvstash:
displayName: Tag ID for scenes from PMVStash
type: STRING
tagID_porndb:
displayName: Tag ID for scenes from PornDB
type: STRING
tagID_fansdb:
displayName: Tag ID for scenes from FansDB
type: STRING
tagID_javstash:
displayName: Tag ID for scenes from JAVStash
type: STRING
hooks:
- name: Scene update
description: Run tasks for PlexSync
triggeredBy:
- Scene.Update.Post

View File

@@ -0,0 +1,38 @@
# Stash Plugin updating your Plex metadata automatically
This plugin solves the problem of "I have many files in my Plex, but they don't get any of the changes I do in Stash, and doing a `refresh all metadata` takes too much time".
With this, Stash behaves as the main source for all your Stash scenes in Plex, and it keeps Plex in sync with changes done via Stash.
# Install
Install the plugin in Stash first, and then install the updated [Stash-Plex-Agent](https://github.com/Darklyter/StashPlexAgent.bundle) on your Plex server.
## Stash side
1. Install plugin via the CommunityScripts repository.
2. Go to the install directory and install requirements: `python3 -m pip install -r requirements.txt -t .` -- or, install the required packages globally `python3 -m pip install stashapi unidecode requests`
3. Configure the plugin in Stash UI.
## Plex side
Do this *after* making sure the Stash side is complete.
1. After installing the newest version of this agent, make sure that `AddPlexURL` is enabled ("Adds the Plex media ID to the scene in Stash; allows Stash to update Plex metadata.")
2. Refresh all metadata in Plex for the libraries using this agent.
Now, you should see scenes being updated in Stash, adding this URL to the scenes: `plex/library/metadata/12345` (12345 being the metadata ID of the scene in Plex)
# Usage
Update your scenes in Stash like normal, and these scenes will be automatically refreshed in Plex. 🎉
# Warnings
- If you have the "clean titles" option enabled in plugin, all titles are processed with `unidecode`. Basically, all non-ASCII characters in your titles will be converted; Cyrillic script for example will be taken away.
- This plugin connects to your Plex via TLS, but it ignores cert errors. But this is not really a problem, as your Stash is most likely on the same host as your Plex...

1
plugins/PlexSync/TODO.md Normal file
View File

@@ -0,0 +1 @@
- Automatic support for getting/creating tag IDs. And/or have them more dynamically name-based.

View File

@@ -0,0 +1,3 @@
stashapp-tools
unidecode
requests