Skip to content

Commit 693e1fb

Browse files
committed
Add Metrics plugin — analytics dashboard with 16 tabs
1 parent bc6b12a commit 693e1fb

62 files changed

Lines changed: 17745 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

plugins/Metrics/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules/
2+
.env
3+
cache/
4+
assets/metrics-cache.json
5+
# Vendored UMD bundles are produced by `npm install` (postinstall). Keep the
6+
# placeholders committed so the plugin loads cleanly out of the box; users
7+
# replace them locally when they run npm install.
8+
!assets/lib/*.js

plugins/Metrics/Metrics.yml

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
name: Metrics
2+
description: >
3+
Comprehensive library analytics for Stash. Adds an interactive Metrics
4+
dashboard with performer-centric demographics, tag co-occurrence, studio
5+
output, collaboration networks and time-series charts. Ships runnable
6+
tasks to generate full JSON/CSV/HTML reports and to refresh the cached
7+
analytics consumed by the dashboard.
8+
version: 1.9.0
9+
url: https://github.com/Stash-Metrics/stash-metrics-plugin
10+
# Stash plugin manifest — see https://docs.stashapp.cc/in-app-manual/plugins/
11+
12+
# Stash's plugin schema requires `exec:` at the plugin level, not per task
13+
# or hook. Every task / hook shares this launcher; the specific mode is
14+
# passed via defaultArgs and read from stdin JSON's `args.mode` by
15+
# backend/compute_metrics.js.
16+
exec:
17+
- node
18+
- "{pluginDir}/backend/compute_metrics.js"
19+
20+
# Communication protocol between Stash and the script.
21+
interface: raw
22+
23+
ui:
24+
javascript:
25+
- assets/lib/chart.umd.min.js
26+
- assets/lib/chartjs-plugin-datalabels.min.js
27+
- assets/lib/chartjs-chart-matrix.min.js
28+
- src/utils/format.js
29+
- src/utils/stats.js
30+
- src/utils/correlations.js
31+
- src/data/graphql.js
32+
- src/data/cache.js
33+
- src/data/preferences.js
34+
# Backend-generated cache bootstrap — Stash's plugin schema only serves
35+
# files declared in ui.javascript, so we ship the metrics cache as a JS
36+
# file that assigns to window.__STASH_METRICS_CACHE__. The file ships
37+
# as a null stub committed to the repo; Update Metrics Cache overwrites
38+
# it with the real payload.
39+
- assets/metrics-cache.js
40+
- src/charts/overview.js
41+
- src/charts/performers.js
42+
- src/charts/tags.js
43+
- src/charts/networks.js
44+
- src/charts/timeseries.js
45+
- src/charts/correlations.js
46+
- src/charts/matches.js
47+
- src/charts/play.js
48+
- src/charts/archetypes.js
49+
- src/charts/insights.js
50+
- src/charts/fantasy.js
51+
- src/charts/quality.js
52+
- src/charts/wrapped.js
53+
- src/charts/bingo.js
54+
- src/charts/tagopt.js
55+
- src/charts/cleanup.js
56+
- src/dashboard.js
57+
- src/metrics.js
58+
css:
59+
- src/styles.css
60+
61+
# Settings appear under Settings → Plugins → Metrics in the Stash UI and
62+
# are exposed to backend scripts via the PLUGIN_SETTINGS_JSON env var.
63+
settings:
64+
cacheTtlMinutes:
65+
displayName: Cache TTL (minutes)
66+
description: How long computed metrics remain valid before the dashboard refetches.
67+
type: NUMBER
68+
disableNetworkGraph:
69+
displayName: Disable collaboration network graph
70+
description: Skip the performer co-occurrence force-directed graph on slow clients.
71+
type: BOOLEAN
72+
topN:
73+
displayName: Top-N items per chart
74+
description: How many entries (performers, tags, studios) to show in ranking charts.
75+
type: NUMBER
76+
ageBuckets:
77+
displayName: Age bucket size (years)
78+
description: Granularity of the performer age pyramid (e.g. 5 = 5-year buckets).
79+
type: NUMBER
80+
heightUnit:
81+
displayName: Height unit
82+
description: cm or in — used for all height-related charts.
83+
type: STRING
84+
excludeTagIds:
85+
displayName: Excluded tag IDs
86+
description: Comma-separated tag IDs to exclude from all tag aggregations.
87+
type: STRING
88+
excludePerformerIds:
89+
displayName: Excluded performer IDs
90+
description: Comma-separated performer IDs to exclude from all performer aggregations.
91+
type: STRING
92+
hideOtherBucket:
93+
displayName: Hide "Other" bucket in top-N charts
94+
description: >
95+
When ON, the tail of tag / country / studio distributions is dropped
96+
entirely instead of being aggregated into an "Other" slice. Cleans
97+
up pie charts and treemaps when the top-N heavily dominates.
98+
type: BOOLEAN
99+
genderFilter:
100+
displayName: Gender filter
101+
description: >
102+
Restrict every tab to the listed genders. Comma-separated list of
103+
Stash gender enum values: FEMALE, MALE, TRANSGENDER_FEMALE,
104+
TRANSGENDER_MALE, INTERSEX, NON_BINARY. Leave blank (or write "all")
105+
for no filter. Examples: "FEMALE" for female-only stats; "FEMALE,MALE"
106+
for both binary genders; "FEMALE,TRANSGENDER_FEMALE" to include trans
107+
women. Scenes are kept when they contain at least one performer of
108+
an allowed gender. Re-run Update Metrics Cache after changing this.
109+
type: STRING
110+
reportFormats:
111+
displayName: Report formats
112+
description: Comma-separated list of report formats to produce. Any of json,csv,html.
113+
type: STRING
114+
refreshOnScanComplete:
115+
displayName: Refresh cache after scans
116+
description: Automatically run the Update Metrics Cache task after Stash finishes scanning.
117+
type: BOOLEAN
118+
refreshOnMetadataUpdate:
119+
displayName: Refresh cache after metadata generation
120+
description: Automatically run the Update Metrics Cache task after metadata generation completes.
121+
type: BOOLEAN
122+
123+
# ---- Correlation & recommender settings (v1.1) ---------------------------
124+
# Feature-flag toggles use `disable*` semantics because Stash reports
125+
# every untouched BOOLEAN as `false` — with `enable*` names, the plugin
126+
# would ship with every tab OFF on a fresh install. `disable*: true`
127+
# explicitly opts out of a heavy computation.
128+
disableCorrelations:
129+
displayName: Disable correlations tab
130+
description: Skip attribute × O-count correlation aggregates on very large libraries.
131+
type: BOOLEAN
132+
correlationMinSupport:
133+
displayName: Correlation min support
134+
description: >
135+
Drop attribute cells with fewer than this many performers / scenes
136+
from correlation aggregates so single-sample groups don't dominate.
137+
type: NUMBER
138+
preferenceProfile:
139+
displayName: Preference profile (JSON)
140+
description: >
141+
JSON document describing your preference profile. The Matches tab reads
142+
this on load (and lets you edit it inline). Keys:
143+
countries, ethnicities, eyeColors, hairColors, cupSizes, hairLengths,
144+
requiredTags, excludedTags, minHeightCm, maxHeightCm, minAge, maxAge,
145+
minOCount, weights{country,ethnicity,eyeColor,hairColor,cup,height,
146+
age,oCount,tagOverlap,rating}, topMatches.
147+
Empty object {} disables preference filtering entirely.
148+
type: STRING
149+
matchMinScore:
150+
displayName: Match minimum score (0–100)
151+
description: Drop performers/scenes whose weighted match score is below this threshold.
152+
type: NUMBER
153+
matchIncludeUnknown:
154+
displayName: Treat missing attributes as partial matches
155+
description: >
156+
When ON, an attribute with no data (e.g. unknown eye color) contributes
157+
0.5 × its weight to the score instead of 0. Useful on libraries with
158+
sparse performer metadata.
159+
type: BOOLEAN
160+
161+
# ---- v1.2 advanced analytics ------------------------------------------
162+
disablePlayHistory:
163+
displayName: Disable Play tab
164+
description: Skip the day-of-week × hour-of-day heatmap + most-watched aggregation.
165+
type: BOOLEAN
166+
disableArchetypes:
167+
displayName: Disable Archetypes tab
168+
description: Skip the O(n²) k-means clustering + cosine-similarity index on very large libraries.
169+
type: BOOLEAN
170+
archetypeClusters:
171+
displayName: Archetype cluster count (k)
172+
description: Number of performer archetype clusters to compute (2–12).
173+
type: NUMBER
174+
disableDiversity:
175+
displayName: Disable diversity analytics
176+
description: Skip Shannon / Gini-Simpson diversity per attribute + gap analysis.
177+
type: BOOLEAN
178+
disableTemporal:
179+
displayName: Disable temporal analytics
180+
description: Skip release-year + career-timeline + tag-evolution charts on the Insights tab.
181+
type: BOOLEAN
182+
disableFantasy:
183+
displayName: Disable Fantasy Builder
184+
description: Skip reverse-engineering a preference profile from your favourites / top-rated / top-O seed set.
185+
type: BOOLEAN
186+
fantasyMode:
187+
displayName: Fantasy Builder seed mode
188+
description: How to pick the seed performers — favorites | top-rated | top-o.
189+
type: STRING
190+
fantasyConsensus:
191+
displayName: Fantasy consensus threshold
192+
description: Fraction of seed performers that must share a value before it's locked into the derived profile (0.3 = loose, 0.7 = strict).
193+
type: NUMBER
194+
195+
# ---- v1.3 quality + excel ---------------------------------------------
196+
enableQuality:
197+
displayName: Enable Quality tab
198+
description: Hidden gems, overrated / underrated insights and a composite library-health score.
199+
type: BOOLEAN
200+
gemRatingFloor:
201+
displayName: Hidden-gem rating floor
202+
description: Minimum rating100 a scene must have to be considered a "hidden gem".
203+
type: NUMBER
204+
gemPlayCeiling:
205+
displayName: Hidden-gem play-count ceiling
206+
description: Maximum play_count for a scene to still qualify as a hidden gem.
207+
type: NUMBER
208+
qualityZThreshold:
209+
displayName: Over/underrated z-score threshold
210+
description: |
211+
|z| above this is required for a scene/performer to land in the
212+
overrated/underrated lists. 1.0 = top ~16% on each tail.
213+
type: NUMBER
214+
qualityMinScenes:
215+
displayName: Minimum scenes for performer anomalies
216+
description: A performer needs at least this many scenes before being eligible for the over/underrated list.
217+
type: NUMBER
218+
219+
# ---- v1.8 tag optimizer ------------------------------------------------
220+
disableTagOptimizer:
221+
displayName: Disable Tag Optimizer tab
222+
description: Skip near-duplicate detection, always-together pair analysis and hierarchy audit.
223+
type: BOOLEAN
224+
tagoptRareThreshold:
225+
displayName: Tag Optimizer — rare tag threshold
226+
description: Tags with fewer scenes than this are surfaced as "rare" cleanup candidates.
227+
type: NUMBER
228+
tagoptPairMinSupport:
229+
displayName: Tag Optimizer — pair min support
230+
description: A tag pair needs at least this many shared scenes before it's considered for merge / specialisation detection.
231+
type: NUMBER
232+
tagoptUndertagMax:
233+
displayName: Tag Optimizer — under-tagged threshold
234+
description: Scenes with this many tags or fewer are flagged as under-tagged.
235+
type: NUMBER
236+
tagoptOvertagMin:
237+
displayName: Tag Optimizer — over-tagged threshold
238+
description: Scenes with this many tags or more are flagged as over-tagged (auto-tagger noise).
239+
type: NUMBER
240+
241+
# Runnable tasks — appear on the Tasks page under Plugin Tasks → Metrics.
242+
# All tasks share the top-level `exec:` above; `defaultArgs.mode` is the
243+
# only per-task distinction and is delivered to the script through
244+
# Stash's stdin JSON payload (args.mode).
245+
tasks:
246+
- name: Generate Full Metrics Report
247+
description: >
248+
Compute the complete analytics package, write JSON + CSV + a standalone
249+
visual HTML report to the plugin's cache/reports directory, and refresh
250+
the dashboard cache. Heavy operation — runs in the background.
251+
defaultArgs:
252+
mode: full-report
253+
254+
- name: Update Metrics Cache
255+
description: >
256+
Recompute the aggregated metrics consumed by the dashboard. Cheap
257+
compared to the full report — no CSV/HTML output. Use after a scan or
258+
metadata regeneration.
259+
defaultArgs:
260+
mode: cache-refresh
261+
262+
- name: Find Matches Based on My Preferences
263+
description: >
264+
Score every performer and scene against the preferenceProfile setting
265+
and write ranked match lists to cache/reports/<ts>/matches.{json,html}.
266+
Also refreshes the dashboard cache so the Matches tab opens instantly.
267+
defaultArgs:
268+
mode: match
269+
270+
- name: Generate Year-in-Review
271+
description: >
272+
Builds a calendar-year summary (top performers, tags, studios,
273+
played + rated scenes, debuts, new tags) and writes a standalone
274+
visual HTML report. Defaults to last year.
275+
defaultArgs:
276+
mode: year-review
277+
278+
- name: Export Full Library to Excel
279+
description: >
280+
Generates a comprehensive .xlsx workbook with one sheet per entity
281+
(Scenes, Performers, Tags, Studios), cross-reference junction
282+
sheets (Scene × Performer, Scene × Tag), tag co-occurrence,
283+
correlations, top matches (if a preference profile is set) and
284+
quality insights. Auto-filters and frozen header rows on every
285+
sheet. Output goes to cache/reports/<ts>/library-export.xlsx +
286+
cache/reports/latest-library-export.xlsx.
287+
defaultArgs:
288+
mode: excel-export
289+
290+
# Optional hooks — wired up if the corresponding setting is on. Stash will
291+
# still call us on every event; the script no-ops when the toggle is off.
292+
hooks:
293+
- name: Refresh metrics after a scan
294+
description: Recomputes the metrics cache once a scan task finishes.
295+
triggeredBy:
296+
- Scan.Complete.Post
297+
defaultArgs:
298+
mode: hook
299+
hook: scan
300+
301+
- name: Refresh metrics after metadata generation
302+
description: Recomputes the metrics cache once metadata generation finishes.
303+
triggeredBy:
304+
- Generate.Complete.Post
305+
defaultArgs:
306+
mode: hook
307+
hook: generate

0 commit comments

Comments
 (0)