Stash Battle

Demo Video (NSFW)

:crossed_swords: Stash Battle

A head-to-head scene comparison plugin for Stash that uses an ELO-style rating system to help you rank your scenes.

Overview

Stash Battle presents you with two scenes side-by-side and asks you to pick the better one. Based on your choices, scene ratings are automatically updated using an ELO algorithm. Over time, this builds an accurate ranking of your entire library based on your personal preferences.

Features

  • Three Comparison Modes:
    • Swiss :balance_scale: – Fair matchups between similarly-rated scenes. Both scenes’ ratings adjust based on the outcome.
    • Gauntlet :bullseye: – Place a random scene in your rankings. It climbs from the bottom, challenging each scene above it until it loses, then settles into its final position.
    • Champion :trophy: – Winner stays on. The winning scene keeps battling until it’s dethroned.

Installation

:warning: Install at your own risk, nearly entirely vibe coded for myself using Claude, I have barely reviewed the code at all.

Recommend saving a backup of your database beforehand (Settings → Interface → Editing)

Source Index:

  1. Add this repo’s source index: https://dtt-git.github.io/stash-battle/main/index.yml to Stash plugin sources
  2. Checkbox the Stash Battle package and click Install

Manual Download:

  1. Download the /plugins/stash-battle/ folder to your Stash plugins directory

Usage

Optional Step: Change Rating System Type to “Decimal” (Settings → Interface → Editing)

  1. Navigate to the Scenes page in Stash
  2. Click the floating :crossed_swords: button in the bottom-right corner
  3. Choose your preferred comparison mode
  4. Click on a scene (or use arrow keys) to pick the winner
  5. Watch your rankings evolve over time!

How It Works

The plugin uses an ELO-inspired algorithm where:

  • Beating a higher-rated scene earns more points than beating a lower-rated one
  • Losing to a lower-rated scene costs more points than losing to a higher-rated one
  • Ratings are stored in Stash’s native rating100 field (1-100 scale which is why changing to decimal rating system type is recommended)

Requirements

  • At least 2 scenes in your library
4 Likes

How hard would it be to do this same thing for rating performers?

1 Like

I’d imagine not too hard if their data is similar to scenes and can be queried with the API as well

i have something working that i forked from your repo. still doing some fine tuning.

kind of reminds me of the old Hot or Not so that’s what i ended up calling it

2 Likes

Hello. I saw your post and loved the idea. I found going through each new scene in my Stash and determining an accurate rank a bit tedious. It inspired me to make something that I could use in my own setup to rank my scenes in a more gamified way. So instead of using this custom ELO you’ve made (which I find would be preferable due to it’s higher precision), I simply use the built in decimal ranking system.

I implemented:

  • Similar gamemodes to yours. Including “Unranked” gamemode which follows the champion gamemode but with only new scenes so I can quickly establish ranks for new scenes
  • VIM keybinds for voting, skipping, etc
  • I prioritized screen width of each scene in the UI over explicit context, but I think more can be adjusted in the UI as I go on
  • I also by default play both scene’s audio and can isolate to one by hovering
  • A rank slider preview to show all neighbors of both current scenes and an animation to show how each scene adjusts based on the output of the vote
  • Matched the community Modern Dark theme in my design for continuity

Here is a demo video I made for context if it will upload (NSFW)


It looks like others are also inspired by your concept, and I look forward to seeing what others come up with to potentially implement into my own solution!

In the future I want to add:

  • A persistent solution to win/ loss for better matchups (right now I simply use browser local storage)
  • Filters for only matchmaking within certain whitelisted/ blacklisted tags at a time (new gamemode)

Maybe we should make a PR to the main Stash repo for more precise rankings (i.e. 0-1000) :wink:

2 Likes

It would be cool if we can filter only scenes from specific studios or performers! Consider this in the next update!

1 Like

This is a great way to score scenes!

Could you make it work for images too? :smiley:

1 Like

Nice!! I really like the ranked slider, maybe I’ll incorporate that sometime. I’m really glad to see all the people who find this a fun concept as well :smile:

I did have an unrated mode initially during development but scrapped it because it was starting to feel overengineered. I may add some sort of filtering in for it later.

Right now the Gauntlet mode is supposed to be the placement mode to find where a scene sits in the entire collection. Although no way to select specific scenes currently.

Unfortunately there’s no way to add custom metadata fields I think, originally I did have the W-L data also stored in LocalStorage but I wanted to be able to rank stuff from my phone as well so I got rid of any local persistence data for now.

That would improve the ELO system I’m doing a bit! I have a lot of videos that have same scores but I figured over time it would all naturally spread out good enough anyways.

I may think about adding some filtering in the future, right now I’m only planning on adding match state persistence and changing the preview to open link instead of new tab because I have to open a separate window when using the plugin with through MultiFunPlayer.

But feel free to fork a version of your own or submit a PR!

EDIT: After thinking about it a bit filtering might be easier than I thought. I could just use the built in Stash filtering and just check for what you currently have filtered and apply that to the plugin. So I may tinker with that soon.

1 Like

Thanks! I don’t have any plans to make it work for images right now because I don’t use images on Stash :sweat_smile:

Maybe in the future I’ll make a big 2.0 update for it to work with everything and add filtering.

It doesn’t seem too hard to adapt what I have to work for other Stash data (see: Hot or Not), so I encourage you to try it for yourself :hugs:

If you need a possible reference for this, I did something similar with a plugin I made where I grab the url params window.location.search and then parse that into the filter used in the GQL call. This is written specifically for filtering images within a gallery but it shouldn’t be too tough to adapt it to handle filtering a different object type:

1 Like

Nice!! I really like the ranked slider, maybe I’ll incorporate that sometime. I’m really glad to see all the people who find this a fun concept as well :smile:

I’m glad you like it too. The animations there are proving a pain. I’m working on implementing an infinite horizontal scroll for selecting scenes from there to rank but it’s also proving a pain getting the fine details right.

I did have an unrated mode initially during development but scrapped it because it was starting to feel overengineered. I may add some sort of filtering in for it later.

Right now the Gauntlet mode is supposed to be the placement mode to find where a scene sits in the entire collection. Although no way to select specific scenes currently.

Yes various sorting filters for tags, unranked scenes, performers, etc could be a nice addition.

Unfortunately there’s no way to add custom metadata fields I think, originally I did have the W-L data also stored in LocalStorage but I wanted to be able to rank stuff from my phone as well so I got rid of any local persistence data for now.

I wasted some time today attempting to write a Python back-end to write to an sqlite DB win/ loss stats. Writing to DB went fine but it’s just not capable to read from the DB synchronously I guess. I ended up abandoning this.

I had the same conclusion with local browser storage. It didn’t satisfy me that it wouldn’t persist across browsers/ sessions. The only solution I could think of for now is writing something like JSON to the details section of the scene, but that’s finicky and not preferable. I found out there are custom fields for performers, adding this to scenes would be helpful too.

That would improve the ELO system I’m doing a bit! I have a lot of videos that have same scores but I figured over time it would all naturally spread out good enough anyways.

Yeah I think it’s kind of a niche request and most users don’t require this much precision.

I don’t mean to hijack your plugin post. I am thinking maybe it is good to just bounce ideas of each other to improve. But please let me know if it would be better for me to discuss elsewhere. But here’s the v2 of my version I’m working on I thought I’d share.

The new features I implemented are:

  • Easy tagging scenes modal popup (I don’t know if there is already a good plugin for tagging better but I found the native interface slow)
  • A statistics page demonstrating the nature of my rankings. I think the zero-sumness is important to properly space each scene from another instead of inflating and having a bunch in the range of 8-10 which I found was happening back when I was manually rating. As you can see I need to do some more ranking to smooth my curve.
  • Major/ minor votes. Major vote asserts 2x the amount of ELO as a minor. For faster sorting of scenes which one feels strongly about
  • Top tags (Just more visualization for myself)
  • Better modal popups, UI refinements, and keybinds

Demo V2 (NSFW)

1 Like

Are you planning on releasing it? It would be better to create your own plugin thread so it doesn’t get noisy here

Are you planning on releasing it? It would be better to create your own plugin thread so it doesn’t get noisy here

Haha no not particularly. It’s more so just for personal use and I just wanted to share for the purposes of sharing and discussing.

Yeah I totally understand and will refrain from bogging down this specific thread.

I’m excited to see how this plugin develops and am happy to assist in terms of feedback or even maybe some PRs when I get the chance!