This commit is contained in:
skier233
2024-06-13 21:17:29 -04:00
13 changed files with 253 additions and 399 deletions

View File

@@ -1,6 +1,6 @@
name: VideoScrollWheel
# requires: CommunityScriptsUILibrary
description: Adds functionality to change volume/time in scene video player by hovering over left/right side of player and scrolling with mouse scrollwheel. Scroll while hovering on left side to adjust volume, scroll on right side to skip forward/back.
#requires: CommunityScriptsUILibrary
version: 0.2
settings:
allowVolumeChange:

View File

@@ -19,7 +19,7 @@ function ok() {
function main() {
var hookContext = input.Args.hookContext;
var type = hookContext.type;
var ID = hookContext.ID;
var ID = hookContext.id;
if (!type || !ID) {
// just return
@@ -183,7 +183,11 @@ function getImagePath(ID) {
"\
query findImage($id: ID) {\
findImage(id: $id) {\
path\
visual_files {\
... on ImageFile {\
path\
}\
}\
}\
}";
@@ -197,7 +201,7 @@ query findImage($id: ID) {\
return null;
}
var path = findImage.path;
var path = findImage["visual_files"][0].path;
return path;
}
@@ -241,7 +245,7 @@ function getTagId(tagName) {
},
};
result = gql.Do(query, variables);
var result = gql.Do(query, variables);
if (result.findTags.tags[0]) {
return result.findTags.tags[0].id;
} else {
@@ -267,7 +271,7 @@ function getPerformerId(performerName) {
},
};
result = gql.Do(query, variables);
var result = gql.Do(query, variables);
if (result.findPerformers.performers[0]) {
return result.findPerformers.performers[0].id;
} else {
@@ -293,7 +297,7 @@ function getStudioId(studioName) {
},
};
result = gql.Do(query, variables);
var result = gql.Do(query, variables);
if (result.findStudios.studios[0]) {
return result.findStudios.studios[0].id;
} else {

View File

@@ -1,7 +1,7 @@
name: Discord Presence
description: Sets currently playing scene data as your Discord status. See README for prerequisites and config options (blue hyperlink next to enable/disable button)
url: https://github.com/stashapp/CommunityScripts/tree/main/plugins/discordPresence
#requires: CommunityScriptsUILibrary
# requires: CommunityScriptsUILibrary
version: 1.0
settings:
discordClientId:

View File

@@ -4,28 +4,139 @@ function ok() {
};
}
function main() {
var hookContext = input.Args.hookContext;
var opInput = hookContext.Input;
var primaryTagID = opInput.PrimaryTagID;
var sceneID = opInput.SceneID;
function includes(haystack, needle) {
for (var i = 0; i < haystack.length; ++i) {
if (haystack[i] == needle) return true;
}
return false;
}
function mapSceneTagsToIds(sceneTags) {
var ret = [];
for (var i = 0; i < sceneTags.length; ++i) {
ret.push(sceneTags[i].id);
}
return ret;
}
function shouldHandleAllTags() {
var query =
"query Query {\
configuration {\
plugins\
}\
}";
var result = gql.Do(query);
//log.Info("Config is " + JSON.stringify(result.configuration));
if (!result.configuration) {
throw "Unable to get library paths";
}
if (result.configuration.plugins.hasOwnProperty("markerTagToScene")) {
//log.Info("allTags is " + result.configuration.plugins.markerTagToScene.allTags);
return !!result.configuration.plugins.markerTagToScene.allTags;
} else {
//log.Info("all tags wasn't found. defaulting to false");
return false;
}
}
function processMarker(marker, shouldHandleAllTags) {
log.Debug("processMarker (allTags = " + shouldHandleAllTags + ") " + marker);
var primaryTagID = marker.primary_tag_id;
var sceneID = marker.scene_id;
var tagIDsToCheck = [];
if (primaryTagID != null) tagIDsToCheck.push(primaryTagID);
if (shouldHandleAllTags && marker.tag_ids != null)
tagIDsToCheck = tagIDsToCheck.concat(marker.tag_ids);
// we can't currently find scene markers. If it's not in the input
// then just return
if (!primaryTagID || !sceneID) {
if (tagIDsToCheck.length == 0) {
// just return
return ok();
}
// get the existing scene tags
var sceneTags = getSceneTags(sceneID);
var sceneTags = mapSceneTagsToIds(getSceneTags(sceneID));
var newTags = [];
for (var i = 0; i < tagIDsToCheck.length; ++i) {
var tag = tagIDsToCheck[i];
if (!includes(sceneTags, tag)) newTags.push(tag);
}
// Combine all tags from scene and the new marker
var allTags = [...new Set([...sceneTags, primaryTagID, ...opInput.TagIds])];
var newTags = allTags.filter((t) => sceneTags.includes(t));
if (newTags.length == 0) {
// All tags were present; don't do anything
log.Debug("All tags were already present on scene " + sceneID);
return ok();
}
var tagIDs = sceneTags.concat(newTags);
setSceneTags(sceneID, tagIDs);
log.Info("adding tags " + newTags + " to scene " + sceneID);
}
setSceneTags(sceneID, allTags);
log.Debug("added new tags " + newTags.join(", ") + " to scene " + sceneID);
function main() {
log.Info(JSON.stringify(input));
if (input.Args.mode == "processMarkers") {
var allTags = shouldHandleAllTags();
log.Trace("Mode is processMarkers, allTags is " + allTags);
var allMarkers = getAllMarkers();
//The markers come back as {primary_tag: { id: 600 } }
//but processMarker (because of the hook) expects 'primary_tag_id', so transform it here
log.Info(
"markerTagToScene has " + allMarkers.length + " markers to process"
);
for (var i = 0; i < allMarkers.length; ++i) {
var marker = allMarkers[i];
var sceneMarker = {};
sceneMarker.id = marker.id;
sceneMarker.scene_id = marker.scene.id;
sceneMarker.primary_tag_id = marker.primary_tag.id;
var tag_ids = [];
for (var j = 0; j < marker.tags.length; ++j) {
tag_ids.push(marker.tags[j].id);
}
sceneMarker.tag_ids = tag_ids;
//log.Info(sceneMarker);
processMarker(sceneMarker, allTags);
log.Progress(i / allMarkers.length);
}
log.Progress("Finished processing markers");
} else if (input.Args.mode == "hook") {
log.Info("Mode is hook");
processMarker(input.Args.hookContext.input, shouldHandleAllTags());
} else {
log.Error("Unknown mode");
}
}
function getAllMarkers() {
var query =
"\
query Query($filter: FindFilterType) {\
findSceneMarkers (filter: $filter) {\
scene_markers {\
id,\
primary_tag {\
id\
}\
tags {\
id\
}\
scene {\
id\
}\
}\
}\
}";
var variables = { filter: { per_page: -1 } };
var result = gql.Do(query, variables);
var findSceneMarkers = result.findSceneMarkers;
if (findSceneMarkers) {
return findSceneMarkers.scene_markers;
}
}
function getSceneTags(sceneID) {
@@ -46,7 +157,7 @@ query findScene($id: ID) {\
var result = gql.Do(query, variables);
var findScene = result.findScene;
if (findScene) {
return findScene.tags.map((t) => t.id);
return findScene.tags;
}
return [];

View File

@@ -6,9 +6,21 @@ version: 1.0
exec:
- markerTagToScene.js
interface: js
settings:
allTags:
displayName: All Tags
description: Add all scene tags instead of just the primary scene tag.
type: BOOLEAN
hooks:
- name: Update scene with scene marker tag
description: Adds primary tag of Scene Marker to the Scene on marker create/update.
triggeredBy:
- SceneMarker.Create.Post
- SceneMarker.Update.Post
defaultArgs:
mode: hook
tasks:
- name: Process all markers
description: Add tags from all markers to scenes
defaultArgs:
mode: processMarkers

View File

@@ -9,7 +9,16 @@ per_page = 100
skip_tag = "[MiscTags: Skip]"
# Defaults if nothing has changed in the stash ui
settings = {"addStashVrCompanionTags": False, "addVrTags": False,"addVSoloTags": True,"addVThreesomeTags":True, "flatStudio": ""}
settings = {"addStashVrCompanionTags": False,
"addVRTags": False,
"addSoloTags": True,
"addThreesomeTags": True,
"addFoursomeTags": True,
"addFivesomeTags": True,
"addSixsomeTags": True,
"addSevensomeTags": True,
"assumeMissingMale": True,
"flatStudio": ""}
VRCTags = {
"flat": {"VRCTags": ["FLAT"], "projTags": []},
@@ -20,7 +29,7 @@ VRCTags = {
"180_lr": {"VRCTags": ["DOME", "SBS"], "projTags": ["180°"]},
"180_3dh_lr": {"VRCTags": ["DOME", "SBS"], "projTags": ["180°"]},
"360_tb": {"VRCTags": ["SPHERE", "TB"], "projTags": ["360°"]},
"mkx200": {"VRCTags": ["MKX200", "FISHEYE", "SBS"], "projTags": ["22"]},
"mkx200": {"VRCTags": ["MKX200", "FISHEYE", "SBS"], "projTags": ["20"]},
"mkx220": {"VRCTags": ["MKX220", "FISHEYE", "SBS"], "projTags": ["220°"]},
"vrca220": {"VRCTags": ["VRCA220", "FISHEYE", "SBS"], "projTags": ["220°"]},
"rf52": {"VRCTags": ["RF52", "FISHEYE", "SBS"], "projTags": ["190°"]},
@@ -32,6 +41,7 @@ VRCTags = {
"5k": {"VRCTags": [], "projTags": ["5K"]},
}
tags_cache = {}
performer_cache = {}
def processScene(scene):
@@ -45,12 +55,21 @@ def processScene(scene):
if settings["addStashVrCompanionTags"]:
processStashVRCompanionTags(scene, tags)
log.debug(tags)
if settings["addVrTags"]:
if settings["addVRTags"]:
processVRTags(scene, tags)
if settings["addVSoloTags"]:
soloTag(scene,tags)
if settings["addVThreesomeTags"]:
threesomeTag(scene, tags)
if settings["addSoloTags"]:
soloTag(scene, tags)
if settings["addThreesomeTags"]:
processGroupMakeup(['threesome'], 'Threesome', 3, scene, tags)
if settings["addFoursomeTags"]:
processGroupMakeup(['foursome', '4some'], 'Foursome', 4, scene, tags)
if settings["addFivesomeTags"]:
processGroupMakeup(['fivesome', 'fiveway'], 'Fivesome', 5, scene, tags)
if settings["addSixsomeTags"]:
processGroupMakeup(['sixsome'], 'Sixsome', 6, scene, tags)
if settings["addSevensomeTags"]:
processGroupMakeup(['sevensome'], 'Sevensome', 7, scene, tags)
if len(settings["flatStudio"]) > 0:
processFlatStudio(scene, tags)
if len(tags) > 0:
@@ -135,58 +154,69 @@ def processFlatStudio(scene, tags):
def soloTag(scene,tags):
"""Add Solo Female, Solo male, Solo Trans where there is a single performer and the solo tag"""
for name in ['solo', 'solo model','solo models']:
for name in ['solo', 'solo model', 'solo models']:
if name in [x["name"].lower() for x in scene['tags']]:
if len(scene['performers']) ==1:
p=stash.find_performer(scene['performers'][0])
if p['gender']=='FEMALE':
if len(scene['performers']) == 1:
p=getPerformer(scene['performers'][0])
if p['gender'] == 'FEMALE':
tags.append('Solo Female')
elif p['gender'] == 'MALE':
tags.append('Solo Male')
elif p['gender'] =='TRANSGENDER_MALE':
elif p['gender'] == 'TRANSGENDER_MALE':
tags.append('Solo Trans')
elif p['gender'] =='TRANSGENDER_FEMALE':
elif p['gender'] == 'TRANSGENDER_FEMALE':
tags.append('Solo Trans')
def threesomeTag(scene, tags):
"""Add Threesome (XXX) tags based on group makeup"""
for name in ['threesome']:
def getPerformer(p):
if p['id'] not in performer_cache:
p2 = stash.find_performer(p)
performer_cache[p['id']] = p2
log.debug(performer_cache)
return p2
return performer_cache[p]
def processGroupMakeup(tag_strings, makeup_label, count, scene, tags):
for name in tag_strings:
if name in [x["name"].lower() for x in scene['tags']]:
if len(scene['performers']) == 3:
makeup=[]
for p in scene['performers']:
p2=stash.find_performer(p)
makeup.append(p2['gender'])
makeup = []
for p in scene['performers']:
p2 = getPerformer(p)
if p2['gender'] == 'FEMALE':
makeup.append('G')
elif p2['gender'] == 'MALE':
makeup.append('B')
elif p2['gender'] == 'TRANSGENDER_FEMALE':
makeup.append('T')
elif p2['gender'] == 'TRANSGENDER_MALE':
makeup.append('T')
elif p2['gender'] == 'INTERSEX':
makeup.append('I')
elif p2['gender'] == 'NON_BINARY':
makeup.append('I')
else:
makeup.append('U')
# unknown or not set yet
#
if settings["assumeMissingMale"]:
# If there is a mising performer
for x in range(len(makeup), count):
makeup.append('B')
if len(makeup) == count:
makeup.sort()
log.debug(makeup)
if makeup[0]=='FEMALE' and makeup[1]=='FEMALE' and makeup[2]=='FEMALE':
tags.append('Threesome (Lesbian)')
elif makeup[0]=='FEMALE' and makeup[1]=='FEMALE' and makeup[2]=='MALE':
tags.append('Threesome (BGG)')
elif makeup[0]=='FEMALE' and makeup[1]=='MALE' and makeup[2]=='MALE':
tags.append('Threesome (BBG)')
elif makeup[0]=='FEMALE' and makeup[1]=='FEMALE' and ( makeup[2]=='TRANSGENDER_FEMALE' or makeup[2]=='TRANSGENDER_MALE'):
tags.append('Threesome (GGT)')
elif makeup[0]=='FEMALE' and ( makeup[1]=='TRANSGENDER_FEMALE' or makeup[1]=='TRANSGENDER_MALE') and ( makeup[2]=='TRANSGENDER_FEMALE' or makeup[2]=='TRANSGENDER_MALE'):
tags.append('Threesome (GTT)')
elif makeup[0]=='FEMALE' and makeup[1]=='MALE' and ( makeup[2]=='TRANSGENDER_FEMALE' or makeup[2]=='TRANSGENDER_MALE'):
tags.append('Threesome (BGT)')
elif makeup[0]=='MALE' and makeup[1]=='MALE' and makeup[2]=='MALE':
tags.append('Threesome (Gay)')
elif makeup[0]=='MALE' and makeup[1]=='MALE' and ( makeup[2]=='TRANSGENDER_FEMALE' or makeup[2]=='TRANSGENDER_MALE'):
tags.append('Threesome (BBT)')
elif makeup[0]=='MALE' and ( makeup[1]=='TRANSGENDER_FEMALE' or makeup[1]=='TRANSGENDER_MALE') and ( makeup[2]=='TRANSGENDER_FEMALE' or makeup[2]=='TRANSGENDER_MALE'):
tags.append('Threesome (BTT)')
elif ( makeup[0]=='TRANSGENDER_FEMALE' or makeup[0]=='TRANSGENDER_MALE') and ( makeup[1]=='TRANSGENDER_FEMALE' or makeup[1]=='TRANSGENDER_MALE') and ( makeup[2]=='TRANSGENDER_FEMALE' or makeup[2]=='TRANSGENDER_MALE'):
tags.append('Threesome (Trans)')
makeup_str = ''.join(makeup)
if makeup_str == ('G' * count):
tags.append('%s (Lesbian)' % (makeup_label, ))
elif makeup_str == ('B' * count):
tags.append('%s (Gay)' % (makeup_label, ))
elif makeup_str == ('G' * count):
tags.append('%s (Lesbian)' % (makeup_label, ))
else:
tags.append('%s (%s)' % (makeup_label, makeup_str, ) )
else:
log.debug('missing performers for group makeup %s, have %s performers instead' % (makeup_label, len(makeup), ))
def processScenes():

View File

@@ -1,6 +1,6 @@
name: Misc Tags
description: Add extra tags for VR and other ues
version: 0.3
version: 0.4
url: https://github.com/stashapp/CommunityScripts/
exec:
- python
@@ -15,14 +15,34 @@ settings:
displayName: Add VR related tags
description: Add projection based tags 180°, 200°, VR
type: BOOLEAN
addVSoloTags:
addSoloTags:
displayName: Add solo tags
description: if there is the "solo" tag and 1 performer add the "Solo Female" tag
type: BOOLEAN
addVThreesomeTags:
displayName: Add threesome tags
addThreesomeTags:
displayName: Add threesome (xxx)
description: if there is the "threesome" tag with 3 tagged performers add a group makeup tag eg Threesome (BGG)
type: BOOLEAN
addFoursomeTags:
displayName: Add Foursome (XXXX)
description: if there is the "foursome" tag with 4 tagged performers add a group makeup tag eg Threesome (BGG)
type: BOOLEAN
addFivesomeTags:
displayName: Add Fivesome (xxxxx) tags
description: if there is the "fivesome" tag with 5 tagged performers add a group makeup tag eg Threesome (BGG)
type: BOOLEAN
addSixsomeTags:
displayName: Add Sixsome (XXXXXX)
description: if there is the "sixsome" tag with 6 tagged performers add a group makeup tag eg Threesome (BGG)
type: BOOLEAN
addSevensomeTags:
displayName: Add Sevensome (XXXXXXX)
description: if there is the "sevensome" tag with 7 tagged performers add a group makeup tag eg Threesome (BGG)
type: BOOLEAN
assumeMissingMale:
displayName: Assume missing male performer
description: For the group makeup tag assume the missing performer is male if there are unknown performers
type: BOOLEAN
flatStudio:
displayName: 2d Studio for stash-vr-companion

View File

@@ -1,5 +1,5 @@
name: Extended Stats
#requires: CommunityScriptsUILibrary
# requires: CommunityScriptsUILibrary
description: Adds new stats to the stats page
version: 1.1
ui:

View File

@@ -1,30 +0,0 @@
# Tag Graph Generator
## Requirements
* python >= 3.7.X
* `pip install -r requirements.txt`
---
## Usage
### Running as a plugin
move the `tagGraph` directory into Stash's plugins directory, reload plugins and you can run the **Generate Graph** task
### Running as a script
> **⚠️ Note:** use this if you are connecting to a remote instance of stash
ensure `STASH_SETTINGS` is configured properly, you will likely need to change it
run `python .\tag_graph.py -script`
### View graph
a `tag_graph.html` file will be generated inside the tagGraph directory, open it with a browser to view/interact with the graph
---
## Customizing the graph
set `SHOW_OPTIONS` to `True` and you will get an interface to play around with that will affect what the graph looks like.
for more info see [pyvis docs](https://pyvis.readthedocs.io/en/latest/tutorial.html#using-the-configuration-ui-to-dynamically-tweak-network-settings)

View File

@@ -1,7 +0,0 @@
STASH_SETTINGS = {
"Scheme": "http",
"Domain": "localhost",
"Port": "9999",
"ApiKey": "YOUR_API_KEY_HERE",
}
SHOW_OPTIONS = False

View File

@@ -1,2 +0,0 @@
pyvis==0.1.9
requests==2.25.1

View File

@@ -1,272 +0,0 @@
import os, re, sys, copy, json, requests
# local dependencies
import config
# external dependencies
from pyvis.network import Network
class StashLogger:
# Log messages sent from a script scraper 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 or e - corresponding to trace, debug, info,
# warning and error levels respectively), then special character
# STX.
#
# The log.trace, log.debug, log.info, log.warning, and log.error methods, and their equivalent
# formatted methods are intended for use by script scraper instances to transmit log
# messages.
#
def __log(self, level_char: bytes, s):
if level_char:
lvl_char = "\x01{}\x02".format(level_char.decode())
s = re.sub(r"data:image.+?;base64(.+?')", "[...]", str(s))
for x in s.split("\n"):
print(lvl_char, x, file=sys.stderr, flush=True)
def trace(self, s):
self.__log(b"t", s)
def debug(self, s):
self.__log(b"d", s)
def info(self, s):
self.__log(b"i", s)
def warning(self, s):
self.__log(b"w", s)
def error(self, s):
self.__log(b"e", s)
def progress(self, p):
progress = min(max(0, p), 1)
self.__log(b"p", str(progress))
class StashInterface:
port = ""
url = ""
headers = {
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/json",
"Accept": "application/json",
"Connection": "keep-alive",
"DNT": "1",
}
cookies = {}
def __init__(self, conn, fragments={}):
global log
if conn.get("Logger"):
log = conn.get("Logger")
else:
raise Exception("No logger passed to StashInterface")
self.port = conn["Port"] if conn.get("Port") else "9999"
scheme = conn["Scheme"] if conn.get("Scheme") else "http"
api_key = conn.get("ApiKey")
if api_key:
self.headers["ApiKey"] = api_key
# Session cookie for authentication
self.cookies = {}
if conn.get("SessionCookie"):
self.cookies.update({"session": conn["SessionCookie"]["Value"]})
domain = conn["Domain"] if conn.get("Domain") else "localhost"
# Stash GraphQL endpoint
self.url = f"{scheme}://{domain}:{self.port}/graphql"
try:
self.get_stash_config()
except Exception:
log.error(f"Could not connect to Stash at {self.url}")
sys.exit()
log.info(f"Using Stash's GraphQl endpoint at {self.url}")
self.fragments = fragments
def __resolveFragments(self, query):
fragmentReferences = list(set(re.findall(r"(?<=\.\.\.)\w+", query)))
fragments = []
for ref in fragmentReferences:
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_request = {"query": query}
if variables is not None:
json_request["variables"] = variables
response = requests.post(
self.url, json=json_request, headers=self.headers, cookies=self.cookies
)
if response.status_code == 200:
result = response.json()
if result.get("errors"):
for error in result["errors"]:
log.error(f"GraphQL error: {error}")
if result.get("error"):
for error in result["error"]["errors"]:
log.error(f"GraphQL error: {error}")
if result.get("data"):
return result["data"]
elif response.status_code == 401:
sys.exit(
"HTTP Error 401, Unauthorized. Cookie authentication most likely failed"
)
else:
raise ConnectionError(
"GraphQL query failed:{} - {}. Query: {}. Variables: {}".format(
response.status_code, response.content, query, variables
)
)
def __match_alias_item(self, search, items):
item_matches = {}
for item in items:
if re.match(rf"{search}$", item.name, re.IGNORECASE):
log.debug(
f'matched "{search}" to "{item.name}" ({item.id}) using primary name'
)
item_matches[item.id] = item
if not item.aliases:
continue
for alias in item.aliases:
if re.match(rf"{search}$", alias.strip(), re.IGNORECASE):
log.debug(
f'matched "{search}" to "{alias}" ({item.id}) using alias'
)
item_matches[item.id] = item
return list(item_matches.values())
def get_stash_config(self):
query = """
query Configuration {
configuration { general { stashes{ path } } }
}
"""
result = self.__callGraphQL(query)
return result["configuration"]
def get_tags_with_relations(self):
query = """
query FindTags($filter: FindFilterType, $tag_filter: TagFilterType) {
findTags(filter: $filter, tag_filter: $tag_filter) {
count
tags {
id
name
parents { id }
children { id }
}
}
}
"""
variables = {
"tag_filter": {
"child_count": {"modifier": "GREATER_THAN", "value": 0},
"OR": {"parent_count": {"modifier": "GREATER_THAN", "value": 0}},
},
"filter": {"q": "", "per_page": -1},
}
result = self.__callGraphQL(query, variables)
return result["findTags"]["tags"]
def script_init():
import logging as log
log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")
stash_connection = config.STASH_SETTINGS
stash_connection["Logger"] = log
generate_graph(stash_connection)
def plugin_init():
log = StashLogger()
stash_connection = json.loads(sys.stdin.read())["server_connection"]
stash_connection["Logger"] = log
generate_graph(stash_connection)
print(json.dumps({"output": "ok"}))
def generate_graph(stash_connection):
log = stash_connection["Logger"]
stash = StashInterface(stash_connection)
log.info("getting tags from stash...")
tags = stash.get_tags_with_relations()
log.info("generating graph...")
if config.SHOW_OPTIONS:
G = Network(
directed=True,
height="100%",
width="66%",
bgcolor="#202b33",
font_color="white",
)
G.show_buttons()
else:
G = Network(
directed=True,
height="100%",
width="100%",
bgcolor="#202b33",
font_color="white",
)
node_theme = {
"border": "#adb5bd",
"background": "#394b59",
"highlight": {"border": "#137cbd", "background": "#FFFFFF"},
}
edge_theme = {"color": "#FFFFFF", "highlight": "#137cbd"}
# create all nodes
for tag in tags:
G.add_node(tag["id"], label=tag["name"], color=node_theme)
# create all edges
for tag in tags:
for child in tag["children"]:
G.add_edge(tag["id"], child["id"], color=edge_theme)
current_abs_path = os.path.dirname(os.path.abspath(__file__))
save_path = os.path.join(current_abs_path, "tag_graph.html")
G.save_graph(save_path)
log.info(f'saved graph to "{save_path}"')
if __name__ == "__main__":
if len(sys.argv) > 1:
script_init()
else:
plugin_init()

View File

@@ -1,12 +0,0 @@
name: Tag Graph
description: Creates a visual of the Tag relations
version: 0.2
exec:
- python
- "{pluginDir}/tag_graph.py"
interface: raw
tasks:
- name: Generate Graph
description: generates graph from current tag data
defaultArgs:
mode: generate