mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2026-05-04 06:00:41 -05:00
[plugin] Add titleFromFilename plugin (#81)
This commit is contained in:
22
plugins/titleFromFilename/README.md
Normal file
22
plugins/titleFromFilename/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
# titleFromFilename
|
||||
Sets a scene's title
|
||||
|
||||
## Requirements
|
||||
- Stash ( versions after the files refactor PR, API>31 )
|
||||
- Python 3.10
|
||||
- Requests Module (https://pypi.org/project/requests/)
|
||||
|
||||
## Installation
|
||||
|
||||
- Download the whole folder `titleFromFilename`
|
||||
- Place it in your **plugins** folder (where the `config.yml` is). If its not there create it
|
||||
- Reload plugins from stash (Settings > Plugins -> Reload Plugins)
|
||||
- titleFromFilename should appear
|
||||
|
||||
## Usage
|
||||
When a scene is created the plugin will set the title to the filename.
|
||||
By default the file extension will not be added to the title.
|
||||
If you want to keep the file extension open `config.py` file and change `STRIP_EXT = True` to `STRIP_EXT = False`
|
||||
|
||||
|
||||
2
plugins/titleFromFilename/config.py
Normal file
2
plugins/titleFromFilename/config.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# strip file extension from title
|
||||
STRIP_EXT = True
|
||||
90
plugins/titleFromFilename/graphql.py
Normal file
90
plugins/titleFromFilename/graphql.py
Normal file
@@ -0,0 +1,90 @@
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
def doRequest(query, variables=None, port=9999, session=None, scheme="http", raise_exception=True):
|
||||
# Session cookie for authentication
|
||||
graphql_port = port
|
||||
graphql_scheme = scheme
|
||||
graphql_cookies = {
|
||||
'session': session
|
||||
}
|
||||
|
||||
graphql_headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"Connection": "keep-alive",
|
||||
"DNT": "1"
|
||||
}
|
||||
graphql_domain = 'localhost'
|
||||
# Stash GraphQL endpoint
|
||||
graphql_url = graphql_scheme + "://" + graphql_domain + ":" + str(graphql_port) + "/graphql"
|
||||
|
||||
json = {'query': query}
|
||||
if variables is not None:
|
||||
json['variables'] = variables
|
||||
try:
|
||||
response = requests.post(graphql_url, json=json,headers=graphql_headers, cookies=graphql_cookies, timeout=20)
|
||||
except Exception as e:
|
||||
exit_plugin(err="f[FATAL] Exception with GraphQL request. {e}")
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("error"):
|
||||
for error in result["error"]["errors"]:
|
||||
if raise_exception:
|
||||
raise Exception(f"GraphQL error: {error}")
|
||||
else:
|
||||
log.LogError(f"GraphQL error: {error}")
|
||||
return None
|
||||
if result.get("data"):
|
||||
return result.get("data")
|
||||
elif response.status_code == 401:
|
||||
exit_plugin(err="HTTP Error 401, Unauthorised.")
|
||||
else:
|
||||
raise ConnectionError(f"GraphQL query failed: {response.status_code} - {response.content}")
|
||||
|
||||
def update_scene_title(scene_id, scene_title, port, session, scheme):
|
||||
query = """
|
||||
mutation UpdateSceneTitle($id: ID!, $title: String) {
|
||||
sceneUpdate(
|
||||
input: {id: $id, title: $title}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
"""
|
||||
variables = {
|
||||
"id": scene_id,
|
||||
"title": scene_title
|
||||
}
|
||||
result = doRequest(query=query, variables=variables, port=port, session=session, scheme=scheme)
|
||||
return result.get('sceneUpdate')
|
||||
|
||||
def get_scene_base(scene_id, port, session, scheme):
|
||||
query = """
|
||||
query FindScene($id: ID!, $checksum: String) {
|
||||
findScene(id: $id, checksum: $checksum) {
|
||||
files {
|
||||
basename
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
variables = {
|
||||
"id": scene_id
|
||||
}
|
||||
result = doRequest(query=query, variables=variables, port=port, session=session, scheme=scheme)
|
||||
return result.get('findScene')
|
||||
|
||||
def get_api_version(port, session, scheme):
|
||||
query = """
|
||||
query SystemStatus {
|
||||
systemStatus {
|
||||
databaseSchema
|
||||
appSchema
|
||||
}
|
||||
}
|
||||
"""
|
||||
result = doRequest(query=query, port=port, session=session, scheme=scheme)
|
||||
return result.get('systemStatus')
|
||||
52
plugins/titleFromFilename/log.py
Normal file
52
plugins/titleFromFilename/log.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import sys
|
||||
|
||||
|
||||
# Log messages sent from a plugin instance are transmitted via stderr and are
|
||||
# encoded with a prefix consisting of special character SOH, then the log
|
||||
# level (one of t, d, i, w, e, or p - corresponding to trace, debug, info,
|
||||
# warning, error and progress levels respectively), then special character
|
||||
# STX.
|
||||
#
|
||||
# The LogTrace, LogDebug, LogInfo, LogWarning, and LogError methods, and their equivalent
|
||||
# formatted methods are intended for use by plugin instances to transmit log
|
||||
# messages. The LogProgress method is also intended for sending progress data.
|
||||
#
|
||||
|
||||
def __prefix(level_char):
|
||||
start_level_char = b'\x01'
|
||||
end_level_char = b'\x02'
|
||||
|
||||
ret = start_level_char + level_char + end_level_char
|
||||
return ret.decode()
|
||||
|
||||
|
||||
def __log(level_char, s):
|
||||
if level_char == "":
|
||||
return
|
||||
|
||||
print(__prefix(level_char) + s + "\n", file=sys.stderr, flush=True)
|
||||
|
||||
|
||||
def LogTrace(s):
|
||||
__log(b't', s)
|
||||
|
||||
|
||||
def LogDebug(s):
|
||||
__log(b'd', s)
|
||||
|
||||
|
||||
def LogInfo(s):
|
||||
__log(b'i', s)
|
||||
|
||||
|
||||
def LogWarning(s):
|
||||
__log(b'w', s)
|
||||
|
||||
|
||||
def LogError(s):
|
||||
__log(b'e', s)
|
||||
|
||||
|
||||
def LogProgress(p):
|
||||
progress = min(max(0, p), 1)
|
||||
__log(b'p', str(progress))
|
||||
1
plugins/titleFromFilename/requirements.txt
Normal file
1
plugins/titleFromFilename/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
requests
|
||||
54
plugins/titleFromFilename/titleFromFilename.py
Normal file
54
plugins/titleFromFilename/titleFromFilename.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
import config
|
||||
import log
|
||||
import graphql
|
||||
|
||||
API_VERSION_BF_FILES = 31 # APP/DB Schema version prior to files refactor PR
|
||||
|
||||
def exit_plugin(msg=None, err=None):
|
||||
if msg is None and err is None:
|
||||
msg = "plugin ended"
|
||||
output_json = {"output": msg, "error": err}
|
||||
print(json.dumps(output_json))
|
||||
sys.exit()
|
||||
|
||||
FRAGMENT = json.loads(sys.stdin.read())
|
||||
#log.LogDebug(json.dumps(FRAGMENT))
|
||||
FRAGMENT_SERVER = FRAGMENT["server_connection"]
|
||||
FRAGMENT_SCENE_ID = FRAGMENT["args"].get("hookContext")
|
||||
|
||||
if FRAGMENT_SCENE_ID:
|
||||
scene_id = FRAGMENT_SCENE_ID["id"]
|
||||
else:
|
||||
exit_plugin("No ID found")
|
||||
|
||||
|
||||
graphql_port = FRAGMENT_SERVER['Port']
|
||||
graphql_scheme = FRAGMENT_SERVER['Scheme']
|
||||
graphql_session = FRAGMENT_SERVER.get('SessionCookie').get('Value')
|
||||
|
||||
system_status = graphql.get_api_version(port=graphql_port, session=graphql_session, scheme=graphql_scheme)
|
||||
|
||||
api_version = system_status.get("appSchema")
|
||||
|
||||
basename = None
|
||||
|
||||
if api_version > API_VERSION_BF_FILES: # only needed for versions after files refactor
|
||||
files_base = graphql.get_scene_base(scene_id=scene_id, port=graphql_port, session=graphql_session, scheme=graphql_scheme)
|
||||
if len(files_base["files"]) > 0:
|
||||
basename = files_base["files"][0].get("basename")
|
||||
else:
|
||||
exit_plugin(f"Stash with API version:{api_version} is not supported. You need at least {API_VERSION_BF_FILES}")
|
||||
|
||||
if basename is None:
|
||||
exit_plugin("No basename found") # file-less scene
|
||||
|
||||
if config.STRIP_EXT:
|
||||
basename = os.path.splitext(basename)[0]
|
||||
|
||||
updated_scene = graphql.update_scene_title(scene_id, basename, port=graphql_port, session=graphql_session, scheme=graphql_scheme)
|
||||
|
||||
exit_plugin(f"Scene title updated. Title:{updated_scene.get('title')}")
|
||||
13
plugins/titleFromFilename/titleFromFilename.yml
Normal file
13
plugins/titleFromFilename/titleFromFilename.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: titleFromFilename
|
||||
description: Set a scene's title from it's filename
|
||||
url: https://github.com/stashapp/CommunityScripts
|
||||
version: 1.0
|
||||
exec:
|
||||
- python
|
||||
- "{pluginDir}/titleFromFilename.py"
|
||||
interface: raw
|
||||
hooks:
|
||||
- name: hook_set_title_from_filename
|
||||
description: Set the title of the scene to it's filename
|
||||
triggeredBy:
|
||||
- Scene.Create.Post
|
||||
Reference in New Issue
Block a user