diff --git a/plugins/CommunityScriptsUILibrary/CommunityScriptsUILibrary.yml b/plugins/CommunityScriptsUILibrary/CommunityScriptsUILibrary.yml
new file mode 100644
index 0000000..55074e8
--- /dev/null
+++ b/plugins/CommunityScriptsUILibrary/CommunityScriptsUILibrary.yml
@@ -0,0 +1,6 @@
+name: CommunityScriptsUILibrary
+description: CommunityScripts UI helper library
+version: 1.0.0
+ui:
+ javascript:
+ - cs-ui-lib.js
diff --git a/plugins/CommunityScriptsUILibrary/cs-ui-lib.js b/plugins/CommunityScriptsUILibrary/cs-ui-lib.js
new file mode 100644
index 0000000..a403b6c
--- /dev/null
+++ b/plugins/CommunityScriptsUILibrary/cs-ui-lib.js
@@ -0,0 +1,49 @@
+// CommunityScripts UI Library
+// cs-ui-lib.js
+(function () {
+ // get base URL for graphQL queries
+ const baseURL = document.querySelector("base")?.getAttribute("href") ?? "/";
+
+ // call GQL query, returns data without `data` wrapper
+ const callGQL = (reqData) =>
+ fetch(`${baseURL}graphql`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(reqData),
+ })
+ .then((res) => res.json())
+ .then((res) => res.data);
+
+ // get configuration via GQL
+ const getConfiguration = async (pluginId, fallback) => {
+ const query = `query Configuration { configuration { plugins }}`;
+ const response = await callGQL({ query });
+ return response.configuration.plugins?.[pluginId] ?? fallback;
+ };
+
+ // wait for key elements
+ function waitForElement(selector, callback) {
+ var el = document.querySelector(selector);
+ if (el) return callback(el);
+ setTimeout(waitForElement, 100, selector, callback);
+ }
+
+ // wait for a path match, then for key elements
+ const PathElementListener = (path, element, callback) => {
+ // startup location
+ if (window.location.pathname.startsWith(path))
+ waitForElement(element, callback);
+ PluginApi.Event.addEventListener("stash:location", (e) => {
+ if (e.detail.data.location.pathname.startsWith(path))
+ waitForElement(element, callback);
+ });
+ };
+
+ // export to window
+ window.csLib = {
+ callGQL,
+ getConfiguration,
+ waitForElement,
+ PathElementListener,
+ };
+})();
diff --git a/plugins/StashBatchResultToggle/stashBatchResultToggle.js b/plugins/StashBatchResultToggle/stashBatchResultToggle.js
deleted file mode 100644
index 9067a2c..0000000
--- a/plugins/StashBatchResultToggle/stashBatchResultToggle.js
+++ /dev/null
@@ -1,377 +0,0 @@
-(function () {
- let running = false;
- const buttons = [];
- let maxCount = 0;
-
- function resolveToggle(el) {
- let button = null;
- if (el?.classList.contains("optional-field-content")) {
- button = el.previousElementSibling;
- } else if (el?.tagName === "SPAN" && el?.classList.contains("ml-auto")) {
- button = el.querySelector(".optional-field button");
- } else if (
- el?.parentElement?.classList.contains("optional-field-content")
- ) {
- button = el.parentElement.previousElementSibling;
- }
- const state = button?.classList.contains("text-success");
- return {
- button,
- state,
- };
- }
-
- function toggleSearchItem(searchItem, toggleMode) {
- const searchResultItem = searchItem.querySelector(
- "li.search-result.selected-result.active"
- );
- if (!searchResultItem) return;
-
- const {
- urlNode,
- url,
- id,
- data,
- nameNode,
- name,
- queryInput,
- performerNodes,
- } = stash.parseSearchItem(searchItem);
-
- const {
- remoteUrlNode,
- remoteId,
- remoteUrl,
- remoteData,
- urlNode: matchUrlNode,
- detailsNode,
- imageNode,
- titleNode,
- codeNode,
- dateNode,
- studioNode,
- performerNodes: matchPerformerNodes,
- matches,
- } = stash.parseSearchResultItem(searchResultItem);
-
- const studioMatchNode = matches.find(
- (o) => o.matchType === "studio"
- )?.matchNode;
- const performerMatchNodes = matches
- .filter((o) => o.matchType === "performer")
- .map((o) => o.matchNode);
-
- const includeTitle = document.getElementById("result-toggle-title").checked;
- const includeCode = document.getElementById("result-toggle-code").checked;
- const includeDate = document.getElementById("result-toggle-date").checked;
- const includeCover = document.getElementById("result-toggle-cover").checked;
- const includeStashID = document.getElementById(
- "result-toggle-stashid"
- ).checked;
- const includeURL = document.getElementById("result-toggle-url").checked;
- const includeDetails = document.getElementById(
- "result-toggle-details"
- ).checked;
- const includeStudio = document.getElementById(
- "result-toggle-studio"
- ).checked;
- const includePerformers = document.getElementById(
- "result-toggle-performers"
- ).checked;
-
- let options = [];
-
- options.push(["title", includeTitle, titleNode, resolveToggle(titleNode)]);
- options.push(["code", includeCode, codeNode, resolveToggle(codeNode)]);
- options.push(["date", includeDate, dateNode, resolveToggle(dateNode)]);
- options.push(["cover", includeCover, imageNode, resolveToggle(imageNode)]);
- options.push([
- "stashid",
- includeStashID,
- remoteUrlNode,
- resolveToggle(remoteUrlNode),
- ]);
- options.push([
- "url",
- includeURL,
- matchUrlNode,
- resolveToggle(matchUrlNode),
- ]);
- options.push([
- "details",
- includeDetails,
- detailsNode,
- resolveToggle(detailsNode),
- ]);
- options.push([
- "studio",
- includeStudio,
- studioMatchNode,
- resolveToggle(studioMatchNode),
- ]);
- options = options.concat(
- performerMatchNodes.map((o) => [
- "performer",
- includePerformers,
- o,
- resolveToggle(o),
- ])
- );
-
- for (const [
- optionType,
- optionValue,
- optionNode,
- { button, state },
- ] of options) {
- let wantedState = optionValue;
- if (toggleMode === 1) {
- wantedState = true;
- } else if (toggleMode === -1) {
- wantedState = false;
- }
- if (optionNode && wantedState !== state) {
- button.click();
- }
- }
- }
-
- function run() {
- if (!running) return;
- const button = buttons.pop();
- stash.setProgress(((maxCount - buttons.length) / maxCount) * 100);
- if (button) {
- const searchItem = getClosestAncestor(button, ".search-item");
- let toggleMode = 0;
- if (btn === btnOn) {
- toggleMode = 1;
- } else if (btn === btnOff) {
- toggleMode = -1;
- } else if (btn === btnMixed) {
- toggleMode = 0;
- }
- toggleSearchItem(searchItem, toggleMode);
- setTimeout(run, 0);
- } else {
- stop();
- }
- }
-
- const btnGroup = document.createElement("div");
- const btnGroupId = "batch-result-toggle";
- btnGroup.setAttribute("id", btnGroupId);
- btnGroup.classList.add("btn-group", "ml-3");
-
- const checkLabel =
- '';
- const timesLabel =
- '';
- const startLabel =
- '';
- let btn;
-
- const btnOffId = "batch-result-toggle-off";
- const btnOff = document.createElement("button");
- btnOff.setAttribute("id", btnOffId);
- btnOff.title = "Result Toggle All Off";
- btnOff.classList.add("btn", "btn-primary");
- btnOff.innerHTML = timesLabel;
- btnOff.onclick = () => {
- if (running) {
- stop();
- } else {
- btn = btnOff;
- start();
- }
- };
- btnGroup.appendChild(btnOff);
-
- const btnMixedId = "batch-result-toggle-mixed";
- const btnMixed = document.createElement("button");
- btnMixed.setAttribute("id", btnMixedId);
- btnMixed.title = "Result Toggle All";
- btnMixed.classList.add("btn", "btn-primary");
- btnMixed.innerHTML = startLabel;
- btnMixed.onclick = () => {
- if (running) {
- stop();
- } else {
- btn = btnMixed;
- start();
- }
- };
- btnGroup.appendChild(btnMixed);
-
- const btnOnId = "batch-result-toggle-on";
- const btnOn = document.createElement("button");
- btnOn.setAttribute("id", btnOnId);
- btnOn.title = "Result Toggle All On";
- btnOn.classList.add("btn", "btn-primary");
- btnOn.innerHTML = checkLabel;
- btnOn.onclick = () => {
- if (running) {
- stop();
- } else {
- btn = btnOn;
- start();
- }
- };
- btnGroup.appendChild(btnOn);
-
- function start() {
- // btn.innerHTML = stopLabel;
- btn.classList.remove("btn-primary");
- btn.classList.add("btn-danger");
- btnMixed.disabled = true;
- btnOn.disabled = true;
- btnOff.disabled = true;
- btn.disabled = false;
- running = true;
- stash.setProgress(0);
- buttons.length = 0;
- for (const button of document.querySelectorAll(".btn.btn-primary")) {
- if (button.innerText === "Search") {
- buttons.push(button);
- }
- }
- maxCount = buttons.length;
- run();
- }
-
- function stop() {
- // btn.innerHTML = startLabel;
- btn.classList.remove("btn-danger");
- btn.classList.add("btn-primary");
- running = false;
- stash.setProgress(0);
- btnMixed.disabled = false;
- btnOn.disabled = false;
- btnOff.disabled = false;
- }
-
- stash.addEventListener("tagger:mutations:header", (evt) => {
- const el = getElementByXpath("//button[text()='Scrape All']");
- if (el && !document.getElementById(btnGroupId)) {
- const container = el.parentElement;
- container.appendChild(btnGroup);
- sortElementChildren(container);
- el.classList.add("ml-3");
- }
- });
-
- const resultToggleConfigId = "result-toggle-config";
-
- stash.addEventListener("tagger:configuration", (evt) => {
- const el = evt.detail;
- if (!document.getElementById(resultToggleConfigId)) {
- const configContainer = el.parentElement;
- const resultToggleConfig = createElementFromHTML(`
-
-
Result Toggle ${startLabel} Configuration
-
-
- `);
- configContainer.appendChild(resultToggleConfig);
- loadSettings();
- }
- });
-
- async function loadSettings() {
- for (const input of document.querySelectorAll(
- `#${resultToggleConfigId} input`
- )) {
- input.checked = await sessionStorage.getItem(
- input.id,
- input.dataset.default === "true"
- );
- input.addEventListener("change", async () => {
- await sessionStorage.setItem(input.id, input.checked);
- });
- }
- }
-
- stash.addEventListener("tagger:mutation:add:remoteperformer", (evt) =>
- toggleSearchItem(getClosestAncestor(evt.detail.node, ".search-item"), 0)
- );
- stash.addEventListener("tagger:mutation:add:remotestudio", (evt) =>
- toggleSearchItem(getClosestAncestor(evt.detail.node, ".search-item"), 0)
- );
- stash.addEventListener("tagger:mutation:add:local", (evt) =>
- toggleSearchItem(getClosestAncestor(evt.detail.node, ".search-item"), 0)
- );
- stash.addEventListener("tagger:mutation:add:container", (evt) =>
- toggleSearchItem(getClosestAncestor(evt.detail.node, ".search-item"), 0)
- );
- stash.addEventListener("tagger:mutation:add:subcontainer", (evt) =>
- toggleSearchItem(getClosestAncestor(evt.detail.node, ".search-item"), 0)
- );
-
- function checkSaveButtonDisplay() {
- const taggerContainer = document.querySelector(".tagger-container");
- const saveButton = getElementByXpath(
- "//button[text()='Save']",
- taggerContainer
- );
- btnGroup.style.display = saveButton ? "inline-block" : "none";
- }
-
- stash.addEventListener(
- "tagger:mutations:searchitems",
- checkSaveButtonDisplay
- );
-})();
diff --git a/plugins/StashBatchResultToggle/stashBatchResultToggle.yml b/plugins/StashBatchResultToggle/stashBatchResultToggle.yml
deleted file mode 100644
index 1277243..0000000
--- a/plugins/StashBatchResultToggle/stashBatchResultToggle.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: Stash Batch Result Toggle.
-# requires: StashUserscriptLibrary
-description: In Scene Tagger, adds button to toggle all stashdb scene match result fields. Saves clicks when you only want to save a few metadata fields. Instead of turning off every field, you batch toggle them off, then toggle on the ones you want
-version: 1.0
-ui:
- requires:
- - StashUserscriptLibrary
- javascript:
- - stashBatchResultToggle.js
diff --git a/plugins/VideoScrollWheel/VideoScrollWheel.yml b/plugins/VideoScrollWheel/VideoScrollWheel.yml
index 42777bb..bd54484 100644
--- a/plugins/VideoScrollWheel/VideoScrollWheel.yml
+++ b/plugins/VideoScrollWheel/VideoScrollWheel.yml
@@ -1,5 +1,6 @@
name: VideoScrollWheel
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:
@@ -36,6 +37,6 @@ settings:
type: NUMBER
ui:
requires:
- - StashUserscriptLibrary
+ - CommunityScriptsUILibrary
javascript:
- - videoScrollWheel.js
+ - VideoScrollWheel.js
diff --git a/plugins/VideoScrollWheel/videoScrollWheel.js b/plugins/VideoScrollWheel/videoScrollWheel.js
index b34a205..c1f8f10 100644
--- a/plugins/VideoScrollWheel/videoScrollWheel.js
+++ b/plugins/VideoScrollWheel/videoScrollWheel.js
@@ -1,8 +1,4 @@
(async () => {
- while (!window.stash) {
- await new Promise((resolve) => setTimeout(resolve, 100));
- }
-
const volumeScrollScale = -0.00065;
const timeScrollScale = 0.01;
const timeScrollFriction = 0.00015;
@@ -11,7 +7,8 @@
let vjsPlayer = null;
let scrollVelocity = 1;
let previousTime = Date.now();
- let pluginSettings = {
+ let pluginSettings = {};
+ const defaultPluginSettings = {
allowVolumeChange: false,
volumeScrollSpeed: 100.0,
timeScrollSpeed: 100.0,
@@ -24,14 +21,11 @@
async function setupVideoScrollWheel() {
// Get settings
- var settings = await getPluginConfig("videoScrollWheel");
- if (settings) {
- for (var key in settings) {
- if (pluginSettings.hasOwnProperty(key)) {
- pluginSettings[key] = settings[key];
- }
- }
- }
+ const settings = await csLib.getConfiguration("VideoScrollWheel", {}); // getConfiguration is from cs-ui-lib.js
+ pluginSettings = {
+ ...defaultPluginSettings,
+ ...settings,
+ };
// Get video player and register wheel event listener.
vjsPlayer = document.getElementById("VideoJsPlayer").player;
@@ -95,26 +89,10 @@
}
}
- // Util functions for getting plugin settings.
- async function getPluginConfigs() {
- const reqData = {
- operationName: "Configuration",
- variables: {},
- query: `query Configuration {
- configuration {
- plugins
- }
- }`,
- };
- return stash.callGQL(reqData);
- }
- async function getPluginConfig(pluginId) {
- const data = await getPluginConfigs();
- return data.data.configuration.plugins[pluginId];
- }
-
// Wait for video player to load on scene page.
- stash.addEventListener("stash:page:scene", function () {
- waitForElementId("VideoJsPlayer", setupVideoScrollWheel);
- });
+ csLib.PathElementListener(
+ "/scenes/",
+ "#VideoJsPlayer",
+ setupVideoScrollWheel
+ ); // PathElementListener is from cs-ui-lib.js
})();
diff --git a/plugins/discordPresence/discordPresence.js b/plugins/discordPresence/discordPresence.js
index ff2a54f..f9aa956 100644
--- a/plugins/discordPresence/discordPresence.js
+++ b/plugins/discordPresence/discordPresence.js
@@ -34,7 +34,6 @@
query FindScene($id: ID!) {
findScene(id: $id) {
...SceneData
- __typename
}
}
@@ -57,39 +56,16 @@
last_played_at
play_duration
play_count
- files {
- duration
- __typename
- }
- studio {
- ...SlimStudioData
- __typename
- }
- __typename
- }
-
- fragment SlimStudioData on Studio {
- id
- name
- __typename
+ files { duration }
+ studio { name }
}
`;
- while (!window.stash) {
- await new Promise((resolve) => setTimeout(resolve, 100));
- }
-
const PLUGIN_ID = "discordPresence";
- let userConfig = await getPluginConfig();
+ const userConfig = await csLib.getConfiguration(PLUGIN_ID, {});
console.debug("Discord Presence Plugin: user config", userConfig);
- for (let [key, val] of Object.entries(userConfig)) {
- if (val === "" || val === undefined || val === null) {
- delete userConfig[key];
- }
- }
-
/** @type {Required} */
const CONFIG = {
// DEFAULTS
@@ -101,7 +77,6 @@
discordLargeImageText: "Stashapp",
discordShowUrlButton: false,
discordUrlButtonText: "Watch",
-
...userConfig,
};
@@ -109,6 +84,7 @@
let SCENE_ID = null;
let INTERVAL_ID = null;
+ let WS_ALIVE = false;
const doUpdatingPresence = (e) => {
clearInterval(INTERVAL_ID);
@@ -128,6 +104,7 @@
// https://github.com/lolamtisch/Discord-RPC-Extension/releases
const ws = new WebSocket("ws://localhost:6969");
+ ws.addEventListener("message", () => (WS_ALIVE = true));
ws.addEventListener("open", () =>
PluginApi.Event.addEventListener("stash:location", doUpdatingPresence)
);
@@ -141,17 +118,17 @@
window.addEventListener("beforeunload", () => {
clearDiscordActivity();
});
-
- /** @returns {Promise} */
- async function getPluginConfig() {
- const reqData = {
- operationName: "Configuration",
- variables: {},
- query: `query Configuration { configuration { plugins } }`,
- };
- const data = await stash.callGQL(reqData);
- return data.data.configuration.plugins[PLUGIN_ID];
- }
+ // set timeout for checking liveliness
+ const checkLiveliness = () => {
+ if (!WS_ALIVE) {
+ unbindVideoListener(document.querySelector("#VideoJsPlayer video"));
+ clearInterval(INTERVAL_ID);
+ throw new Error(`Discord Presence Plugin: Discord RPC Extension not running
+ Please consult the README on how to set up the Discord RPC Extension
+ (https://github.com/stashapp/CommunityScripts/tree/main/plugins/discordPresence)`);
+ }
+ };
+ setTimeout(checkLiveliness, 2000);
/** @return {Promise} */
async function getSceneData(sceneId) {
@@ -159,18 +136,16 @@
return { sceneData: null, duration: 0 };
}
const reqData = {
- operationName: "FindScene",
variables: { id: sceneId },
query: SCENE_GQL_QUERY,
};
/** @type {GQLSceneDataResponse} */
- const data = await stash.callGQL(reqData);
- const sceneData = data.data.findScene;
+ const sceneData = await csLib
+ .callGQL(reqData)
+ .then((data) => data.findScene);
- if (sceneData === null) {
- return null;
- }
+ if (!sceneData) return null;
const newProps = {
studio_name: sceneData.studio?.name ?? "Unknown Studio",
@@ -196,38 +171,31 @@
async function setDiscordActivity() {
const sceneData = await getSceneData(SCENE_ID);
-
- if (!sceneData) {
- return;
- }
+ if (!sceneData) return;
const currentTime = getCurrentVideoTime() ?? 0;
const endTimestamp =
Date.now() + (sceneData.file_duration - currentTime) * 1000;
- let body = {};
-
- if (sceneData !== null) {
- body = {
- details: replaceVars(CONFIG.discordDetailsText, sceneData),
- state: replaceVars(CONFIG.discordStateText, sceneData),
- largeImageKey: CONFIG.discordShowImage
- ? CONFIG.discordLargeImageKey
+ let body = {
+ details: replaceVars(CONFIG.discordDetailsText, sceneData),
+ state: replaceVars(CONFIG.discordStateText, sceneData),
+ largeImageKey: CONFIG.discordShowImage
+ ? CONFIG.discordLargeImageKey
+ : undefined,
+ largeImageText: replaceVars(CONFIG.discordLargeImageText, sceneData),
+ endTimestamp: sceneData.file_duration > 0 ? endTimestamp : undefined,
+ buttons:
+ CONFIG.discordShowUrlButton && URL.canParse(sceneData.url)
+ ? [
+ {
+ label: replaceVars(CONFIG.discordUrlButtonText, sceneData),
+ url: sceneData.url,
+ },
+ ]
: undefined,
- largeImageText: replaceVars(CONFIG.discordLargeImageText, sceneData),
- endTimestamp: sceneData.file_duration > 0 ? endTimestamp : undefined,
- buttons:
- CONFIG.discordShowUrlButton && isValidUrl(sceneData.url)
- ? [
- {
- label: replaceVars(CONFIG.discordUrlButtonText, sceneData),
- url: sceneData.url,
- },
- ]
- : undefined,
- instance: true,
- };
- }
+ instance: true,
+ };
if (!ws.OPEN) {
return;
@@ -242,15 +210,8 @@
);
}
- function getCurrentVideoTime() {
- const videoElem = document.querySelector("#VideoJsPlayer video");
-
- if (!videoElem) {
- return null;
- }
-
- return videoElem.currentTime;
- }
+ const getCurrentVideoTime = () =>
+ document.querySelector("#VideoJsPlayer video")?.currentTime;
/**
* Performs string replacement on templated config vars with scene data
@@ -262,13 +223,20 @@
return templateStr.replace(pattern, (_, token) => sceneData[token] ?? "");
}
- function isValidUrl(str) {
- try {
- new URL(str);
- } catch {
- return false;
- }
-
- return true;
- }
+ // add listener for video events
+ const videoListener = (video) => {
+ SCENE_ID = parseInt(location.pathname.split("/")[2]);
+ video.addEventListener("playing", setDiscordActivity);
+ video.addEventListener("play", setDiscordActivity);
+ video.addEventListener("seeked", setDiscordActivity);
+ // end on video end
+ video.addEventListener("ended", clearDiscordActivity);
+ };
+ const unbindVideoListener = (video) => {
+ video.removeEventListener("playing", setDiscordActivity);
+ video.removeEventListener("play", setDiscordActivity);
+ video.removeEventListener("seeked", setDiscordActivity);
+ video.removeEventListener("ended", clearDiscordActivity);
+ };
+ csLib.PathElementListener("/scenes/", "video", videoListener);
})();
diff --git a/plugins/discordPresence/discordPresence.yml b/plugins/discordPresence/discordPresence.yml
index 4385427..67de7f6 100644
--- a/plugins/discordPresence/discordPresence.yml
+++ b/plugins/discordPresence/discordPresence.yml
@@ -1,6 +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
version: 1.0
settings:
discordClientId:
@@ -37,6 +38,9 @@ settings:
type: STRING
ui:
requires:
- - StashUserscriptLibrary
+ - CommunityScriptsUILibrary
javascript:
- discordPresence.js
+ csp:
+ connect-src:
+ - ws://localhost:6969
diff --git a/plugins/sceneCoverCropper/sceneCoverCropper.js b/plugins/sceneCoverCropper/sceneCoverCropper.js
index eaddea7..78fdc52 100644
--- a/plugins/sceneCoverCropper/sceneCoverCropper.js
+++ b/plugins/sceneCoverCropper/sceneCoverCropper.js
@@ -4,16 +4,10 @@
(function () {
let cropping = false;
let cropper = null;
-
- try {
- stash.getVersion();
- } catch (e) {
- console.error(
- "Stash not loaded - please install 1. stashUserscriptLibrary from CommunityScripts"
- );
- }
+ const csLib = window.csLib;
function setupCropper() {
+ console.log("setupCropper");
const cropBtnContainerId = "crop-btn-container";
if (document.getElementById(cropBtnContainerId)) return;
const sceneId = window.location.pathname
@@ -92,7 +86,7 @@
cropAccept.setAttribute("id", "crop-accept");
cropAccept.classList.add("btn", "btn-success", "mr-2");
cropAccept.innerText = "OK";
- cropAccept.addEventListener("click", async (evt) => {
+ cropAccept.addEventListener("click", async (e) => {
cropping = false;
cropStart.style.display = "inline-block";
cropAccept.style.display = "none";
@@ -107,13 +101,9 @@
id: sceneId,
},
},
- query: `mutation SceneUpdate($input: SceneUpdateInput!) {
- sceneUpdate(input: $input) {
- id
- }
- }`,
+ query: `mutation SceneUpdate($input: SceneUpdateInput!) { sceneUpdate(input: $input) { id }}`,
};
- await stash.callGQL(reqData);
+ await csLib.callGQL(reqData);
reloadImg(image.src);
cropper.destroy();
cropperModal.close("cropAccept");
@@ -141,7 +131,5 @@
cropBtnContainer.appendChild(cropInfo);
}
- stash.addEventListener("stash:page:scene", function () {
- waitForElementId("scene-edit-details", setupCropper);
- });
+ csLib.PathElementListener("/scenes/", "#scene-edit-details", setupCropper);
})();
diff --git a/plugins/sceneCoverCropper/sceneCoverCropper.yml b/plugins/sceneCoverCropper/sceneCoverCropper.yml
index 5706c5f..995d41e 100644
--- a/plugins/sceneCoverCropper/sceneCoverCropper.yml
+++ b/plugins/sceneCoverCropper/sceneCoverCropper.yml
@@ -1,10 +1,10 @@
name: Scene Cover Cropper
-# requires: StashUserscriptLibrary
description: Crop Scene Cover Images
+# requires: CommunityScriptsUILibrary
version: 1.0
ui:
requires:
- - StashUserscriptLibrary
+ - CommunityScriptsUILibrary
css:
- https://cdn.jsdelivr.net/npm/cropperjs@1.6.1/dist/cropper.min.css
javascript:
diff --git a/plugins/stashAI/stashai.js b/plugins/stashAI/stashai.js
index e1b4665..759af2d 100644
--- a/plugins/stashAI/stashai.js
+++ b/plugins/stashAI/stashai.js
@@ -34,26 +34,6 @@
"Cumshot",
];
- function waitForElm(selector) {
- return new Promise((resolve) => {
- if (document.querySelector(selector)) {
- return resolve(document.querySelector(selector));
- }
-
- const observer = new MutationObserver((mutations) => {
- if (document.querySelector(selector)) {
- resolve(document.querySelector(selector));
- observer.disconnect();
- }
- });
-
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- });
- });
- }
-
/**
* Retrieves the tags associated with a given scene ID.
*
@@ -61,17 +41,10 @@
* @returns {Promise} - A promise that resolves with an array of tag IDs.
*/
async function getTagsForScene(scene_id) {
- const reqData = {
- query: `{
- findScene(id: "${scene_id}") {
- tags {
- id
- }
- }
- }`,
- };
- var result = await stash.callGQL(reqData);
- return result.data.findScene.tags.map((p) => p.id);
+ const query = `query { findScene(id: "${scene_id}") { tags { id }}}`;
+ return csLib
+ .callGQL({ query })
+ .then((data) => data.findScene.tags.map((p) => p.id));
}
/**
@@ -81,15 +54,10 @@
* @returns {Promise