From 9866c98a1721fe8b074de7e34489a25562caf05e Mon Sep 17 00:00:00 2001 From: IAmKontrast <57725912+IAmKontrast@users.noreply.github.com> Date: Wed, 22 Mar 2023 19:36:09 +0100 Subject: [PATCH 1/2] [markerTagToScene] Translated from JS to PYTHON --- plugins/markerTagToScene/log.py | 52 +++++++ plugins/markerTagToScene/markerTagToScene.js | 81 ----------- plugins/markerTagToScene/markerTagToScene.py | 134 ++++++++++++++++++ plugins/markerTagToScene/markerTagToScene.yml | 8 +- 4 files changed, 190 insertions(+), 85 deletions(-) create mode 100644 plugins/markerTagToScene/log.py delete mode 100644 plugins/markerTagToScene/markerTagToScene.js create mode 100644 plugins/markerTagToScene/markerTagToScene.py diff --git a/plugins/markerTagToScene/log.py b/plugins/markerTagToScene/log.py new file mode 100644 index 00000000..f3812522 --- /dev/null +++ b/plugins/markerTagToScene/log.py @@ -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)) diff --git a/plugins/markerTagToScene/markerTagToScene.js b/plugins/markerTagToScene/markerTagToScene.js deleted file mode 100644 index 77ceecca..00000000 --- a/plugins/markerTagToScene/markerTagToScene.js +++ /dev/null @@ -1,81 +0,0 @@ -function ok() { - return { - output: "ok" - }; -} - -function main() { - var hookContext = input.Args.hookContext; - var opInput = hookContext.input; - var primaryTagID = opInput.primary_tag_id; - var sceneID = opInput.scene_id; - - // we can't currently find scene markers. If it's not in the input - // then just return - if (!primaryTagID || !sceneID) { - // just return - return ok(); - } - - // get the existing scene tags - var sceneTags = getSceneTags(sceneID); - var tagIDs = []; - for (var i = 0; i < sceneTags.length; ++i) { - var tagID = sceneTags[i].id; - if (tagID == primaryTagID) { - log.Debug("primary tag already exists on scene"); - return; - } - - tagIDs.push(tagID); - } - - // set the tag on the scene if not present - tagIDs.push(primaryTagID); - - setSceneTags(sceneID, tagIDs); - log.Info("added primary tag " + primaryTagID + " to scene " + sceneID); -} - -function getSceneTags(sceneID) { - var query = "\ -query findScene($id: ID) {\ - findScene(id: $id) {\ - tags {\ - id\ - }\ - }\ -}"; - - var variables = { - id: sceneID - }; - - var result = gql.Do(query, variables); - var findScene = result.findScene; - if (findScene) { - return findScene.tags; - } - - return []; -} - -function setSceneTags(sceneID, tagIDs) { - var mutation = "\ -mutation sceneUpdate($input: SceneUpdateInput!) {\ - sceneUpdate(input: $input) {\ - id\ - }\ -}"; - - var variables = { - input: { - id: sceneID, - tag_ids: tagIDs - } - }; - - gql.Do(mutation, variables); -} - -main(); \ No newline at end of file diff --git a/plugins/markerTagToScene/markerTagToScene.py b/plugins/markerTagToScene/markerTagToScene.py new file mode 100644 index 00000000..39968705 --- /dev/null +++ b/plugins/markerTagToScene/markerTagToScene.py @@ -0,0 +1,134 @@ +import json +import sys +import time +import requests +import log + +START_TIME = time.time() +FRAGMENT = json.loads(sys.stdin.read()) + +FRAGMENT_SERVER = FRAGMENT["server_connection"] +PLUGIN_DIR = FRAGMENT_SERVER["PluginDir"] + +def callGraphQL(query, variables=None): + # Session cookie for authentication + graphql_port = str(FRAGMENT_SERVER['Port']) + graphql_scheme = FRAGMENT_SERVER['Scheme'] + graphql_cookies = {'session': FRAGMENT_SERVER['SessionCookie']['Value']} + graphql_headers = { + "Accept-Encoding": "gzip, deflate, br", + "Content-Type": "application/json", + "Accept": "application/json", + "Connection": "keep-alive", + "DNT": "1" + } + graphql_domain = FRAGMENT_SERVER['Host'] + if graphql_domain == "0.0.0.0": + graphql_domain = "localhost" + # Stash GraphQL endpoint + graphql_url = f"{graphql_scheme}://{graphql_domain}:{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] Error with the graphql request {e}") + if response.status_code == 200: + result = response.json() + if result.get("error"): + for error in result["error"]["errors"]: + raise Exception(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 exit_plugin(msg=None, err=None): + if msg is None and err is None: + msg = "plugin ended" + log.LogDebug("Execution time: {}s".format(round(time.time() - START_TIME, 5))) + output_json = {"output": msg, "error": err} + print(json.dumps(output_json)) + sys.exit() + + + +def graphql_getSceneTags(sceneID): + query = """ + query FindScene($id:ID!) { + findScene(id: $id) { + tags { + id + } + } + } + """ + variables = { + "id": sceneID + } + result = callGraphQL(query, variables) + findScene = result.get('findScene') + if findScene.get('tags') is not None: + return findScene.get('tags') + + return [] + + + +def graphql_setSceneTags(sceneID, tagIDs: list): + query = """ + mutation SceneUpdate($input: SceneUpdateInput!) { + sceneUpdate(input: $input) { + id + } + } + """ + variables = { + "input": { + "id": sceneID, + "tag_ids": tagIDs + } + } + result = callGraphQL(query, variables) + return result + + + +def main(): + + CONTEXT = FRAGMENT['args']['hookContext']['input'] + + primaryTagID = CONTEXT['primary_tag_id'] + sceneID = CONTEXT['scene_id'] + + if not primaryTagID or not sceneID: + return + + sceneTags = graphql_getSceneTags(sceneID) + tagIDs = [] + + for sceneTags in sceneTags: + tagID = sceneTags['id']; + if tagID == primaryTagID: + log.LogDebug("Primary tag already exists on scene") + return + + tagIDs.append(tagID); + + # set the tag on the scene if not present + tagIDs.append(primaryTagID); + + graphql_setSceneTags(sceneID, tagIDs); + log.LogDebug("Added primary tag " + primaryTagID + " to scene " + sceneID) + + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/plugins/markerTagToScene/markerTagToScene.yml b/plugins/markerTagToScene/markerTagToScene.yml index 2dcb10e7..5330b4ad 100644 --- a/plugins/markerTagToScene/markerTagToScene.yml +++ b/plugins/markerTagToScene/markerTagToScene.yml @@ -1,11 +1,11 @@ -# example plugin config name: Scene Marker Tags to Scene description: Adds primary tag of Scene Marker to the Scene on marker create/update. url: https://github.com/stashapp/CommunityScripts -version: 1.0 +version: 2.0.0 exec: - - markerTagToScene.js -interface: js + - python + - "{pluginDir}/markerTagToScene.py" +interface: raw hooks: - name: Update scene with scene marker tag description: Adds primary tag of Scene Marker to the Scene on marker create/update. From d7855b2c4c83bc4046650e22a7faa585588bea83 Mon Sep 17 00:00:00 2001 From: IAmKontrast <57725912+IAmKontrast@users.noreply.github.com> Date: Wed, 22 Mar 2023 20:43:06 +0100 Subject: [PATCH 2/2] [markerTagToScene] Add all tags of Scene Marker to the Scene --- plugins/markerTagToScene/markerTagToScene.py | 39 +++++++++++-------- plugins/markerTagToScene/markerTagToScene.yml | 6 +-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/plugins/markerTagToScene/markerTagToScene.py b/plugins/markerTagToScene/markerTagToScene.py index 39968705..60ac2e14 100644 --- a/plugins/markerTagToScene/markerTagToScene.py +++ b/plugins/markerTagToScene/markerTagToScene.py @@ -4,6 +4,8 @@ import requests import log +ALL_TAGS = False + START_TIME = time.time() FRAGMENT = json.loads(sys.stdin.read()) @@ -104,29 +106,34 @@ def graphql_setSceneTags(sceneID, tagIDs: list): def main(): CONTEXT = FRAGMENT['args']['hookContext']['input'] - - primaryTagID = CONTEXT['primary_tag_id'] sceneID = CONTEXT['scene_id'] - - if not primaryTagID or not sceneID: + if not sceneID: return + + prevSceneTags = graphql_getSceneTags(sceneID) + prevSceneTagIDs = [] + for prevSceneTag in prevSceneTags: + prevSceneTagIDs.append(prevSceneTag['id']) - sceneTags = graphql_getSceneTags(sceneID) - tagIDs = [] + nextTagIDs = [] - for sceneTags in sceneTags: - tagID = sceneTags['id']; - if tagID == primaryTagID: - log.LogDebug("Primary tag already exists on scene") - return + # Primary tag + primaryTagID = CONTEXT['primary_tag_id'] + if primaryTagID is not None: + nextTagIDs = set(prevSceneTagIDs + [primaryTagID]) - tagIDs.append(tagID); + # All tags + if ALL_TAGS: + tagIDs = CONTEXT['tag_ids'] + if tagIDs is not None: + nextTagIDs = set(set(nextTagIDs) | set(prevSceneTagIDs) | set(tagIDs)) - # set the tag on the scene if not present - tagIDs.append(primaryTagID); + if len(prevSceneTagIDs) >= len(nextTagIDs): + log.LogDebug("No new tag added") + return - graphql_setSceneTags(sceneID, tagIDs); - log.LogDebug("Added primary tag " + primaryTagID + " to scene " + sceneID) + graphql_setSceneTags(sceneID, list(nextTagIDs)) + log.LogDebug("Added new tags to scene " + sceneID) diff --git a/plugins/markerTagToScene/markerTagToScene.yml b/plugins/markerTagToScene/markerTagToScene.yml index 5330b4ad..bc4b9a1e 100644 --- a/plugins/markerTagToScene/markerTagToScene.yml +++ b/plugins/markerTagToScene/markerTagToScene.yml @@ -1,14 +1,14 @@ name: Scene Marker Tags to Scene -description: Adds primary tag of Scene Marker to the Scene on marker create/update. +description: Adds primary tag and opt-in all tags of Scene Marker to the Scene on marker create/update. url: https://github.com/stashapp/CommunityScripts -version: 2.0.0 +version: 2.1.0 exec: - python - "{pluginDir}/markerTagToScene.py" interface: raw hooks: - name: Update scene with scene marker tag - description: Adds primary tag of Scene Marker to the Scene on marker create/update. + description: Adds primary tag and opt-in all tags of Scene Marker to the Scene on marker create/update. triggeredBy: - SceneMarker.Create.Post - SceneMarker.Update.Post