Stash Sorter

:placard: Summary Provides advanced sorting capabilities including multi-field sorting, random sorting, interleaved sorting, and more.
:link: Repository https://github.com/efirlus/stashsorter

Stash Sorter

Advanced scene group sorting and management tool for StashApp

:open_book: Overview

While StashApp natively supports only single-field sorting, Stash Sorter provides advanced sorting capabilities including multi-field sorting, random sorting, interleaved sorting, and more.

Why Stash Sorter?

This project was developed with a focus on portability and independence:

  • Pure GraphQL API: Instead of relying on external libraries like stashapp-tools, this tool communicates directly with Stash via the GraphQL API. This ensures lightweight execution and avoids issues caused by library version mismatches or incomplete documentation.
  • AI-Optimized Architecture: The entire logic was orchestrated by Claude Code, utilizing raw API calls to ensure precise control over data manipulation without the overhead of third-party wrappers.

Key Features

  • :bullseye: Multi-Field Sorting: Complex sorting with multiple fields (e.g., rating → date → studio)
  • :game_die: Random Sorting: Randomly shuffle scenes with the same field values
  • :shuffle_tracks_button: Interleaved Sorting: Randomly interleave groups while maintaining order within each group
  • :magnifying_glass_tilted_left: Advanced Filters: Precise scene search with 8 filter types
  • :clipboard: Template System: Save and reuse custom sorting configurations
  • :recycling_symbol: Group Management: Auto-remove played scenes, re-sort existing groups
  • :laptop: User-Friendly: Interactive menu-based interface
  • :shield: DRY_RUN Mode: Safe testing before making actual changes

:rocket: Quick Start

1. Requirements

  • Python 3.8 or higher
  • StashApp server (v0.20.0 or higher recommended)
  • StashApp API Key

2. Installation

# Clone the repository
git clone <repository-url>
cd stashsorter

# Install dependencies
pip install -r requirements.txt

3. Configuration

Create a .env file and configure the following:

STASH_URL=http://localhost:9999/graphql
STASH_API_KEY=your_api_key_here

# Optional settings
LOG_LEVEL=INFO
DRY_RUN=false
TIMEOUT=30
MAX_RETRIES=3

How to get your API Key:

  1. Open StashApp web interface
  2. Go to Settings → Security → Generate API Key

4. Run

python run.py

:books: Usage

Main Menu

1. Create Sorted Group - Create new group with filters and sorting rules
2. Manage Group - Remove scenes and re-sort existing groups
3. Exit

Creating a Sorted Group

Phase 1: Filter Setup

Define criteria to search for scenes.

Available Filters:

  • Rating (rating100)
  • Path (path)
  • Tags (tags)
  • Play Count (play_count)
  • Performers (performers)
  • Studio (studio)
  • Date (date)
  • Organized (organized)

Example:

Rating >= 80 + Play Count = 0 + Path includes "/favorites/"

Phase 2: Sorting Method Selection

Option A: Use Template

  • Select from built-in templates:
    • Interleaved by Folder, Sorted by Filename
    • Interleaved by Folder, Sorted by Path
    • Random Folder + Rating Descending
    • Random Studio + Rating Descending
  • Or use your saved custom templates

Option B: Custom Sort

  • Manually configure sort keys
  • Optionally save as a template for future use

Sort Directions:

  • asc: Ascending order (smallest first)
  • desc: Descending order (largest first)
  • random: Random shuffle
  • interleaved: Randomly interleave groups, maintain order within groups

Example:

1. rating100 (desc) - Highest rated first
2. date (asc) - Oldest first
3. studio.parent_studio.name (random) - Random within each studio

Phase 3: Preview & Confirmation

  • Preview first 50 sorted scenes
  • View directory distribution analysis
  • View directory transition patterns
  • Options:
    • Confirm and proceed to group creation
    • Re-sort with different settings
    • Cancel

Phase 4: Group Creation

  • Enter group name
  • Review final summary
  • Create group and add scenes

Group Management

Remove Played Scenes

Automatically removes scenes with play_count > 0 from a group.

  1. Enter group ID
  2. Review list of scenes to be removed
  3. Confirm and bulk remove

Re-sort Group

Re-sorts scenes in a group using sorting rules stored in the group description.

  1. Enter group ID
  2. Auto-parse sorting rules (or manually input)
  3. Re-sort scenes and update group

:bullseye: Use Cases

Example 1: High-Rated Unwatched Scenes

Filters:
- rating100 >= 80
- play_count = 0

Sort:
1. rating100 (desc)
2. date (asc)

Result: Unwatched scenes rated 80+ sorted by rating, then by date

Example 2: Interleaved Folder Playlist

Filters:
- path INCLUDES "/favorites/"
- organized = true

Sort:
1. files.0.parent_folder.path (interleaved)
2. files.0.basename (asc)

Result: Folders randomly interleaved, files within each folder sorted alphabetically

Example 3: Random Studio Rotation

Filters:
- date >= 2024-01-01

Sort:
1. studio.name (random)
2. rating100 (desc)

Result: Studios in random order, scenes within each studio sorted by rating

Example 4: Date + Performer Sorting

Filters:
- date >= 2024-01-01
- performers INCLUDES_ALL [1, 5, 10]

Sort:
1. date (desc)
2. performers.0.name (asc)
3. rating100 (desc)

Result: Latest first, then by performer name, then by rating

:open_file_folder: Project Structure

stashsorter/
├── run.py                              # Main launcher
├── lib/                                # Core library modules
│   ├── config.py                       # Configuration
│   ├── logger.py                       # Logging
│   ├── stash_client.py                 # GraphQL client
│   ├── validators.py                   # Validation functions
│   ├── ui_helpers.py                   # UI helper functions
│   ├── sorters.py                      # Sorting logic
│   ├── template_manager.py             # Template management
│   └── cache_manager.py                # Cache management
├── scripts/                            # Executable scripts
│   ├── create_sorted_group.py          # Create sorted groups
│   ├── create_sorted_group_interactive.py  # Interactive workflow
│   └── manage_group.py                 # Group management
├── templates/                          # Sorting templates
│   ├── builtin_templates.json          # Built-in templates
│   └── user_templates.json             # User-created templates
├── cache/                              # Cache files (auto-generated)
├── logs/                               # Log files (auto-generated)
├── .env                                # Environment variables
├── .env.example                        # Environment template
├── requirements.txt                    # Python dependencies
└── README.md                           # This file

:clipboard: Sortable Fields

Field Name Description Type
title Scene title String
date Scene date Date
rating100 Rating (0-100) Number
play_count Play count Number
play_duration Total play duration Number
last_played_at Last played timestamp Date
o_counter O counter Number
created_at Created timestamp Date
updated_at Updated timestamp Date
duration Video duration Number
filesize File size Number
framerate Frame rate Number
bitrate Bit rate Number
path File path String
organized Organized flag Boolean
studio.name Studio name String

Nested Field Access:

studio.name
studio.parent_studio.name
files.0.path
files.0.basename
files.0.parent_folder.path
performers.0.name
tags.0.name

:gear: Configuration Options

Environment Variables

Variable Required Default Description
STASH_URL :white_check_mark: - StashApp GraphQL endpoint
STASH_API_KEY :white_check_mark: - StashApp API key
DRY_RUN :cross_mark: false Test mode (no actual changes)
LOG_LEVEL :cross_mark: INFO Log level (DEBUG, INFO, WARNING, ERROR)
TIMEOUT :cross_mark: 30 API request timeout (seconds)
MAX_RETRIES :cross_mark: 3 Maximum API request retries

:magnifying_glass_tilted_left: Troubleshooting

Stash Server Connection Failed

Error: Failed to connect to Stash server

Solutions:

  1. Verify Stash server is running
  2. Check STASH_URL in .env is correct
  3. Verify API Key is valid
  4. Check firewall settings

Invalid API Key Error

Error: Invalid API Key

Solutions:

  1. Generate new API Key in StashApp Settings → Security
  2. Update .env file with new key
  3. Restart the program

No Scenes Found

Error: No scenes found matching criteria

Solutions:

  1. Check if filter conditions are too strict
  2. Try the same filters in StashApp web UI
  3. Set LOG_LEVEL=DEBUG and check query output

Template Not Found

Error: Template not found

Solutions:

  1. Check templates/ directory exists
  2. Verify template files are valid JSON
  3. Re-create templates if corrupted