update Set Scene Cover to use stashapp-tools

issue 110 addressed within stashapp-tools flag
This commit is contained in:
stg-annon
2023-10-20 10:33:45 -04:00
parent 3f9bc24bde
commit e96c711a53
4 changed files with 27 additions and 208 deletions

View File

@@ -1,52 +0,0 @@
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 trace(s):
__log(b't', s)
def debug(s):
__log(b'd', s)
def info(s):
__log(b'i', s)
def warning(s):
__log(b'w', s)
def error(s):
__log(b'e', s)
def progress(p):
progress = min(max(0, p), 1)
__log(b'p', str(progress))

View File

@@ -4,8 +4,13 @@ import sys
import json
import base64
import log
from stash_interface import StashInterface
try:
import stashapi.log as log
from stashapi.tools import file_to_base64
from stashapi.stashapp import StashInterface
except ModuleNotFoundError:
print("You need to install the stashapi module. (pip install stashapp-tools)",
file=sys.stderr)
MANUAL_ROOT = None # /some/other/path to override scanning all stashes
cover_pattern = r'(?:thumb|poster|cover)\.(?:jpg|png)'
@@ -21,7 +26,7 @@ def main():
if MANUAL_ROOT:
scan(MANUAL_ROOT, handle_cover)
else:
for stash_path in stash.get_root_paths():
for stash_path in get_stash_paths():
scan(stash_path, handle_cover)
except Exception as e:
log.error(e)
@@ -34,30 +39,32 @@ def handle_cover(path, file):
filepath = os.path.join(path, file)
with open(filepath, "rb") as img:
b64img_bytes = base64.b64encode(img.read())
if not b64img_bytes:
b64img = file_to_base64(filepath)
if not b64img:
log.warning(f"Could not parse {filepath} to b64image")
return
b64img = f"data:image/jpeg;base64,{b64img_bytes.decode('utf-8')}"
scene_ids = stash.get_scenes_id(filter={
scenes = stash.find_scenes(f={
"path": {
"modifier": "INCLUDES",
"value": f"{path}\""
}
})
}, fragment="id")
log.info(f'Found Cover: {[int(s) for s in scene_ids]}|{filepath}')
log.info(f'Found Cover: {[int(s["id"]) for s in scenes]}|{filepath}')
if mode_arg == "set_cover":
for scene_id in scene_ids:
for scene in scenes:
stash.update_scene({
"id": scene_id,
"id": scene["id"],
"cover_image": b64img
})
log.info(f'Applied cover Scenes')
log.info(f'Applied cover to {len(scenes)} scenes')
def get_stash_paths():
config = stash.get_configuration("general { stashes { path excludeVideo } }")
stashes = config["configuration"]["general"]["stashes"]
return [s["path"] for s in stashes if not s["excludeVideo"]]
def scan(ROOT_PATH, _callback):
log.info(f'Scanning {ROOT_PATH}')
@@ -66,4 +73,5 @@ def scan(ROOT_PATH, _callback):
if re.match(cover_pattern, file, re.IGNORECASE):
_callback(root, file)
main()
if __name__ == '__main__':
main()

View File

@@ -1,6 +1,6 @@
name: Set Scene Cover
description: Searchs Stash for Scenes with a cover image in the same folder and sets the cover image in stash to that image
version: 0.3
description: searches Stash for Scenes with a cover image in the same folder and sets the cover image in stash to that image
version: 0.4
url: https://github.com/stg-annon/CommunityScripts/tree/main/plugins/setSceneCoverFromFile
exec:
- python
@@ -8,7 +8,7 @@ exec:
interface: raw
tasks:
- name: Scan
description: searchs stash dirs for cover images and logs results
description: searches stash dirs for cover images and logs results
defaultArgs:
mode: scan
- name: Set Cover

View File

@@ -1,137 +0,0 @@
import requests
import sys
import re
import log
class StashInterface:
port = ""
url = ""
headers = {
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/json",
"Accept": "application/json",
"Connection": "keep-alive",
"DNT": "1"
}
cookies = {}
def __init__(self, conn, fragments={}):
self.port = conn['Port']
scheme = conn['Scheme']
# Session cookie for authentication
self.cookies = {
'session': conn.get('SessionCookie').get('Value')
}
domain = conn.get('Domain') if conn.get('Domain') else 'localhost'
# Stash GraphQL endpoint
self.url = scheme + "://" + domain + ":" + str(self.port) + "/graphql"
log.debug(f"Using stash GraphQl endpoint at {self.url}")
self.fragments = fragments
self.fragments.update(stash_gql_fragments)
def __resolveFragments(self, query):
fragmentRefrences = list(set(re.findall(r'(?<=\.\.\.)\w+', query)))
fragments = []
for ref in fragmentRefrences:
fragments.append({
"fragment": ref,
"defined": bool(re.search("fragment {}".format(ref), query))
})
if all([f["defined"] for f in fragments]):
return query
else:
for fragment in [f["fragment"] for f in fragments if not f["defined"]]:
if fragment not in self.fragments:
raise Exception(f'GraphQL error: fragment "{fragment}" not defined')
query += self.fragments[fragment]
return self.__resolveFragments(query)
def __callGraphQL(self, query, variables=None):
query = self.__resolveFragments(query)
json = {'query': query}
if variables is not None:
json['variables'] = variables
response = requests.post(self.url, json=json, headers=self.headers, cookies=self.cookies)
if response.status_code == 200:
result = response.json()
if result.get("error", None):
for error in result["error"]["errors"]:
raise Exception("GraphQL error: {}".format(error))
if result.get("data", None):
return result.get("data")
elif response.status_code == 401:
sys.exit("HTTP Error 401, Unauthorised. Cookie authentication most likely failed")
else:
raise ConnectionError(
"GraphQL query failed:{} - {}. Query: {}. Variables: {}".format(
response.status_code, response.content, query, variables)
)
def get_scenes_id(self, filter={}):
query = """
query FindScenes($filter: FindFilterType, $scene_filter: SceneFilterType, $scene_ids: [Int!]) {
findScenes(filter: $filter, scene_filter: $scene_filter, scene_ids: $scene_ids) {
count
scenes {
id
}
}
}
"""
variables = {
"filter": { "per_page": -1 },
"scene_filter": filter
}
result = self.__callGraphQL(query, variables)
scene_ids = [s["id"] for s in result.get('findScenes').get('scenes')]
return scene_ids
def update_scene(self, scene_data):
query = """
mutation SceneUpdate($input:SceneUpdateInput!) {
sceneUpdate(input: $input) {
id
}
}
"""
variables = {'input': scene_data}
result = self.__callGraphQL(query, variables)
return result["sceneUpdate"]["id"]
def get_root_paths(self):
query = """
query Configuration {
configuration {
general{
stashes{
path
excludeVideo
}
}
}
}
"""
result = self.__callGraphQL(query)
stashes = result["configuration"]["general"]["stashes"]
paths = [s["path"] for s in stashes if not s["excludeVideo"]]
return paths
stash_gql_fragments = {}