Skip to content

Instantly share code, notes, and snippets.

@Maista6969
Last active April 29, 2023 10:37
Show Gist options
  • Save Maista6969/568826199a314adbc15abe7813c4ac55 to your computer and use it in GitHub Desktop.
Save Maista6969/568826199a314adbc15abe7813c4ac55 to your computer and use it in GitHub Desktop.
Shows the summarized O-counter and scene ratings for performer cards in Stash
// ==UserScript==
// @name Rating stats for performers
// @author Maista
// @namespace com.maista.userscripts
// @version 1.0
// @require https://gist.githubusercontent.com/Maista6969/aaf8f04b1af7603ed27866e9e7f46a02/raw/53f00a1ccc3370e65af4735c46bcc0a71ac5ef77/onElementReady.js
// @include http://localhost:9999/*
// @grant GM_xmlhttpRequest
// @icon http://localhost:9999/favicon.ico
// ==/UserScript==
const script_name = GM_info.script.name.toLowerCase().split(' ').join('-');
onElementReady('.performer-card', showStats, script_name);
async function showStats(performerCard) {
const performerId = performerCard.querySelector('a[href*=performers]').href.split('/').pop();
const popoverRow = performerCard.querySelector('.card-popovers');
if (popoverRow === null) return;
const newElems = await getPerformerData(performerId).then(summarizeSceneData).then(makeIcons);
newElems.forEach(el => popoverRow.appendChild(el));
}
function makeIcons({id, name, o_total, avgRating, numScenes}) {
const elems = [];
const baseUrl = `http://localhost:9999/scenes?c=(%22type%22:%22performers%22,%22value%22:%5B(%22id%22:%22${id}%22,%22label%22:%22${name}%22)%5D,%22modifier%22:%22INCLUDES%22)`;
if (o_total > 0) {
const oEl = document.createElement('a');
oEl.title = `${o_total} total Os`;
oEl.href = `${baseUrl}&sortby=o_counter&sortdir=desc`;
const oButton = document.createElement('button');
oButton.classList.add("minimal", "btn", "btn-primary");
oButton.innerHTML = `<svg class="svg-inline--fa fa-icon" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="currentColor" d="M22.855.758L7.875 7.024l12.537 9.733c2.633 2.224 6.377 2.937 9.77 1.518c4.826-2.018 7.096-7.576 5.072-12.413C33.232 1.024 27.68-1.261 22.855.758zm-9.962 17.924L2.05 10.284L.137 23.529a7.993 7.993 0 0 0 2.958 7.803a8.001 8.001 0 0 0 9.798-12.65zm15.339 7.015l-8.156-4.69l-.033 9.223c-.088 2 .904 3.98 2.75 5.041a5.462 5.462 0 0 0 7.479-2.051c1.499-2.644.589-6.013-2.04-7.523z"></path></svg><span>${o_total}</span>`;
oEl.appendChild(oButton);
elems.push(oEl);
}
if (!avgRating.includes("NaN")) {
const arEl = document.createElement('a');
arEl.title = `${avgRating} average rating based on ${numScenes} rated scenes`;
arEl.href = `${baseUrl}&sortby=rating&sortdir=desc`;
let arButton = document.createElement('button');
arButton.classList.add("minimal", "btn", "btn-primary");
arButton.innerHTML = `<svg class="svg-inline--fa fa-star fa-icon unset" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M287.9 0C297.1 0 305.5 5.25 309.5 13.52L378.1 154.8L531.4 177.5C540.4 178.8 547.8 185.1 550.7 193.7C553.5 202.4 551.2 211.9 544.8 218.2L433.6 328.4L459.9 483.9C461.4 492.9 457.7 502.1 450.2 507.4C442.8 512.7 432.1 513.4 424.9 509.1L287.9 435.9L150.1 509.1C142.9 513.4 133.1 512.7 125.6 507.4C118.2 502.1 114.5 492.9 115.1 483.9L142.2 328.4L31.11 218.2C24.65 211.9 22.36 202.4 25.2 193.7C28.03 185.1 35.5 178.8 44.49 177.5L197.7 154.8L266.3 13.52C270.4 5.249 278.7 0 287.9 0L287.9 0zM287.9 78.95L235.4 187.2C231.9 194.3 225.1 199.3 217.3 200.5L98.98 217.9L184.9 303C190.4 308.5 192.9 316.4 191.6 324.1L171.4 443.7L276.6 387.5C283.7 383.7 292.2 383.7 299.2 387.5L404.4 443.7L384.2 324.1C382.9 316.4 385.5 308.5 391 303L476.9 217.9L358.6 200.5C350.7 199.3 343.9 194.3 340.5 187.2L287.9 78.95z"></path></svg><span>${avgRating}</span>`;
arEl.appendChild(arButton);
elems.push(arEl);
}
return elems;
}
function summarizeSceneData({scenes, ...rest}) {
const o_total = scenes.map(({o_counter}) => o_counter).reduce((a, b) => a+b, 0);
const ratings = scenes.map(({rating100}) => rating100).filter(rating => rating !== null);
const numScenes = ratings.length;
const avgRating = (ratings.reduce((a, b) => a+b, 0) / numScenes / 20).toPrecision(2);
return { o_total, avgRating, numScenes, ...rest };
}
function getPerformerData(id) {
let query = JSON.stringify(
{
"query": "query FindPerformer($id: ID!) { findPerformer(id: $id) { name id scenes { o_counter, rating100 } } }",
"variables": {
"id": id
}
});
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "POST",
responseType: "json",
url: "http://localhost:9999/graphql",
headers: { "Content-Type": "application/json" },
data: query,
onload: (res) => {
try {
if (res.status != 200) {
let errors = res.response.errors.map((e) => e.message).join('\n');
reject(`Query for '${id}' failed: ${errors}`);
return;
}
resolve(res.response.data.findPerformer);
} catch (error) {
reject(error.message);
}
}
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment