From 59a9b9765c976a008ba1c85c73c55f7e588f41fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 06:05:33 +0000 Subject: [PATCH] Deployed b2809f1 with MkDocs version: 1.6.1 --- metadata-sources/scrapers/index.html | 12 ++++++------ search/search_index.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/metadata-sources/scrapers/index.html b/metadata-sources/scrapers/index.html index 6161153..a067029 100644 --- a/metadata-sources/scrapers/index.html +++ b/metadata-sources/scrapers/index.html @@ -2071,9 +2071,9 @@
Scrapers includes: All other scrapers.
This is the most common type of scrapers, which use either XPath parser to pin-point the information and retrieve them, or send out JSON requests to get the information. xpathScraper and jsonScraper can be mixed in the same .yml file.
This type of scrapers is mostly the same as XPath/JSON scrapers, except it will launch a headless Chrome browser to retrieve the information from websites. It can also get cookies, simulate a mouse click and other actions. These scrapers have useCDP: true
setting in them.
Stash is a web application written in Go for serving and organizing your porn collection. It is self-hosted and released under AGPL-3.0 license. Stash currently supports Windows, macOS, Linux, FreeBSD and Docker.
"},{"location":"#about-stash","title":"About Stash","text":"You can learn more about the software generally via the README on the official repository or via official website.
"},{"location":"#get-started","title":"Get started","text":"To get started go to Installation and grab the latest version for your operating system.
"},{"location":"#support","title":"Support","text":"There is a GraphQL API which allows to do things automatically. GraphQL is also self-documenting.
Stash has integrated playground where you run interact with the API and view the documentation.
<server>:<port>/playground
(default is http://localhost:9999/playground
). All HTTP requests have to go to <server>:<port>/graphql
(default is http://localhost:9999/graphql
).
You just need to add the key you generated in Stash (for more info about the API Key check stash's help section) in a header for every request you make.
Example using curlcurl -X POST -H \"ApiKey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiJiaWxsIiwiaWF0IjoxNjE3MDkzMDYwLCJzdWIiOiJBUElLZXkifQ.WhUyvmnVeW8wGV5fkVyje3xLfz5A97HFwyZy-4i8Q-I\" -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation { metadataScan (input:{})}\" }' localhost:9999/graphql\n
"},{"location":"api/#legacy-cookie-authentication","title":"Legacy cookie authentication","text":"If you have configured a username/password you have to use cookies to authenticate.
Example using curlcurl --verbose --cookie-jar cookie.txt --data 'username=stash&password=**' localhost:9998/login\ncurl --cookie cookie.txt -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation { metadataScan ( input: {} ) } \"}' localhost:9999/graphql\n
Using the API Key
is recommended instead of the above cookie method.
HTTP-POST
Example using curl {\n \"query\": \"mutation { metadataScan ( input: {} ) }\"\n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \" mutation { metadataScan (input: {} ) }\" }' localhost:9999/graphql\n
"},{"location":"api/#create-backup","title":"Create backup","text":"HTTP-POST
Example using curl {\n \"query\": \"mutation { backupDatabase(input: {download: false})}\"\n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation {backupDatabase(input: {download: false})}\" }' localhost:9999/graphql\n
If download:
is true
the created backup is returned and not stored locally.
HTTP-POST
Example using curl Payload (set desired content to generate covers, sprites, previews, imagePreviews, markers, transcodes, phashes, interactiveHeatmapsSpeeds, imageThumbnails, clipPreviews to true
or false
.
{\n \"query\": \"mutation { metadataGenerate ( input : { sprites: true previews: false imagePreviews: false markers: false transcodes: false } ) }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation { metadataGenerate ( input : { sprites: false previews: true imagePreviews: false markers: false transcodes: false } ) }\" }' localhost:9999/graphql\n
"},{"location":"api/#get-studios","title":"Get studios","text":"HTTP-POST
Example using curl Payload (must be at least one of id
checksum
url
name
image_path
scene_count
).
{\n \"query\": \"{ allStudios { id checksum url name image_path scene_count } }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ allStudios { name url scene_count} }\" }' localhost:9999/graphql\n
"},{"location":"api/#scrape-perfomer-attributes-from-freeones","title":"Scrape perfomer attributes from Freeones","text":"HTTP-POST
Example using curl Payload
$performer name
is the name of the Performer you are scraping forname
url
twitter
instagram
birthdate
ethnicity
country
eye_color
height
measurements
fake_tits
career_length
tattoos
piercings
aliases
{\n \"query\": \"{ scrapeFreeones(performer_name: $performer_name) { name url twitter instagram birthdate ethnicity country eye_color height measurements fake_tits career_length tattoos piercings aliases } }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ scrapeFreeones ( performer_name : \\\"Abella Danger\\\" ) { name height birthdate} }\" }' localhost:9999/graphql\n
"},{"location":"api/#get-list-of-perfomer-names-that-match-a-name-or-alias-from-freeones","title":"Get list of perfomer names that match a name or alias from Freeones","text":"HTTP-POST
Example using curl Payload ($q
is the name or alias (or partial name , alias) of the performer you are looking for).
{\n \"query\": \"{ scrapeFreeonesPerformerList(query: $q) }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ scrapeFreeonesPerformerList (query: \\\"bella\\\" ) }\" }' localhost:9999/graphql\n
"},{"location":"api/#get-system-status","title":"Get system status","text":"HTTP-POST
Example using curl {\n \"query\": \"{ systemStatus { databaseSchema databasePath configPath appSchema status } }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ systemStatus { appSchema status } }\" }' localhost:9999/graphql\n
"},{"location":"code-of-conduct/","title":"Code of conduct","text":""},{"location":"code-of-conduct/#our-pledge","title":"Our Pledge","text":"We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
"},{"location":"code-of-conduct/#our-standards","title":"Our Standards","text":"Examples of behavior that contributes to a positive environment for our community include:
Examples of unacceptable behavior include:
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
"},{"location":"code-of-conduct/#scope","title":"Scope","text":"This Code of Conduct applies within all community spaces, community servers, code repositories, and also applies when an individual is officially representing the community in public spaces.
"},{"location":"code-of-conduct/#enforcement","title":"Enforcement","text":"Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement. You can contact Admin or Org Lead members directly via Discord or using an integrated report function on other platforms. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
"},{"location":"code-of-conduct/#enforcement-guidelines","title":"Enforcement Guidelines","text":"Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
"},{"location":"code-of-conduct/#warning","title":"Warning","text":"Offense: First time offence.
Consequence: A public or private written warning depending on the space where offense happened.
"},{"location":"code-of-conduct/#temporary-or-permanent-ban","title":"Temporary or Permanent Ban","text":"Offense: Second time offense.
Consequence: Temporary or permanent ban from any sort of public interaction within the community and removal of any previously given elevated permissions.
"},{"location":"code-of-conduct/#attribution","title":"Attribution","text":"This Code of Conduct is a modified and adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
"},{"location":"matrix/","title":"Matrix","text":""},{"location":"matrix/#what-is-matrix","title":"What is Matrix?","text":"Matrix is an open-source internet protocol for secure, decentralised, real-time communication. Unlike other popular platforms like Discord, Matrix is federated. It consists of many servers, each server hosts Matrix accounts and chats. You can create an account on any Matrix server and the join other servers without having to re-create your account. One common example of federated protocol everyone uses today is email.
On Matrix, usernames are referred to as MXIDs (Matrix IDs), chats as rooms, servers as homeservers. Think of homeserver as the domain that hosts the instance. You can also group rooms together to form spaces (similar to Discord server).
In comparison to Discord: Username = Matrix ID Channel = Room Server = Space1
1 Spaces are a collection of individual rooms.
"},{"location":"matrix/#registration-on-matrix","title":"Registration on Matrix","text":"There is no central place to register on. You can create an account on any homeserver and join spaces and rooms across all of them.
"},{"location":"matrix/#popular-homeservers","title":"Popular homeservers","text":"2 Redirects to element.io domain, which is affiliated with matrix.org.
"},{"location":"matrix/#clients","title":"Clients","text":"Matrix supports a variety of clients on web, desktop (Windows, Linux, and macOS), and mobile (Android, iOS). matrix.org maintains a list of clients on their website here.
TipWeb-based clients are great to start and register. Element (web) is feature-rich and easy to use client.
"},{"location":"matrix/#stash-space","title":"Stash space","text":"Our official space is located at #stashapp:unredacted.org. Alternative addresses are on matrix.im: #stashapp:matrix.im.
Tip
Rooms can be joined from inside the space. You can join one, or more rooms, or all rooms from the space. They are not directly tied to each other.
"},{"location":"matrix/#stash-rooms","title":"Stash rooms","text":"Info
We are using a bridge bot that relays Discord and Matrix messages both ways in some rooms. They will be marked (bridged). Some features doesn't translate through the bridge like reactions and threads.
Some rooms are designated as [NSFW]. Adult focused media is allowed to be posted in those rooms without /spoiler as long as they within space rules.
"},{"location":"matrix/#matrix-focused-rooms","title":"Matrix focused rooms","text":"The following is our recommended procedure for new Stash users who want to get info for their scenes as quickly, easily, and as accurately as possible. Pulling info directly from StashDB is still the best option, but unfortunately this will not always be possible. Alternative methods are also covered for when StashDB doesn't have what you need. This is an expanded version of @Scruffy's pinned post in the #stashdb-general channel in our Discord. Go there if you'd like something more succinct and direct. Hopefully this guide will reduce the pain and frustration for those who are lost and don't know where to start.
The following sections are in this particular order for a reason, so please follow this guide from the beginning.
"},{"location":"beginner-guides/guide-to-scraping/#generate-phashes","title":"Generate pHashes","text":"Navigate to the Settings page (\u2699 icon in top right), make sure you're on \"Tasks\" in the sidebar to the left, then find the first heading \"Library\" in the middle of the page. Make sure \"Generate perceptual hashes\" is turned on so pHashes will be created automatically each time you run a scan to add new scenes. This will slow down the scanning process, but for most users it's worth it. pHashes are the main way to match your scenes with our data on StashDB.
pHash generation is not turned on by default, so you'll need to generate them manually if you haven't already. This can be done on your entire library on the same Settings --> Tasks page, scroll down to the \"Generated Content\" heading. Make sure \"Perceptual hashes (for deduplication)\" is turned on and click the \"Generate\" button at the top. As long as \"Overwrite existing generated files\" is turned off, this will only generate missing files and hashes.
If you haven't set up StashDB in your Stash settings yet, now's the time to do it. The best way to do that is to follow this guide to Accessing StashDB. It includes step-by-step instructions for both signing up to StashDB and connecting your new account to Stash.
"},{"location":"beginner-guides/guide-to-scraping/#use-the-scene-tagger","title":"Use the Scene Tagger","text":"Go to your Scenes page on Stash and click the double \ud83d\udd16 icon to the far right of the search bar. This is your Scene Tagger view and should be your first choice for pulling data, not Identify / Autotag / Filename Parser / URL Scrapers / etc. Always use the Scene Tagger first, the rest are for users with more specific needs who understand the strengths and weaknesses of each tool.
Important
Tags are not created automatically. You need to click +
icon near the tag name to create it for you locally and attach it to the scene. Once it's created, it will match automatically in the future.
First, click the \"Scrape All\" button. This will use your pHashes to find matching scenes on StashDB for every scene on the current page. The \"Scrape by fragment\" buttons will do the same thing but just for one scene at a time. Also, you may want to change your Scene Tagger settings with the \u2699 icon next to \"Scrape All.\" You can tell it to Merge (keep all) tags, Overwrite (keep only new) tags, or ignore StashDB's tags entirely (leave box unchecked). If you plan on contributing to StashDB, you should have \"Show male performers\" turned on to better follow these guidelines.
If your fingerprint search doesn't return a correct result for your scene, you can try searching with the \"Query\" field using title, performer, release date, or studio. Try to use as little text as possible to find your scene. Otherwise, unnecessary words that do not match StashDB's info may block correct results. If you can find the matching scene on StashDB.org but can't find it using the Scene Tagger, you can use the scene's StashID as your Tagger query.
Be sure to double-check that each selected result matches your scene before clicking the \"Save\" button at the bottom of each card. If you're confident that all of your saved matches are accurate, you may click the \"Submit fingerprints\" button after you're done. This will add your files' hashes to StashDB to make them easier for other users to find. But again, make sure your files were matched correctly first. The button will appear right next to the \"Scrape All\" button.
{:style=\"counter-reset:none\"} 1. First step is to make an account at theporndb.net. With your account created, navigate to your API Tokens page. Type \"stash\" as your token's name (or whatever you'd prefer), make sure the \"read\" permission is checked (you don't need the others), and click the \"Create\" button. A pop-up will display your newly created token. Save your API token somewhere so you can find it later!. It will not be visible on ThePornDB's website after you close the pop-up. If you lose it, you may need to create a new one and repeat this entire setup process. This can be done in a password manager, notes app, or a well-placed text file.
![How to create an API token on ThePornDB](/assets/beginner-guides/create-tpdb-token.jpg)\n
{:style=\"counter-reset:none\"} 1. Click Add and fill out the form that pops up: paste in your API key you created earlier amd enter ThePornDB
(or anything else you'd like, like TPDB) for Name, and enter https://theporndb.net/graphql
as the GraphQL endpoint.
Click Test Credentials to make sure you've entered everything correctly, then click Confirm.
Finally, we can use the Scene Tagger to scrape from ThePornDB. First you'll need to switch to \"ThePornDB\" as the Tagger's source. It will always default to the first Stash-Box source, so you'll need to switch it every time you need something else. Use the same process here as we used with StashDB and the Scene Tagger. The \"Scrape All\" and \"Scrape by fragment\" buttons will match by using file hashes (pHash and oshash). If these don't give you the right results, you can try the \"Search\" button and customize your search terms as needed. Remember to use as few terms as possible in your search because unneccessary words that don't match ThePornDB's info may block correct results. You can also copy-paste additional terms from TPDB's page if you need to narrow down the Tagger's results more.
For those wanting to contribute to StashDB
As noted before, ThePornDB leans heavily on automated scrapers to pull all of their info. Often that data is incomplete or inaccurate compared to what we'd want on StashDB. Before you submit your scene to StashDB, you'll need to double-check your info, clean it up a bit first, and make sure you're following these guidelines. Submitting to StashDB is discussed further in the last step of this guide.
"},{"location":"beginner-guides/guide-to-scraping/#use-site-specific-scrapers","title":"Use Site-Specific Scrapers","text":"If you've already tried StashDB, you've already tried ThePornDB, and you still want to scrape a site directly, you can try using a site-specific scraper. However, every scraper is going to work differently. Some will need Python installed. Others will need you to set a user agent or a Chrome CDP path. A handful will need to be edited and configured first. Only a few can search a studio's website for the right scene. The entire process is much more advanced and is different for each scraper, which is why we recommend StashDB and TPDB first for new users. They can all be found in the same repo. You can download them individually, or you can download the entire repo as a zip archive.
First you'll want to search this page for your website to see if we have a scraper for it and to get an idea of what its requirements are. For most of these scrapers, you'll need to find and save a studio URL to your scene first. If you've managed to set up a fragment scraper, you can click on the \"Scrape with...\" button in the scene's edit tab to select your scraper. Typically fragment scrapers are better than URL scrapers. Otherwise, you'll need to click the button at the far right end of the URL field to run a URL scraper. It should light up when the field is filled with a URL that matches one of your installed scrapers. That's about as detailed as we can get in this guide for new users. If you've tried StashDB, tried TPDB, checked the relevant documentation, checked your logs, and still can't get one of these scrapers working, you can ask for help on Discord in the #help channel. More advanced discussions might be moved to the #scrapers channel
If you're certain a scene isn't on StashDB and you've found the info using ThePornDB or some other scraper, please consider submitting it to StashDB yourself. That way nobody else will have to duplicate the same work you've done for that particular scene if they can match their pHash with yours. You'll need to ask for edit privileges in our Discord and follow the guidelines on this website. In particular, please note that not every scene can be added to StashDB at this time. Some studios aren't allowed and full movies likely won't be eligible either.
Also, please don't blindly resubmit data gotten from ThePornDB. You should verify the data is correct and complete first, make sure the URL is right, check for any missing performers, and look up any relevant guidelines if something else seems funky to you. You should update your data within Stash before submitting a draft or you can edit the draft on StashDB itself before creating the edit. You should also have the studio URL now, so you should also compare with that page manually or even scrape again with a site-specific scraper as explained in the previous step of this guide. Also please note in your edit comment where your data is coming from.
Info
Please check your logs after migrating to this release. A log warning will be generated on startup if duplicate image checksums exist in your system. Search for the images using the logged checksums, and remove the unwanted ones.
Info
The system will now stop serving requests if authentication is not configured and it detects a connection from public internet. See this link for details.
"},{"location":"changelog/v0100/#new-features","title":"\u2728 New Features","text":"libvips
) and made optional. (#1655)The Stash developers would greatly appreciate if you take a short, anonymous survey. It would help us out a great deal to make yourself heard, let us know how you use Stash, and tell us what you'd like to see in the future.
"},{"location":"changelog/v0110/#new-features","title":"\u2728 New Features","text":"Auto Tag
scene scraper to match performers, studio and tags from filename - using AutoTag logic. (#1817)or
keywords and exclude keywords. See the Browsing
section of the manual for details. (#1982)Info
Image Slideshow Delay (in Interface Settings) is now in seconds rather than milliseconds and has not been converted. Please adjust your settings as needed.
"},{"location":"changelog/v0140/#new-features","title":"\u2728 New Features","text":"theme_color
property in config.yml
(#2365).
characters. (#2658)Info
After migrating, please run a scan on your entire library to populate missing data, and to ingest identical files which were previously ignored.
"},{"location":"changelog/v0170/#known-issues-and-other-changes","title":"\ud83d\udca5 Known issues and other changes","text":"Set name, date, details from embedded file metadata
scan flag is no longer supported. This functionality may be implemented as a built-in scraper in the future.Don't include file extension as part of the title
scan flag is no longer supported.parseDate
scraper post processor. (#2817)autostartVideoOnPlaySelected
option not applying when navigating from scene queue. (#2896)database is locked
errors when performing operations while running a scan. (#3153)index.html
not correctly served from custom mapped folders. (#3168)ffmpeg
during generation and live-transcoding. (#3216)r x x
keyboard shortcuts to set decimal ratings. (#3226)Info
After upgrading performance will be degraded until a full scan has been completed.
Info
Language has been set to `English (United States)` by default, which affects number and date formatting.
"},{"location":"changelog/v020/#new-features","title":"\u2728 New Features","text":"Info
The cache directory is now required if using HLS/DASH streaming. Please set the cache directory in the System Settings page.
Info
The image data subsystem has been reworked in this release. Existing systems will have their storage system set to Database
, which stores all image data in the database. This can be changed in the System Settings page.
A migration is required to change the storage system, and can be accessed from the Tasks page.
The Database
storage system is not recommended for large libraries, as it can cause performance issues. The Filesystem
storage system is recommended for large libraries, and is the default for new systems.
Info
The generated/screenshots
jpg files are now considered legacy. These files can be migrated into the blob storage system by running the Migrate Screenshots
task from the Tasks page.
Once migrated, these files can be deleted. The files can be optionally deleted during the migration.
"},{"location":"changelog/v0200/#new-features","title":"\u2728 New Features","text":"Is Missing Cover
scene filter criterion. (#3187)/stream
endpoint serving directory list. (#3541).forcegallery
to directory. (#3715).nogallery
to directory. (#3715)-v/--version
command line flag. (#3883)Mark as Organized on save
is false when saving a scene in the tagger. (#4213)Info
A number of settings and tasks are now only available when Advanced Mode
is set to true in the settings, including the Auto Tag
and Identify
tasks.
.forcegallery
file not being honoured when re-scanning after adding the file. (#4627)baseURL
not being applied to some links. (#4501)bmp
files being treated as video files in the lightbox. (#4653)Mousetrap
and MousetrapPause
to PluginApi.libraries
. (#4489)useToast
to PluginApi.hooks
. (#4546)PluginApi.components
. (#4546)task_name
parameter optional, added an optional description
parameter and deprecated args
for a generic map parameter args_map
in runPluginTask
. (#4603)runPluginOperation
to run synchronous plugin operations with a return value, without using the task manager. (#4603)PluginApi.Event.addEventListener
and stash:location
event dispatching.Info
The Enable Scene Play History
setting has been set to true for existing systems. This setting enables play counts and resuming scenes from where they were previously played. If you do not want this enabled, please disable it explicitly in Settings -> Interface -> Scene Player -> Enable Scene Play History
.
Settings -> System
, and can also be downloaded from this screen. (#4688)console
object in javascript runtime environment. (#4944)ErrUnauthorized
errors. (#4842)Info
The Movie concept has been renamed to Group.
Info
Tagger settings have been reset, but are now persisted between browser sessions. Show male performers
and Set Tags
are now defaulted to true. Please verify your settings before using the Tagger.
Groups
and now may contain orderable sub-groups with descriptions. (#5105)ffmpeg
instances while scrubbing. (#5340)STASH_BLOBS
. (#5345)Metadata Providers
page, and improved presentation. (#5040)Rescan
on the details pages will now properly recalculate file details. (#5043)career length
, measurements
and weight
. (#5129)path
column option to scene and gallery list tables. (#5005)Reload scrapers
option to top of Scrapers menus. (#5142)scene
filter criterion for Scene Marker queries. (#5097)movies
scene filter. (#5348)n
- prefixed version numbers. (#5102)PluginAPI.patch.instead
now allows for multiple plugins to hook into a single function. (#5125)Info
After upgrading, the next scan will populate all scenes with oshash hashes. MD5 calculation can be disabled after populating the oshash for all scenes. See `Hashing Algorithms` in the `Configuration` section of the manual for details.
"},{"location":"changelog/v030/#new-features","title":"\u2728 New Features","text":"Info
After upgrading, please verify your stash library settings and perform a scan to populate gallery images and the file modification times in the database.
"},{"location":"changelog/v040/#new-features","title":"\u2728 New Features","text":"STASH_STASH
environment variable if not already set.Info
After upgrading, all scene file sizes will be 0B until a new scan is run.
"},{"location":"changelog/v050/#new-features","title":"\u2728 New Features","text":"generated
directory from the library.downloads
directory when first run.python3
or python
for python script scrapers.url
field to URLReplace
, and make queryURLReplace
available when scraping by URL.cover.jpg
not being detected as cover image when in sub-directory.lbToKg
post-process action for performer scrapers.count
filter criteria and sort options./healthz
.tmp
and downloads
generated folders takes more than one second.today
and yesterday
for parseDate
in scrapers.Clear Image
button not updating image preview.Host
in input to plugins. (#1514)CreatedAt
and UpdatedAt
(and FileModTime
where applicable) to API objects. (#1421)subtractDays
post-process scraper action. (#1399)FAQ section is split into multiple categories for easier browsing, but if you have specific issue or question try using search. You can access search from the header or you can use keyboard shortcuts F , S , / to access it from any page.
"},{"location":"faq/#community-support","title":"Community support","text":"If you can't find an answer to your question here, you can always ask for help from the community.
Performer images uploaded in WebP format will not display on versions of Safari prior to version 13 or on anything earlier than MacOS Big Sur. This is a limitation of Safari. As a workaround, ensure you are uploading performer images in .jpg or .png format.
"},{"location":"faq/performers/","title":"Performers","text":""},{"location":"faq/performers/#how-can-i-add-performers-in-bulk","title":"How can I add performers in bulk?","text":"Info
You will need to have a stash-box attached as a source.
Info
You will need to have a stash-box attached as a source.
Stash tracks video files 2 ways:
Stash can still find the file even if one of them changes, all you need to do is run a scan task to trigger it. If both gets changed at the same time, Stash will create a new scene.
"},{"location":"faq/settings/","title":"Settings","text":""},{"location":"faq/settings/#how-can-i-move-my-library-from-one-location-to-another","title":"How can I move my library from one location to another?","text":"This will update all the paths for the existing objects without having to re-generate supported files.
Danger
Do not run a Clean task in between these steps, or you will lose the metadata from the affected objects. Your files will not be affected.
"},{"location":"faq/setup/","title":"Setup","text":""},{"location":"faq/setup/#how-do-i-recover-a-forgotten-username-or-password","title":"How do I recover a forgotten username or password?","text":"Stash saves login credentials in the config.yml
file. You must reset both login and password if you have forgotten your password by doing the following:
config.yml
file found in your Stash directory with a text editor;login
and password
lines from the file and save;Find the local IP address of your Stash Server (guides for Windows, MacOS, Linux). Then, on another device on your local network, open a browser to http://SERVER.IP.ADDRESS.HERE:9999
.
See this article for ideas on accessing your stash from outside your network.
"},{"location":"faq/setup/#how-do-i-serve-stash-over-ssltls-https","title":"How do I serve Stash over SSL/TLS (HTTPS)?","text":"This is typically accomplished by putting Stash behind a reverse proxy, such as Nginx or Caddy. Stash can also serve SSL directly. To use the built-in SSL:
First you must generate a SSL certificate and key combo.
Example using OpenSSLopenssl req -x509 -newkey rsa:4096 -sha256 -days 7300 -nodes -keyout stash.key -out stash.crt -extensions san -config <(echo \"[req]\"; echo distinguished_name=req; echo \"[san]\"; echo subjectAltName=DNS:stash.server,IP:127.0.0.1) -subj /CN=stash.server\n
This command would need customizing for your environment. This link might be useful.
Once you have a certificate and key file name them stash.crt
and stash.key
and place them in the same directory as the config.yml
file, or the ~/.stash
directory. Stash detects these and starts up using HTTPS rather than HTTP.
The basepath defaults to /
. When running stash via a reverse proxy in a subpath, the basepath can be changed by having the reverse proxy pass X-Forwarded-Prefix
(and optionally X-Forwarded-Port
) headers. When detects these headers, it alters the basepath URL of the UI.
config.yml
file. Usually located at %userprofile%/.stash
or $HOME/.stash
.generated:
line. generated: absolute_path_to_your_generated_folder
.If Stash is unable to find or download FFMPEG, then download and install it yourself.
The ffmpeg.exe
and ffprobe.exe
files should be placed in C:\\Users\\YourUsername\\.stash
on Windows. The ffmpeg
and ffprobe
files should be placed in ~/.stash
on macOS / Linux.
It can mean that you database got corrupted. You can verify that by running a few SQL statements. The easiest way to do so is to install a simple program called DB Browser for SQLite. Start the program and in the menu select File
> Open Database...
and select your Stash .sqlite database file. Then navigate to the Execute SQL
tab and run: - PRAGMA integrity_check;
- it should return ok
. - PRAGMA foreign_key_check;
- it should return nothing.
If you get something different it means there is an issue with your database. It's still possible that it can be recovered. You can ask for more help in one of the support channels. Another option would be to try using an older backup if you have one.
"},{"location":"faq/setup/#my-python-installation-is-not-detected","title":"My Python installation is not detected","text":"Make sure your Python version is added to environment variable PATH. This is a common issue with Python installed from Microsoft Store on Windows.
How to add Python to PATHA handy guide how you set a PATH on different operating systems: https://realpython.com/add-python-to-path/.
If you use multiple versions or have non standard configuration you can specify which version to use in Settings > System and under Applications Paths header set Python Executable Path.
Running multiple instances of Stash can be done by specifying both the -c
switch to denote an alternate config.yml
filepath, and the --p
switch to denote a unique port number.
Step-by-step Linux guide to running mutiple instances of Stash:
NEW_DIRECTORY_LOCATION
.NEW_PORT_NUMBER
../stash-linux --port NEW_PORT_NUMBER -c NEW_DIRECTORY_LOCATION/config.yml
.config.yml
to use NEW_PORT_NUMBER
. Find the line port: 9999
and replace with port: NEW_PORT_NUMBER
../stash-linux -c NEW_DIRECTORY_LOCATION/config.yml
Stash data is considered private, and Stash is not designed to be publicly exposed, except to trusted confidants. Stash has a built-in protection against accidentally exposing itself publicly outside of your network. If Stash receives a request from the public internet, and you do not have a password enabled, Stash will reject the request and stop handling requests to protect your privacy.
This often happens when you use the port-forwarding feature of your router or install Stash on a publicly accessible server, such as a VPS. When you do this, anybody in the world can access your Stash instance, so we enforce a password requirement. If your Stash instance has shutdown due to an insecure configuration, it will not handle requests again until you tell it that you have fixed the problem. After setting up either authentication, firewall, or removing your port forwarding rules, you can edit .stash/config/config.yml
and remove the key security_tripwire_accessed_from_public_internet
.
You may use several methods to safely access Stash from outside of your home network. In the most basic, you can enable authentication in Stash, and re-enable port forwarding. You can also use a VPN solution that allows you to securely access your home network, such as Tailscale, Zerotier, Wireguard, or others.
"},{"location":"faq/setup/#using-an-external-authentication-provider","title":"Using an external authentication provider","text":"If you are an advanced user, and have secured your Stash instance behind an authwall provided by a reverse proxy or hosting solution, you may continue to use that. You simply have to edit .stash/config/config.yml
and set dangerous_allow_public_without_auth
to true
. If you have already tripped the security feature, you will also have to remove the security_tripwire_accessed_from_public_internet
key in order to allow Stash to serve requests.
Info
Migrating between filesystems with different path separators (/
and \\
) is currently unsupported.
Danger
Use at your own risk. If you do this, make sure backup your database before starting.
It's possible to manually migrate the folders
table using SQL.
The following example query would replace \\
with /
and D:/
with /mnt/
.
UPDATE folders SET path = REPLACE(path, '\\', '/');\nUPDATE folders SET path = REPLACE(path, 'D:/', '/mnt/');\n
"},{"location":"faq/studios/","title":"Studios","text":""},{"location":"faq/studios/#how-can-i-add-studios-in-bulk","title":"How can I add studios in bulk?","text":"Info
You will need to have a stash-box attached as a source.
Info
You will need to have a stash-box attached as a source.
Info
If you decide to cancel the task in the queue, next time you will start the task, it will skip the files that were already scanned.
"},{"location":"guides/","title":"Guides","text":"In this section the community written guides will be published. You can submit your own via Stash-Docs repository.
If you find the guide has a typo or is outdated you can submit a pull request to fix it or make an issue on the GitHub. Thank you!
"},{"location":"guides/advanced-configuration-options/","title":"Advanced configuration options","text":"Some configuration options can not be edited through the UI and should only be used if needed.
Depending on the option they can be configured either by editing the config.yml
configuration file or by using an enviroment variable or in a few cases by using flags when running stash.
As an example the port
option can be changed from the default 9999
to 1234
by one of the below methods:
port: 1234
to the config.yml fileSTASH_PORT=1234 ./stash
./stash --port 1234
Always use the UI to create a backup of the database. As with all live databases DO NOT copy manually the database file as a means of backup.
Stash uses an sqlite database with WAL
mode enabled. This practically means that along with the main db file stash.go-sqlite
there can be a -shm
and a -wal
file present (more info). Even stopping Stash might leave some of these index files present so again DO NOT manually copy the database file.
The Backup or Download Backup tasks are the proper way to create a backup file.
Assuming you have properly created a backup file you can use it to restore your database if needed.
Info
The restore procedure uses the default stash-go.sqlite
filename, if you changed that when configuring Stash adjust accordingly.
The following steps are recommended when restoring a database file:
stash-go.sqlite
database file (along with the -shm
-wal
.journal
files if present).stash-go.sqlite
.stash-go.sqlite
file and that no -shm
-wal
.journal
files are present. You should now have Stash running with a working and restored database.
"},{"location":"guides/backup-and-restore-database/#advanced-troubleshooting","title":"Advanced troubleshooting","text":"If you get a database malformed message during upgrade or backup that probably means that the database is already corrupt. One way to get past that is to do a full export and check the error log. If there are not a lot of errors you can then try to do a full import and get a working db with minimal losses. As the full import is destructive proceed with caution. For cases like this it is better to ask for support.
"},{"location":"guides/importing-via-csv-using-gql-iterate/","title":"Bulk importing via CSV using gql-iterate","text":"If you want to add a collection of performers, tags, studios, etc, and you have a text/spreadsheet list of them, here's the walkthrough of how to do it via a simple CLI method.
"},{"location":"guides/importing-via-csv-using-gql-iterate/#step-1-install-gql-iterate","title":"Step 1: Install gql-iterate","text":"gql-iterate repository
npm install @efstajas/gql-iterate -g
or yarn add @efstajas/gql-iterate -g
For latest versions of NodeJS (14>) you need to go where you globally install your npm modules (AppData/Roaming/npm/node_modules/@efstajas/gql-iterate/bin) and add the following to the first line of the cli.js file.
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
See below for example versions of performers.gql and tags.gql samples that should work for you. Others can be figured out (with minor changes needeed) from stash/graphql/documents/mutations
These are NOT identical to the original files found above. Compare you'll see how they differ. This is very specific to be used for gql-iterate.
tags.gqlperformers.gql mutation TagCreate( \n $name: String!,\n $image: String) {\n tagCreate(input: { \n name: $name, \n image: $image \n }) {\n id\n }\n }\n
mutation PerformerCreate( \n $name: String!, \n $url: String, \n $gender: GenderEnum, \n $birthdate: String, \n $ethnicity: String, \n $country: String, \n $eye_color: String, \n $height: String, \n $measurements: String, \n $fake_tits: String, \n $career_length: String, \n $tattoos: String, \n $piercings: String, \n $aliases: String, \n $twitter: String, \n $instagram: String, \n $favorite: Boolean, \n $image: String) {\n performerCreate(input: { \n name: $name, \n url: $url, \n gender: $gender, \n birthdate: $birthdate, \n ethnicity: $ethnicity, \n country: $country, \n eye_color: $eye_color, \n height: $height, \n measurements: $measurements, \n fake_tits: $fake_tits, \n career_length: $career_length, \n tattoos: $tattoos,\n piercings: $piercings, \n aliases: $aliases, \n twitter: $twitter, \n instagram: $instagram, \n favorite: $favorite, \n image: $image }\n ) \n { id } \n }\n
If you have a suggested change, please add it below.
"},{"location":"guides/importing-via-csv-using-gql-iterate/#step-3-prepare-your-textfile-or-spreadsheet-into-a-csv","title":"Step 3: Prepare your textfile or spreadsheet into a CSV","text":"let's say you have a textfile with these performers (just names and eyecolors for a simple example) If you have a spreadsheet, add a first line with the column headers, you HAVE to provide all fields listed above in the first line, but you don't have to actually have data in them.
name,url,gender,birthdate,ethnicity,country,eye_color,height,measurements,fake_tits,career_length,tattoos,piercings,aliases,twitter,instagram,favorite,image
then add your data if text, or export as CSV if it's a spreadsheet (gender is not a string, see documentation in code, and favorite is a boolean, if you want to add those)
Alice,,,,,,blue\nBetty,,,,,,green\nCarter,,,,,,brown\n
the above lines all go into a file, like performerdata.csv
Gender is complicated due to Stash using GenderEnum.
For tags, you only need the tag title, and if desired, a url to a image
If you're unable to get this to work, then omit the favorite and image property from your CSV header, and from the performers.gql file.
"},{"location":"guides/importing-via-csv-using-gql-iterate/#step-4","title":"Step 4","text":"Note
Must use numerical IP instead of localhost.
Run this CLI command (assumes your files are in current directory and location for gql-interate is in your path)
gql-iterate --host http://_yourserverIP:portgoeshere_/graphql --input ./performerdata.csv --query ./performers.gql
It will run and add performers, it won't duplicate existing names, so you can run it multiple times if you want to add more names. Or delete something and readd it, if need be.
"},{"location":"guides/manually-editing-the-stash-sqlite3-database/","title":"Manually editing the Stash sqlite3 database","text":""},{"location":"guides/manually-editing-the-stash-sqlite3-database/#location","title":"Location","text":"The Stash Sqlite3 database file is located at ~/.stash/stash-go.sqlite
.
Before making changes to the Stash sqlite3 database - please make a backup first!
You can use the sqlite3
client to directly edit this file.
cd ~/.stash\nsqlite3 stash-go.sqlite\n
"},{"location":"guides/manually-editing-the-stash-sqlite3-database/#examples","title":"Examples","text":""},{"location":"guides/manually-editing-the-stash-sqlite3-database/#deleting-all-tags","title":"Deleting all tags","text":"If you need to delete all tags, you can use the following commands:
sqlite> DELETE FROM scenes_tags;\nsqlite> DELETE FROM tags;\n
Note
This will not work if you have Scene marker tags.
"},{"location":"guides/reverse-proxy/","title":"Reverse proxy","text":"The use of a reverse proxy for Stash is possible.
"},{"location":"guides/reverse-proxy/#general","title":"General","text":"Generally, the following headers will need to be set (check your proxy's documentation for how to configure).
See issue 134 for more information.
"},{"location":"guides/reverse-proxy/#using-a-url-prefix","title":"Using a URL prefix","text":"Stash also supports running under a URL prefix, in which case the the X-Forwarded-Prefix
header must also be set. The proxy also needs to remove the prefix from the requested URLs. For example, if you want your homepage to be accessible at http://example.domain.com/stash
, then you need to set X-Forwarded-Prefix: /stash
.
You can also set the host that will be served by Stash manually by adding an external_host:
setting in your Stash config.yml and assigning it the publicly accessible hostname, including the http://
or https://
. X-Forwarded-Prefix
will still need to be set if using a prefix.
external_host: http://example.domain.com\n
"},{"location":"guides/reverse-proxy/#server-configuration-examples","title":"Server Configuration Examples","text":""},{"location":"guides/reverse-proxy/#nginx","title":"Nginx","text":"location / {\n proxy_pass http://127.0.0.1:9999;\n\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_read_timeout 60000s;\n}\n
"},{"location":"guides/reverse-proxy/#nginx-docker-linuxserver-letsencrypt","title":"Nginx + Docker (Linuxserver Letsencrypt)","text":"If you are using the linuxserver letencrypt docker you can use create a stash.subdomain.conf
file in your proxy-confs
folder and use this as the config:
# make sure that your dns has a cname set for stash\n\nserver {\n listen 443 ssl;\n listen [::]:443 ssl;\n\n server_name stash.*;\n\n include /config/nginx/ssl.conf;\n\n client_max_body_size 0;\n\n # enable for ldap auth, fill in ldap details in ldap.conf\n #include /config/nginx/ldap.conf;\n\n location / {\n # enable the next two lines for http auth\n #auth_basic \"Restricted\";\n #auth_basic_user_file /config/nginx/.htpasswd;\n\n # enable the next two lines for ldap auth\n #auth_request /auth;\n #error_page 401 =200 /login;\n\n include /config/nginx/proxy.conf;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n resolver 127.0.0.11 valid=30s;\n set $upstream_app stash;\n set $upstream_port 9999;\n set $upstream_proto http;\n proxy_pass $upstream_proto://$upstream_app:$upstream_port;\n proxy_set_header Host $http_host;\n proxy_read_timeout 60000s;\n }\n}\n
"},{"location":"guides/reverse-proxy/#nginx-with-prefix","title":"Nginx with prefix","text":"An example for nginx
using the prefix /stash
:
location /stash/ {\n # Notice the trailing slash - this causes nginx to remove the /stash prefix from requested URLs\n proxy_pass http://192.168.0.1:9999/;\n\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Port $server_port;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_set_header X-Forwarded-Prefix /stash;\n proxy_read_timeout 60000s;\n}\n
"},{"location":"guides/reverse-proxy/#nginx-with-external_host","title":"Nginx with external_host","text":"Another example for nginx
:
In this case we are using stash.home
as our domain and 192.168.0.1
is stash's ip so edit acccordingly.
The external_host
configuration option should also be set, in this case external_host: http://stash.home
. Refer to external_host for more details.
server {\n listen 80;\n listen [::]:80;\n\n server_name stash.home;\n client_max_body_size 0;\n\n location / {\n proxy_pass http://192.168.0.1:9999;\n\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Port $server_port;\n proxy_set_header X-Forwarded-Proto $scheme;\n }\n}\n
"},{"location":"guides/reverse-proxy/#apache","title":"Apache","text":"# if using apache < 2.4.47, remove upgrade=websocket\nProxyPass \"/stash\" \"http://127.0.0.1:9999\" upgrade=websocket\nProxyPassReverse \"/stash\" \"http://127.0.0.1:9999\"\nRequestHeader setIfEmpty X-Forwarded-Prefix \"/stash\"\nProxyPreserveHost on\n\n# for name resolution\nServerAdmin admin@example.com\nServerName example.com\nServerAlias stash.example.com\n\n# to enable websockets for apache < 2.4.47\n#RewriteEngine on\n#RewriteCond %{HTTP:Upgrade} websocket [NC]\n#RewriteCond %{HTTP:Connection} upgrade [NC]\n#RewriteRule ^/?stash/(.*) \"ws://127.0.0.1:9999/$1\" [P,L]\n\n# to add SSL\nSSLEngine on\nSSLCertificateFile /path/to/cert.pem\nSSLCertificateKeyFile /path/to/cert.key\n
"},{"location":"guides/reverse-proxy/#prerequisites","title":"Prerequisites","text":"sudo a2enmod proxy\nsudo a2enmod proxy_http\nsudo a2enmod proxy_balancer\nsudo a2enmod lbmethod_byrequests\n\nsudo a2enmod rewrite\nsudo a2enmod headers\n\n# for SSL\nsudo a2enmod ssl\n
"},{"location":"guides/reverse-proxy/#caddy-v2","title":"Caddy v2","text":"stash.example.com {\n reverse_proxy 127.0.0.1:9999 {\n header_up Host {host}\n header_up X-Real-IP {remote_host}\n header_up X-Forwarded-Port {server_port}\n }\n}\n
The external_host
configuration option should also be set, in this case external_host: http://stash.home
. Refer to external_host for more details.
504
errors during stash db migration due to timeout. Adjusting the proxy_read_timeout
value ( proxy.conf
file in Letencrypt/Swag docker container)proxy.conf
file in the Letencrypt Unraid docker container for instance) as mentioned here should fix the issue.proxy_http_version 1.1;\nproxy_set_header Upgrade $http_upgrade;\nproxy_set_header Connection \"upgrade\";\n
"},{"location":"guides/reverse-proxy/#cloudflare-tunnel","title":"Cloudflare Tunnel","text":"Cloudflare Tunnels are not recommended since they throttle non-HTML traffic (which video falls under).
See Cloudflare blog post for more details.
"},{"location":"guides/run-cdp-on-truenas-scale/","title":"Run CDP on TrueNAS Scale","text":"Info
Written by WiiGe. Originally posted on stashapp/stash discussions1.
A way to use CDP scraper on TrueNAS Scale and install chromedp/headless-shell on TrueNAS Scale.
People using stash-app on TrueNAS Scale like me may face the problem that no supported CDP app by truecharts or truenas , and now I found a way to properly run chromedp/headless-shell.
This can be done by custom-app.
According to docker hub page of chromedp/headless-shell, we start container with docker run -d -p 9222:9222 --rm --name headless-shell --shm-size 2G chromedp/headless-shell
, but this's not enough for TrueNAS Scale which run everything with K3s.
In order to run a docker image on K3s, we need to warp docker image with custom-app, fill the Container Repository with chromedp/headless-shell
and Container Tag with latest
so that TrueNAS can pull the image for you.
As for the docker args docker run -d -p 9222:9222 --rm --name headless-shell --shm-size 2G chromedp/headless-shell
, we need to translate the args and env parameter into custom-app configuration. Under the Workload Settings section of custom-app configuration page, there will be a list of Extra Args, we put --name headless-shell --shm-size 2G
here in custom-app way.
But due to this issue, K3s will report an error of zygote: ERROR:zygote_host_impl_linux.cc(262)] Failed to adjust OOM score of renderer with pid 28: Permission denied (13)
, solution is simple - just offer extra args to disable it :--headless --disable-gpu --no-sandbox --no-zygote --disable-software-rasterizer --disable-dev-shm-usage
.
--remote-debugging-address=0.0.0.0 --remote-debugging-port=9222
is not needed because we will set port and ip on Networking and Services section for LoadBalancer (I am using 192.168.1.45 and 9222, change it for your own scenario).
The Networking section and the final Extra Args page should be like this:
and click Install button then your headless-shell will be good to go.
The last step: just fill stash's CDP setting with http://192.168.1.45:9222/json/version
(still, change ip:port for your own scenario), and now cdp should be running for you.
An extra note is Ingress section of custom-app, you may want to use chromedp/headless-shell remotely (e.g. accessing cdp by https://cdp.example.com/json/version), you need to modify the header of request with SetHeader function, see Host header is specified and is not an IP address or localhost. Obviously stash scraper do not support such operation, write your own scraper in this circumstances.
I just put the info I found together and share here, hope this page help more people who try to use CDP scraper on K3s-based OS.
https://github.com/stashapp/stash/discussions/4719 \u21a9
A regular scraper can only scrape information from webpages that are open to the public access. If you want to scrape a webpage that requires login or behind a paywall, you need to use the \"Visible CDP\" technique.
Normal CDP scraping will launch a headless chrome browser, which will not show up for any user interactions. \"Visible CDP\" turns the \"headless chrome\" into a \"visible\" instance.
driver:\n useCDP: true\n
chrome.exe --remote-debugging-port=9222
. This will launch a special Chrome instance that Stash Scrapers can control later on.http://localhost:9222/json/version
.stash-box is an open-source video indexing and metadata API server for porn developed by Stash team. It provides a crowdsourced database of metadata for adult performers, studios and scenes.
Stash has several ways to scrape from stash-box instances. From automatic to manual. Each has its own advantages and disadvantages.
Scan task and its options are applied when the content is being added to the database the first time.
Generate task and its options are applied when you want to generate additional things for content that is already in your database.
"},{"location":"guides/scraping-scenes-via-stash-box/#configure-stash-box-endpoint","title":"Configure stash-box endpoint","text":"Known stash-box instances
A list of public stash-box instances is available here.
Recommended to people that value accuracy the most. It can automatically go through scenes and match them based on perceptual hash, but object creation and verification is left to you and nothing is saved until you click Save.
Opposite the Source click on the to open configuration.
You can enable Mark as Organized on save which will apply Organized flag.
Organized flagOrganized flag has a technical purpose in addition to being able to be used in a filter. All objects marked as organized will be ignored by automatic tasks like Identify and Auto Tag.
Click on Scrape All and look through the results. Add missing objects and click Save.
For scenes that you clicked Save on, you can submit your file fingerprints (hashes) back to the instance to help improve the accuracy. Scroll to the top and click Submit x fingerprints.
FingerprintsAll fingerprints are tied to the user API key, no other information is sent to the stash-box instance. Privacy is paramount.
For people that want fully automatic option and don't mind some potential inaccuracies. The task will automatically go through all scenes and match them based on perceptual hash. You can also create all missing objects automatically. No manual verification is possible.
Warning
Task is irreversible, so it's a good idea to make a backup before running it.
Under Sources select a stash-box instance(s) you want to match against.
Info
Identify task iterates through sources until it finds a match, once it finds a match, it will ignore all other sources for that scene.
Configure default options that will apply to all sources (they can be overwritten for individual sources by clicking next to each source).
In addition to previous methods, there is also a completely manual way to match scenes individually.
You can use the ffprobe command to gather useful information about a video file:
ffprobe -show_format -show_streams big_buck_bunny.mkv\n
This can be useful for example, when filing bug reports, or discussing in chat.
"},{"location":"guides/troubleshooting-video-playback/#remuxing-files","title":"Remuxing files","text":"Another good test, is to see if remuxing the file into a new video file helps:
ffmpeg -i big_buck_bunny.mkv -c:v copy -c:a copy remuxed_file.mkv\n
"},{"location":"guides/troubleshooting-video-playback/#extracting-a-sample-of-a-video","title":"Extracting a sample of a video","text":"If you are asked for a sample of a video (e.g. for developers to analyse), you can use
ffmpeg -ss 120 -i big_buck_bunny.mkv -t 30 -c:v copy -c:a copy 30_second_sample.mkv\n
The above command starts at the 120-second marker, and takes a 30-second sample of the video file.
"},{"location":"in-app-manual/","title":"In-app manual","text":"Info
Stash internal help manual, mirrored from stashapp/stash/ui/v2.5/src/docs/en/Manual.
Internal links will be broken as a result, but will work correctly when browsing the Help section inside Stash.
"},{"location":"in-app-manual/browsing/","title":"Browsing","text":""},{"location":"in-app-manual/browsing/#querying-and-filtering","title":"Querying and Filtering","text":""},{"location":"in-app-manual/browsing/#keyword-searching","title":"Keyword searching","text":"The text field allows you to search using keywords. Keyword searching matches on different fields depending on the object type:
Type Fields searched Scene Title, Details, Path, OSHash, Checksum, Marker titles Image Title, Path, Checksum Group Title Marker Title, Scene title Gallery Title, Path, Checksum Performer Name, Aliases Studio Name, Aliases Tag Name, AliasesKeyword matching uses the following rules:
foo bar
matches scenes with both foo
and bar
in the title.or
keyword or symbol (|
) is used to match either fields. For example, foo or bar
(or foo | bar
) matches scenes with foo
or bar
in the title. Or sets can be combined. For example, foo or bar or baz xyz or zyx
matches scenes with one of foo
, bar
and baz
, and xyz
or zyx
.-
) is used to exclude terms. For example, foo -bar
matches scenes with foo
and excludes those with bar
. The not symbol cannot be combined with an or operand. That is, -foo or bar
will be interpreted to match -foo
or bar
. On the other hand, foo or bar -baz
will match foo
or bar
and exclude baz
.\"
) matches on that exact phrase. For example, \"foo bar\"
matches scenes with foo bar
in the title. Quotes may also be used to escape the keywords and symbols. For example, foo \"-bar\"
will match scenes with foo
and -bar
.\"foo bar\" or baz -\"xyz zyx\"
will match scenes with foo bar
or baz
, and exclude those with xyz zyx
.or
keywords or symbols at the start or end of a line will be treated literally. That is, or foo
will match scenes with or
and foo
.Filters can be accessed by clicking the filter button on the right side of the query text field.
Note that only one filter criterion per criterion type may be assigned.
"},{"location":"in-app-manual/browsing/#regex-modifiers","title":"Regex modifiers","text":"Some filters have regex modifier as an option. Regex modifiers are always case-sensitive.
"},{"location":"in-app-manual/browsing/#sorting-and-page-size","title":"Sorting and page size","text":"The current sorting field is shown next to the query text field, indicating the current sort field and order. The page size dropdown allows selecting from a standard set of objects per page, and allows setting a custom page size.
"},{"location":"in-app-manual/browsing/#saved-filters","title":"Saved filters","text":"Saved filters can be accessed with the bookmark button on the left of the query text field. The current filter can be saved by entering a filter name and clicking on the save button. Existing saved filters may be overwritten with the current filter by clicking on the save button next to the filter name. Saved filters may also be deleted by pressing the delete button next to the filter name.
Saved filters are sorted alphabetically by title with capitalized titles sorted first.
"},{"location":"in-app-manual/browsing/#default-filter","title":"Default filter","text":"The default filter for the top-level pages may be set to the current filter by clicking the Set as default
button in the saved filter menu.
Stash supports captioning with SRT and VTT files.
These files need to be named as follows:
"},{"location":"in-app-manual/captions/#scene","title":"Scene","text":"Where {language_code}
is defined by the ISO-6399-1 (2 letters) standard and ext
is the file extension. Captions files without a language code will be labeled as Unknown in the video player but will work fine.
Scenes with captions can be filtered with the captions
criterion.
Note: If the caption file was added after the scene was initially added during scan you will need to run a Selective Scan task for it to show up.
"},{"location":"in-app-manual/configuration/","title":"Configuration","text":""},{"location":"in-app-manual/configuration/#library","title":"Library","text":"This section allows you to add and remove directories from your library list. Files in these directories will be included when scanning. Files that are outside of these directories will be removed when running the Clean task.
\u26a0\ufe0f Note: Don't forget to click Save
after updating these directories!
Given a valid regex, files that match even partially are excluded during the Scan process and are not entered in the database. Also during the Clean task if these files exist in the DB they are removed from it and their generated files get deleted. Prior to matching both the filenames and patterns are converted to lower case so the match is case insensitive.
Regex patterns can be added in the config file or from the UI. If you add manually to the config file a restart is needed while from the UI you just need to click the Save button. When added through the config file directly special care must be given to double escape the \\
character.
There are 2 separate exclusion settings. One is for videos, another is for images/galleries.
Some examples:
\"sample\\.mp4$\"
will exclude all files ending in sample.mp4
. \"/\\.[[:word:]]+/\"
will exclude all hidden directories like /.directoryname/
.\"c:\\\\stash\\\\videos\\\\exclude\"
will exclude specific Windows directory c:\\stash\\videos\\exclude
.\"^/stash/videos/exclude/\"
will exclude all directories that match /stash/videos/exclude/
pattern.\"\\\\\\\\stash\\\\network\\\\share\\\\excl\\\\\"
will exclude specific Windows network path \\\\stash\\network\\share\\excl\\
.Note: If a directory is excluded for images and videos, then the directory will be excluded from scans completely.
There is a useful regex101 site that can help test and experiment with regexps.
"},{"location":"in-app-manual/configuration/#gallery-creation-from-folders","title":"Gallery creation from folders","text":"In the Library section you can find an option to create a gallery from each folder containing images. This will be applied on all libraries when activated, including the base folder of a library.
If you wish to apply this on a per folder basis, you can create a file called .nogallery or .forcegallery in a folder that should act different than this global setting.
This will either exclude the folder from becoming a gallery even if the setting is set, or create a gallery from the folder even if the setting is not set.
The file will only be recognized if written in lower case letters.
Files with a dot in front are handled as hidden in the Linux OS and Mac OS, so you will not see those files after creation on your system without setting your file manager accordingly.
"},{"location":"in-app-manual/configuration/#hashing-algorithms","title":"Hashing algorithms","text":"Stash identifies video files by calculating a hash of the file. There are two algorithms available for hashing: oshash
and MD5
. MD5
requires reading the entire file, and can therefore be slow, particularly when reading files over a network. oshash
(which uses OpenSubtitle's hashing algorithm) only reads 64k from each end of the file.
The hash is used to name the generated files such as preview images and videos, and sprite images.
By default, new systems have MD5 calculation disabled for optimal performance. Existing systems that are upgraded will have the oshash populated for each scene on the next scan.
"},{"location":"in-app-manual/configuration/#changing-the-hashing-algorithm","title":"Changing the hashing algorithm","text":"To change the file naming hash to oshash, all scenes must have their oshash values populated. oshash population is done automatically when scanning.
To change the file naming hash to MD5
, the MD5 must be populated for all scenes. To do this, Calculate MD5
for videos must be enabled and the library must be rescanned.
MD5 calculation may only be disabled if the file naming hash is set to oshash
.
After changing the file naming hash, any existing generated files will now be named incorrectly. This means that stash will not find them and may regenerate them if the Generate task
is used. To remedy this, run the Rename generated files
task, which will rename existing generated files to their correct names.
These instructions are for existing users whose systems will be defaulted to use and calculate MD5 checksums. Once completed, MD5 checksums will no longer be calculated when scanning, and oshash will be used for generated file naming. Existing calculated MD5 checksums will remain on scenes, but checksums will not be calculated for new scenes.
Calculate MD5
and select oshash
as file naming hash. Save the configuration.Rename generated files
migration button.This setting controls how many sub-tasks will be run in parallel during scanning and generation tasks. (See Tasks)
Auto-detection can be enabled by setting this to zero. This will calculate the number of parallel tasks to be logical cores/4 + 1.
This setting can be used to increase/decrease overall CPU utilisation in two scenarios:
Note: If this is set too high it will decrease overall performance and causes failures (out of memory).
"},{"location":"in-app-manual/configuration/#hardware-accelerated-live-transcoding","title":"Hardware accelerated live transcoding","text":"Hardware accelerated live transcoding can be enabled by setting the FFmpeg hardware encoding
setting. Stash outputs the supported hardware encoders to the log file on startup at the Info log level. If a given hardware encoder is not supported, it's error message is logged to the Debug log level for debugging purposes.
To stream using HLS (such as on Apple devices) or DASH, the Cache path must be set. This directory is used to store temporary files during the live-transcoding process. The Cache path can be set in the System settings page.
"},{"location":"in-app-manual/configuration/#ffmpeg-arguments","title":"ffmpeg arguments","text":"Additional arguments can be injected into ffmpeg when generating previews and sprites, and when live-transcoding videos.
The ffmpeg arguments configuration is split into Input
and Output
arguments. Input arguments are injected before the input file argument, and output arguments are injected before the output file argument.
Arguments are accepted as a list of strings. Each string is a separate argument. For example, a single argument of -foo bar
would be treated as a single argument \"-foo bar\"
. The correct way to pass this argument would be to split it into two separate arguments: \"-foo\", \"bar\"
.
Some websites require a legitimate User-Agent string when receiving requests, or they will be rejected. If entered, this string will be applied as the User-Agent
header value in http scrape requests.
Some scrapers require a Chrome instance to function correctly. If left empty, stash will attempt to find the Chrome executable in the path environment, and will fail if it cannot find one.
Chrome CDP path
can be set to a path to the chrome executable, or an http(s) address to remote chrome instance (for example: http://localhost:9222/json/version
).
By default, stash is not configured with any sort of password protection. To enable password protection, both Username
and Password
must be populated. Note that when entering a new username and password where none was set previously, the system will immediately request these credentials to log you in.
If password protection is enabled, you may also generate an API key. An API key is used by external systems to access your stash system without needing to login first.
External systems using the API key must set the ApiKey
header value to the configured API key in order to bypass the login requirement.
The logout button is situated in the upper-right part of the screen when you are logged in.
"},{"location":"in-app-manual/configuration/#recovering-from-a-forgotten-username-or-password","title":"Recovering from a forgotten username or password","text":"Stash saves login credentials in the config.yml file. You must reset both login and password if you have forgotten your password by doing the following: * Close your Stash process * Open the config.yml
file found in your Stash directory with a text editor * Delete the login
and password
lines from the file and save Stash authentication should now be reset with no authentication credentials.
These options are typically not exposed in the UI and must be changed manually in the config.yml
file.
custom_served_folders
A map of URLs to file system folders. See below. custom_ui_location
The file system folder where the UI files will be served from, instead of using the embedded UI. Empty to disable. Stash must be restarted to take effect. developer_options.extra_blob_paths
A list of alternative blob paths. These paths will be read for blob files. Blobs will not be written or deleted from these paths. Intended for developer use only. max_upload_size
Maximum file upload size for import files. Defaults to 1GB. theme_color
Sets the theme-color
property in the UI. gallery_cover_regex
The regex responsible for selecting images as gallery covers proxy
The url of a HTTP(S) proxy to be used when stash makes calls to online services Example: https://user:password@my.proxy:8080 no_proxy
A list of domains for which the proxy must not be used. Default is all local LAN: localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12 sequential_scanning
Modifies behaviour of the scanning functionality to generate support files (previews/sprites/phash) at the same time as fingerprinting/screenshotting. Useful when scanning cached remote files. The following environment variables are also supported:
Environment variable RemarksSTASH_SQLITE_CACHE_SIZE
Sets the SQLite cache size. See https://www.sqlite.org/pragma.html#pragma_cache_size. Default is -2000
which is 2MB."},{"location":"in-app-manual/configuration/#custom-served-folders","title":"Custom served folders","text":"Custom served folders are served when the server handles a request with the /custom
URL prefix. The following is an example configuration:
custom_served_folders:\n /: D:\\stash\\static\n /foo: D:\\bar\n
With the above configuration, a request for /custom/foo/bar.png
would serve D:\\bar\\bar.png
.
The /
entry matches anything that is not otherwise mapped by the other entries. For example, /custom/baz/xyz.png
would serve D:\\stash\\static\\baz\\xyz.png
.
Financial contributions are welcomed and are accepted using Open Collective.
"},{"location":"in-app-manual/contributing/#development-related","title":"Development-related","text":"The Stash backend is written in Go, using a SQLite database. The UI is written in Typescript, using React. Bug fixes, improvements and new features are welcomed. Please see the DEVELOPMENT.md file for details on how to get started. Assistance is available via our Discord.
"},{"location":"in-app-manual/contributing/#documentation","title":"Documentation","text":"Efforts to improve documentation in Stash helps new users and reduces the number of questions we have to field in Discord. Contributions to documentation are welcomed. While submitting documentation changes via GitHub pull requests is ideal, we will gladly accept submissions via GitHub issues or on Discord.
For those with web page experience, we also welcome contributions to our website (which as of writing is very undeveloped).
"},{"location":"in-app-manual/contributing/#testing-features-improvements-and-bug-fixes","title":"Testing features, improvements and bug fixes","text":"Testing is currently covered by a very small group, so new testers are welcomed. Being able to build Stash locally is ideal, but binaries for pull requests are also available.
First, you will need to be signed in to GitHub. Find and open the relevant pull request, and then click on the Checks
tab. On the right, there should be a button titled Artifacts
- click that, and you should get a dropdown with links to download binaries built from that pull request for Linux, Windows and macOS.
We welcome ideas for future improvements and features, and bug reports help everyone. These can all be found on GitHub.
"},{"location":"in-app-manual/contributing/#providing-support","title":"Providing support","text":"Offering support for new users on Discord is also welcomed.
"},{"location":"in-app-manual/deduplication/","title":"Dupe Checker","text":"The dupe checker searches your collection for scenes that are perceptually similar. This means that the files don't need to be identical, and will be identified even with different bitrates, resolutions, and intros/outros.
To achieve this stash needs to generate what's called a phash, or perceptual hash. Similar to sprite generation stash will generate a set of 25 images from fixed points in the scene. These images will be stitched together, and then hashed using the phash algorithm. The phash can then be used to find scenes that are the same or similar to others in the database. Phash generation can be run during scan, or as a separate task. Note that generation can take a while due to the work involved with extracting screenshots.
The dupe checker can be run with four different levels of accuracy. Exact
looks for scenes that have exactly the same phash. This is a fast and accurate operation that should not yield any false positives except in very rare cases. The other accuracy levels look for duplicate files within a set distance of each other. This means the scenes don't have exactly the same phash, but are very similar. High
and Medium
should still yield very good results with few or no false positives. Low
is likely to produce some false positives, but might still be useful for finding dupes.
Note that to generate a phash stash requires an uncorrupted file. If any errors are encountered during sprite generation the phash will not be generated. This is to prevent false positives.
"},{"location":"in-app-manual/images/","title":"Images and Galleries","text":"Images are the parts which make up galleries, but you can also have them be scanned independently. To declare an image part of a gallery, there are four ways:
You can add images to every gallery manually in the gallery detail page. Deleting can be done by selecting the according images in the same view and clicking on the minus next to the edit button.
For best results, images in zip file should be stored without compression (copy, store or no compression options depending on the software you use. Eg on linux: zip -0 -r gallery.zip foldertozip/
). This impacts heavily on the zip read performance.
If a filename of an image in the gallery zip file ends with cover.jpg
, it will be treated like a cover and presented first in the gallery view page and as a gallery cover in the gallery list view. If more than one images match the name the first one found in natural sort order is selected.
Images can also be clips/gifs. These are meant to be short video loops. Right now they are not possible in zipfiles. To declare video files to be images, there are two ways:
A clip/gif will be a stillframe in the wall and grid view by default. To view the loop, you can go into the Lightbox Carousel (e.g. by clicking on an image in the wall view) or the image detail page.
If you want the loop to be used as a preview on the wall and grid view, you will have to generate them. You can do this as you scan for the new clip file by activating Generate previews for image clips on the scan settings, or do it after by going to the Generated Content section in the task section of your settings, activating Image Clip Previews and clicking generate. This takes a while, as the files are transcoded.
"},{"location":"in-app-manual/interactive/","title":"Interactivity","text":"Stash currently supports syncing with Handy devices, using funscript files.
In order for stash to connect to your Handy device, the Handy Connection Key must be entered in Settings -> Interface.
Funscript files must be in the same directory as the matching video file and must have the same base name. For example, a funscript file for video.mp4
must be named video.funscript
. A scan must be run to update scenes with matching funscript files.
Scenes with funscript files can be filtered with the interactive
criterion.
Setting the language affects the formatting of numbers and dates.
"},{"location":"in-app-manual/interface/#scenemarker-wall-preview-type","title":"Scene/Marker Wall Preview Type","text":"The Scene Wall and Marker pages display scene preview videos (mp4) by default. This can be changed to animated image (webp) or static image.
\u26a0\ufe0f Note: scene/marker preview videos must be generated to see them in the applicable wall page if Video preview type is selected. Likewise, if Animated Image is selected, then Image Previews must be generated.
"},{"location":"in-app-manual/interface/#show-studios-as-text","title":"Show Studios as text","text":"By default, a scene's studio will be shown as an image overlay. Checking this option changes this to display studios as a text name instead.
"},{"location":"in-app-manual/interface/#scene-player-options","title":"Scene Player options","text":"By default, scene videos do not automatically start when navigating to the scenes page. Checking the \"Auto-start video\" option changes this to auto play scene videos.
The maximum loop duration option allows looping of shorter videos. Set this value to the maximum scene duration that scene videos should loop. Setting this to 0 disables this functionality.
"},{"location":"in-app-manual/interface/#activity-tracking","title":"Activity tracking","text":"The \"Track Activity\" option allows tracking of scene play count and duration, and sets the resume point when a scene video is not finished.
The \"Minimum Play Percent\" gives the minimum proportion of a video that must be played before the play count of the scene is incremented.
By default, when a scene has a resume point, the scene player will automatically seek to this point when the scene is played. Setting \"Always start video from beginning\" to true disables this behaviour.
"},{"location":"in-app-manual/interface/#custom-css","title":"Custom CSS","text":"The stash UI can be customised using custom CSS. See here for a community-curated set of CSS snippets to customise your UI.
Stash Plex Theme is a community created theme inspired by the popular Plex interface.
"},{"location":"in-app-manual/interface/#custom-javascript","title":"Custom Javascript","text":"Stash supports the injection of custom javascript to assist with theming or adding additional functionality. Be aware that bad Javascript could break the UI or worse.
"},{"location":"in-app-manual/interface/#custom-locales","title":"Custom Locales","text":"The localisation strings can be customised. The master list of default (en-GB) locale strings can be found here. The custom locale format is the same as this json file.
For example, to override the actions.add_directory
label (which is Add Directory
by default), you would have the following in the custom locale:
{\n \"actions\": {\n \"add_directory\": \"Some other description\"\n }\n}\n
"},{"location":"in-app-manual/interface/#custom-served-folders","title":"Custom served folders","text":"It is possible to expose specific folders to the UI. This configuration is performed manually in the config.yml
file only.
Custom served content is exposed via the /custom
URL path prefix.
For example, in the config.yml
file:
custom_served_folders:\n /: D:\\stash\\static\n /foo: D:\\bar\n
With the above configuration, a request for /custom/foo/bar.png
would return D:\\bar\\bar.png
. The /
entry matches anything that is not otherwise mapped by the other entries. For example, /custom/baz/xyz.png
would return D:\\stash\\static\\baz\\xyz.png
.
Applications for this include using static images in custom css, like the Plex theme. For example, using the following config:
custom_served_folders:\n /: <stash folder>\\custom\n
The background.png
and noise.png
files can be placed in the custom
folder, then in the custom css, the ./background.png
and ./noise.png
strings can be replaced with /custom/background.png
and /custom/noise.png
respectively.
Other applications are to add custom UIs to stash, accessible via /custom
.
Stash works by cataloging your media using the paths that you provide. Once you have configured the locations where your media is stored, you can click the Scan button in Settings -> Tasks
and stash will begin scanning and importing your media into its library.
For the best experience, it is recommended that after a scan is finished, that video previews and sprites are generated. You can do this in Settings -> Tasks
. Note that currently it is only possible to perform one task at a time and but there is a task queue, so the generate tasks should be performed after scan is complete.
Once your media is imported, you are ready to begin creating Performers, Studios and Tags, and curating your content!
"},{"location":"in-app-manual/keyboardshortcuts/","title":"Keyboard Shortcuts","text":""},{"location":"in-app-manual/keyboardshortcuts/#global-shortcuts","title":"Global shortcuts","text":"Keyboard sequence Action?
Display manual"},{"location":"in-app-manual/keyboardshortcuts/#global-navigation","title":"Global Navigation","text":"Keyboard sequence Target page g s
Scenes g i
Images g v
Groups g k
Markers g l
Galleries g p
Performers g u
Studios g t
Tags g z
Settings"},{"location":"in-app-manual/keyboardshortcuts/#query-page-shortcuts","title":"Query page shortcuts","text":"Keyboard sequence Action /
Focus search field / focus query field in filter dialog f
Show Add Filter dialog r
Reshuffle if sorted by random v g
Set view to grid v l
Set view to list v w
Set view to wall +
Increase zoom slider -
Decrease zoom slider \u2190
Previous page of results \u2192
Next page of results Shift + \u2190
Go to current results page -10 Shift + \u2192
Go to current results page +10 Ctrl + Home
Go to first page of results Ctrl + End
Go to last page of results s a
Select all on page s n
Unselect all e
Edit selected d d
Delete selected"},{"location":"in-app-manual/keyboardshortcuts/#scenes-page-shortcuts","title":"Scenes page shortcuts","text":"Keyboard sequence Action p r
Play random scene"},{"location":"in-app-manual/keyboardshortcuts/#scene-page-shortcuts","title":"Scene page shortcuts","text":"Keyboard sequence Action a
Details tab q
Queue tab k
Markers tab i
File info tab e
Edit tab h
History tab ,
Hide/Show sidebar .
Hide/Show scene scrubber o
Increment O-Counter p n
Play next scene in queue p p
Play previous scene in queue p r
Play random scene in queue Space
Play/pause player Enter
Play/pause player \u2190
Seek backwards by 10 seconds \u2192
Seek forwards by 10 seconds Shift + \u2190
Seek backwards by 5 seconds Shift + \u2192
Seek forwards by 5 seconds Ctrl/Alt + \u2190
Seek backwards by 1 minute Ctrl/Alt + \u2192
Seek forwards by 1 minute {1-9}
Seek to 10-90% duration [
Scrub backwards 10% duration ]
Scrub forwards 10% duration \u2191
Increase volume 10% \u2193
Decrease volume 10% m
Toggle mute l
A/B looping toggle. Press once to set start point. Press again to set end point. Press again to disable loop. Shift + l
Toggle looping of scene when it's over"},{"location":"in-app-manual/keyboardshortcuts/#scene-markers-tab-shortcuts","title":"Scene Markers tab shortcuts","text":"Keyboard sequence Action n
Display Create Markers dialog"},{"location":"in-app-manual/keyboardshortcuts/#edit-scene-tab-shortcuts","title":"Edit Scene tab shortcuts","text":"Keyboard sequence Action r {1-5}
Set rating (stars) r 0
Unset rating (stars) r {0-9} {0-9}
Set rating (decimal - 00
for 10.0
) r `
Unset rating (decimal) s s
Save Scene d d
Delete Scene Ctrl + v
Paste Scene cover"},{"location":"in-app-manual/keyboardshortcuts/#groups-page-shortcuts","title":"Groups Page shortcuts","text":"Keyboard sequence Action n
New Group"},{"location":"in-app-manual/keyboardshortcuts/#group-page-shortcuts","title":"Group Page shortcuts","text":"Keyboard sequence Action e
Edit Group s s
Save Group d d
Delete Group r {1-5}
[Edit mode] Set rating (stars) r 0
[Edit mode] Unset rating (stars) r {0-9} {0-9}
[Edit mode] Set rating (decimal - r 0 0
for 10.0
) r `
[Edit mode] Unset rating (decimal) ,
Expand/Collapse Details Ctrl + v
Paste Group image"},{"location":"in-app-manual/keyboardshortcuts/#markers-page-shortcuts","title":"Markers Page shortcuts","text":"Keyboard sequence Action p r
Play random marker"},{"location":"in-app-manual/keyboardshortcuts/#performers-page-shortcuts","title":"Performers Page shortcuts","text":"Keyboard sequence Action n
New Performer p r
Open random Performer"},{"location":"in-app-manual/keyboardshortcuts/#performer-page-shortcuts","title":"Performer Page shortcuts","text":"Keyboard sequence Action c
Scenes tab e
Edit tab o
Operations tab f
Toggle favourite ,
Expand/Collapse Details"},{"location":"in-app-manual/keyboardshortcuts/#edit-performer-tab-shortcuts","title":"Edit Performer tab shortcuts","text":"Keyboard sequence Action s s
Save Performer d d
Delete Performer Ctrl + v
Paste Performer image"},{"location":"in-app-manual/keyboardshortcuts/#studios-page-shortcuts","title":"Studios Page shortcuts","text":"Keyboard sequence Action n
New Studio"},{"location":"in-app-manual/keyboardshortcuts/#studio-page-shortcuts","title":"Studio Page shortcuts","text":"Keyboard sequence Action e
Edit Studio s s
Save Studio d d
Delete Studio ,
Expand/Collapse Details Ctrl + v
Paste Studio image"},{"location":"in-app-manual/keyboardshortcuts/#tags-page-shortcuts","title":"Tags Page shortcuts","text":"Keyboard sequence Action n
New Tag"},{"location":"in-app-manual/keyboardshortcuts/#tag-page-shortcuts","title":"Tag Page shortcuts","text":"Keyboard sequence Action e
Edit Tag s s
Save Tag d d
Delete Tag ,
Expand/Collapse Details Ctrl + v
Paste Tag image"},{"location":"in-app-manual/tagger/","title":"Scene Tagger","text":"Stash can be integrated with stash-box which acts as a centralized metadata database. This is in the early stages of development but can be used for fingerprint/keyword lookups and automated tagging of performers and scenes. The batch tagging interface can be accessed from the scene view. For more information join our Discord.
"},{"location":"in-app-manual/tagger/#searching","title":"Searching","text":"The fingerprint search matches your current selection of files against the remote stash-box instance. Any scenes with a matching fingerprint will be returned, although there is currently no validation of fingerprints so it\u2019s recommended to double-check the validity before saving.
If no fingerprint match is found it\u2019s possible to search by keywords. The search works by matching the query against a scene\u2019s title, release date, studio name, and performer names. By default the tagger uses metadata set on the file, or parses the filename, this can be changed in the config.
An important thing to note is that it only returns a match if all query terms are a match. As an example, if a scene is titled \"A Trip to the Mall\"
with the performer \"Jane Doe\"
, a search for \"Trip to the Mall 1080p\"
will not match, however \"trip mall doe\"
would. Usually a few pieces of info is enough, for instance performer name + release date or studio name. To avoid common non-related keywords you can add them to the blacklist in the tagger config. Any items in the blacklist are stripped out of the query.
When a scene is matched stash will try to match the studio and performers against your local studios and performers. If you have previously matched them, they will automatically be selected. If not you either have to select the correct performer/studio from the dropdown, choose create to create a new entity, or skip to ignore it.
Once a scene is saved the scene and the matched studio/performers will have the stash_id
saved which will then be used for future tagging.
By default male performers are not shown, this can be enabled in the tagger config. Likewise scene tags are by default not saved. They can be set to either merge with existing tags on the scene, or overwrite them. It is not recommended to set tags currently since they are hard to deduplicate and can litter your data.
"},{"location":"in-app-manual/tagger/#submitting-fingerprints","title":"Submitting fingerprints","text":"After a scene is saved you will prompted to submit the fingerprint back to the stash-box instance. This is optional, but can be helpful for other users who have an identical copy who will then be able to match via the fingerprint search. No other information than the stash_id
and file fingerprint is submitted.
Stash supports plugins that can do the following: - perform custom tasks when triggered by the user from the Tasks page - perform custom tasks when triggered from specific events - add custom CSS to the UI - add custom JavaScript to the UI
Plugin tasks can be implemented using embedded Javascript, or by calling an external binary.
\u26a0\ufe0f Note: Plugin support is still experimental and is likely to change.
"},{"location":"in-app-manual/plugins/#managing-plugins","title":"Managing Plugins","text":"Plugins can be installed and managed from the Settings > Plugins
page.
Scrapers are installed using the Available Plugins
section. This section allows configuring sources from which to install plugins. The Community (stable)
source is configured by default. This source contains plugins for the current stable version of stash.
These are the plugin sources maintained by the stashapp organisation:
Name Source URL Recommended Local Path Notes Community (stable)https://stashapp.github.io/CommunityScripts/stable/index.yml
stable
For the current stable version of stash. Community (develop) https://stashapp.github.io/CommunityScripts/develop/index.yml
develop
For the develop version of stash. Installed plugins can be updated or uninstalled from the Installed Plugins
section.
The source URL must return a yaml file containing all the available packages for the source. An example source yaml file looks like the following:
- id: <package id>\n name: <package name>\n version: <version>\n date: <date>\n requires:\n - <ids of packages required by this package (optional)>\n - ...\n path: <path to package zip file>\n sha256: <sha256 of zip>\n metadata:\n <optional key/value pairs for extra information>\n- ...\n
Path can be a relative path to the zip file or an external URL.
"},{"location":"in-app-manual/plugins/#adding-plugins-manually","title":"Adding plugins manually","text":"By default, Stash looks for plugin configurations in the plugins
sub-directory of the directory where the stash config.yml
is read. This will either be the $HOME/.stash
directory or the current working directory.
Plugins are added by adding configuration yaml files (format: pluginName.yml
) to the plugins
directory.
Loaded plugins can be viewed in the Plugins page of the Settings. After plugins are added, removed or edited while stash is running, they can be reloaded by clicking Reload Plugins
button.
Plugins provide tasks which can be run from the Tasks page.
"},{"location":"in-app-manual/plugins/#creating-plugins","title":"Creating plugins","text":""},{"location":"in-app-manual/plugins/#plugin-configuration-file-format","title":"Plugin configuration file format","text":"The basic structure of a plugin configuration file is as follows:
name: <plugin name>\ndescription: <optional description of the plugin>\nversion: <optional version tag>\nurl: <optional url>\n\nui:\n # optional list of css files to include in the UI\n css:\n - <path to css file>\n\n # optional list of js files to include in the UI\n javascript:\n - <path to javascript file>\n\n # optional list of plugin IDs to load prior to this plugin\n requires:\n - <plugin ID>\n\n # optional list of assets \n assets:\n urlPrefix: fsLocation\n ...\n\n # content-security policy overrides\n csp:\n script-src:\n - http://alloweddomain.com\n\n style-src:\n - http://alloweddomain.com\n\n connect-src:\n - http://alloweddomain.com\n\n # map of setting names to be displayed in the plugins page in the UI\n settings:\n # internal name\n foo:\n # name to display in the UI\n displayName: Foo\n # type of the attribute to show in the UI\n # can be BOOLEAN, NUMBER, or STRING\n type: BOOLEAN\n\n# the following are used for plugin tasks only\nexec:\n - ...\ninterface: [interface type]\nerrLog: [one of none trace, debug, info, warning, error]\ntasks:\n - ...\n
The name
, description
, version
and url
fields are displayed on the plugins page.
The exec
, interface
, errLog
and tasks
fields are used only for plugins with tasks.
The settings
field is used to display plugin settings on the plugins page. Plugin settings can also be set using the graphql mutation configurePlugin
- the settings set this way do not need to be specified in the settings
field unless they are to be displayed in the stock plugin settings UI.
The css
and javascript
field values may be relative paths to the plugin configuration file, or may be full external URLs.
The requires
field is a list of plugin IDs which must have their javascript/css files loaded before this plugins javascript/css files.
The assets
field is a map of URL prefixes to filesystem paths relative to the plugin configuration file. Assets are mounted to the /plugin/{pluginID}/assets
path.
As an example, for a plugin with id foo
with the following assets
value:
assets:\n foo: bar\n /: .\n
The following URLs will be mapped to these locations: /plugin/foo/assets/foo/file.txt
-> {pluginDir}/bar/file.txt
/plugin/foo/assets/file.txt
-> {pluginDir}/file.txt
/plugin/foo/assets/bar/file.txt
-> {pluginDir}/bar/file.txt
(via the /
entry) Mappings that try to go outside of the directory containing the plugin configuration file will be ignored.
The csp
field contains overrides to the content security policies. The URLs in script-src
, style-src
and connect-src
will be added to the applicable content security policy.
See External Plugins for details for making plugins with external tasks.
See Embedded Plugins for details for making plugins with embedded tasks.
"},{"location":"in-app-manual/plugins/#plugin-task-input","title":"Plugin task input","text":"Plugin tasks may accept an input from the stash server. This input is encoded according to the interface, and has the following structure (presented here in JSON format):
{\n \"server_connection\": {\n \"Scheme\": \"http\",\n \"Port\": 9999,\n \"SessionCookie\": {\n \"Name\":\"session\",\n \"Value\":\"cookie-value\",\n \"Path\":\"\",\n \"Domain\":\"\",\n \"Expires\":\"0001-01-01T00:00:00Z\",\n \"RawExpires\":\"\",\n \"MaxAge\":0,\n \"Secure\":false,\n \"HttpOnly\":false,\n \"SameSite\":0,\n \"Raw\":\"\",\n \"Unparsed\":null\n },\n \"Dir\": <path to stash config directory>,\n \"PluginDir\": <path to plugin config directory>,\n },\n \"args\": {\n \"argKey\": \"argValue\"\n }\n}\n
The server_connection
field contains all the information needed for a plugin to access the parent stash server, if necessary.
Plugin task output is expected in the following structure (presented here as JSON format):
{\n \"error\": <optional error string>\n \"output\": <anything>\n}\n
The error
field is logged in stash at the error
log level if present. The output
is written at the debug
log level.
Tasks are configured using the following structure:
tasks:\n - name: <operation name>\n description: <optional description>\n defaultArgs:\n argKey: argValue\n
A plugin configuration may contain multiple tasks.
The defaultArgs
field is used to add inputs to the plugin input sent to the plugin.
Stash supports executing plugin operations via triggering of a hook during a stash operation.
Hooks are configured using a similar structure to tasks:
hooks:\n - name: <operation name>\n description: <optional description>\n triggeredBy:\n - <trigger types>...\n defaultArgs:\n argKey: argValue\n
Note: it is possible for hooks to trigger eachother or themselves if they perform mutations. For safety, hooks will not be triggered if they have already been triggered in the context of the operation. Stash uses cookies to track this context, so it's important for plugins to send cookies when performing operations.
"},{"location":"in-app-manual/plugins/#trigger-types","title":"Trigger types","text":"Trigger types use the following format: <object type>.<operation>.<hook type>
For example, a post-hook on a scene create operation will be Scene.Create.Post
.
The following object types are supported:
Scene
SceneMarker
Image
Gallery
Group
Performer
Studio
Tag
The following operations are supported:
Create
Update
Destroy
Merge
(for Tag
only)Currently, only Post
hook types are supported. These are executed after the operation has completed and the transaction is committed.
Plugin tasks triggered by a hook include an argument named hookContext
in the args
object structure. The hookContext
is structured as follows:
{\n \"id\": <object id>,\n \"type\": <trigger type>,\n \"input\": <operation input>,\n \"inputFields\": <fields included in input>\n}\n
The input
field contains the JSON graphql input passed to the original operation. This will differ between operations. For hooks triggered by operations in a scan or clean, the input will be nil. inputFields
is populated in update operations to indicate which fields were passed to the operation, to differentiate between missing and empty fields.
For example, here is the args
values for a Scene update operation:
{\n \"hookContext\": {\n \"type\":\"Scene.Update.Post\",\n \"id\":45,\n \"input\":{\n \"clientMutationId\":null,\n \"id\":\"45\",\n \"title\":null,\n \"details\":null,\n \"url\":null,\n \"date\":null,\n \"rating\":null,\n \"organized\":null,\n \"studio_id\":null,\n \"gallery_ids\":null,\n \"performer_ids\":null,\n \"groups\":null,\n \"tag_ids\":[\"21\"],\n \"cover_image\":null,\n \"stash_ids\":null\n },\n \"inputFields\":[\n \"tag_ids\",\n \"id\"\n ]\n }\n}\n
"},{"location":"in-app-manual/plugins/embeddedplugins/","title":"Embedded Plugin Tasks","text":"Embedded plugin tasks are executed within the stash process using a scripting system.
"},{"location":"in-app-manual/plugins/embeddedplugins/#supported-script-languages","title":"Supported script languages","text":"Stash currently supports Javascript embedded plugin tasks using goja.
"},{"location":"in-app-manual/plugins/embeddedplugins/#javascript-plugins","title":"Javascript plugins","text":""},{"location":"in-app-manual/plugins/embeddedplugins/#plugin-input","title":"Plugin input","text":"The input is provided to Javascript plugin tasks using the input
global variable, and is an object based on the structure provided in the Plugin input
section of the Plugins page. Note that the server_connection
field should not be necessary in most embedded plugins.
The output of a Javascript plugin task is derived from the evaluated value of the script. The output should conform to the structure provided in the Plugin output
section of the Plugins page.
There are a number of ways to return the plugin output:
"},{"location":"in-app-manual/plugins/embeddedplugins/#example-1","title":"Example #1","text":"(function() {\n return {\n Output: \"ok\"\n };\n})();\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#example-2","title":"Example #2","text":"function main() {\n return {\n Output: \"ok\"\n };\n}\n\nmain();\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#example-3","title":"Example #3","text":"var output = {\n Output: \"ok\"\n};\n\noutput;\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#logging","title":"Logging","text":"See the Javascript API
section below on how to log with Javascript plugins.
For embedded plugins, the exec
field is a list with the first element being the path to the Javascript file that will be executed. It is expected that the path to the Javascript file is relative to the directory of the plugin configuration file.
For embedded plugins, the interface
field must be set to one of the following values: * js
Stash provides the following API for logging in Javascript plugins:
Method Descriptionlog.Trace(<string>)
Log with the trace
log level. log.Debug(<string>)
Log with the debug
log level. log.Info(<string>)
Log with the info
log level. log.Warn(<string>)
Log with the warn
log level. log.Error(<string>)
Log with the error
log level. log.Progress(<float between 0 and 1>)
Sets the progress of the plugin task, as a float, where 0
represents 0% and 1
represents 100%."},{"location":"in-app-manual/plugins/embeddedplugins/#gql","title":"GQL","text":"Stash provides the following API for communicating with stash using the graphql interface:
Method Descriptiongql.Do(<query/mutation string>, <variables object>)
Executes a graphql query/mutation on the stash server. Returns an object in the same way as a graphql query does."},{"location":"in-app-manual/plugins/embeddedplugins/#example","title":"Example","text":"// creates a tag\nvar mutation = \"\\\nmutation tagCreate($input: TagCreateInput!) {\\\n tagCreate(input: $input) {\\\n id\\\n }\\\n}\";\n\nvar variables = {\n input: {\n 'name': tagName\n }\n};\n\nresult = gql.Do(mutation, variables);\nlog.Info(\"tag id = \" + result.tagCreate.id);\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#utility-functions","title":"Utility functions","text":"Stash provides the following API for utility functions:
Method Descriptionutil.Sleep(<milliseconds>)
Suspends the current thread for the specified duration."},{"location":"in-app-manual/plugins/externalplugins/","title":"External Plugin Tasks","text":"External plugin tasks are executed by running an external binary.
"},{"location":"in-app-manual/plugins/externalplugins/#plugin-interfaces","title":"Plugin interfaces","text":"Stash communicates with external plugin tasks using an interface. Stash currently supports RPC and raw interface types.
"},{"location":"in-app-manual/plugins/externalplugins/#rpc-interface","title":"RPC interface","text":"The RPC interface uses JSON-RPC to communicate with the plugin process. A golang plugin utilising the RPC interface is available in the stash source code under pkg/plugin/examples/gorpc
. RPC plugins are expected to provide an interface that fulfils the RPCRunner
interface in pkg/plugin/common
.
RPC plugins are expected to accept requests asynchronously.
When stopping an RPC plugin task, the stash server sends a stop request to the plugin and relies on the plugin to stop itself.
"},{"location":"in-app-manual/plugins/externalplugins/#raw-interface","title":"Raw interface","text":"Raw interface plugins are not required to conform to any particular interface. The stash server will send the plugin input to the plugin process via its stdin stream, encoded as JSON. Raw interface plugins are not required to read the input.
The stash server reads stdout for the plugin's output. If the output can be decoded as a JSON representation of the plugin output data structure then it will do so. If not, it will treat the entire stdout string as the plugin's output.
When stopping a raw plugin task, the stash server kills the spawned process without warning or signals.
"},{"location":"in-app-manual/plugins/externalplugins/#logging","title":"Logging","text":"External plugins may log to the stash server by writing to stderr. By default, data written to stderr will be logged by stash at the error
level. This default behaviour can be changed by setting the errLog
field in the plugin configuration file.
Plugins can log for specific levels or log progress by prefixing the output string with special control characters. See pkg/plugin/common/log
for how this is done in go.
For external plugin tasks, the exec
field is a list with the first element being the binary that will be executed, and the subsequent elements are the arguments passed. The execution process will search the path for the binary, then will attempt to find the program in the same directory as the plugin configuration file. The exe
extension is not necessary on Windows systems.
\u26a0\ufe0f Note: The plugin execution process sets the current working directory to that of the stash process.
Arguments can include the plugin's directory with the special string {pluginDir}
.
For example, if the plugin executable my_plugin
is placed in the plugins
subdirectory and requires arguments foo
and bar
, then the exec
part of the configuration would look like the following:
exec:\n - my_plugin\n - foo\n - bar\n
Another example might use a python script to execute the plugin. Assuming the python script foo.py
is placed in the same directory as the plugin config file, the exec
fragment would look like the following:
exec:\n - python\n - {pluginDir}/foo.py\n
"},{"location":"in-app-manual/plugins/externalplugins/#interface","title":"interface","text":"For external plugin tasks, the interface
field must be set to one of the following values: * rpc
* raw
See the Plugin interfaces
section above for details on these interface types.
The interface
field defaults to raw
if not provided.
The errLog
field tells stash what the default log level should be when the plugin outputs to stderr without encoding a log level. It defaults to the error
level if no provided. This field is not necessary if the plugin outputs logging with the appropriate encoding. See the Logging
section above for details.
In addition to the standard task configuration, external tasks may be configured with an optional execArgs
field to add extra parameters to the execution arguments for the task.
For example:
tasks:\n - name: <operation name>\n description: <optional description>\n execArgs:\n - <arg to add to the exec line>\n
"},{"location":"in-app-manual/plugins/uipluginapi/","title":"UI Plugin API","text":"The PluginApi
object is a global object in the window
object.
PluginApi
is considered experimental and is subject to change without notice. This documentation covers only the plugin-specific API. It does not necessarily cover the core UI API. Information on these methods should be referenced in the UI source code.
An example using various aspects of PluginApi
may be found in the source code under pkg/plugin/examples/react-component
.
React
","text":"An instance of the React library.
"},{"location":"in-app-manual/plugins/uipluginapi/#reactdom","title":"ReactDOM
","text":"An instance of the ReactDOM library.
"},{"location":"in-app-manual/plugins/uipluginapi/#gql","title":"GQL
","text":"This namespace contains the generated graphql client interface. This is a low-level interface. In many cases, StashService
should be used instead.
libraries
","text":"libraries
provides access to the following UI libraries: - ReactRouterDOM
- Bootstrap
- Apollo
- Intl
- FontAwesomeRegular
- FontAwesomeSolid
- Mousetrap
- MousetrapPause
register
","text":"This namespace contains methods used to register page routes and components.
"},{"location":"in-app-manual/plugins/uipluginapi/#pluginapiregisterroute","title":"PluginApi.register.route
","text":"Registers a route in the React Router.
Parameter Type Descriptionpath
string
The path to register. This should generally use the /plugin/
prefix. component
React.FC
A React function component that will be rendered when the route is loaded. Returns void
.
PluginApi.register.component
","text":"Registers a component to be used by plugins. The component will be available in the components
namespace.
name
string
The name of the component to register. This should be unique and should ideally be prefixed with plugin-
. component
React.FC
A React function component. Returns void
.
components
","text":"This namespace contains all of the components available to plugins. These include a selection of core components and components registered using PluginApi.register.component
.
utils
","text":"This namespace provides access to the NavUtils
and StashService
namespaces. It also provides access to the loadComponents
method.
PluginApi.utils.loadComponents
","text":"Due to code splitting, some components may not be loaded and available when a plugin page is rendered. loadComponents
loads all of the components that a plugin page may require.
In general, PluginApi.hooks.useLoadComponents
hook should be used instead.
components
Promise[]
The list of components to load. These values should come from the PluginApi.loadableComponents
namespace. Returns a Promise<void>
that resolves when all of the components have been loaded.
hooks
","text":"This namespace provides access to the following core utility hooks: - useSpriteInfo
- useToast
It also provides plugin-specific hooks.
"},{"location":"in-app-manual/plugins/uipluginapi/#pluginapihooksuseloadcomponents","title":"PluginApi.hooks.useLoadComponents
","text":"This is a hook used to load components, using the PluginApi.utils.loadComponents
method.
components
Promise[]
The list of components to load. These values should come from the PluginApi.loadableComponents
namespace. Returns a boolean
which will be true
if the components are loading.
loadableComponents
","text":"This namespace contains all of the components that may need to be loaded using the loadComponents
method. Components are added to this namespace as needed. Please make a development request if a required component is not in this namespace.
patch
","text":"This namespace provides methods to patch components to change their behaviour.
"},{"location":"in-app-manual/plugins/uipluginapi/#pluginapipatchbefore","title":"PluginApi.patch.before
","text":"Registers a before function. A before function is called prior to calling a component's render function. It accepts the same parameters as the component's render function, and is expected to return a list of new arguments that will be passed to the render.
Parameter Type Descriptioncomponent
string
The name of the component to patch. fn
Function
The before function. It accepts the same arguments as the component render function and is expected to return a list of arguments to pass to the render function. Returns void
.
PluginApi.patch.instead
","text":"Registers a replacement function for a component. The provided function will be called with the arguments passed to the original render function, plus the next render function as the last argument. Replacement functions will be called in the order that they are registered. If a replacement function does not call the next render function then the following replacement functions will not be called or applied.
Parameter Type Descriptioncomponent
string
The name of the component to patch. fn
Function
The replacement function. It accepts the same arguments as the original render function, plus the next render function, and is expected to return the replacement component. Returns void
.
PluginApi.patch.after
","text":"Registers an after function. An after function is called after the render function of the component. It accepts the arguments passed to the original render function, plus the result of the original render function. It is expected to return the rendered component.
Parameter Type Descriptioncomponent
string
The name of the component to patch. fn
Function
The after function. It accepts the same arguments as the original render function, plus the result of the original render function, and is expected to return the rendered component. Returns void
.
App
BooleanSetting
ChangeButtonSetting
CompressedPerformerDetailsPanel
ConstantSetting
CountrySelect
DateInput
FolderSelect
GalleryIDSelect
GallerySelect
GallerySelect.sort
Icon
ImageDetailPanel
ModalSetting
GroupIDSelect
GroupSelect
GroupSelect.sort
NumberSetting
PerformerDetailsPanel
PerformerDetailsPanel.DetailGroup
PerformerIDSelect
PerformerSelect
PerformerSelect.sort
PluginRoutes
SceneCard
SceneCard.Details
SceneCard.Image
SceneCard.Overlays
SceneCard.Popovers
SceneIDSelect
SceneSelect
SceneSelect.sort
SelectSetting
Setting
SettingModal
StringSetting
StringListSetting
StudioIDSelect
StudioSelect
StudioSelect.sort
TagIDSelect
TagSelect
TagSelect.sort
PluginSettings
Setting
SettingGroup
PluginApi.Event
","text":"Allows plugins to listen for Stash's events.
PluginApi.Event.addEventListener(\"stash:location\", (e) => console.log(\"Page Changed\", e.detail.data.location.pathname))\n
"},{"location":"in-app-manual/scraping/","title":"Metadata Scraping","text":"Stash supports scraping of metadata from various external sources.
"},{"location":"in-app-manual/scraping/#scraper-types","title":"Scraper Types","text":"Type Description Fragment Uses existing metadata for an Item and match it to a result from a metadata source. Search/By Name Uses a provided query string to search a metadata source for a list of matches for the user to pick from. URL Extracts metadata from a given URL."},{"location":"in-app-manual/scraping/#supported-scrapers","title":"Supported Scrapers","text":"Fragment Search URL gallery \u2714\ufe0f \u2714\ufe0f group \u2714\ufe0f performer \u2714\ufe0f \u2714\ufe0f scene \u2714\ufe0f \u2714\ufe0f \u2714\ufe0f"},{"location":"in-app-manual/scraping/#included-scrapers","title":"Included Scrapers","text":"Stash provides the following built-in scrapers:
Scraper Description Freeonessearch
Performer scraper for freeones.xxx. Auto Tag Scene fragment
scraper that matches existing performers, studio and tags using the filename."},{"location":"in-app-manual/scraping/#managing-scrapers","title":"Managing Scrapers","text":"Scrapers can be installed and managed from the Settings > Metadata Providers
page.
Scrapers are installed using the Available Scrapers
section. This section allows configuring sources from which to install scrapers. The Community (stable)
source is configured by default. This source contains scrapers for the current stable version of stash.
These are the scraper sources maintained by the stashapp organisation:
Name Source URL Recommended Local Path Notes Community (stable)https://stashapp.github.io/CommunityScrapers/stable/index.yml
stable
For the current stable version of stash. Community (develop) https://stashapp.github.io/CommunityScrapers/develop/index.yml
develop
For the develop version of stash. Installed scrapers can be updated or uninstalled from the Installed Scrapers
section.
The source URL must return a yaml file containing all the available packages for the source. An example source yaml file looks like the following:
- id: <package id>\n name: <package name>\n version: <version>\n date: <date>\n requires:\n - <ids of packages required by this package (optional)>\n - ...\n path: <path to package zip file>\n sha256: <sha256 of zip>\n metadata:\n <optional key/value pairs for extra information>\n- ...\n
Path can be a relative path to the zip file or an external URL.
"},{"location":"in-app-manual/scraping/#adding-scrapers-manually","title":"Adding Scrapers manually","text":"By default, Stash looks for scraper configurations in the scrapers
sub-directory of the directory where the stash config.yml
is read. This will either be the $HOME/.stash
directory or the current working directory.
Scrapers are added manually by placing yaml configuration files (format: scrapername.yml
) in the scrapers
directory.
\u26a0\ufe0f Note: Some scrapers may require more than just the yaml file, consult the individual scraper documentation
After the yaml files are added, removed or edited while stash is running, they can be reloaded going to Settings > Metadata Providers > Scrapers
and clicking Reload Scrapers
.
Click on the Scrape With...
button in the edit
tab of an item, then select the scraper you wish to use.
Click on the \ud83d\udd0d button in the edit
tab of an item. You will be presented with a search dialog with a pre-populated query to search for, after searching you will be presented with a list of results to pick from
Enter the URL in the edit
tab of an Item. If a scraper is installed that supports that url, then a button will appear to scrape the metadata.
The Tagger view is accessed from the scenes page. It allows the user to run scrapers on all items on the current page. The Tagger presents the user with potential matches for an item from a selected stash-box instance or metadata source if supported. The user needs to select the correct metadata information to save.
When used in combination with stash-box, the user can optionally submit scene fingerprints to contribute to a stash-box instance. A scene fingerprint consists of any generated hashes (phash
, oshash
, md5
) and the scene duration. Fingerprint submissions are associated with your stash-box account. Submitting fingerprints assists others in matching their files, because stash-box returns a count of matching user submitted fingerprints with every potential match.
This task iterates through your Scenes and attempts to identify the scene using a selection of scraping sources. This task can be found under Settings -> Tasks -> \"Identify...\" (Button)
. For more information see the Tasks > Identify page.
Scrapers can be contributed to the community by creating a PR in this repository.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scraper-configuration-file-format","title":"Scraper configuration file format","text":"name: <site>\nperformerByName:\n <single scraper config>\nperformerByFragment:\n <single scraper config>\nperformerByURL:\n <multiple scraper URL configs>\nsceneByName:\n <single scraper config>\nsceneByQueryFragment:\n <single scraper config>\nsceneByFragment:\n <single scraper config>\nsceneByURL:\n <multiple scraper URL configs>\ngroupByURL:\n <multiple scraper URL configs>\ngalleryByFragment:\n <single scraper config>\ngalleryByURL:\n <multiple scraper URL configs>\n<other configurations>\n
name
is mandatory, all other top-level fields are optional. The inclusion of each top-level field determines what capabilities the scraper has.
A scraper configuration in any of the top-level fields must at least have an action
field. The other fields are required based on the value of the action
field.
The scraping types and their required fields are outlined in the following table:
Behavior Required configuration Scraper inScrape...
dropdown button in Performer Edit page Valid performerByName
and performerByFragment
configurations. Scrape performer from URL Valid performerByURL
configuration with matching URL. Scraper in query dropdown button in Scene Edit page Valid sceneByName
and sceneByQueryFragment
configurations. Scraper in Scrape...
dropdown button in Scene Edit page Valid sceneByFragment
configuration. Scrape scene from URL Valid sceneByURL
configuration with matching URL. Scrape group from URL Valid groupByURL
configuration with matching URL. Note: movieByURL
is also supported but is deprecated. Scraper in Scrape...
dropdown button in Gallery Edit page Valid galleryByFragment
configuration. Scrape gallery from URL Valid galleryByURL
configuration with matching URL. URL-based scraping accepts multiple scrape configurations, and each configuration requires a url
field. stash iterates through these configurations, attempting to match the entered URL against the url
fields in the configuration. It executes the first scraping configuration where the entered URL contains the value of the url
field.
Executes a script to perform the scrape. The script
field is required for this action and accepts a list of string arguments. For example:
action: script\nscript:\n - python\n - iafdScrape.py\n - query\n
If the script specifies the python executable, Stash will find the correct python executable for your system, either python
or python3
. So for example. this configuration could execute python iafdScrape.py query
or python3 iafdScrape.py query
. python3
will be looked for first and if it's not found, we'll check for python
. In the case neither are found, you will get an error.
Stash sends data to the script process's stdin
stream and expects the output to be streamed to the stdout
stream. Any errors and progress messages should be output to stderr
.
The script is sent input and expects output based on the scraping type, as detailed in the following table:
Scrape type Input OutputperformerByName
{\"name\": \"<performer query string>\"}
Array of JSON-encoded performer fragments (including at least name
) performerByFragment
JSON-encoded performer fragment JSON-encoded performer fragment performerByURL
{\"url\": \"<url>\"}
JSON-encoded performer fragment sceneByName
{\"name\": \"<scene query string>\"}
Array of JSON-encoded scene fragments sceneByQueryFragment
, sceneByFragment
JSON-encoded scene fragment JSON-encoded scene fragment sceneByURL
{\"url\": \"<url>\"}
JSON-encoded scene fragment groupByURL
{\"url\": \"<url>\"}
JSON-encoded group fragment galleryByFragment
JSON-encoded gallery fragment JSON-encoded gallery fragment galleryByURL
{\"url\": \"<url>\"}
JSON-encoded gallery fragment For performerByName
, only name
is required in the returned performer fragments. One entire object is sent back to performerByFragment
to scrape a specific performer, so the other fields may be included to assist in scraping a performer. For example, the url
field may be filled in for the specific performer page, then performerByFragment
can extract by using its value.
Python example of a performer Scraper:
import json\nimport sys\nimport string\n\ndef readJSONInput():\n input = sys.stdin.read()\n return json.loads(input)\n\n\ndef searchPerformer(name):\n # perform scraping here - using name for the query\n\n # fill in the output\n ret = []\n\n # example shown for a single found performer \n p = {}\n p['name'] = \"some name\"\n p['url'] = \"performer url\"\n ret.append(p)\n\n return ret\n\ndef scrapePerformer(input):\n ret = []\n # get the url from the input\n url = input['url']\n return scrapePerformerURL(url)\n\ndef debugPrint(t):\n sys.stderr.write(t + \"\\n\")\n\ndef scrapePerformerURL(url):\n debugPrint(\"Reading url...\")\n debugPrint(\"Parsing html...\")\n\n # parse html\n\n # fill in performer details - single object\n ret = {}\n\n ret['name'] = \"fred\"\n ret['aliases'] = \"freddy\"\n ret['ethnicity'] = \"\"\n # and so on\n\n return ret\n\n# read the input \ni = readJSONInput()\n\nif sys.argv[1] == \"query\":\n ret = searchPerformer(i['name'])\n print(json.dumps(ret))\nelif sys.argv[1] == \"scrape\":\n ret = scrapePerformer(i)\n print(json.dumps(ret))\nelif sys.argv[1] == \"scrapeURL\":\n ret = scrapePerformerURL(i['url'])\n print(json.dumps(ret))\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapexpath","title":"scrapeXPath","text":"This action scrapes a web page using an xpath configuration to parse. This action is not valid for performerByFragment
.
This action requires that the top-level xPathScrapers
configuration is populated. The scraper
field is required and must match the name of a scraper name configured in xPathScrapers
. For example:
sceneByURL:\n- action: scrapeXPath\n url: \n - pornhub.com/view_video.php\n scraper: sceneScraper\n
The above configuration requires that sceneScraper
exists in the xPathScrapers
configuration.
XPath scraping configurations specify the mapping between object fields and an xpath selector. The xpath scraper scrapes the applicable URL and uses xpath to populate the object fields.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapejson","title":"scrapeJson","text":"This action works in the same way as scrapeXPath
, but uses a mapped json configuration to parse. It uses the top-level jsonScrapers
configuration. This action is not valid for performerByFragment
.
JSON scraping configurations specify the mapping between object fields and a GJSON selector. The JSON scraper scrapes the applicable URL and uses GJSON to parse the returned JSON object and populate the object fields.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapexpath-and-scrapejson-use-with-performerbyname","title":"scrapeXPath and scrapeJson use withperformerByName
","text":"For performerByName
, the queryURL
field must be present also. This field is used to perform a search query URL for performer names. The placeholder string sequence {}
is replaced with the performer name search string. For the subsequent performer scrape to work, the URL
field must be filled in with the URL of the performer page that matches a URL given in a performerByURL
scraping configuration. For example:
name: Boobpedia\nperformerByName:\n action: scrapeXPath\n queryURL: http://www.boobpedia.com/wiki/index.php?title=Special%3ASearch&search={}&fulltext=Search\n scraper: performerSearch\nperformerByURL:\n - action: scrapeXPath\n url: \n - boobpedia.com/boobs/\n scraper: performerScraper\nxPathScrapers:\n performerSearch:\n performer:\n Name: # name element\n URL: # URL element that matches the boobpedia.com/boobs/ URL above\n performerScraper:\n # ... performer scraper details ...\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapexpath-and-scrapejson-use-with-scenebyfragment-and-scenebyqueryfragment","title":"scrapeXPath and scrapeJson use with sceneByFragment
and sceneByQueryFragment
","text":"For sceneByFragment
and sceneByQueryFragment
, the queryURL
field must also be present. This field is used to build a query URL for scenes. For sceneByFragment
, the queryURL
field supports the following placeholder fields:
{checksum}
- the MD5 checksum of the scene{oshash}
- the oshash of the scene{filename}
- the base filename of the scene{title}
- the title of the scene{url}
- the url of the sceneThese placeholder field values may be manipulated with regex replacements by adding a queryURLReplace
section, containing a map of placeholder field to regex configuration which uses the same format as the replace
post-process action covered below.
For example:
sceneByFragment:\n action: scrapeJson\n scraper: sceneQueryScraper\n queryURL: https://metadataapi.net/api/scenes?parse={filename}&limit=1\n queryURLReplace:\n filename:\n - regex: <some regex>\n with: <replacement>\n
The above configuration would scrape from the value of queryURL
, replacing {filename}
with the base filename of the scene, after it has been manipulated by the regex replacements.
<scene|performer|gallery|group>ByURL
","text":"For sceneByURL
, performerByURL
, galleryByURL
the queryURL
can also be present if we want to use queryURLReplace
. The functionality is the same as sceneByFragment
, the only placeholder field available though is the url
: * {url}
- the url of the scene/performer/gallery
sceneByURL:\n - action: scrapeJson\n url:\n - metartnetwork.com\n scraper: sceneScraper\n queryURL: \"{url}\"\n queryURLReplace:\n url:\n - regex: '^(?:.+\\.)?([^.]+)\\.com/.+movie/(\\d+)/(\\w+)/?$'\n with: https://www.$1.com/api/movie?name=$3&date=$2\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#stash","title":"Stash","text":"A different stash server can be configured as a scraping source. This action applies only to performerByName
, performerByFragment
, and sceneByFragment
types. This action requires that the top-level stashServer
field is configured.
stashServer
contains a single url
field for the remote stash server. The username and password can be embedded in this string using username:password@host
. Alternatively, the apiKey
field can be used to authenticate with the remote stash server.
An example stash scrape configuration is below:
name: stash\nperformerByName:\n action: stash\nperformerByFragment:\n action: stash\nsceneByFragment:\n action: stash\nstashServer:\n apiKey: <api key>\n url: http://stashserver.com:9999\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#xpath-and-json-scrapers-configuration","title":"Xpath and JSON scrapers configuration","text":"The top-level xPathScrapers
field contains xpath scraping configurations, freely named. These are referenced in the scraper
field for scrapeXPath
scrapers.
Likewise, the top-level jsonScrapers
field contains json scraping configurations.
Collectively, these configurations are known as mapped scraping configurations.
A mapped scraping configuration may contain a common
field, and must contain performer
, scene
, group
or gallery
depending on the scraping type it is configured for.
Within the performer
/scene
/group
/gallery
field are key/value pairs corresponding to the golang fields on the performer/scene object. These fields are case-sensitive.
The values of these may be either a simple selector value, which tells the system where to get the value of the field from, or a more advanced configuration (see below). For example, for an xpath configuration:
performer:\n Name: //h1[@itemprop=\"name\"]\n
This will set the Name
attribute of the returned performer to the text content of the element that matches <h1 itemprop=\"name\">...
.
For a json configuration:
performer:\n Name: data.name\n
The value may also be a sub-object. If it is a sub-object, then the selector must be set to the selector
key of the sub-object. For example, using the same xpath as above:
performer:\n Name: \n selector: //h1[@itemprop=\"name\"]\n postProcess:\n # post-processing config values\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#fixed-attribute-values","title":"Fixed attribute values","text":"Alternatively, an attribute value may be set to a fixed value, rather than scraping it from the webpage. This can be done by replacing selector
with fixed
. For example:
performer:\n Gender: \n fixed: Female\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#common-fragments","title":"Common fragments","text":"The common
field is used to configure selector fragments that can be referenced in the selector strings. These are key-value pairs where the key is the string to reference the fragment, and the value is the string that the fragment will be replaced with. For example:
common:\n $infoPiece: //div[@class=\"infoPiece\"]/span\nperformer:\n Measurements: $infoPiece[text() = 'Measurements:']/../span[@class=\"smallInfo\"]\n
The Measurements
xpath string will replace $infoPiece
with //div[@class=\"infoPiece\"]/span
, resulting in: //div[@class=\"infoPiece\"]/span[text() = 'Measurements:']/../span[@class=\"smallInfo\"]
.
\u26a0\ufe0f Note: Recursive common fragments are not supported. Referencing a common fragment within another common fragment will cause an error. For example:
common:\n $info: //div[@class=\"info\"]\n # Referencing $info in $models will cause an error\n $models: $info/a[@class=\"model\"]\nscene:\n Title: $info/h1\n Performers:\n Name: $models\n URL: $models/@href\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#post-processing-options","title":"Post-processing options","text":"Post-processing operations are contained in the postProcess
key. Post-processing operations are performed in the order they are specified. The following post-processing operations are available: * javascript
: accepts a javascript code block, that must return a string value. The input string is declared in the value
variable. If an error occurs while compiling or running the script, then the original value is returned. Example:
performer:\n Name:\n selector: //div[@class=\"example element\"]\n postProcess:\n - javascript: |\n // capitalise the first letter\n if (value && value.length) {\n return value[0].toUpperCase() + value.substring(1)\n }\n
Note that the otto
javascript engine is missing a few built-in methods and may not be consistent with other modern javascript implementations. * feetToCm
: converts a string containing feet and inches numbers into centimeters. Looks for up to two separate integers and interprets the first as the number of feet, and the second as the number of inches. The numbers can be separated by any non-numeric character including the .
character. It does not handle decimal numbers. For example 6.3
and 6ft3.3
would both be interpreted as 6 feet, 3 inches before converting into centimeters. * lbToKg
: converts a string containing lbs to kg. * map
: contains a map of input values to output values. Where a value matches one of the input values, it is replaced with the matching output value. If no value is matched, then value is unmodified. Example:
performer:\n Gender:\n selector: //div[@class=\"example element\"]\n postProcess:\n - map:\n F: Female\n M: Male\n Height:\n selector: //span[@id=\"height\"]\n postProcess:\n - feetToCm: true\n Weight:\n selector: //span[@id=\"weight\"]\n postProcess:\n - lbToKg: true\n
Gets the contents of the selected div element, and sets the returned value to Female
if the scraped value is F
; Male
if the scraped value is M
. Height and weight are extracted from the selected spans and converted to cm
and kg
. parseDate
: if present, the value is the date format using go's reference date (2006-01-02). For example, if an example date was 14-Mar-2003
, then the date format would be 02-Jan-2006
. See the time.Parse documentation for details. When present, the scraper will convert the input string into a date, then convert it to the string format used by stash (YYYY-MM-DD
). Strings \"Today\", \"Yesterday\" are matched (case insensitive) and converted by the scraper so you don't need to edit/replace them. Unix timestamps (example: 1660169451) can also be parsed by selecting unix
as the date format. Example:
Date:\n selector: //div[@class=\"value epoch\"]/text()\n postProcess:\n - parseDate: unix\n
subtractDays
: if set to true
it subtracts the value in days from the current date and returns the resulting date in stash's date format. Example:
Date:\n selector: //strong[contains(text(),\"Added:\")]/following-sibling::text()\n postProcess:\n - replace:\n - regex: (\\d+)\\sdays\\sago.+\n with: $1\n - subtractDays: true\n
replace
: contains an array of sub-objects. Each sub-object must have a regex
and with
field. The regex
field is the regex pattern to replace, and with
is the string to replace it with. $
is used to reference capture groups - $1
is the first capture group, $2
the second and so on. Replacements are performed in order of the array.
Example:
CareerLength: \n selector: $infoPiece[text() = 'Career Start and End:']/../span[@class=\"smallInfo\"]\n postProcess:\n - replace:\n - regex: \\s+to\\s+\n with: \"-\"\n
Replaces 2001 to 2003
with 2001-2003
. subScraper
: if present, the sub-scraper will be executed after all other post-processes are complete and before parseDate. It then takes the value and performs an http request, using the value as the URL. Within the subScraper
config is a nested scraping configuration. This allows you to traverse to other webpages to get the attribute value you are after. For more info and examples have a look at #370, #606Additionally, there are a number of fixed post-processing fields that are specified at the attribute level (not in postProcess
) that are performed after the postProcess
operations: * concat
: if an xpath matches multiple elements, and concat
is present, then all of the elements will be concatenated together * split
: the inverse of concat
. Splits a string to more elements using the separator given. For more info and examples have a look at PR #579
Example:
Tags:\n Name:\n selector: //span[@class=\"list_attributes\"]\n split: \",\"\n
Splits a comma separated list of tags located in the span and returns the tags. For backwards compatibility, replace
, subscraper
and parseDate
are also allowed as keys for the attribute.
Post-processing on attribute post-process is done in the following order: concat
, replace
, subscraper
, parseDate
and then split
.
To print the received html/json from a scraper request to the log file, add the following to your scraper yml file:
debug:\n printHTML: true\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#cdp-support","title":"CDP support","text":"Some websites deliver content that cannot be scraped using the raw html file alone. These websites use javascript to dynamically load the content. As such, direct xpath scraping will not work on these websites. There is an option to use Chrome DevTools Protocol to load the webpage using an instance of Chrome, then scrape the result.
Chrome CDP support can be enabled for a specific scraping configuration by adding the following to the root of the yml configuration:
driver:\n useCDP: true\n
Optionally, you can add a sleep
value under the driver
section. This specifies the amount of time (in seconds) that the scraper should wait after loading the website to perform the scrape. This is needed as some sites need more time for loading scripts to finish. If unset, this value defaults to 2 seconds.
When useCDP
is set to true, stash will execute or connect to an instance of Chrome. The behavior is dictated by the Chrome CDP path
setting in the user configuration. If left empty, stash will attempt to find the Chrome executable in the path environment, and will fail if it cannot find one.
Chrome CDP path
can be set to a path to the chrome executable, or an http(s) address to remote chrome instance (for example: http://localhost:9222/json/version
). As remote instance a docker container can also be used with the chromedp/headless-shell
image being highly recommended.
When using CDP you can use the clicks
part of the driver
section to do Mouse Clicks on elements you need to collapse or toggle. Each click element has an xpath
value that holds the XPath for the button/element you need to click and an optional sleep
value that is the time in seconds to wait for after clicking. If the sleep
value is not set it defaults to 2
seconds.
A demo scraper using clicks
follows.
name: clickDemo # demo only for a single URL\nsceneByURL:\n - action: scrapeXPath\n url:\n - https://getbootstrap.com/docs/4.3/components/collapse/\n scraper: sceneScraper\n\nxPathScrapers:\n sceneScraper:\n scene:\n Title: //head/title\n Details: # shows the id/s of the visible div/s for the Multiple targets example of the page\n selector: //div[@class=\"bd-example\"]//div[@class=\"multi-collapse collapse show\"]/@id\n concat: \"\\n\\n\"\n\ndriver:\n useCDP: true\n sleep: 1\n clicks: # demo usage toggle on off multiple times\n - xpath: //a[@href=\"#multiCollapseExample1\"] # toggle on first element\n - xpath: //button[@data-target=\"#multiCollapseExample2\"] # toggle on second element\n sleep: 4\n - xpath: //a[@href=\"#multiCollapseExample1\"] # toggle off fist element\n sleep: 1\n - xpath: //button[@data-target=\"#multiCollapseExample2\"] # toggle off second element\n - xpath: //button[@data-target=\"#multiCollapseExample2\"] # toggle on second element\n
\u26a0\ufe0f Note: each click
adds an extra delay of clicks sleep
seconds, so the above adds 2+4+1+2+2=11
seconds to the loading time of the page.
In some websites the use of cookies is needed to bypass a welcoming message or some other kind of protection. Stash supports the setting of cookies for the direct xpath scraper and the CDP based one. Due to implementation issues the usage varies a bit.
To use the cookie functionality a cookies
sub section needs to be added to the driver
section. Each cookie element can consist of a CookieURL
and a number of Cookies
.
CookieURL
is only needed if you are using the direct / native scraper method. It is the request url that we expect from the site we scrape. It must be in the same domain as the cookies we try to set otherwise all cookies in the same group will fail to set. If the CookieURL
is not a valid URL then again the cookies of that group will fail.
Cookies
are the actual cookies we set. When using CDP that's the only part required. They have Name
, Value
, Domain
, Path
values.
In the following example we use cookies for a site using the direct / native xpath scraper. We expect requests to come from https://www.example.com
and https://api.somewhere.com
that look for a _warning
and a _warn
cookie. A _test2
cookie is also set just as a demo.
driver:\n cookies:\n - CookieURL: \"https://www.example.com\"\n Cookies:\n - Name: \"_warning\"\n Domain: \".example.com\"\n Value: \"true\"\n Path: \"/\"\n - Name: \"_test2\"\n Value: \"123412\"\n Domain: \".example.com\"\n Path: \"/\"\n - CookieURL: \"https://api.somewhere.com\"\n Cookies:\n - Name: \"_warn\"\n Value: \"123\"\n Domain: \".somewhere.com\"\n
The same functionality when using CDP would look like this:
driver:\n useCDP: true\n cookies:\n - Cookies:\n - Name: \"_warning\"\n Domain: \".example.com\"\n Value: \"true\"\n Path: \"/\"\n - Name: \"_test2\"\n Value: \"123412\"\n Domain: \".example.com\"\n Path: \"/\"\n - Cookies:\n - Name: \"_warn\"\n Value: \"123\"\n Domain: \".somewhere.com\"\n
For some sites, the value of the cookie itself doesn't actually matter. In these cases, we can use the ValueRandom
property instead of Value
. Unlike Value
, ValueRandom
requires an integer value greater than 0
where the value indicates how long the cookie string should be.
In the following example, we will adapt the previous cookies to use ValueRandom
instead. We set the _test2
cookie to randomly generate a value with a length of 6 characters and the _warn
cookie to a length of 3.
driver:\n cookies:\n - CookieURL: \"https://www.example.com\"\n Cookies:\n - Name: \"_warning\"\n Domain: \".example.com\"\n Value: \"true\"\n Path: \"/\"\n - Name: \"_test2\"\n ValueRandom: 6\n Domain: \".example.com\"\n Path: \"/\"\n - CookieURL: \"https://api.somewhere.com\"\n Cookies:\n - Name: \"_warn\"\n ValueRandom: 3\n Domain: \".somewhere.com\"\n
When developing a scraper you can have a look at the cookies set by a site by adding
a CookieURL
if you use the direct xpath scraper
a Domain
if you use the CDP scraper
and having a look at the log / console in debug mode.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#headers","title":"Headers","text":"Sending request headers is possible when using a scraper. Headers can be set in the driver
section and are supported for plain, CDP enabled and JSON scrapers. They consist of a Key and a Value. If the Key is empty or not defined then the header is ignored.
driver:\n headers:\n - Key: User-Agent\n Value: My Stash Scraper\n - Key: Authorization\n Value: Bearer ds3sdfcFdfY17p4qBkTVF03zscUU2glSjWF17bZyoe8\n
User-Agent
configuration option is applied. This means setting a User-Agent
header from the scraper overrides the one in the configuration settings.A performer and scene xpath scraper is shown as an example below:
name: Pornhub\nperformerByURL:\n - action: scrapeXPath\n url: \n - pornhub.com\n scraper: performerScraper\nsceneByURL:\n - action: scrapeXPath\n url: \n - pornhub.com/view_video.php\n scraper: sceneScraper\nxPathScrapers:\n performerScraper:\n common:\n $infoPiece: //div[@class=\"infoPiece\"]/span\n performer:\n Name: //h1[@itemprop=\"name\"]\n Birthdate: \n selector: //span[@itemprop=\"birthDate\"]\n parseDate: Jan 2, 2006\n Twitter: //span[text() = 'Twitter']/../@href\n Instagram: //span[text() = 'Instagram']/../@href\n Measurements: $infoPiece[text() = 'Measurements:']/../span[@class=\"smallInfo\"]\n Height: \n selector: $infoPiece[text() = 'Height:']/../span[@class=\"smallInfo\"]\n postProcess:\n - replace: \n - regex: .*\\((\\d+) cm\\)\n with: $1\n Ethnicity: $infoPiece[text() = 'Ethnicity:']/../span[@class=\"smallInfo\"]\n FakeTits: $infoPiece[text() = 'Fake Boobs:']/../span[@class=\"smallInfo\"]\n Piercings: $infoPiece[text() = 'Piercings:']/../span[@class=\"smallInfo\"]\n Tattoos: $infoPiece[text() = 'Tattoos:']/../span[@class=\"smallInfo\"]\n CareerLength: \n selector: $infoPiece[text() = 'Career Start and End:']/../span[@class=\"smallInfo\"]\n postProcess:\n - replace:\n - regex: \\s+to\\s+\n with: \"-\"\n sceneScraper:\n common:\n $performer: //div[@class=\"pornstarsWrapper\"]/a[@data-mxptype=\"Pornstar\"]\n $studio: //div[@data-type=\"channel\"]/a\n scene:\n Title: //div[@id=\"main-container\"]/@data-video-title\n Tags: \n Name: //div[@class=\"categoriesWrapper\"]//a[not(@class=\"add-btn-small \")]\n Performers:\n Name: $performer/@data-mxptext\n URL: $performer/@href\n Studio:\n Name: $studio\n URL: $studio/@href \n
See also #333 for more examples.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#json-scraper-example","title":"JSON scraper example","text":"A performer and scene scraper for ThePornDB is shown below:
name: ThePornDB\nperformerByName:\n action: scrapeJson\n queryURL: https://api.metadataapi.net/performers?q={}\n scraper: performerSearch\nperformerByURL:\n - action: scrapeJson\n url:\n - https://api.metadataapi.net/performers/\n scraper: performerScraper\nsceneByURL:\n - action: scrapeJson\n url:\n - https://api.metadataapi.net/scenes/\n scraper: sceneScraper\nsceneByFragment:\n action: scrapeJson\n queryURL: https://api.metadataapi.net/scenes?parse={filename}&hash={oshash}&limit=1\n scraper: sceneQueryScraper\n queryURLReplace:\n filename:\n - regex: \"[^a-zA-Z\\\\d\\\\-._~]\" # clean filename so that it can construct a valid url\n with: \".\" # \"%20\"\n - regex: HEVC\n with:\n - regex: x265\n with:\n - regex: \\.+\n with: \".\"\njsonScrapers:\n performerSearch:\n performer:\n Name: data.#.name\n URL:\n selector: data.#.id\n postProcess:\n - replace:\n - regex: ^\n with: https://api.metadataapi.net/performers/\n\n performerScraper:\n common:\n $extras: data.extras\n performer:\n Name: data.name\n Gender: $extras.gender\n Birthdate: $extras.birthday\n Ethnicity: $extras.ethnicity\n Height:\n selector: $extras.height\n postProcess:\n - replace:\n - regex: cm\n with:\n Measurements: $extras.measurements\n Tattoos: $extras.tattoos\n Piercings: $extras.piercings\n Aliases: data.aliases\n Image: data.image\n\n sceneScraper:\n common:\n $performers: data.performers\n scene:\n Title: data.title\n Details: data.description\n Date: data.date\n URL: data.url\n Image: data.background.small\n Performers:\n Name: data.performers.#.name\n Studio:\n Name: data.site.name\n Tags:\n Name: data.tags.#.tag\n\n sceneQueryScraper:\n common:\n $data: data.0\n $performers: data.0.performers\n scene:\n Title: $data.title\n Details: $data.description\n Date: $data.date\n URL: $data.url\n Image: $data.background.small\n Performers:\n Name: $data.performers.#.name\n Studio:\n Name: $data.site.name\n Tags:\n Name: $data.tags.#.tag\ndriver:\n headers:\n - Key: User-Agent\n Value: Stash JSON Scraper\n - Key: Authorization\n Value: Bearer lPdwFdfY17p4qBkTVF03zscUU2glSjdf17bZyoe # use an actual API Key here\n# Last Updated April 7, 2021\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#object-fields","title":"Object fields","text":""},{"location":"in-app-manual/scraping/scraperdevelopment/#performer","title":"Performer","text":"Name\nGender\nURL\nTwitter\nInstagram\nBirthdate\nDeathDate\nEthnicity\nCountry\nHairColor\nEyeColor\nHeight\nWeight\nMeasurements\nFakeTits\nCareerLength\nTattoos\nPiercings\nAliases\nTags (see Tag fields)\nImage\nDetails\n
Note: - Gender
must be one of male
, female
, transgender_male
, transgender_female
, intersex
, non_binary
(case insensitive).
Title\nDetails\nCode\nDirector\nURL\nDate\nImage\nStudio (see Studio Fields)\nGroups (see Group Fields)\nTags (see Tag fields)\nPerformers (list of Performer fields)\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#studio","title":"Studio","text":"Name\nURL\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#tag","title":"Tag","text":"Name\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#group","title":"Group","text":"Name\nAliases\nDuration\nDate\nRating\nDirector\nStudio\nSynopsis\nURL\nFrontImage\nBackImage\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#gallery","title":"Gallery","text":"Title\nDetails\nURL\nDate\nRating\nStudio (see Studio Fields)\nTags (see Tag fields)\nPerformers (list of Performer fields)\n
"},{"location":"in-app-manual/tasks/","title":"Tasks","text":"This page allows you to direct the stash server to perform a variety of tasks.
"},{"location":"in-app-manual/tasks/#scanning","title":"Scanning","text":"The scan function walks through the stash directories you have configured for new and moved files.
Stash currently identifies files by performing a quick file hash. This means that if the file is renamed for moved elsewhere within your configured stash directories, then the scan will detect this and update its database accordingly.
Stash currently ignores duplicate files. If two files contain identical content, only the first one it comes across is used.
The scan task accepts the following options:
Option Description Generate scene covers Generates scene covers for video files. Generate previews Generates video previews (mp4) which play when hovering over a scene. Generate animated image previews Also generate animated (webp) previews, only required when Scene/Marker Wall Preview Type is set to Animated Image. When browsing they use less CPU than the video previews, but are generated in addition to them and are larger files. Generate scrubber sprites The set of images displayed below the video player for easy navigation. Generate perceptual hashes Generates perceptual hashes for scene deduplication and identification. Generate thumbnails for images Generates thumbnails for image files. Generate previews for image clips Generates a gif/looping video as thumbnail for image clips/gifs. Rescan By default, Stash will only rescan existing files if the file's modified date has been updated since its previous scan. Stash will rescan files in the path when this option is enabled, regardless of the file modification time. Only required Stash needs to recalculate video/image metadata, or to rescan gallery zips."},{"location":"in-app-manual/tasks/#auto-tagging","title":"Auto Tagging","text":"See the Auto Tagging page.
"},{"location":"in-app-manual/tasks/#scene-filename-parser","title":"Scene Filename Parser","text":"See the Scene Filename Parser page.
"},{"location":"in-app-manual/tasks/#generated-content","title":"Generated Content","text":"The scanning function automatically generates a screenshot of each scene. The generated content provides the following:
The generate task accepts the following options:
Option Description Scene covers Generates scene covers for video files. Previews Generates video previews (mp4) which play when hovering over a scene. Animated image previews Generates animated previews (webp). Only required if the Preview Type is set to Animated Image. Requires Generate previews to be enabled. Scene Scrubber Sprites The set of images displayed below the video player for easy navigation. Markers Previews Generates 20 second video previews (mp4) which begin at the marker timecode. Marker Animated Image Previews Also generate animated (webp) previews, only required when Scene/Marker Wall Preview Type is set to Animated Image. When browsing they use less CPU than the video previews, but are generated in addition to them and are larger files. Marker Screenshots Generates static JPG images for markers. Only required if Preview Type is set to Static Image. Requires Marker Previews to be enabled. Transcodes MP4 conversions of unsupported video formats. Allows direct streaming instead of live transcoding. Perceptual hashes (for deduplication) Generates perceptual hashes for scene deduplication and identification. Generate heatmaps and speeds for interactive scenes Generates heatmaps and speeds for interactive scenes. Image Clip Previews Generates a gif/looping video as thumbnail for image clips/gifs. Overwrite existing generated files By default, where a generated file exists, it is not regenerated. When this flag is enabled, then the generated files are regenerated."},{"location":"in-app-manual/tasks/#transcodes","title":"Transcodes","text":"Web browsers support a limited number of video and audio codecs and containers. Stash will directly stream video files where the browser supports the codecs and container. Originally, stash did not support viewing scene videos where the browser did not support the codecs/container, and generating transcodes was a way of viewing these files.
Stash has since implemented live transcoding, so transcodes are essentially unnecessary now. Further, transcodes use up a significant amount of disk space and are not guaranteed to be lossless.
"},{"location":"in-app-manual/tasks/#image-gallery-thumbnails","title":"Image gallery thumbnails","text":"These are generated when the gallery is first viewed, so generating them beforehand is not necessary.
"},{"location":"in-app-manual/tasks/#cleaning","title":"Cleaning","text":"This task will walk through your configured media directories and remove any scene from the database that can no longer be found. It will also remove generated files for scenes that subsequently no longer exist.
Care should be taken with this task, especially where the configured media directories may be inaccessible due to network issues.
"},{"location":"in-app-manual/tasks/#exporting-and-importing","title":"Exporting and Importing","text":"The import and export tasks read and write JSON files to the configured metadata directory. Import from file will merge your database with a file.
\u26a0\ufe0f Note: The full import task wipes the current database completely before importing.
See the JSON Specification page for details on the exported JSON format.
"},{"location":"in-app-manual/tasks/autotagging/","title":"Auto Tagging","text":"When media filepaths or filenames contain a Performer, Studio, or Tag name, it is assigned those Performers, Studios, and Tags. It will only tag based on Performer, Studio, and Tag names that exist in your database.
When the Performer/Studio/Tag name has multiple words, the search will include paths/filenames where the Performer/Studio/Tag name is separated with .
, -
, _
, and whitespace characters.
For example, auto tagging for performer Jane Doe
will match the following filenames:
Jane.Doe.1.mp4
Jane_Doe.2.mp4
Jane-Doe.3.mp4
Jane Doe.4.mp4
Matching is case insensitive, and should only match exact wording within word boundaries. For example, the tag Jane Doe
will not match Maryjane-Doe
or Jane-Doen
, but will match Mary-Jane-Doe
, Jane-Doe_n
, and [OF]jane doe
.
Auto tagging for specific Performers, Studios, and Tags can be performed from the individual Performer/Studio/Tag page.
Note: Performer autotagging does not currently match on performer aliases.
"},{"location":"in-app-manual/tasks/identify/","title":"Identify","text":"This task iterates through your Scenes and attempts to identify the scene using a selection of scraping sources.
This task accepts one or more scraper sources. Valid scraper sources for the Identify task are stash-box instances, and scene scrapers which support scraping via Scene Fragment. The order of the sources may be rearranged.
For each Scene, the Identify task iterates through the scraper sources, in the order provided, and tries to identify the scene using each source. If a result is found in a source, then the Scene is updated, and no further sources are checked for that scene.
"},{"location":"in-app-manual/tasks/identify/#options","title":"Options","text":"The following options can be set:
Option Description Include male performers If false, then male performers will not be created or set on scenes. Set cover images If false, then scene cover images will not be modified. Set organised flag If true, the organised flag is set to true when a scene is organised. Skip matches that have more than one result If this is not enabled and more than one result is returned, one will be randomly chosen to match Tag skipped matches with If the above option is set and a scene is skipped, this will add the tag so that you can filter for it in the Scene Tagger view and choose the correct match by hand Skip single name performers with no disambiguation If this is not enabled, performers that are often generic like Samantha or Olga will be matched Tag skipped performers with If the above options is set and a performer is skipped, this will add the tag so that you can filter for in it the Scene Tagger view and choose how you want to handle those performersField specific options may be set as well. Each field may have a Strategy. The behaviour for each strategy value is as follows:
Strategy Description Ignore Not set. Overwrite Overwrite existing value. Merge (default) For multi-value fields, adds to existing values. For single-value fields, only sets if not already set.For Studio, Performers and Tags, an option is also available to Create Missing objects. This is enabled by default. When true, if a Studio/Performer/Tag is included during the identification process and does not exist in the system, then it will be created.
Default Options are applied to all sources unless overridden in specific source options.
The result of the identification process for each scene is output to the log.
"},{"location":"in-app-manual/tasks/jsonspec/","title":"Import/Export JSON Specification","text":"The metadata given to Stash can be exported into the JSON format. This structure can be modified, or replicated by other means. The resulting data can then be imported again, giving the possibility for automatic scraping of all kinds. The format of this metadata bulk is a folder structure, containing the following folders:
files
galleries
images
performers
scenes
studios
groups
When exported, files are named with different formats depending on the object type:
Type Format Files/Folders<path depth in hex, two character width>.<basename>.<hash>.json
Galleries <first zip filename>.<path hash>.json
or <folder basename>.<path hash>.json
or <title>.json
Images <title or first file basename>.<hash>.json
Performers <name>.json
Scenes <title or first file basename>.<hash>.json
Studios <name>.json
Groups <name>.json
Note that the file naming is not significant when importing. All json files will be read from the subdirectories.
"},{"location":"in-app-manual/tasks/jsonspec/#content-of-the-json-files","title":"Content of the json files","text":"In the following, the values of the according jsons will be shown. If the value should be a number, it is written with after comma values (like 29.98
or 50.0
), but still as a string. The meaning from most of them should be obvious due to the previous explanation or from the possible values stash offers when editing, otherwise a short comment will be added.
The json values are given as strings, if not stated otherwise. Every new line will stand for a new value in the json. If the value is a list of objects, the values of that object will be shown indented.
If a value is empty in any file, it can be left out of the file entirely. Many files have an created_at
and updated_at
, both are kept in the following format:
YYYY-MM-DDThh:mm:ssTZD \n
Example: \"created_at\": \"2019-05-03T21:36:58+01:00\"\n
"},{"location":"in-app-manual/tasks/jsonspec/#performer","title":"Performer","text":"name \nurl \ntwitter \ninstagram \nbirthdate \ndeath_date \nethnicity \ncountry \nhair_color \neye_color \nheight \nweight \nmeasurements \nfake_tits \ncareer_length \ntattoos \npiercings \nimage (base64 encoding of the image file) \ncreated_at \nupdated_at\nrating (integer)\ndetails\n
"},{"location":"in-app-manual/tasks/jsonspec/#studio","title":"Studio","text":"name \nurl \nimage (base64 encoding of the image file) \ncreated_at \nupdated_at\nrating (integer) \ndetails \n
"},{"location":"in-app-manual/tasks/jsonspec/#scene","title":"Scene","text":"title \nstudio \nurl \ndate \nrating (integer) \ndetails \nperformers (list of strings, performers name) \ntags (list of strings) \nmarkers \n title \n seconds \n primary_tag \n tags (list of strings) \n created_at \n updated_at \nfile (not a list, but a single object) \n size (in bytes, no after comma values) \n duration (in seconds) \n video_codec (example value: h264) \n audio_codec (example value: aac) \n width (integer, in pixel) \n height (integer, in pixel) \n framerate \n bitrate (integer, in Bit) \ncreated_at \nupdated_at \n
"},{"location":"in-app-manual/tasks/jsonspec/#image","title":"Image","text":"title \nstudio \nrating (integer) \nperformers (list of strings, performers name) \ntags (list of strings) \nfiles (list of path strings)\ngalleries\n zip_files (list of path strings)\n folder_path\n title (for user-created gallery)\ncreated_at \nupdated_at \n
"},{"location":"in-app-manual/tasks/jsonspec/#gallery","title":"Gallery","text":"title \nstudio \nurl \ndate \nrating (integer) \ndetails \nperformers (list of strings, performers name) \ntags (list of strings) \nzip_files (list of path strings)\nfolder_path \ncreated_at \nupdated_at \n
"},{"location":"in-app-manual/tasks/jsonspec/#files","title":"Files","text":""},{"location":"in-app-manual/tasks/jsonspec/#folder","title":"Folder","text":"zip_file (path to containing zip file)\nmod_time\ntype (= folder)\npath\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#video-file","title":"Video file","text":"zip_file (path to containing zip file)\nmod_time\ntype (= video)\npath\nfingerprints\n type\n fingerprint\nsize\nformat\nwidth\nheight\nduration\nvideo_codec\naudio_codec\nframe\nbitrate\ninteractive (bool)\ninteractive_speed (integer)\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#image-file","title":"Image file","text":"zip_file (path to containing zip file)\nmod_time\ntype (= image)\npath\nfingerprints\n type\n fingerprint\nsize\nformat\nwidth\nheight\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#other-files","title":"Other files","text":"zip_file (path to containing zip file)\nmod_time\ntype (= file)\npath\nfingerprints\n type\n fingerprint\nsize\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#in-json-format","title":"In JSON format","text":"For those preferring the json-format, defined here, the following format may be more interesting:
"},{"location":"in-app-manual/tasks/jsonspec/#performerjson","title":"performer.json","text":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://docs.stashapp.cc/in-app-manual/tasks/jsonspec#performerjson\",\n \"title\": \"performer\",\n \"description\": \"A json file representing a performer. The file is named by a MD5 Code.\",\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"description\": \"Name of the performer\",\n \"type\": \"string\"\n },\n \"url\": {\n \"description\": \"URL to website of the performer\",\n \"type\": \"string\"\n },\n \"twitter\": {\n \"description\": \"Twitter name of the performer\",\n \"type\": \"string\"\n },\n \"instagram\": {\n \"description\": \"Instagram name of the performer\",\n \"type\": \"string\"\n },\n \"birthdate\": {\n \"description\": \"Birthdate of the performer. Format is YYYY-MM-DD\",\n \"type\": \"string\"\n },\n \"death_date\": {\n \"description\": \"Death date of the performer. Format is YYYY-MM-DD\",\n \"type\": \"string\"\n },\n \"ethnicity\": {\n \"description\": \"Ethnicity of the Performer. Possible values are black, white, asian or hispanic\",\n \"type\": \"string\"\n },\n \"country\": {\n \"description\": \"Country of the performer\",\n \"type\": \"string\"\n },\n \"hair_color\": {\n \"description\": \"Hair color of the performer\",\n \"type\": \"string\"\n },\n \"eye_color\": {\n \"description\": \"Eye color of the performer\",\n \"type\": \"string\"\n },\n \"height\": {\n \"description\": \"Height of the performer in centimeters\",\n \"type\": \"string\"\n },\n \"weight\": {\n \"description\": \"Weight of the performer in kilograms\",\n \"type\": \"string\"\n },\n \"measurements\": {\n \"description\": \"Measurements of the performer\",\n \"type\": \"string\"\n },\n \"fake_tits\": {\n \"description\": \"Whether performer has fake tits. Possible are Yes or No\",\n \"type\": \"string\"\n },\n \"career_length\": {\n \"description\": \"The time the performer has been in business. In the format YYYY-YYYY\",\n \"type\": \"string\"\n },\n \"tattoos\": {\n \"description\": \"Giving a description of Tattoos of the performer if any\",\n \"type\": \"string\"\n },\n \"piercings\": {\n \"description\": \"Giving a description of Piercings of the performer if any\",\n \"type\": \"string\"\n },\n \"image\": {\n \"description\": \"Image of the performer, parsed into base64\",\n \"type\": \"string\"\n },\n \"created_at\": {\n \"description\": \"The time this performers data was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this performers data was last changed in the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"details\": {\n \"description\": \"Description of the performer\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"name\", \"ethnicity\", \"image\", \"created_at\", \"updated_at\"]\n}\n
"},{"location":"in-app-manual/tasks/jsonspec/#studiojson","title":"studio.json","text":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://docs.stashapp.cc/in-app-manual/tasks/jsonspec#studiojson\",\n \"title\": \"studio\",\n \"description\": \"A json file representing a studio. The file is named by a MD5 Code.\",\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"description\": \"Name of the studio\",\n \"type\": \"string\"\n },\n \"url\": {\n \"description\": \"URL to the studios websites\",\n \"type\": \"string\"\n },\n \"image\": {\n \"description\": \"Logo of the studio, parsed into base64\",\n \"type\": \"string\"\n },\n \"created_at\": {\n \"description\": \"The time this studios data was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this studios data was last changed in the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"details\": {\n \"description\": \"Description of the studio\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"name\", \"image\", \"created_at\", \"updated_at\"]\n}\n
"},{"location":"in-app-manual/tasks/jsonspec/#scenejson","title":"scene.json","text":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://docs.stashapp.cc/in-app-manual/tasks/jsonspec#scenejson\",\n \"title\": \"scene\",\n \"description\": \"A json file representing a scene. The file is named by the MD5 Code of the file its data is referring to.\",\n \"type\": \"object\",\n \"properties\": {\n \"title\": {\n \"description\": \"Title of the scene\",\n \"type\": \"string\"\n },\n \"studio\": {\n \"description\": \"The name of the studio that produced that scene\",\n \"type\": \"string\"\n },\n \"url\": {\n \"description\": \"The url to the scenes original source\",\n \"type\": \"string\"\n },\n \"date\": {\n \"description\": \"The release date of the scene. Its given in the format YYYY-MM-DD\",\n \"type\": \"string\"\n },\n \"rating\": {\n \"description\": \"The scenes Rating. Its given in stars, from 1 to 5\",\n \"type\": \"integer\"\n },\n \"details\": {\n \"description\": \"A description of the scene, containing things like the story arc\",\n \"type\": \"string\"\n },\n \"performers\": {\n \"description\": \"A list of names of the performers in this gallery\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"tags\": {\n \"description\": \"A list of the tags associated with this scene\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"markers\": {\n \"description\": \"Markers mark certain events in the scene, most often the change of the position. They are attributed with their own tags.\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"title\": {\n \"description\": \"Searchable name of the marker\",\n \"type\": \"string\"\n },\n \"seconds\": {\n \"description\": \"At what second the marker is set. It is given with after comma values, such as 10.0 or 17.5\",\n \"type\": \"string\"\n },\n \"primary_tag\": {\n \"description\": \"A tag identifying this marker. Multiple markers from the same scene with the same primary tag are concatenated, showing them as similar in nature\",\n \"type\": \"string\"\n },\n \"tags\": {\n \"description\": \"A list of the tags associated with this marker\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"created_at\": {\n \"description\": \"The time this marker was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this marker was updated the last time. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n }\n\n },\n \"required\": [\"seconds\", \"primary_tag\", \"created_at\", \"updated_at\"]\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"files\": {\n \"description\": \"A list of paths of the files for this scene\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"created_at\": {\n \"description\": \"The time this studios data was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this studios data was last changed in the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"files\", \"created_at\", \"updated_at\"]\n}\n
"},{"location":"in-app-manual/tasks/scenefilenameparser/","title":"Scene Filename Parser","text":"This tool parses the scene filenames in your library and allows setting the metadata from those filenames.
"},{"location":"in-app-manual/tasks/scenefilenameparser/#parser-options","title":"Parser Options","text":"To use this tool, a filename pattern must be entered. The pattern accepts the following fields:
Field Remarktitle
Text captured within is set as the title of the scene. ext
Matches the end of the filename. It is not captured. Does not include the last .
character. d
Matches delimiter characters (-_.
). Not captured. i
Matches any ignored word entered in the Ignored words
field. Ignored words are entered as space-delimited words. Not captured. Use this to match release artifacts like DVDRip
or release groups. date
Matches yyyy-mm-dd
and sets the date of the scene. rating
Matches a single digit and sets the rating of the scene. performer
Sets the scene performer, based on the text captured. tag
Sets the scene tag, based on the text captured. studio
Sets the studio performer, based on the text captured. {}
Matches any characters. Not captured. \u26a0\ufe0f Note: performer
, tag
and studio
fields will only match against Performers/Tags/Studios that already exist in the system.
The performer
/tag
/studio
fields will remove any delimiter characters (.-_
) before querying. Name matching is case-insensitive.
The following partial date fields are also supported. The date will only be set on the scene if a date string can be built using the partial date components:
Field Remarkyyyy
Four digit year yy
Two digit year. Assumes the first two digits are 20
mm
Two digit month mmm
Three letter month, such as Jan
(case-insensitive) dd
Two digit date The following full date fields are supported, using the same partial date rules as above:
yyyymmdd
yymmdd
ddmmyyyy
ddmmyy
mmddyyyy
mmddyy
All of these fields are available from the Add Field
button.
Title generation also has the following options:
Option Remark Whitespace characters These characters are replaced with whitespace (defaults to._
, to handle filenames like three.word.title.avi
Capitalize title capitalises the first letter of each word The fields to display can be customised with the Display Fields
drop-down section. By default, any field with new/different values will be displayed.
Once the options are correct, click on the Find
button. The system will search for scenes that have filenames that match the given pattern.
The results are presented in a table showing the existing and generated values of the discovered fields, along with a checkbox to determine whether or not the field will be set on each scene. These fields can also be edited manually.
The Apply
button updates the scenes based on the set fields.
\u26a0\ufe0f Note: results are paged and the Apply
button only applies to scenes on the current page.
Stash offers native binaries for the following platforms:
All official binaries can be downloaded from our GitHub release page. Latest version is available here.
Official Discord image is hosted on Docker Hub. Latest version can be pulled from stashapp/stash:latest
.
Info
Before starting make sure your system has Docker installed. You can follow the instructions on how to install Docker from Docker Docs.
Info
Official Stash image is located at stashapp/stash
.
Note
Stash README on Docker installation is available here.
"},{"location":"installation/docker/#using-docker-compose","title":"Using Docker Compose","text":""},{"location":"installation/docker/#install","title":"Install","text":"docker-compose.yml
file from our GitHub.docker-compose.yml
or cd
to that directory.docker-compose up -d
If you are upgrading from older than v0.20 version make sure to re-download the docker-compose.yml
file from our GitHub as new volume was added. Alternatively you can edit the docker-compose.yml
to manually include new volume - ./blobs:/blobs
.
docker-compose.yml
is saved.docker-compose pull
. Pulls the new image.docker-compose down
. Removes old container.docker-compose up -d
. Creates and starts the new container. docker-compose.yml
file. docker-compose.yml
is saved.docker container kill
. Force stops the container.docker container rm
. Removes the container.docker-compose.yml
file.Info
The following step by step was tested using TrueNAS Scale Cobia (23.10.1.3).
"},{"location":"installation/freenas-truenas/#installation","title":"Installation","text":"To install the stashapp, we will use the TrueCharts app database. To install, we'll follow the official documentation at https://truecharts.org/manual/SCALE/guides/getting-started/
After the update is complete, use the search bar to search for \"stash\". When found, click Install.
"},{"location":"installation/freenas-truenas/#options","title":"Options","text":"The installation window will contain several customizable options, but the most important one is the storage option. Search for \"Additional App Storage\" on the page and click \"Add\".
In \"Type of Storage\", select \"Host Path\" if the desired folder is a Dataset. \"Host Path\" should be where your content will be. \"Mount Path\" is the name that appears in the stash for the selection. You can put anything here, like /stash-content for example. After that, click Install.
Installation will take a few minutes. After the stash appears as \"Running\", click \"Open\" on the right and continue with the stash configuration. When entering the folder that contains its contents, remember to search for the same name you entered previously. In the case of this guide, the name was /stash-content.
"},{"location":"installation/freenas-truenas/#truenas-core","title":"TrueNAS Core","text":"Info
We are now offering pre-compiled FreeBSD binary. You can grab it from release page.
Warning
The install guide below was reported as outdated.
"},{"location":"installation/freenas-truenas/#caveats-and-assumptions","title":"Caveats and assumptions","text":"In order for the stash-linux
binary to work in a FreeBSD system, Linux compatibility must be enabled both in the system and the jail. To enable Linux compatibility:
System -> Tunables
in the TrueNAS Web UIAdd
and enter the following:linux_enable
YES
rc.conf
/etc/rc.conf
to add: enable_linux=\"YES\"\n
Go into your iocage jail and install ffmpeg
pkg install ffmpeg\n
"},{"location":"installation/freenas-truenas/#create-user-and-group","title":"Create user and group","text":"It is recommended to not run services as root. Adjust this step to your system. in this example the user stash
will be created and set to run the service.
pw useradd -n stash -u 1069 -d /nonexistent -s /usr/sbin/nologin\n
"},{"location":"installation/freenas-truenas/#download-stash-linux","title":"Download stash-linux","text":"Choose where you would like to store the binary, in this example /usr/local/bin
is selected as this is where the ffmpeg binaries also reside. Check github for latest release. Also remember to fix permissions and ownership
cd /usr/local/bin\nfetch https://github.com/stashapp/stash/releases/download/v0.22.1/stash-linux\nchown stash:stash stash-linux\nchmod +x stash-linux\n
"},{"location":"installation/freenas-truenas/#create-configuration-directory","title":"Create configuration directory","text":"stash needs a directory for its config file, database and more. Remember to change ownership and permission for the folder you select. The script we will look at in the next step has this path as the default:
mkdir /usr/local/etc/stash\nchown stash:stash /usr/local/etc/stash\n
"},{"location":"installation/freenas-truenas/#rcd-startup-script","title":"rc.d startup script","text":"In order for stash to run as a daemon in the background, and also start at boot, you need a rc.d script.
mkdir /usr/local/etc/rc.d\nee /usr/local/etc/rc.d/stash\n
Enter the following in the editor: #!/bin/sh\n\n# PROVIDE: stash\n# REQUIRE: DAEMON\n# KEYWORD: shutdown\n\n\n. /etc/rc.subr\n\nname=stash\nrcvar=stash_enable\n\nload_rc_config $name\n\n: ${stash_enable:=\"NO\"}\n: ${stash_user:=\"stash\"}\n: ${stash_group:=\"stash\"}\n: ${stash_config_dir:=\"/usr/local/etc/stash/config.yml\"}\n: ${stash_exec_bin:=\"/usr/local/bin/stash-linux\"}\n\n#daemon\npidfile=\"/var/run/${name}.pid\"\ncommand=\"/usr/sbin/daemon\"\ncommand_args=\"-f -P ${pidfile} ${stash_exec_bin} --config ${stash_config_dir}\"\nstart_precmd=\"stash_precmd\"\n\nstash_precmd() {\n install -o ${stash_user} -g ${stash_group} /dev/null ${pidfile}\n}\n\nrun_rc_command $1\n
To save, press ESC + Enter
and confirm with a
and make it executable with chmod +x /usr/local/etc/rc.d/stash
"},{"location":"installation/freenas-truenas/#enable-the-service-at-boot","title":"Enable the service at boot","text":"If you want Stash to run when you start the jail, run the following command:
sysrc \"stash_enable=YES\"\n
And to start the service, reboot the jail or run this command: service stash start\n
Stash is now available at http://jail-IP:9999/ During setup you can leave all the paths for config, database and etc empty to use the default. They will then be stored in the config-folder we created earlier so you can easily backup the folder. Only add your media content.
"},{"location":"installation/freenas-truenas/#optional-steps","title":"Optional steps","text":"You can change the location where stash stores the configuration files and database. Please note that the path needs to end with config.yml
even if it does not exist yet. Stash will create it for you. Remember to fix ownership and permissions of the location you choose.
sysrc \"stash_config_dir=path/to/location/config.yml\"\n
You can change the user and group that Stash runs as. Remember that the config_dir needs to be owned by the user that Stash runs as, aswell as the stash-linux binary
sysrc \"stash_user=usernamegoeshere\"\nsysrc \"stash_group=groupnamegoeshere\"\n
Its also possible to change the location of the stash-linux binary ``` sysrc \"stash_exec_bin=/path/to/stash-linux\"
"},{"location":"installation/linux/","title":"Linux","text":"Info
It is recommended that you install ffmpeg
from your distribution's package manager. In case you don't, Stash will prompt you to download a copy during setup.
Note
Stash offers different binaries for different architectures. You can find your processor architecture by running a simple command uname -p
in a terminal. Replace <binary-name>
in the following tutorial accordingly.
stash-linux
= amd64 (x86_64) stash-linux-arm32v6
= arm32v6 (armel) stash-linux-arm32v7
= arm32v7 (armhf) stash-linux-arm64v8
= arm64v8 (arm64)
<binary-name>
binary from GitHub repository depending on your architecture. ./<binary-name>
from the terminal.chmod u+x <binary-name>
to make the file executable.<binary-name>
binary from GitHub repository.<binary-name>
binary and replace it with the newly downloaded one. ./<binary-name>
from the terminal.chmod u+x <binary-name>
to make the file executable.<binary-name>
binary file.$HOME/.stash
folder.On macOS, Stash can be run as either a packaged app (Stash.app
) or as a command-line app (stash-macos
). Both are universal apps, and will therefore run natively on both Apple silicon and Intel-based Macs.
Note
The packaged app is recommended for most users.
It supports desktop notifications, displays a menu bar icon, and does not need to be launched from the terminal.
However, due to app restrictions, it only supports setting up in $HOME/.stash
. If you would like to use a different folder, then you will need to use the command-line app.
Stash.app.zip
from GitHub repository.Stash.app.zip
archive and drag the Stash
app to your Applications folder.Stash
app.Stash.app.zip
from GitHub repository.Stash
app. Stash.app.zip
archive and drag the Stash
app to your Applications folder. Stash
app.Stash
app.$HOME/.stash
.Note
The command-line app is only recommended for users who are familiar with the terminal, or for those who do not want to set up in $HOME/.stash
.
It does not support desktop notifications and does not display a menu bar icon. It must be launched from the terminal.
"},{"location":"installation/macos/#install_1","title":"Install","text":"stash-macos
binary from GitHub repository.Run ./stash-macos
from the terminal.
If you have trouble, try running chmod u+x stash-macos
to make the file executable.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-macos
binary from GitHub repository.stash-macos
binary and replace it with the newly downloaded one. Run ./stash-macos
from the terminal.
If you have trouble, try running chmod u+x stash-macos
to make the file executable.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-macos
.$HOME/.stash
.Info
Written by Muldec.
"},{"location":"installation/synology/#foreword","title":"Foreword","text":"Synology devices comes in two categories : those who support containerization through Docker, and those who don't. To see in which category you stand, refer to the \"Applied Models\" section of the Docker Package page.
Now, follow the installation instructions based on whether you can use Docker or you cannot use Docker.
"},{"location":"installation/synology/#to-install-stash-with-docker","title":"To install Stash with Docker","text":"Note
Running Stash without Docker is possible even if your NAS is Docker ready. It offers more control on your Stash instance startup. As an example, it allows you to store your porn collection in an Encrypted Shared Folder, and only run Stash when the Encrypted folder is Mounted (Decrypted).
(These will need to be the same as the Volumes you created in the \"Volume\" tab.)
variable Value PATH (keep as is) STASH_CACHE /cache STASH_METADATA /metadata STASH_GENERATED /generated STASH_STASH /data"},{"location":"installation/synology/#port-tab","title":"\"Port\" tab","text":"You will need to set a default port in the \"Port\" tab, otherwise Docker will assign a different port every time Stash is launched. Leave the container port as-is.
"},{"location":"installation/synology/#network-tab","title":"\"Network\" tab","text":"Make sure that \"Use The Same Network As Docker Host\" is checked.
(thanks to backer Herelam80 for these instructions)
"},{"location":"installation/synology/#to-install-stash-without-docker","title":"To install Stash without Docker","text":"Warning
This method uses SSH to run command lines on the NAS. If you are unfamiliar with SSH or linux command lines, I suggest you not to go further, as making a mistake in the SSH session can really screw your NAS.
This is intended to work on DSM 7.0 and later. It will not work on any version prior to 7.0.
"},{"location":"installation/synology/#install-prerequisites","title":"Install Prerequisites","text":"In DSM, navigate to Package Center > Settings
. In the Package Sources
tab, click Add
, type SynoCommunity as Name and https://packages.synocommunity.com/ as Location and then press OK
to validate.
Go back to the Package Center and look for Python 3.11
in the Community tab. Click on \u00ccnstall
and agree to the Third-Party Package warning.
Then look for Ffmpeg 6
in the Community tab. Click on \u00ccnstall
and agree to the Third-Party Package warning.
In DSM, navigate to Control Panel > Connectivity > Terminal & SNMP
and check the Enable SSH service
box.
Control Panel > File Sharing > User & Group
Create
buttonNext
until you are on the \"Join groups\" screenNext
until you are on the \"Assign shared folders permissions\" screenNext
until you are on the \"Assign application permissions\" screenDeny
for all applicationsNext
until you can click on Done
With your terminal, connect to your NAS using the newly created account that is part of the administrators group.
ssh stash@your_nas_hostname\n
"},{"location":"installation/synology/#link-ffprobe-ffmpeg","title":"Link ffprobe & ffmpeg","text":"ffmpeg has been installed earlier, but is missing a link to ffprobe (also installed) and the new version of ffmpeg. Run the following command.
sudo ln -s /var/packages/ffmpeg6/target/bin/ffprobe /usr/local/bin/ffprobe\nsudo ln -s /var/packages/ffmpeg6/target/bin/ffmpeg /usr/local/bin/ffmpeg\n
"},{"location":"installation/synology/#download-stash","title":"Download Stash","text":"Download the lastest version of Stash and its checksum from GitHub
# find what architecture your synology is running on\nuname -m\n\n# depending on the architecture, you'll have to download the right version of stash\n\n# x86_64\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux\n# armv6l\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux-arm32v6\n# armv7l\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux-arm32v7\n# aarch64\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux-arm64v8\n\n# Download the CHECKSUM\nwget https://github.com/stashapp/stash/releases/latest/download/CHECKSUMS_SHA1\n\n# Perform the checksum validation\nsha1sum -c --ignore-missing CHECKSUMS_SHA1\n\n# you should see a line that says `stash-linux: OK`\n# if not, something went wrong during the download\n\n# Clean up the now unnecessary file\nrm CHECKSUMS_SHA1\n
Danger
DO NOT run stash yet or it will generate a bunch of files/folders where we don't want them.
"},{"location":"installation/synology/#python","title":"Python","text":"Prepare a python environment (for scrapers and plugins)
python3.11 -m ensurepip --Update\npython3.11 -m venv stash-env\nsource stash-env/bin/activate\npip3 install pipreqs\n
"},{"location":"installation/synology/#configure-your-nas-to-run-stash","title":"Configure your NAS to run Stash","text":"Create a profile file
echo 'PATH=/usr/local/bin:$PATH' > .profile\necho 'source stash-env/bin/activate' >> .profile\n
Create the service file by running cat > stash.service
, copy/pasting the following, and hitting CTRL+D when it's done to save the file (hit again if you are not back to the prompt) :
[Unit]\nDescription=Run Stash at startup\nAfter=network.target\n\n[Service]\nWorkingDirectory=/var/services/homes/stash\nType=simple\nUser=stash\nExecStart=/bin/bash -c -l '\\\n exec ./stash-linux'\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target\n
Note
Change the ExecStart
line by providing the exact name of the stash executable that you downloaded previously.
Start and activate the service
sudo systemctl enable \"$(pwd)/stash.service\"\nsudo systemctl start stash.service\n
"},{"location":"installation/synology/#verify-that-it-is-working","title":"Verify that it is working","text":"You can now access to stash by navigating to your NAS url on port 9999 : http://nas-hostname:9999
Whenever you install a new python scraper or plugin, do the following from the stash user home directory
pipreqs .stash/.\npip3 install -r .stash/requirements.txt\n
Note
Using pipreqs allows to scan all scrapers and plugins installed and find dependencies that they require. You can do the same thing without pipreqs by going into each individual directory and run pip3 install -r requirements.txt
Control Panel > File Sharing > User & Group
Edit
User Groups
tab, uncheck \"administrators\" and click on Save
Info
Unraid app is maintained by a 3rd party. For Unraid specific support you can go to support thread by CorneliousJD.
Note
For users that want to try the development branch of Stash you can change the repository to stashapp/stash:development
.
Apps
tab.Stash
.Stash
.Info
binarygeek119/stash-cuda:latest
repository is not maintained by Stash core team.
First off you need the unraid Nvidia plugin for this to work. On Unraid go to apps and do a search for nvidia driver
and install, this will take some time to install. When the dialog is done it is still installing in the background. When it has finshed you will get a popup saying it is safe to reboot now.
Warning
Do not restart Unraid server until the plugin is done installing itself!
After getting the popup, reboot your server. After it back online you may continue to the next steps.
"},{"location":"installation/unraid/#container-configuration","title":"Container configuration","text":"
Now we can change some thing to have Stash work with a Nvidia GPU.
stashapp/stash:development
to binarygeek119/stash-cuda:latest
. --runtime=nvidia
. Add another Path, Port, Variable, Label or Device
. path
to Variable
and add the following: Name:
enter NVIDIA_DRIVER_CAPABILITIES
Key:
enter NVIDIA_DRIVER_CAPABILITIES
Value:
enter all
and click save. Add another Path, Port, Variable, Label or Device
. path
to Variable
and add the following:Name:
enter NVIDIA_VISIBLE_DEVICES
Key:
enter NVIDIA_VISIBLE_DEVICES
Value:
enter GPU-xxxx-xxxx-xxx-xxxx-xxxx-xxx-xxxxxxxxxxxx
Where GPU-xxxx-xxxx-xxx-xxxx-xxxx-xxx-xxxxxxxxxxxx
you must enter your own GPUID. To find it do the folowing:
Variable
called Value
.Note
Some Windows 11 versions might open Stash via Terminal instead of going to notification area. You can bypass that by running the program as administrator or use a shortcut to run it via conhost.exe. As a result of running as administrator Stash might fail to detect your Python installtion in PATH, so you need point it the correct way yourself after installation. In Settings > System and under Applications Paths header set Python Executable Path.
"},{"location":"installation/windows/#install","title":"Install","text":"stash-win.exe
binary from GitHub repository.Run the executable (typically stash-win.exe
).
Running the executable might present a security prompt since the binary isn't signed yet. Just click more info and then the run anyway
button.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-win.exe
binary from GitHub repository.stash-win.exe
binary and replace it with the newly downloaded one. Run the executable (typically stash-win.exe
).
Running the executable might present a security prompt since the binary isn't signed yet. Just click more info and then the run anyway
button.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-win.exe
binary file.%userprofile%/.stash
folder.Info
Integrations are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Integrations are ways to integrate Stash into other programs.
To install follow the provided install instructions.
"},{"location":"integrations/list/","title":"List of integrations","text":"stash-git-indexExhaustive list of git repositories related to Stash Google Sheets document.
Integration no longer worksIf you found that integration is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"integrations/list/#jellyfinpluginstash","title":"Jellyfin.Plugin.Stash","text":"DescriptionAuthorScreenshotsPulls data from your Stash using the filename to query on.
DirtyRacer1337
"},{"location":"integrations/list/#pluginvideostash","title":"plugin.video.stash","text":"DescriptionAuthorScreenshotsplugin.video.stash is an add-on for the Kodi home theater center software to incorporate Stash, an organizer for your porn.
gitgiggety
"},{"location":"integrations/list/#stashplexagentbundle","title":"StashPlexAgent.bundle","text":"DescriptionAuthorScreenshotsA very simplistic Plex agent to pull metadata from Stash.
Darklyter
"},{"location":"metadata-sources/","title":"Metadata sources","text":"There are several ways to get metadata into Stash.
You can configure your metadata sources under Settings > Metadata Providers. See sections below for more details.
Scrapers are the way to retrieve information from websites for your scenes/groups/galleries/performers. Using scrapers wisely, you can avoid typing information manually and repetitively. They can help you quickly establish links between groups/scenes and performers/studios, add relative tags, then download covers/posters for easy recognition. It's a great feature to organize your video or image collections.
"},{"location":"metadata-sources/scrapers/#managing-scrapers","title":"Managing scrapers","text":"Scrapers can be installed and managed from the Settings > Metadata Providers page.
Scrapers are installed using the Available Scrapers section. The Community (stable) source is configured by default.
Installed plugins can be updated or uninstalled from the Installed Scrapers section.
"},{"location":"metadata-sources/scrapers/#adding-sources","title":"Adding sources","text":"Anyone can create their own source index for scrapers. To add a new source go to Settings > Metadata Providers page and under Available Scrapers click Add Source.
"},{"location":"metadata-sources/scrapers/#installing-scrapers-manually","title":"Installing scrapers manually","text":"By default, Stash looks for scrapers configurations in the scrapers sub-directory of the directory where the stash config.yml
is read. This will either be the %USERPROFILE%\\.stash\\scrapers
on Windows or /root/.stash/scrapers
on Unix systems (Mac, Linux, etc.) or the current working directory.
Scrapers are added by adding configuration yaml files (format: scraperName.yml
) to the scrapers
directory.
Loaded scrapers can be viewed in the Settings > Metadata Providers page. After scrapers are added, removed or edited while Stash is running, they can be reloaded by clicking Reload scrapers button.
CommunityScrapers repository is the source for community maintained scrapers.
"},{"location":"metadata-sources/scrapers/#scraper-types","title":"Scraper types","text":""},{"location":"metadata-sources/scrapers/#by-searching-type","title":"By searching type","text":""},{"location":"metadata-sources/scrapers/#fragment","title":"Fragment","text":"This kind of scrapers will fetch the metadata from a website, by using existing data from Stash, like a scene's file name, performer's name...etc. Fragment scrapers will get all the data Stash knows about that scene/performer/gallery, so it's quite flexible when fetching information.
"},{"location":"metadata-sources/scrapers/#search-by-name","title":"Search by name","text":"A Search-By-Name scraper will get only \"name\" input from a scene or performer, then it will search a website with that name, and return a list of results.
Scrapers includes: Babepedia.yml, FreeonesCommunity.yml, IAFD.yml
"},{"location":"metadata-sources/scrapers/#search-by-url","title":"Search by URL","text":"Most scrapers fetch metadata from a given URL, either by using XPath, JSON, or scripts. For this kind of scrapers you need to know the URL for that scene/performer/gallery/group so they can extract information from it.
Scrapers includes: All other scrapers.
"},{"location":"metadata-sources/scrapers/#by-implementation","title":"By implementation","text":""},{"location":"metadata-sources/scrapers/#xpath-and-json-ccrapers","title":"XPath and JSON ccrapers","text":"This is the most common type of scrapers, which use either XPath parser to pin-point the information and retrieve them, or send out JSON requests to get the information. xpathScraper and jsonScraper can be mixed in the same .yml file.
"},{"location":"metadata-sources/scrapers/#cdp-scrapers","title":"CDP scrapers","text":"This type of scrapers is mostly the same as XPath/JSON scrapers, except it will launch a headless Chrome browser to retrieve the information from websites. It can also get cookies, simulate a mouse click and other actions. These scrapers have useCDP: true
setting in them.
This type of scrapers will launch Python, Ruby to retrieve information from websites. Script scrapers are powerful, versatile and cross-platform. So they usually can do much more than regular scrapers. To install this kind of scrapers, you need to copy not only the .yml file, but also all the script files like .py, .rb that associated with it.
"},{"location":"metadata-sources/scrapers/#more-details","title":"More details","text":"You can view the detailed information about scrapers here or CommunityScrapers README.
"},{"location":"metadata-sources/scrapers/#create-your-own","title":"Create your own","text":"To create your own scraper, there is detailed information about that as well. Best way to start is to read the simple ones and understand how xpath works. The XPath Cheetsheet is quite useful in creating a .yml file. In Firefox you can use xpath search in \"Web Developer Tools (F12)\". The \"search HTML\" bar actually accepts xpath searches. You can use it to verify your xpath queries.
"},{"location":"metadata-sources/scrapers/#contribution","title":"Contribution","text":"The Scraper community always welcome new members. If you create a nice scraper and find it stable and useful, you can share it via the GitHub repository. Create a pull request, and let the mod review your work. The mods are busy, so it will probably take a few days, or a couple of weeks, but it will be a great feeling once your contribution is accepted by the community.
"},{"location":"metadata-sources/stash-box-instances/","title":"stash-box instances","text":""},{"location":"metadata-sources/stash-box-instances/#fansdb","title":"FansDB","text":"FansDB is a community-driven metadata database focused on adult content platforms (OnlyFans, Fansly, ManyVids, etc.) where the independent creators are the primary focus.
Website | Guidelines | Discord | Endpoint https://fansdb.cc/graphql
| Join
JAVStash is a community-driven metadata database focused on Japanese Adult Video content and their original metadata in Japanese.
Website | Guidelines1 | Discord | Endpoint https://javstash.org/graphql
| Join2
PMV Stash is a community-driven metadata database focused on remixed pornographic art such as Porn Music Videos, Cock Hero, Hypno Vids, Compilations.
Website | Guidelines | Discord | Endpoint https://pmvstash.org/graphql
| Join
StashDB is a community-driven metadata database focused on digital scenes of all orientations.
Website | Guidelines | Discord | Matrix | Endpoint https://stashdb.org/graphql
| Join
ThePornDB is a metadata database focused on digital scenes and movies, relying on automated scrapers.
Website | Discord | Endpoint https://theporndb.net/graphql
| Join3
Link leads to a private Discord server.\u00a0\u21a9
Link leads to a private Discord server.\u00a0\u21a9
Requires registration to access the site.\u00a0\u21a9
Stash data is considered private, and Stash is not designed to be publicly exposed, except to trusted confidants. Stash has a built-in protection against accidentally exposing itself publicly outside of your network. If Stash receives a request from the public internet, and you do not have a password enabled, Stash will reject the request and stop handling requests to protect your privacy.
This often happens when you use the port-forwarding feature of your router or install Stash on a publicly accessible server, such as a VPS. When you do this, anybody in the world can access your Stash instance, so we enforce a password requirement. If your Stash instance has shutdown due to an insecure configuration, it will not handle requests again until you tell it that you have fixed the problem. After setting up either authentication, firewall, or removing your port forwarding rules, you can edit .stash/config/config.yml
and remove the key security_tripwire_accessed_from_public_internet
.
You may use several methods to safely access Stash from outside of your home network. In the most basic, you can enable authentication in Stash, and re-enable port forwarding. You can also use a VPN solution that allows you to securely access your home network, such as Tailscale, Zerotier, Wireguard, or others.
"},{"location":"networking/authentication-required-when-accessing-stash-from-the-internet/#using-an-external-authentication-provider","title":"Using an external authentication provider","text":"If you are an advanced user, and have secured your Stash instance behind an authwall provided by a reverse proxy or hosting solution, you may continue to use that. You simply have to edit .stash/config/config.yml
and set dangerous_allow_public_without_auth
to true
. If you have already tripped the security feature, you will also have to remove the security_tripwire_accessed_from_public_internet
key in order to allow Stash to serve requests.
Info
Plugins are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Plugins adds further features that Stash doesn't itself provide.
"},{"location":"plugins/#managing-plugins","title":"Managing plugins","text":"Plugins can be installed and managed from the Settings > Plugins page.
Plugins are installed using the Available Plugins section. The Community (stable) source is configured by default.
Installed plugins can be updated or uninstalled from the Installed Plugins section.
"},{"location":"plugins/#adding-sources","title":"Adding sources","text":"Anyone can create their own source index for plugins. To add a new source go to Settings > Plugins page and under Available Plugins click Add Source.
"},{"location":"plugins/#installing-plugins-manually","title":"Installing plugins manually","text":"By default, Stash looks for plugin configurations in the plugins sub-directory of the directory where the stash config.yml
is read. This will either be the %USERPROFILE%\\.stash\\plugins
on Windows or /root/.stash/plugins
on Unix systems (Mac, Linux, etc.) or the current working directory.
Plugins are added by adding configuration yaml files (format: pluginName.yml
) to the plugins
directory.
Loaded plugins can be viewed in the Settings > Plugins page. After plugins are added, removed or edited while Stash is running, they can be reloaded by clicking Reload plugins button.
"},{"location":"plugins/list/","title":"List of plugins","text":""},{"location":"plugins/list/#add-images-to-tags","title":"Add Images to Tags","text":"DescriptionSource URLREADMEAuthorScreenshotsAuto add images to tags using first found image from Google API. Requires modifying the .py file to provide your own API key and CSE ID
https://rosa-umineko.github.io/CommunityScripts/stable/index.yml\n
No README available
rosa-umineko
"},{"location":"plugins/list/#adulttime-interactive-downloader","title":"Adulttime Interactive Downloader","text":"DescriptionSource URLREADMEAuthorScreenshotsDownload Interactive Files for Adulttime Scenes
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
tooliload
"},{"location":"plugins/list/#ai-tagger","title":"AI Tagger","text":"DescriptionSource URLREADMEAuthorScreenshotsTag videos and Images with Locally hosted AI using Skier's Free and Patreon AI models
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
skier233
"},{"location":"plugins/list/#audio-transcodes","title":"audio-transcodes","text":"DescriptionSource URLREADMEAuthorScreenshotsGenerate a transcode video from an audio file
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#auto-select-updatable-plugins-and-scrapers","title":"Auto Select Updatable Plugins and Scrapers","text":"DescriptionSource URLREADMEAuthorScreenshotsAuto selects updatable Plugins and Scrapers when Check for Updates is clicked
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#auto-update-plugins-and-scrapers","title":"Auto Update Plugins and Scrapers","text":"DescriptionSource URLREADMEAuthorScreenshots
Automatically updates Plugins and Scrappers on website Startup
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#autovr","title":"autovr","text":"DescriptionSource URLREADMEAuthorScreenshotsautomatically toggle VR mode
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#average-rating","title":"Average Rating","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds average rating to performers and studios
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#backup-plugins","title":"Backup Plugins","text":"DescriptionSource URLREADMEAuthorScreenshotsCreates a backup of the 'plugins' directory.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#bulk-import-performers","title":"Bulk Import Performers","text":"DescriptionSource URLREADMEAuthorScreenshotsBulk Import Performers based on names from a text file.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#cjs-card-tweaks","title":"CJ's Card Tweaks.","text":"DescriptionSource URLREADMEAuthorScreenshotsProvides various tweaks for the Stash Cards.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
No Author
"},{"location":"plugins/list/#cleanupui","title":"CleanupUI","text":"DescriptionSource URLREADMEAuthorScreenshots
UI plugin to hide features you don't want
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
View README
S3L3CT3DLoves
"},{"location":"plugins/list/#comic-info-extractor","title":"Comic Info Extractor","text":"DescriptionSource URLREADMEAuthorScreenshotsExtract the metadata from cbz with the Comicrack standard (ComicInfo.xml)
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
yoshnopa
"},{"location":"plugins/list/#communityscriptsuilibrary","title":"CommunityScriptsUILibrary","text":"DescriptionSource URLREADMEAuthorScreenshotsCommunityScripts UI helper library
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
No Author
"},{"location":"plugins/list/#completethestash","title":"CompleteTheStash","text":"DescriptionSource URLREADMEAuthorScreenshotsFinds missing scenes for selected performers and creates missing scene metadata to another missing Stash instance. You can use either StashDB or TPDB or both as a source for missing scenes.
https://minasukihikimuna.github.io/MidnightRider-Stash/index.yml\n
View README
MinasukiHikimuna
"},{"location":"plugins/list/#cuptag","title":"cuptag","text":"DescriptionSource URLREADMEAuthorScreenshotsTag performers with cup sizes
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#date-parser","title":"Date Parser","text":"DescriptionSource URLREADMEAuthorScreenshotsFind date in path or filename and add it
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
HijackHornet
"},{"location":"plugins/list/#default-data-for-path","title":"Default Data For Path","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds configured Tags, Performers and/or Studio to all newly scanned Scenes, Images and Galleries.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
TheSinfulKing
"},{"location":"plugins/list/#deletefp","title":"deletefp","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a button to delete fingerprints
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#discord-presence","title":"Discord Presence","text":"DescriptionSource URLREADMEAuthorScreenshotsSets currently playing scene data as your Discord status. See README for prerequisites and config options (blue hyperlink next to enable/disable button)
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
NotForMyCV
"},{"location":"plugins/list/#dupe-marker-detector","title":"Dupe Marker Detector","text":"DescriptionSource URLREADMEAuthorScreenshotsFinds and marks duplicate markers
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#dupfilemanager","title":"DupFileManager","text":"DescriptionSource URLREADMEAuthorScreenshotsManages duplicate files.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
No Author
"},{"location":"plugins/list/#duplicate-scene-marker-cleaner","title":"Duplicate Scene Marker Cleaner","text":"DescriptionSource URLREADMEAuthorScreenshotsAutomatically detects and removes duplicate scene markers based on scene ID, seconds, and title upon scene updates or via manual trigger.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#easytag","title":"EasyTag","text":"DescriptionSource URLREADMEAuthorScreenshotsUI plugin to add shortcuts for commonly used tags
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
View README
S3L3CT3DLoves
"},{"location":"plugins/list/#edit-unorganized","title":"edit-unorganized","text":"DescriptionSource URLREADMEAuthorScreenshotsDefault to edit tab on unorganized scenes
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#extended-stats","title":"Extended Stats","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds new stats to the stats page
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#filemonitor","title":"FileMonitor","text":"DescriptionSource URLREADMEAuthorScreenshotsMonitors the Stash library folders, and updates Stash if any changes occurs in the Stash library paths.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
David-Maisonave
"},{"location":"plugins/list/#filename-parser","title":"Filename parser","text":"DescriptionSource URLREADMEAuthorScreenshots
Parses filename into studio, date, performers and title
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
gitgiggety
"},{"location":"plugins/list/#filepath-copy","title":"filepath-copy","text":"DescriptionSource URLREADMEAuthorScreenshotsCopy file path to clipboard when selected
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#find-file-errors","title":"Find File Errors","text":"DescriptionSource URLREADMEAuthorScreenshotsfind files that stash has previously errored on from the log file
https://stg-annon.github.io/StashScripts/stable/index.yml\n
No README available
stg-annon
"},{"location":"plugins/list/#find-marker-tag-images","title":"Find Marker Tag Images","text":"DescriptionSource URLREADMEAuthorScreenshotsScript to update tag images based on scene markers
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#foldersort","title":"folderSort","text":"DescriptionSource URLREADMEAuthorScreenshotsOrganise your PMV folder(s) based on Stash info
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
View README
S3L3CT3DLoves
"},{"location":"plugins/list/#fontawesome-js","title":"fontawesome-js","text":"DescriptionSource URLREADMEAuthorScreenshotsUse fontawesome icons from React libraries
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#funscript-markers","title":"Funscript Markers","text":"DescriptionSource URLREADMEAuthorScreenshotsCreate markers if there is a funscript with \"chapters\" included in the metadata of the script
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#glassy-branding","title":"Glassy - Branding","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#hashthestash","title":"HashTheStash","text":"DescriptionSource URLREADMEAuthorScreenshotsCalculates additional fingerprints for scenes.
https://minasukihikimuna.github.io/MidnightRider-Stash/index.yml\n
No README available
MinasukiHikimuna
"},{"location":"plugins/list/#hot-cards","title":"Hot Cards","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds custom styling to card elements that match a Tag ID or a Rating Threshold.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
HandyRandyx
"},{"location":"plugins/list/#image2scene","title":"image2Scene","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd a mechanism to link images to scenes in the Image Edit Panel.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#lightbox-visual-novel","title":"Lightbox Visual Novel","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplay the image description with Typewriter effect on the footer.
https://w0lfiew0lf.github.io/StashApp-Tools/index.yml\n
View README
W0lfieW0lf
"},{"location":"plugins/list/#log-console","title":"log-console","text":"DescriptionSource URLREADMEAuthorScreenshots
display log messages in console
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#log-toast","title":"log-toast","text":"DescriptionSource URLREADMEAuthorScreenshotsdisplay log messages as toasts
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#marker-delete-button","title":"Marker Delete Button","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a delete button to entries on the Markers page and on the Scene page.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
[WeedLordVegeta420](https://github.com/WeedLordVegeta420]
"},{"location":"plugins/list/#markergen","title":"markergen","text":"DescriptionSource URLREADMEAuthorScreenshotsGenerate markers on save
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#mcmetadata","title":"mcMetadata","text":"DescriptionSource URLREADMEAuthorScreenshotsGenerates metadata for use with other media servers like Emby and Jellyfin, and optionally organizes/renames your tagged scenes.
https://carrotwaxr.github.io/stash-plugins/stable/index.yml\n
View README
carrotwaxr
"},{"location":"plugins/list/#misc-tags","title":"Misc Tags","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd extra tags for VR and other ues
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Tweeticoats
"},{"location":"plugins/list/#movie-duration-from-scenes","title":"Movie Duration from Scenes","text":"DescriptionSource URLREADMEAuthorScreenshotsMore accurately reflect your movie's duration with the sum of durations of its scenes.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy","title":"Movie-Fy","text":"DescriptionSource URLREADMEAuthorScreenshotsMovie-Fy meta-package
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-bulk-movie-scraper","title":"Movie-Fy Bulk Movie Scraper","text":"DescriptionSource URLREADMEAuthorScreenshotsUpdate your movie metadata in bulk.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-check-and-update-scene-titles","title":"Movie-Fy Check and Update Scene Titles","text":"DescriptionSource URLREADMEAuthorScreenshotsCheck and update titles for scenes in the Movie studio
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-create-movie-studio","title":"Movie-Fy Create Movie Studio","text":"DescriptionSource URLREADMEAuthorScreenshotsCreates a new Movie Studio to be used with Mass_Movie_Create
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-scene-studio-bulk-update","title":"Movie-Fy Scene Studio Bulk Update","text":"DescriptionSource URLREADMEAuthorScreenshotsBulk update scene studios based on movie studios.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-update-movie-scene-covers","title":"Movie-Fy Update Movie Scene Covers","text":"DescriptionSource URLREADMEAuthorScreenshotsUpdate scene cover images with movie cover images.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#path-parser","title":"Path Parser","text":"DescriptionSource URLREADMEAuthorScreenshotsUpdates scene info based on the file path.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
ImJustMatt
"},{"location":"plugins/list/#performer-body-calculator","title":"Performer Body Calculator","text":"DescriptionSource URLREADMEAuthorScreenshotsTags performers based on existing metadata, with tags matching the performers body type
https://stg-annon.github.io/StashScripts/stable/index.yml\n
View README
stg-annon
"},{"location":"plugins/list/#performer-details-extended","title":"Performer Details Extended","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplays additional metadata on performer pages, such as their most regular scene partners, top studio, and total play duration. Requires Stash v0.27.0 or higher.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#performer-gallery-scraper-plugin","title":"Performer Gallery Scraper Plugin","text":"DescriptionSource URLREADMEAuthorScreenshotsA plugin to scrape galleries from porngals4.com for specific performers and create zip archives.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#performer-scene-compare","title":"Performer Scene Compare","text":"DescriptionSource URLREADMEAuthorScreenshotsCompares local performer scenes with StashDB and updates the local database.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#phash-duplicate-tagger","title":"PHash Duplicate Tagger","text":"DescriptionSource URLREADMEAuthorScreenshotsPHash Duplicate Tagger (PDT) Will tag scenes based on duplicate PHashes for easier/safer removal.
https://stg-annon.github.io/StashScripts/stable/index.yml\n
View README
stg-annon
"},{"location":"plugins/list/#play-video-if-preview-not-found","title":"Play Video If Preview Not Found","text":"DescriptionSource URLREADMEAuthorScreenshotsPlays video on scene card hover if preview is not found
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#public-ip","title":"Public IP","text":"DescriptionSource URLREADMEAuthorScreenshots
Query ident.me to check my current IP (ensure VPN is working)
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
No README available
S3L3CT3DLoves
"},{"location":"plugins/list/#python-tools-installer","title":"Python Tools Installer","text":"DescriptionSource URLREADMEAuthorScreenshotsDownload stashapp-tools for DockerEnv
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
tooliload
"},{"location":"plugins/list/#quickrating","title":"QuickRating","text":"DescriptionSource URLREADMEAuthorScreenshotsMore rating UI options (only enable one)
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
No README available
S3L3CT3DLoves
"},{"location":"plugins/list/#qx-scene-card","title":"Qx Scene Card","text":"DescriptionSource URLREADMEAuthorScreenshotsRedesigns the scene card.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Qx
"},{"location":"plugins/list/#rebrand","title":"Rebrand","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a name override of your choice in Stash
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#renamefile","title":"RenameFile","text":"DescriptionSource URLREADMEAuthorScreenshotsRenames video (scene) file names when the user edits the [Title] field located in the scene [Edit] tab.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
David-Maisonave
"},{"location":"plugins/list/#renamer","title":"Renamer","text":"DescriptionSource URLREADMEAuthorScreenshotsRenames scene files based on scene details and updates associated scenes with a \"Renamed\" tag.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#renamer-dev","title":"Renamer-Dev","text":"DescriptionSource URLREADMEAuthorScreenshotsRenames scene files based on scene details and updates associated scenes with a \"Renamed\" tag.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#renameronupdate","title":"renamerOnUpdate","text":"DescriptionSource URLREADMEAuthorScreenshotsRename/move filename based on a template.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Belleyy
"},{"location":"plugins/list/#replace-thumbnails-with-high-res-images","title":"Replace Thumbnails With High-Res Images","text":"DescriptionSource URLREADMEAuthorScreenshots
Replaces thumbnails with original high res images
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#scene-cover-cropper","title":"Scene Cover Cropper","text":"DescriptionSource URLREADMEAuthorScreenshotsCrop Scene Cover Images
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#scene-marker-tags-to-scene","title":"Scene Marker Tags to Scene","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds primary tag of Scene Marker to the Scene on marker create/update.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
WithoutPants
"},{"location":"plugins/list/#scene-page-remember-states","title":"Scene Page Remember States","text":"DescriptionSource URLREADMEAuthorScreenshotsUses local storage to remember the state of the scene page detail panel nav bar and activate it on page load. Remembers collapse state of the divider.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#scenehub","title":"SceneHub","text":"DescriptionSource URLREADMEAuthorScreenshotsCollects the latest scenes from popular network sites and displays them all in one page.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#serechopsscenecard","title":"SerechopsSceneCard","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom scene card via the Plugin API.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#set-scene-cover","title":"Set Scene Cover","text":"DescriptionSource URLREADMEAuthorScreenshotssearches Stash for Scenes with a cover image in the same folder and sets the cover image in stash to that image
https://rosa-umineko.github.io/CommunityScripts/stable/index.yml\n
No README available
rosa-umineko
"},{"location":"plugins/list/#set-scene-cover_1","title":"Set Scene Cover","text":"DescriptionSource URLREADMEAuthorScreenshotssearches Stash for Scenes with a cover image in the same folder and sets the cover image in stash to that image
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
stg-annon
"},{"location":"plugins/list/#skip-intro","title":"skip-intro","text":"DescriptionSource URLREADMEAuthorScreenshotsSkips static duration intros
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stash-accessibility","title":"Stash Accessibility","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an Accessibility button in the top right navbar that offers various accessibility features.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-ai","title":"Stash AI","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd Tags or Markers to a video using AI
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cc1234475
"},{"location":"plugins/list/#stash-batch-create-all","title":"Stash Batch Create All","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a 'Create All' button to the scene tagger view. It will target all 'Create' buttons and add new tags as well.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-batch-query-edit","title":"Stash Batch Query Edit","text":"DescriptionSource URLREADMEAuthorScreenshotsBatch modify scene tagger search query
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-batch-result-toggle","title":"Stash Batch Result Toggle","text":"DescriptionSource URLREADMEAuthorScreenshots
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
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-batch-save","title":"Stash Batch Save","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a batch save button to scenes tagger
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-batch-search","title":"Stash Batch Search","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a batch search button to scenes and performers tagger
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-disable-all","title":"Stash Disable All","text":"DescriptionSource URLREADMEAuthorScreenshots
Disables all UI configs and plugins. Saves the current config to a JSON file so that it can be restored to original state.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-dynamic-groups","title":"Stash Dynamic Groups","text":"DescriptionSource URLREADMEAuthorScreenshotsDesignate dynamic groups that can be populated simply by assigning a tag.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-enable-all","title":"Stash Enable All","text":"DescriptionSource URLREADMEAuthorScreenshotsRestores the UI to its original state via a saved JSON config.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-fps-overlay","title":"Stash FPS Overlay","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an FPS overlay on the scene cards.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-jellyfin-exporter","title":"Stash Jellyfin Exporter","text":"DescriptionSource URLREADMEAuthorScreenshotsRestructures your Stash library to be Jellyfin compliant to better serve and populate metadata within your Jellyfin server.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-markdown","title":"Stash Markdown","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds markdown parsing to tag description fields
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-markers-autoscroll","title":"Stash Markers Autoscroll","text":"DescriptionSource URLREADMEAuthorScreenshots
Automatically scrolls markers page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-matched-performer-scrape","title":"Stash Matched Performer Scrape","text":"DescriptionSource URLREADMEAuthorScreenshots
Scrapes performers in bulk from ThePornDB and StashDB on exact name matches only.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-mergers","title":"Stash Mergers","text":"DescriptionSource URLREADMEAuthorScreenshotsA plugin for selectively merging data between performers in Stash.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#stash-new-performer-filter-button","title":"Stash New Performer Filter Button","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a customizable button to the performers page. Links to a new performers filter by default.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-notes","title":"Stash Notes","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a button to the navigation bar which opens a small window for writing notes to your browser's local storage.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
QxxxGit
"},{"location":"plugins/list/#stash-open-media-player","title":"Stash Open Media Player","text":"DescriptionSource URLREADMEAuthorScreenshotsOpen scene filepath links in an external media player
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-audit-task-button","title":"Stash Performer Audit Task Button","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a button to the performers page to run the audit plugin task
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-custom-fields","title":"Stash Performer Custom Fields","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds custom fields to performers that are stored in performer details as JSON.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
View README
7dJx1qP
"},{"location":"plugins/list/#stash-performer-favicons","title":"Stash Performer Favicons","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds the performer URL favicons as a new line item in the performer details.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-performer-image-cropper","title":"Stash Performer Image Cropper","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an image cropper to performer page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-image-extractor","title":"Stash Performer Image Extractor","text":"DescriptionSource URLREADMEAuthorScreenshots
Extracts all performers from your localdb to a local directory for easy editing.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-performer-markers-tab","title":"Stash Performer Markers Tab","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a Markers link to performer pages
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-tagger-additions","title":"Stash Performer Tagger Additions","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds performer birthdate and url to tagger view. Makes clicking performer name open stash profile in new tab instead of current tab.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-url-searchbox","title":"Stash Performer URL Searchbox","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a search by performer url textbox to the performers page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-realbooru","title":"Stash Realbooru","text":"DescriptionSource URLREADMEAuthorScreenshots
Add tags based on the realbooru model, This works on individual images.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cc1234475
"},{"location":"plugins/list/#stash-reels","title":"Stash Reels","text":"DescriptionSource URLREADMEAuthorScreenshotsTikTok for Stash.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#stash-right-click-galleries","title":"Stash Right Click Galleries","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the gallery cards to perform various quick tasks related to galleries.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-images","title":"Stash Right Click Images","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the image cards to perform various quick tasks related to images.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-performer-merge","title":"Stash Right Click Performer Merge","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the to perform various quick tasks related to settings.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-performers","title":"Stash Right Click Performers","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the performer cards to perform various quick tasks related to performers.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-scenes","title":"Stash Right Click Scenes","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the scene cards to perform various quick tasks related to scenes.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-settings","title":"Stash Right Click Settings","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the settings icon to perform various quick tasks related to settings.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-suite","title":"Stash Right Click Suite","text":"DescriptionSource URLREADMEAuthorScreenshotsMeta-package installer for the Stash Right-Click Suite tools.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-right-click-tags","title":"Stash Right Click Tags","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the tag cards to perform various quick tasks related to tags.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-scene-file-size","title":"Stash Scene File Size","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplay file size on scene cards.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-scene-specs-overlay","title":"Stash Scene Specs Overlay","text":"DescriptionSource URLREADMEAuthorScreenshotsHides all the scene specs overlay within the scene card and reveals them on hover.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-scene-tagger-additions","title":"Stash Scene Tagger Additions","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds scene duration and filepath to tagger view.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-scene-tagger-colorizer","title":"Stash Scene Tagger Colorizer","text":"DescriptionSource URLREADMEAuthorScreenshots
Colorize scene tagger match results to show matching and mismatching scene data.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-scene-tagger-draft-submit","title":"Stash Scene Tagger Draft Submit","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds button to Scene Tagger to submit draft to stashdb
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-set-stashbox-favorite-performers","title":"Stash Set Stashbox Favorite Performers","text":"DescriptionSource URLREADMEAuthorScreenshots
Set Stashbox favorite performers according to stash favorites
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stashbox-scene-count","title":"Stash Stashbox Scene Count","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds stashbox scene counts to performers and studios
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stashid-icon","title":"Stash StashID Icon","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds checkmark icon to performer and studio cards that have a stashid
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stashid-input","title":"Stash StashID Input","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds input for entering new stash id to performer details page and studio page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stats","title":"Stash Stats","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds stats to stats page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
View README
7dJx1qP
"},{"location":"plugins/list/#stash-studio-logo-wall-view","title":"Stash Studio Logo Wall View","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds the studio logo on the scene cards in Wall view.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-tag-custom-colors","title":"Stash Tag Custom Colors","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom button in the navbar to stylize tag chips based on CSS snippets, regex patterns, or basic color-coding.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-tag-image-cropper","title":"Stash Tag Image Cropper","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an image cropper to tag page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-timestamps","title":"Stash TimeStamps","text":"DescriptionSource URLREADMEAuthorScreenshots
Create timestamps from pre-existing markers within the scene's details.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-toggle-scene-sprites","title":"Stash Toggle Scene Sprites","text":"DescriptionSource URLREADMEAuthorScreenshotsToggles scene sprites to replace static preview image of all scenes on the current index page.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-ui-plugin-example","title":"Stash UI Plugin Example","text":"DescriptionSource URLREADMEAuthorScreenshotsAn attempt to simplify the process of building UI plugins.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-video-player-ab-loop-time-input","title":"Stash Video Player AB Loop Time Input","text":"DescriptionSource URLREADMEAuthorScreenshotsReplaces the video player AB loop start and end buttons with time inputs
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-omnisearch","title":"stash-omnisearch","text":"DescriptionSource URLREADMEAuthorScreenshots
search all the things on stash
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stash-open","title":"stash-open","text":"DescriptionSource URLREADMEAuthorScreenshotsOpens media files in local media player
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stash-s6-helper","title":"stash-s6 helper","text":"DescriptionSource URLREADMEAuthorScreenshotsstash-s6 helper plugin
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stashappandroidtv-companion","title":"StashAppAndroidTV Companion","text":"DescriptionSource URLREADMEAuthorScreenshotsA companion plugin for StashAppAndroidTV
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
damontecres
"},{"location":"plugins/list/#stashaudioplayer","title":"StashAudioPlayer","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd an audio-only toggle button and support for audio files in the Stash player through hls transcoder.
https://raw.githubusercontent.com/d0t-d0t-d0t/stash-repo/refs/heads/dist/index.yml\n
View README
d0t-d0t-d0t
"},{"location":"plugins/list/#stashdb-performer-gallery","title":"stashdb performer gallery","text":"DescriptionSource URLREADMEAuthorScreenshotsAutomatically download performer images from stashdb or other stash-boxes. Add the [Stashbox Performer Gallery] tag to a performer and it will create a gallery of images from that stash-box database. Apply the tag [Set Profile Image] to an image to set it as the profile image of that performer. Note you will need to configure the download path and add this as a path under settings > library
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Tweeticoats
"},{"location":"plugins/list/#stashdb-tag-import","title":"StashDB Tag Import","text":"DescriptionSource URLREADMEAuthorScreenshotsImport StashDB's list of Tags for your Stash.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stashdb-fullimg","title":"stashdb-fullimg","text":"DescriptionSource URLREADMEAuthorScreenshotsDownload full-size images from StashDB
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stashdisable","title":"stashDisable","text":"DescriptionSource URLREADMEAuthorScreenshotsstashDisable meta-package
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stashlist-sync","title":"stashlist-sync","text":"DescriptionSource URLREADMEAuthorScreenshotsSync stashIDs to stashlist history
https://feederbox826.github.io/stashlist/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stashnewperformerscenes","title":"stashNewPerformerScenes","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom icon in the performer card should they have a new scene released within the specified date range from the navbar button.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stashtagperformerimage","title":"stashTagPerformerImage","text":"DescriptionSource URLREADMEAuthorScreenshotsChecks parent directory of image on Image.Update.Post and compares to any existing performers in the db. Updates that image with the related performer.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#studio-background-shadow","title":"Studio background shadow","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd drop shadows to studio icons for visibility
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#studio-top-performer","title":"Studio Top Performer","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a Queen icon with the top performer listed in the studio cards as determined by most scenes starred in from that particular studio.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#tag-graph","title":"Tag Graph","text":"DescriptionSource URLREADMEAuthorScreenshotsInteractive tag graph with vis.js, to view go to http://localhost:9999/plugin/tagGraph/assets/graph/
https://stg-annon.github.io/StashScripts/stable/index.yml\n
View README
stg-annon
"},{"location":"plugins/list/#tag-scenes-from-performer-tags","title":"Tag Scenes From Performer Tags","text":"DescriptionSource URLREADMEAuthorScreenshotstags scenes with performer tags.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Dankonite
"},{"location":"plugins/list/#tag-filter","title":"tag-filter","text":"DescriptionSource URLREADMEAuthorScreenshotsFilter out and hide meta-tags
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#tag-import","title":"tag-import","text":"DescriptionSource URLREADMEAuthorScreenshots
feederbox opinionated tag import
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#tag-video","title":"tag-video","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd <video> support to tag images
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#tagger-img-res","title":"tagger-img-res","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds resolutions to all tagger images
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#tetrax-userscript-library","title":"Tetrax Userscript Library","text":"DescriptionSource URLREADMEAuthorScreenshotsUtility library for Tetrax userscripts
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#the-porn-db-markers","title":"The Porn DB Markers","text":"DescriptionSource URLREADMEAuthorScreenshotsSync Markers from The Porn DB aka theporndb.net
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Tweeticoats
"},{"location":"plugins/list/#theme-colorpalette","title":"Theme - colorPalette","text":"DescriptionSource URLREADMEAuthorScreenshotsBased on the default theme, change the overall color of the page by setting the hue value. Make minor changes to the remaining styles.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#theme-switch","title":"Theme Switch","text":"DescriptionSource URLREADMEAuthorScreenshotsTheme and CSS script manager located in main menu bar top right.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
elkorol
"},{"location":"plugins/list/#timestamp-trade","title":"Timestamp Trade","text":"DescriptionSource URLREADMEAuthorScreenshots
Sync Markers with timestamp.trade, a new database for sharing markers.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Tweeticoats
"},{"location":"plugins/list/#titlefromfilename","title":"titleFromFilename","text":"DescriptionSource URLREADMEAuthorScreenshotsSet a scene's title from it's filename
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
bnkai
"},{"location":"plugins/list/#titleobserver","title":"titleobserver","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an event listener for title changes
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#valkyr-scene-cards","title":"Valkyr Scene Cards","text":"DescriptionSource URLREADMEAuthorScreenshotsA customisable rework of the scene card component for Stash.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#videoscrollwheel","title":"VideoScrollWheel","text":"DescriptionSource URLREADMEAuthorScreenshots
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.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
WeedLordVegeta420
"},{"location":"plugins/list/#visage","title":"Visage","text":"DescriptionSource URLREADMEAuthorScreenshotsUse facial Recognition To Lookup Performers.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cc1234475
"},{"location":"plugins/list/#vjs-mmb-fullscreen","title":"vjs-mmb-fullscreen","text":"DescriptionSource URLREADMEAuthorScreenshotsVideoJS middle mouse button fullscreen
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#vjs-shortcut","title":"vjs-shortcut","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd YouTube keyboard shortcuts to VideoJS
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#vjs-vr-zoom","title":"vjs-vr-zoom","text":"DescriptionSource URLREADMEAuthorScreenshotsVideoJS VR zoom controls
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#watched-video-icon","title":"Watched Video Icon","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds icon and css class to watched videos
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"scripts/","title":"Scripts","text":"
Info
Scripts are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Scripts are standalone programs that can interact with Stash either through GraphQL queries, custom Javascript or by directly editing Stash database or external files.
To install a script follow the script's install instructions.
"},{"location":"scripts/list/","title":"List of scripts","text":"stash-git-indexExhaustive list of git repositories related to Stash Google Sheets document.
Script no longer worksIf you found that script is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"scripts/list/#addmarkerono","title":"AddMarkerOnO","text":"DescriptionAuthorScreenshotsWill auto-generate a marker when the SceneAddO event is trigger
rosa-umineko
"},{"location":"scripts/list/#blurrycardbackground","title":"blurryCardBackground","text":"DescriptionAuthorScreenshotsAdd blurry background to scene/movie/gallery/image/studio.
philpw99
"},{"location":"scripts/list/#filenameperformerstocsv","title":"FilenamePerformersToCSV","text":"DescriptionAuthorScreenshotsParse performer names from your media filenames into CSV files for batch import into Stash!
ALonelyJuicebox
"},{"location":"scripts/list/#get-profilepictures","title":"Get-ProfilePictures","text":"DescriptionAuthorScreenshotsGet-ProfilePictures
MinasukiHikimuna
"},{"location":"scripts/list/#kodi-helper","title":"Kodi helper","text":"DescriptionAuthorScreenshotsGenerates nfo and strm for use with Kodi.
WithoutPants
"},{"location":"scripts/list/#ofmetadatatostash","title":"OFMetadataToStash","text":"DescriptionAuthorScreenshotsOnlyFans metadata import tool for Stash, written in Powershell.
ALonelyJuicebox
"},{"location":"scripts/list/#plex-to-stash-ratings","title":"plex-to-stash-ratings","text":"DescriptionAuthorScreenshots
Transfer scene rating and view count from Plex to Stash.
oikmeg
"},{"location":"scripts/list/#pwplayerjs-scene-card-quick-player","title":"pwPlayer.js - Scene Card Quick Player","text":"DescriptionAuthorScreenshotsThis Javascript will create a \"Play\" button in each scene card. You can click on it and the video for that scene will be played right away. Click on the video again, then you are back to the scene list.
philpw99
"},{"location":"scripts/list/#sqlite-renamer-for-stash","title":"SQLITE Renamer for Stash","text":"DescriptionAuthorScreenshotsUsing metadata from your database (SQLITE) to rename your file.
Belleyy
"},{"location":"scripts/list/#stash-watcher","title":"Stash Watcher","text":"DescriptionAuthorScreenshotsStash Watcher is a service that watches your Stash library directories for changes and then triggers a Metadata Scan when new files are added to those directories. It then waits a period of time before triggering another scan to keep Stash from constantly scanning if you're making many changes. Note that updates are watched during that window; the update is merely delayed.
DuctTape42
"},{"location":"scripts/list/#stashapp-tag-importer","title":"stashapp-tag-importer","text":"DescriptionAuthorScreenshotsCreates tags and aliases, resolves tag conflicts, and updates tag titles and descriptions from Stashbox (StashDB) to your local Stash instance. It can be run periodically to perform a one way sync to keep your Stash instance up to date with Stashbox (StashDB).
soundchaser128
"},{"location":"scripts/list/#stashgalleryupdate","title":"StashGalleryUpdate","text":"DescriptionAuthorScreenshotsDumb little script to match and update Stash galleries from scenes
Darklyter
"},{"location":"scripts/list/#stashstudiosync","title":"StashStudioSync","text":"DescriptionAuthorScreenshotsAn easy way to query a stashbox GQL endpoint and import any unknown studio IDs.
Stash-KennyG
"},{"location":"scripts/list/#stashtagskins","title":"StashTagSkins","text":"DescriptionAuthorScreenshotsUsed to quickly apply and change themes of tags for Stash.
Stash-KennyG
"},{"location":"scripts/list/#stashvideohashernode","title":"StashVideohasherNode","text":"DescriptionAuthorScreenshots
This is a very simple script that can be run on multiple systems to process a large Stash import of scenes. Instead of running cover and phash generation tasks on the Stash server itself, this script will allow you to do the same thing on as many computers as you would like, with all of the nodes contributing back to the Stash server.
Darklyter
"},{"location":"themes/","title":"Themes","text":"Info
Themes are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Stash supports CSS themes to adjust the look-and-feel of the interface. There are several that have been created by the maintainers and users.
Themes can be installed either via plugin or as Custom CSS.
"},{"location":"themes/#installing-via-plugin","title":"Installing via plugin","text":"Plugins can be installed and managed from the Settings > Plugins page.
Plugins are installed using the Available Plugins section. The Community (stable) source is configured by default that has several themes.
Installed plugins can be updated or uninstalled from the Installed Plugins section.
"},{"location":"themes/#adding-sources","title":"Adding sources","text":"Anyone can create their own source index for plugins. To add a new source go to Settings > Plugins page and under Available Plugins click Add Source.
"},{"location":"themes/#installing-via-custom-css","title":"Installing via Custom CSS","text":"Custom CSS allows you to modify Stash stock stylesheets.
The following is a list of some useful CSS snippets. You may use them by copying-and-pasting them into the Custom CSS editor found in the Settings > Interface panel or by navigating to localhost:9999/settings?tab=interface
Warning
Reduce left and right padding on Scene and Performer grid pages allowing for more thumbnails on each row.
/* [Scenes tab] Fit more thumbnails on each row */\n\n.grid { padding: 0px !important; }\n
"},{"location":"themes/custom-css-snippets/#allow-for-longer-string-when-displaying-studio-as-text-on-scene-thumbnails","title":"Allow for longer string when displaying \"Studio as Text\" on scene thumbnails","text":"DescriptionAuthorScreenshotsCSS code Allow for longer string when displaying \"Studio as Text\" on scene thumbnails.
/* [Scenes tab] Allow for longer string when displaying \"Studio as Text\" on scene thumbnails */\n\n.scene-studio-overlay {\n font-weight: 600 !important;\n opacity: 1 !important;\n width: 60% !important;\n text-overflow: ellipsis !important;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-scene-specs-resolution-duration-from-scene-card","title":"Hide scene specs (resolution, duration) from scene card","text":"DescriptionAuthorScreenshotsCSS code Hide scene specs (resolution, duration) from scene card.
/* [Scenes tab] Hide scene specs (resolution, duration) from scene card */\n\n.scene-specs-overlay {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-studio-logotext-from-scene-card","title":"Hide studio logo/text from scene card","text":"DescriptionAuthorScreenshotsCSS code Hide studio logo/text from scene card.
/* [Scenes tab] Hide studio logo/text from scene card */\n\n.scene-studio-overlay {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#make-the-list-of-tags-take-up-less-width","title":"Make the list of tags take up less width","text":"DescriptionAuthorScreenshotsCSS code Make the list of tags take up less width.
/* [Scenes tab] Make the list of tags take up less width */\n\n.bs-popover-bottom {\nmax-width: 500px\n}\n
"},{"location":"themes/custom-css-snippets/#swap-studio-and-resolutionduration-positions","title":"Swap studio and resolution/duration positions","text":"DescriptionAuthorScreenshotsCSS code Swap studio and resolution/duration positions.
/* [Scenes tab] Swap studio and resolution/duration positions */\n\n.scene-studio-overlay {\nbottom: 1rem;\nright: 0.7rem;\nheight: inherit;\ntop: inherit;\n}\n\n.scene-specs-overlay {\nright: 0.7rem;\ntop: 0.7rem;\nbottom: inherit;\n}\n
"},{"location":"themes/custom-css-snippets/#adjust-the-mouse-over-behaviour-in-wall-mode","title":"Adjust the mouse over behaviour in wall mode","text":"DescriptionAuthorScreenshotsCSS code Adjust the mouse over behaviour in wall mode.
/* [Scenes tab] Adjust the mouse over behaviour in wall mode */\n\n@media (min-width: 576px) {\n.wall-item:hover::before {\nopacity: 0; \n}\n\n.wall-item:hover .wall-item-container {\ntransform: scale(1.5);\n}\n}\n
"},{"location":"themes/custom-css-snippets/#disable-zoom-on-hover-in-wall-mode","title":"Disable zoom on hover in wall mode","text":"DescriptionAuthorScreenshotsCSS code Disable zoom on hover in wall mode.
/* [Scenes tab] Disable zoom on hover in wall mode */\n\n.wall-item:hover .wall-item-container {\n transform: none;\n}\n.wall-item:before {\n opacity: 0 !important;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-scene-scrubber","title":"Hide the scene scrubber","text":"DescriptionAuthorScreenshotsCSS code This will hide the large scene scrubber under the video player and max out the player's height.
/* [Scenes tab] Hide the scene scrubber and max out the player's height */\n.scrubber-wrapper {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-truncated-text","title":"Hide the truncated text","text":"DescriptionAuthorScreenshotsCSS code This will hide the truncated text that appears under the tile and date.
/* [Scenes Tab] - Hide the truncated text on scene card */\n\n.TruncatedText.scene-card__description { \ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#images","title":"Images","text":""},{"location":"themes/custom-css-snippets/#disable-lightbox-animation","title":"Disable lightbox animation","text":"DescriptionAuthorScreenshotsCSS code Disable lightbox animation.
/* [Images tab] Disable lightbox animation */\n\n.Lightbox-carousel {\ntransition: none;\n}\n
"},{"location":"themes/custom-css-snippets/#dont-crop-preview-thumbnails","title":"Don't crop preview thumbnails","text":"DescriptionAuthorScreenshotsCSS code Don't crop preview thumbnails.
/* [Images tab] Don't crop preview thumbnails */\n\n.flexbin > * > img {\nobject-fit: inherit;\nmax-width: none;\nmin-width: initial;\n}\n
"},{"location":"themes/custom-css-snippets/#groups","title":"Groups","text":""},{"location":"themes/custom-css-snippets/#better-group-layout-for-desktops-regular-size-poster","title":"Better Group layout for desktops, regular size poster","text":"DescriptionAuthorScreenshotsCSS code Making the front and back image much bigger. Left panel uses 70% while the right uses 30%.
/* [Groups tab] Better Group layout for desktops: Regular size poster */\n\n.group-details.mb-3.col.col-xl-4.col-lg-6 {\nflex-basis: 70%\n}\n.col-xl-8.col-lg-6{\nflex-basis: 30% \n}\n.group-images{\nflex-wrap: wrap\n}\n.group-image-container {\nflex: 0 0 500px\n}\n
"},{"location":"themes/custom-css-snippets/#better-group-layout-for-desktops-larger-size-poster","title":"Better Group layout for desktops, larger size poster","text":"DescriptionAuthorScreenshotsCSS code Making the front and back image much bigger. Left panel uses 70% while the right uses 30%.
/* [Groups tab] Better Group layout for desktops: Larger size poster */\n\n.group-details.mb-3.col.col-xl-4.col-lg-6 {\nflex-basis: 70%\n}\n.col-xl-8.col-lg-6{\nflex-basis: 30% \n}\n.group-images{\nflex-direction: column;\nflex-wrap: wrap\n}\n.group-image-container {\nflex: 1 1 700px\n}\n
"},{"location":"themes/custom-css-snippets/#galleries","title":"Galleries","text":""},{"location":"themes/custom-css-snippets/#grid-view-for-galleries","title":"Grid view for galleries","text":"DescriptionAuthorScreenshotsCSS code Grid view for galleries.
/* [Galleries tab] Grid view for galleries */\n\n.col.col-sm-6.mx-auto.table .d-none.d-sm-block {\n display: none !important;\n}\n.col.col-sm-6.mx-auto.table .w-100.w-sm-auto {\n width: 175px !important;\n background-color: rgba(0, 0, 0, .45);\n box-shadow: 0 0 2px rgba(0, 0, 0, .35);\n}\n.col.col-sm-6.mx-auto.table tr {\n display: inline-table;\n}\n
"},{"location":"themes/custom-css-snippets/#disable-lightbox-image-transition","title":"Disable lightbox image transition","text":"DescriptionAuthorScreenshotsCSS code Disable lightbox image transition.
/* [Gallery tab] Disable lightbox image transition */\n.Lightbox-carousel {\ntransition: unset;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-lightbox-header-and-footer","title":"Hide the lightbox header and footer","text":"DescriptionAuthorScreenshotsCSS code Hides the lightbox header and footer to make the image area larger. Mouse reveals them as an overlay to the image.
peresabcod
/* [Gallery tab] Hides the lightbox header and footer to make the image area larger. Mouse reveals them as an overlay to the image*/\n\n.Lightbox-header,\n.Lightbox-footer{\nz-index:9999;\nposition:absolute;\nwidth:100%;\nopacity:0;\nbackground-color:#0008;\ntransition: opacity 0.5s ease;\n}\n\n.Lightbox-footer{\nbottom:0;}\n\n.Lightbox-navbutton{\nopacity:0;\ntransition: opacity 0.5s ease;\n}\n\n\n.Lightbox-navbutton:hover,\n.Lightbox-header:hover,\n.Lightbox-footer:hover{\nopacity:1;\n}\n
"},{"location":"themes/custom-css-snippets/#performers","title":"Performers","text":""},{"location":"themes/custom-css-snippets/#show-entire-performer-image-in-performer-card","title":"Show entire performer image in performer card","text":"DescriptionAuthorScreenshotsCSS code Show entire performer image in performer card.
/* [Performers tab] Show entire performer image in performer card */\n\n.performer.image {\nbackground-size: contain !important;\n}\n
"},{"location":"themes/custom-css-snippets/#show-a-larger-image-in-performers-page-for-desktop","title":"Show a larger image in performer's page for desktop","text":"DescriptionAuthorScreenshotsCSS code Show a larger image in performer's page for desktop.
/* [Performers tab] Show a larger image in performer's page for desktop */\n.performer-image-container{\nflex: 0 0 50%;\nmax-width: 50%;\n}\n/* Changing .col-md-8 settings also affects studios and tags display. 50% should be good enough. */\n.col-md-8 {\nflex: 0 0 50%;\nmax-width: 50%;\n}\n
"},{"location":"themes/custom-css-snippets/#place-performer-image-in-the-background-on-performer-page","title":"Place performer image in the background on performer page","text":"DescriptionAuthorScreenshotsCSS code Place performer image in the background on performer page.
/* [Performers tab] Place performer image in the background on performer page */\n\n.performer-image-container.col-md-4.text-center {\n flex: 0 0 0%;\n max-width: 0%;\n}\n\n#performer-page .performer-image-container .btn.btn-link {\n position: fixed;\n width: 100%;\n top: 0;\n left: 0;\n padding: 0;\n}\n\n#performer-page .performer-image-container .btn.btn-link:before {\n content: '';\n position:absolute;\n top:0;\n left: 0;\n right: 0;\n bottom: 0;\n background: linear-gradient(to left, rgba(0,0,0,0) 0%,rgb(0 0 0 / 75%) 100%);\n z-index: 1;\n}\n\n#performer-page .performer-image-container .performer {\n max-height: none;\n max-width: none;\n width: 100%;\n}\n
"},{"location":"themes/custom-css-snippets/#show-larger-performer-images-in-performers-list","title":"Show larger performer images in performers list","text":"DescriptionAuthorScreenshotsCSS code Show larger performer images in performers list.
/* [Performers tab] Show larger performer images in performers list */\n/* original value: height: 30rem; min-width:13.25rem; */\n.performer-card-image{\nheight: 45rem;\nmin-width: 20rem;\n}\n
"},{"location":"themes/custom-css-snippets/#move-the-buttons-in-the-performers-edit-panel-to-the-top-instead-of-bottom","title":"Move the buttons in the Performer's edit panel to the top instead of bottom","text":"DescriptionAuthorScreenshotsCSS code Move the buttons in the Performer's edit panel to the top instead of bottom (in newer version of Stash, the buttons are already positioned both at top and bottom.
/* [Performers tab] Move the buttons in the Performer's edit panel to the top instead of bottom (in newer version of Stash, the buttons are already positioned both at top and bottom. */\n\nform#performer-edit {\n display: flex;\n flex-direction: column;\n}\n#performer-edit > .row {\n order: 1;\n}\n#performer-edit > .row:last-child {\n order: 0;\n margin-bottom: 1rem;\n}\n
"},{"location":"themes/custom-css-snippets/#move-the-tags-row-in-the-performers-edit-panel-to-the-second-position-just-after-name","title":"Move the tags row in the Performer's edit panel to the second position (just after name)","text":"DescriptionAuthorScreenshotsCSS code Move the tags row in the Performer's edit panel to the second position (just after name).
/* [Performers tab] Move the tags row in the Performer's edit panel to the second position (just after name). */\n\nform#performer-edit {\n display: flex;\n flex-direction: column;\n}\n#performer-edit > .row:nth-child(24) {\n order: -1;\n}\n#performer-edit > .row:first-child {\n order: -2;\n}\n
"},{"location":"themes/custom-css-snippets/#studios","title":"Studios","text":""},{"location":"themes/custom-css-snippets/#different-studio-cards-layout","title":"Different studio cards layout","text":"DescriptionAuthorScreenshotsCSS code Changes the layout of studio cards.
Qx#1573
/* [Studios tab] Changes the layout of studio cards */\n.studio-card.grid-card.card div.card-section div.rating-banner { display: none; }\n.slick-slide .studio-card-image { height: 300px; }\n\n.studio-card, .recommendation-row .studio-card {\n padding: 0;\n width: 500px;\n height: 300px;\n}\n\n.studio-card-image, .recommendation-row .studio-card .studio-card-image {\n max-height: 300px;\n width: 500px;\n}\n\n.studio-card.grid-card.card div.card-section {\n position: absolute;\n bottom: 0em;\n width: inherit;\n background-color: rgba(0, 0, 0, 0.7);\n overflow: hidden;\n height: 2.5em;\n transition: 0.5s ease-in-out;\n}\n\n.studio-card.grid-card.card div.card-section:hover {\n height: 7em;\n}\n
"},{"location":"themes/custom-css-snippets/#more-studio-per-row","title":"More studio per row","text":"DescriptionAuthorScreenshotsCSS code Display more studio per row
hijack_hornet
/* [Studios tab] Show more item per row */\n:not(.recommendation-row .studio-card).studio-card {\n width: 15%\n}\n:not(.recommendation-row .studio-card-image).studio-card-image {\n width: 100%\n}\n.studio-card h5 {\n text-align: center !important;\n display: block;\n}\n
"},{"location":"themes/custom-css-snippets/#tags","title":"Tags","text":""},{"location":"themes/custom-css-snippets/#different-tag-cards-layout","title":"Different tag cards layout","text":"DescriptionAuthorScreenshotsCSS code Changes the layout of tag cards on tags tab and when hovering on tags in different content.
Qx#1573
/* [Tags changes] changes the layout of tag cards on tags page and hover */\n.tag-parent-tags, .tag-sub-tags { display: none;}\n.tag-card.zoom-0.grid-card.card div.card-section div.card-popovers.btn-group { margin-top: 1em; }\n.tag-card.zoom-0.grid-card.card div.thumbnail-section a.tag-card-header img.tag-card-image { object-fit: cover; }\n.tag-card.zoom-0.grid-card.card div.card-section hr { display: none; }\n\n.tag-card.zoom-0.grid-card.card {\n padding: 0;\n width: 300px;\n height: 180px;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section {\n position: absolute;\n text-shadow: 2px 2px 2px #000;\n width: 100%;\n background-color: rgba(0, 0, 0, 0.3);\n height: 3em;\n overflow: hidden;\n transition: 0.8s ease-in-out;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section a {\n text-decoration: none;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section:hover {\n height: 22em;\n}\n\n.tag-card.zoom-0.grid-card.card \n div.card-section a \n h5.card-section-title.flex-aligned \n div.TruncatedText {\n white-space: nowrap;\n text-overflow: ellipsis;\n width: 300px;\n overflow: hidden;\n display: block;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section div.TruncatedText.tag-description {\n position: relative;\n top: 0.5em;\n -webkit-text-stroke-width: 1px;\n font-size: 16px;\n}\n\n.tag-card .card-popovers .btn {\n text-shadow: 1px 1px 1px #000;\n stroke: black;\n stroke-width: 15;\n}\n
"},{"location":"themes/custom-css-snippets/#alternative-tag-layout","title":"Alternative tag layout","text":"DescriptionAuthorScreenshotsCSS code Changes the tags layout to show more images, and details on hover.
hijack_hornet
/*Tag layout changes*/\n.tag-card {\n width: 16rem;\n padding: 0;\n}\n\n.tag-card .card-section {\n height: 2.5rem;\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: #0000007a;\n line-height: none;\n}\n.tag-card .card-section .TruncatedText {\n -webkit-line-clamp: 1 !important;\n}\n.tag-card h1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n line-height: normal;\n}\n.tag-card hr,\n.tag-description {\n display: none;\n}\n.tag-card .btn-group {\n position: absolute;\n width: 100%;\n bottom: 2.5rem;\n margin-bottom: 0;\n opacity: 0;\n transition: ease 0.2s;\n}\n.tag-card .btn-group:hover {\n opacity: 1;\n transition: ease 0.2s;\n background: #0000007a;\n}\n\n.tag-card-image {\n object-fit: cover;\n object-position: center;\n}\n\n.zoom-0 .tag-card-image {\n max-height: none;\n height: 16rem;\n width: 12rem;\n}\n\n.zoom-1 .tag-card-image {\n max-height: none;\n height: 20rem;\n width: 15rem;\n}\n\n.zoom-2 .tag-card-image {\n max-height: none;\n height: 24rem;\n width: 18rem;\n}\n\n.zoom-3 .tag-card-image {\n max-height: none;\n height: 28rem;\n width: 21rem;\n}\n\n.zoom-0.tag-card,\n.zoom-1.tag-card,\n.zoom-2.tag-card,\n.zoom-3.tag-card {\n width: initial;\n}\n\n.tag-card .card-section > a {\n position: absolute;\n width: 100%;\n height: 100%;\n display: block;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n padding: 7px 14px 0px 14px;\n}\n.tag-card .card-section .tag-sub-tags {\n position: relative;\n margin-top: 2rem;\n z-index: 1;\n}\n.tag-sub-tags {\n font-size: 0;\n}\n.tag-parent-tags {\n display: none;\n}\n
"},{"location":"themes/custom-css-snippets/#subtag-explorer","title":"Subtag explorer","text":"DescriptionAuthorScreenshotsCSS code This snipset includes the above tag layout snipset with a twist. Its meant to be used for people who use subtags as a hierachy. For example Watermelon is a subtag of Fruits, so when i click Fruits i want to see both oranges and watermelons, but i might want to get into the list of fruits subtags more easily. That what this snipset is used for. Any tag that has a subtag will show a (...) icon. When clicking its name you will show all subtags of this tag. if you click its image, it will instead open the tag itself normaly. You can change '137cbd' in the icon url to any color you want to match you theme.
hijack_hornet
/*Tag layout changes*/\n.tag-card {\n width: 16rem;\n padding: 0;\n}\n\n.tag-card .card-section {\n height: 2.5rem;\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: #0000007a;\n line-height: none;\n}\n.tag-card .card-section .TruncatedText {\n -webkit-line-clamp: 1 !important;\n}\n.tag-card h1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n line-height: normal;\n}\n.tag-card hr,\n.tag-description {\n display: none;\n}\n.tag-card .btn-group {\n position: absolute;\n width: 100%;\n bottom: 2.5rem;\n margin-bottom: 0;\n opacity: 0;\n transition: ease 0.2s;\n}\n.tag-card .btn-group:hover {\n opacity: 1;\n transition: ease 0.2s;\n background: #0000007a;\n}\n\n.tag-card-image {\n object-fit: cover;\n object-position: center;\n}\n\n.zoom-0 .tag-card-image {\n max-height: none;\n height: 16rem;\n width: 12rem;\n}\n\n.zoom-1 .tag-card-image {\n max-height: none;\n height: 20rem;\n width: 15rem;\n}\n\n.zoom-2 .tag-card-image {\n max-height: none;\n height: 24rem;\n width: 18rem;\n}\n\n.zoom-3 .tag-card-image {\n max-height: none;\n height: 28rem;\n width: 21rem;\n}\n\n.zoom-0.tag-card,\n.zoom-1.tag-card,\n.zoom-2.tag-card,\n.zoom-3.tag-card {\n width: initial;\n}\n\n.tag-card .card-section > a {\n position: absolute;\n width: 100%;\n height: 100%;\n display: block;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n padding: 7px 14px 0px 14px;\n}\n.tag-card .card-section .tag-sub-tags {\n position: relative;\n margin-top: 2rem;\n z-index: 1;\n}\n.tag-sub-tags {\n font-size: 0;\n}\n.tag-parent-tags {\n display: none;\n}\n/*Tag subtag exploration snipset*/\n.tag-card .card-section > a {\n cursor: default;\n pointer-events: none;\n}\n.tag-card .card-section > hr {\n margin-top: 2rem;\n}\n.tag-card .card-section .tag-sub-tags {\n position: absolute !important;\n margin-top: 0 !important;\n width: 100%;\n height: 100%;\n display: block;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n padding: 0;\n}\n.tag-sub-tags::before {\n content: \"\";\n display: block;\n background: url(\"https://img.icons8.com/material-outlined/24/137cbd/connection-status-off.png\")\n no-repeat;\n background-size: 1.5rem 1.5rem;\n width: 1.5rem;\n height: 1.5rem;\n float: right;\n margin: 0.5rem 0.5rem 0 0;\n}\n.tag-sub-tags > a {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.tag-card .btn-group a {\n z-index: 10;\n}\n.tag-sub-tags {\n font-size: 0;\n}\n.tag-parent-tags {\n display: none;\n}\n
"},{"location":"themes/custom-css-snippets/#global","title":"Global","text":""},{"location":"themes/custom-css-snippets/#change-the-order-of-navigation-bar-buttons","title":"Change the order of navigation bar buttons","text":"DescriptionAuthorScreenshotsCSS code Use order
values below 0 to move specific buttons to the left of the non-ordered buttons, and values above 1 to move them to the right of the non-ordered buttons.
/* [Global changes] Change the order of navigation bar buttons */\n\nnav .navbar-nav:first-child {\ndisplay: flex;\nflex-direction: row;\n}\ndiv.nav-link[data-rb-event-key=\"/tags\"] {\norder: -2;\n}\ndiv.nav-link[data-rb-event-key=\"/groups\"] {\norder: -1;\n}\ndiv.nav-link[data-rb-event-key=\"/scenes\"] {\norder: 1;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-donate-button","title":"Hide the Donate button","text":"DescriptionAuthorScreenshotsCSS code Hide the Donate button.
/* [Global changes] Hide the Donate button */\n\n.btn-primary.btn.donate.minimal {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#blur-nsfw-images","title":"Blur NSFW images","text":"DescriptionAuthorScreenshotsCSS code Use for when working on stash but don't want to expose NSFW images and text. May not be exhaustive.
/* [Global changes] Blur NSFW images */\n\n.scene-card-preview-video,\n.scene-card-preview-image,\n.image-card-preview-image,\n.image-thumbnail,\n.gallery-card-image,\n.performer-card-image,\n.tag-card-image,\nimg.performer,\n.group-card-image,\n.gallery .flexbin img,\n.wall-item-media,\n.scene-studio-overlay .image-thumbnail,\n.image-card-preview-image,\n#scene-details-container .text-input,\n#scene-details-container .scene-header,\n#scene-details-container .react-select__single-value,\n.scene-details .pre,\n#scene-tabs-tabpane-scene-file-info-panel span.col-8.text-truncate > a,\n.gallery .flexbin img,\n.group-details .logo {\nfilter: blur(12px);\n}\n\n.scene-card-video {\nfilter: blur(13px);\n}\n\n.jw-video,\n.jw-preview,\n.jw-flag-floating,\n.image-container,\n.studio-logo,\n.scene-cover {\nfilter: blur(20px);\n}\n\n.group-card .text-truncate,\n.scene-card .card-section {\nfilter: blur(4px);\n}\n
"},{"location":"themes/custom-css-snippets/#blur-nsfw-images-and-unblur-on-mouse-over","title":"Blur NSFW images and unblur on mouse over","text":"DescriptionAuthorScreenshotsCSS code Blur NSFW images and unblur on mouse over.
fl0w#9497
/* [Global changes] Blur NSFW images and unblur on mouse over */\n/* === MORE BLUR === */\n/* scene */\n.scene-card-preview,\n.vjs-poster,\nvideo,\n.scene-cover,\n.scrubber-item,\n\n/* image */\n.image-card-preview,\n.image-image,\n.gallery-image,\n\n/* group */\n.group-card-image,\n.group-images,\n\n/* gallery */\n.gallery-card-image,\ntable > tbody > tr > td > a > img.w-100,\n\n/* performer */\n.performer-card-image,\nimg.performer,\n\n/* studio */\n.studio-card-image,\n\n/* tag */\n.tag-card-image\n\n{\nfilter: blur(30px);\n}\n\n/* === LESS BLUR === */\n/* common */\n.card-section-title,\n\n/* scene */\n.scene-studio-overlay,\n.scene-header > h3,\nh3.scene-header,\n.studio-logo,\n.image-thumbnail,\n\n/* image */\nh3.image-header,\n\n/* group */\n.group-details > div > h2,\n\n/* gallery */\nh3.gallery-header,\n\n/* studio */\n.studio-details .logo,\n.studio-details > div > h2,\n\n/* tag */\n.logo-container > .logo,\n.logo-container > h2\n\n{\nfilter: blur(2px);\n}\n\n/* === UNBLUR ON HOVER === */\n/* common */\n.thumbnail-section:hover *,\n.card:hover .card-section-title,\n\n/* scene */\n.card:hover .scene-studio-overlay,\n.video-js:hover .vjs-poster,\nvideo:hover,\n.scene-header:hover > h3,\ndiv:hover > .scene-header,\n.studio-logo:hover,\n.scene-cover:hover,\n.image-thumbnail:hover,\n.scene-card-preview:hover,\n.scrubber-item:hover,\n\n/* image */\n.image-image:hover,\ndiv:hover > .image-header,\n.gallery-image:hover,\n\n/* group */\n.group-images:hover,\n.group-details > div > h2:hover,\n\n/* gallery */\ndiv:hover > .gallery-header,\ntable > tbody > tr > td:hover > a > img.w-100,\n\n/* performer */\nimg.performer:hover,\n\n/* studio */ \n.studio-details .logo:hover,\n.studio-details:hover > div > h2,\n\n/* tag */\n.logo-container > .logo:hover,\n.logo-container:hover > h2\n{\nfilter: blur(0px);\n}\n
"},{"location":"themes/custom-css-snippets/#hide-0-count-badges","title":"Hide 0 count badges","text":"DescriptionAuthorScreenshotsCSS code Hide 0 count badges.
echo6ix
/* [Global changes] Hide 0 count badges */\nspan.badge[data-value=\"0\"] {\n display: none;\n}\n
"},{"location":"themes/custom-css-snippets/#border-around-cards-activated-with-checkbox-selection","title":"Border around cards activated with checkbox selection","text":"DescriptionAuthorScreenshotsCSS code Add a noticeable border around any cards that have been selected using the checkbox selection. Border color uses Stash's --primary
color variable to maintain consistency with any theme that uses Stash's color variables.
echo6ix
/* [Global changes] Modify card when checkbox is selected */\n.grid-card.card:has(input:checked) {\nbox-shadow: 0 0 0 1px var(--primary,rgba(255, 255, 255, 0.30));\n}\n
"},{"location":"themes/list/","title":"List of themes","text":""},{"location":"themes/list/#alternative-tag-layout","title":"alternative-tag-layout","text":"DescriptionSource URLREADMEAuthorScreenshots Changes the tags layout to show more images, and details on hover
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#direct-stream","title":"direct-stream","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds styling to settings to indicate direct stream
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#dracula-theme","title":"Dracula Theme","text":"DescriptionSource URLREADMEAuthorScreenshotsA dark theme for Stash based on the popular Dracula theme.
https://uncertainmongoose.github.io/dracula-for-stash/index.yml\n
No README available
UncertainMongoose
"},{"location":"themes/list/#glassy-a-window-to-your-collection","title":"Glassy - A Window to Your Collection","text":"DescriptionSource URLREADMEAuthorScreenshotsA Stash Theme
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-font-overhaul","title":"Glassy - Font Overhaul","text":"DescriptionSource URLREADMEAuthorScreenshotsA Stash Theme
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-front-page-animations-and-blur","title":"Glassy - Front Page Animations and Blur","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-marker-wall-redesign","title":"Glassy - Marker Wall Redesign","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-performer-scene-card-details-redesign","title":"Glassy - Performer Scene Card Details Redesign","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-and-movie-card-redesign","title":"Glassy - Scene and Movie Card Redesign","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-and-movie-card-redesign-no-animated-titles","title":"Glassy - Scene and Movie Card Redesign - No Animated Titles","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-player-details-6040","title":"Glassy - Scene Player-Details 60/40","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-player-details-reversed","title":"Glassy - Scene Player-Details Reversed","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-player-details-reversed-6040","title":"Glassy - Scene Player-Details Reversed 60/40","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-smaller-performer-cards-on-main-page","title":"Glassy - Smaller Performer Cards on Main Page","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-smaller-performer-image-cards","title":"Glassy - Smaller Performer Image Cards","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-video-res-icons","title":"Glassy - Video-Res Icons","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-images","title":"Glassy Images","text":"DescriptionSource URLREADMEAuthorScreenshotsImages for A Stash Theme
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-installer","title":"Glassy Installer","text":"DescriptionSource URLREADMEAuthorScreenshotsGlassy meta-package for requirements.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#hide-donate","title":"hide-donate","text":"DescriptionSource URLREADMEAuthorScreenshotsHide the Donate button.
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#hide-ocount","title":"hide-ocount","text":"DescriptionSource URLREADMEAuthorScreenshotsHide O-Count and O-Count trakcers
https://feederbox826.github.io/themes/main/index.yml\n
No README available
feederbox826
"},{"location":"themes/list/#more-studio-row","title":"more-studio-row","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplay more studio per row
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#performer-grid","title":"performer-grid","text":"DescriptionSource URLREADMEAuthorScreenshotsAligns performer details in a grid
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#theme-blackhole","title":"Theme - BlackHole","text":"DescriptionSource URLREADMEAuthorScreenshotsBlackHole Theme for Stash by BViking78
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
BViking78
"},{"location":"themes/list/#theme-moderndark","title":"Theme - ModernDark","text":"DescriptionSource URLREADMEAuthorScreenshotsModernDark Theme for Stash by cj13
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cj13
"},{"location":"themes/list/#theme-neondark","title":"Theme - NeonDark","text":"DescriptionSource URLREADMEAuthorScreenshotsNeonDark Theme for Stash by Dankonite
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Dankonite
"},{"location":"themes/list/#theme-night","title":"Theme - Night","text":"DescriptionSource URLREADMEAuthorScreenshotsNight Theme for Stash (unknown author)
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"themes/list/#theme-plex","title":"Theme - Plex","text":"DescriptionSource URLREADMEAuthorScreenshotsPlex Theme for Stash by Fidelio 2020
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Fidelio
"},{"location":"themes/list/#theme-plex-better-styles","title":"Theme - Plex Better Styles","text":"DescriptionSource URLREADMEAuthorScreenshots
A modified version of Stash-Plex theme
https://tetrax-10.github.io/stash-stuffs/index.yml\n
View README
tetrax-10
"},{"location":"themes/list/#theme-pornhub","title":"Theme - Pornhub","text":"DescriptionSource URLREADMEAuthorScreenshots
PornHub Theme for Stash by neurokinin
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
ronilaukkarinen
"},{"location":"themes/list/#theme-pulsar","title":"Theme - Pulsar","text":"DescriptionSource URLREADMEAuthorScreenshotsPlex Theme for Stash by Fonzie 2020-21
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Fonzie
"},{"location":"themes/list/#theme-pulsarlight","title":"Theme - PulsarLight","text":"DescriptionSource URLREADMEAuthorScreenshotsPlex Theme for Stash by Fonzie 2021
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Fonzie
"},{"location":"themes/list/#theme-rounded-yellow","title":"Theme - Rounded Yellow","text":"DescriptionSource URLREADMEAuthorScreenshotsTheme with rounded corners and yellow accents
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Fonzie
"},{"location":"themes/list/#wrap-subtag","title":"wrap-subtag","text":"DescriptionSource URLREADMEAuthorScreenshotsWraps detail values (subtags)
https://feederbox826.github.io/themes/main/index.yml\n
No README available
feederbox826
"},{"location":"userscripts/","title":"Userscripts","text":"Info
Userscripts are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Userscripts are programs written in Javascript that modifies web pages to improve browsing with new features, formatting and more.
"},{"location":"userscripts/#install","title":"Install","text":"To install the userscript you will need a browser extension such as:
Exhaustive list of git repositories related to Stash Google Sheets document.
Userscript no longer worksIf you found that userscript is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"userscripts/list/#stash-userscripts","title":"Stash userscripts","text":"CompatabilityMake sure your instance URL is declared in @match
.
Automate batch creation and tagging
Serechops
"},{"location":"userscripts/list/#performer-image-carousel","title":"Performer Image Carousel","text":"DescriptionAuthorScreenshotsDisplays a carousel of performer images in the header.
Serechops
"},{"location":"userscripts/list/#stash-box-userscripts","title":"stash-box userscripts","text":"stash-box compatabilitySometimes just updating @match
is enough to make the userscript to work on a different stash-box instance. But it's not a guarantee.
Adds Noto Color Emoji to stash-box instances
feederbox826
"},{"location":"userscripts/list/#fansdb-submission-helper","title":"FansDB Submission Helper","text":"DescriptionREADMEAuthorScreenshotsView README
mmenanno, DogmaDragon
"},{"location":"userscripts/list/#stashdb-submission-helper","title":"StashDB Submission Helper","text":"DescriptionREADMEAuthorScreenshots
View README
mmenanno
"},{"location":"userscripts/list/#stashdb-diff","title":"stashdb-diff","text":"DescriptionAuthorScreenshots
add character-by-character diff for stashdb
feederbox826
"},{"location":"userscripts/list/#stashdb-link-chip","title":"stashdb-link-chip","text":"DescriptionAuthorScreenshotsadd chips to links in edit queue
feederbox826
"},{"location":"userscripts/list/#stashdb-relative-date","title":"stashdb-relative-date","text":"DescriptionAuthorScreenshotsadds relative dates to stashdb
feederbox826
"},{"location":"userscripts/list/#stashdb-rm","title":"stashdb-rm","text":"DescriptionAuthorScreenshotsRemove scenes from loaded studios on stashdb.org
feederbox826
"},{"location":"userscripts/list/#stashbox-notifications","title":"StashBox Notifications","text":"DescriptionAuthorScreenshotsNotifications for StashBox !
S3L3CT3DLoves
"},{"location":"userscripts/list/#studio-image-blur-for-stashdb","title":"Studio Image Blur for StashDB","text":"DescriptionAuthorScreenshotsBlurs images from specific studios on StashDB scene cards, based on studio name and img src
Serechops
"},{"location":"userscripts/list/#utility-userscripts","title":"Utility userscripts","text":"There are some userscripts that might be useful to Stash users, but does not directly involve Stash or stash-box instances.
"},{"location":"userscripts/list/#twitter-media-unblur","title":"twitter-media-unblur","text":"DescriptionAuthorScreenshotsunblur all twitter sensitive media post
feederbox826
"},{"location":"userscripts/list/#pmvhaven-autodl","title":"PMVHaven AutoDL","text":"DescriptionAuthorScreenshotsDashboard to simplify PMV downloading on PMVHaven
S3L3CT3DLoves
"},{"location":"userscripts/list/#spankbang-autodl","title":"SpankBang AutoDL","text":"DescriptionAuthorScreenshotsDashboard to download all a user's videos on SpankBang
S3L3CT3DLoves
"},{"location":"userscripts/list/#spankbang-frontend-scraper","title":"SpankBang Frontend Scraper","text":"DescriptionAuthorScreenshotsUse in Stash to scrape Spankbang from the browser, bypassing cloudflare issues
S3L3CT3DLoves
"},{"location":"userscripts/list/#lifeselector-unblur","title":"LifeSelector unblur","text":"DescriptionAuthorScreenshotsUnblur LifeSelector website
feederbox826
"},{"location":"userscripts/list/#redgifs-autosettings","title":"redgifs autosettings","text":"DescriptionAuthorScreenshotsAuto Unmute / Play / HD redgifs
feederbox826
"},{"location":"userscripts/list/#stash-tmdb-syncscraper","title":"Stash-TMDB Sync/Scraper","text":"DescriptionAuthorScreenshotsSync Button in TMDB Site.to Create Movie/Performer in Stash and Update performer missing info.
W0lfieW0lf
"},{"location":"utilities/","title":"Utilities","text":"
Info
Utilities are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Utilities are other external applications that utilise or interact with Stash in some way.
To install follow the utilities install instructions.
"},{"location":"utilities/list/","title":"List of utilities","text":"stash-git-indexExhaustive list of git repositories related to Stash Google Sheets document.
Utility no longer worksIf you found that utility is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"utilities/list/#clip-mash","title":"clip-mash","text":"DescriptionAuthorScreenshotsVideo editing app that allows you to automate creating compilations from multiple videos. It runs in your browser. It's mostly made for, ahem, adult content, which is why it can connect to Stash and fetch videos and scene markers from there to guide the video creation process. You can also use local files and set the markers in ClipMash itself and then generate a compilation based on that.
soundchaser128
"},{"location":"utilities/list/#stash-app-for-android-tv","title":"Stash App for Android TV","text":"DescriptionAuthorScreenshotsA basic Android TV app for browsing and playing videos from a Stash server. Not all features of Stash are supported, but the basics for browsing, searching, and playing scenes should work. The app is not intended to perform administrative functions such as scanning, scraping, or editing details.
damontecres
"},{"location":"utilities/list/#stash-compilation-maker","title":"stash-compilation-maker","text":"DescriptionAuthorScreenshots
Connects to your Stash instance and creates simple compilation videos from scene markers. You select one or more tags, or one or more performers and it will take (currently) the first 15 seconds of video after the marker start and compile all of the markers into one video.
soundchaser128
"},{"location":"utilities/list/#stash-qmt","title":"stash-qmt","text":"DescriptionAuthorScreenshotsstash-qmt (quick manual tagger) is a simple GUI tool designed to help with cases of manually tagging multiple similar scenes (manually, as in, with having to actually watch them) in Stash.
PokerFacowaty
"},{"location":"utilities/list/#stash-vr-companion","title":"stash-vr-companion","text":"DescriptionAuthorScreenshots
Similar to stash-deovr as above but designed as a web app that sits in a docker container next to stash to make it easier to use and add more functionality.
Tweeticoats
"},{"location":"utilities/list/#stash-vr","title":"stash-vr","text":"DescriptionAuthorScreenshotsWatch your Stash library in VR for that full immersion effect.
Stash-VR bridges your Stash instance and VR video player allowing you to browse, play and manage your scenes using the video players native VR UI.
o-fl0w
"},{"location":"utilities/list/#stash-webvr","title":"stash-webvr","text":"DescriptionAuthorScreenshotsWebVR friendly Stash client that displays only videos tagged with \"Virtual Reality\" tag.
stishadmin
"},{"location":"utilities/list/#stash_helper","title":"Stash_helper","text":"DescriptionAuthorScreenshotsAdds some helping features to Stash (Bookmarks, playlist, external player, etc). Windows only.
philpw99
"},{"location":"utilities/list/#stashbox-performer-bot","title":"StashBox Performer Bot","text":"DescriptionAuthorScreenshotsThis program is designed to help automate the creation and updating of Performers on StashBox instances. It is designed to copy Performer info from one StashBox to another, to avoid having to maintain the information in both sources manually.
S3L3CT3DLoves
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Stash is a web application written in Go for serving and organizing your porn collection. It is self-hosted and released under AGPL-3.0 license. Stash currently supports Windows, macOS, Linux, FreeBSD and Docker.
"},{"location":"#about-stash","title":"About Stash","text":"You can learn more about the software generally via the README on the official repository or via official website.
"},{"location":"#get-started","title":"Get started","text":"To get started go to Installation and grab the latest version for your operating system.
"},{"location":"#support","title":"Support","text":"There is a GraphQL API which allows to do things automatically. GraphQL is also self-documenting.
Stash has integrated playground where you run interact with the API and view the documentation.
<server>:<port>/playground
(default is http://localhost:9999/playground
). All HTTP requests have to go to <server>:<port>/graphql
(default is http://localhost:9999/graphql
).
You just need to add the key you generated in Stash (for more info about the API Key check stash's help section) in a header for every request you make.
Example using curlcurl -X POST -H \"ApiKey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiJiaWxsIiwiaWF0IjoxNjE3MDkzMDYwLCJzdWIiOiJBUElLZXkifQ.WhUyvmnVeW8wGV5fkVyje3xLfz5A97HFwyZy-4i8Q-I\" -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation { metadataScan (input:{})}\" }' localhost:9999/graphql\n
"},{"location":"api/#legacy-cookie-authentication","title":"Legacy cookie authentication","text":"If you have configured a username/password you have to use cookies to authenticate.
Example using curlcurl --verbose --cookie-jar cookie.txt --data 'username=stash&password=**' localhost:9998/login\ncurl --cookie cookie.txt -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation { metadataScan ( input: {} ) } \"}' localhost:9999/graphql\n
Using the API Key
is recommended instead of the above cookie method.
HTTP-POST
Example using curl {\n \"query\": \"mutation { metadataScan ( input: {} ) }\"\n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \" mutation { metadataScan (input: {} ) }\" }' localhost:9999/graphql\n
"},{"location":"api/#create-backup","title":"Create backup","text":"HTTP-POST
Example using curl {\n \"query\": \"mutation { backupDatabase(input: {download: false})}\"\n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation {backupDatabase(input: {download: false})}\" }' localhost:9999/graphql\n
If download:
is true
the created backup is returned and not stored locally.
HTTP-POST
Example using curl Payload (set desired content to generate covers, sprites, previews, imagePreviews, markers, transcodes, phashes, interactiveHeatmapsSpeeds, imageThumbnails, clipPreviews to true
or false
.
{\n \"query\": \"mutation { metadataGenerate ( input : { sprites: true previews: false imagePreviews: false markers: false transcodes: false } ) }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"mutation { metadataGenerate ( input : { sprites: false previews: true imagePreviews: false markers: false transcodes: false } ) }\" }' localhost:9999/graphql\n
"},{"location":"api/#get-studios","title":"Get studios","text":"HTTP-POST
Example using curl Payload (must be at least one of id
checksum
url
name
image_path
scene_count
).
{\n \"query\": \"{ allStudios { id checksum url name image_path scene_count } }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ allStudios { name url scene_count} }\" }' localhost:9999/graphql\n
"},{"location":"api/#scrape-perfomer-attributes-from-freeones","title":"Scrape perfomer attributes from Freeones","text":"HTTP-POST
Example using curl Payload
$performer name
is the name of the Performer you are scraping forname
url
twitter
instagram
birthdate
ethnicity
country
eye_color
height
measurements
fake_tits
career_length
tattoos
piercings
aliases
{\n \"query\": \"{ scrapeFreeones(performer_name: $performer_name) { name url twitter instagram birthdate ethnicity country eye_color height measurements fake_tits career_length tattoos piercings aliases } }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ scrapeFreeones ( performer_name : \\\"Abella Danger\\\" ) { name height birthdate} }\" }' localhost:9999/graphql\n
"},{"location":"api/#get-list-of-perfomer-names-that-match-a-name-or-alias-from-freeones","title":"Get list of perfomer names that match a name or alias from Freeones","text":"HTTP-POST
Example using curl Payload ($q
is the name or alias (or partial name , alias) of the performer you are looking for).
{\n \"query\": \"{ scrapeFreeonesPerformerList(query: $q) }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ scrapeFreeonesPerformerList (query: \\\"bella\\\" ) }\" }' localhost:9999/graphql\n
"},{"location":"api/#get-system-status","title":"Get system status","text":"HTTP-POST
Example using curl {\n \"query\": \"{ systemStatus { databaseSchema databasePath configPath appSchema status } }\" \n}\n
curl -X POST -H \"Content-Type: application/json\" --data '{ \"query\": \"{ systemStatus { appSchema status } }\" }' localhost:9999/graphql\n
"},{"location":"code-of-conduct/","title":"Code of conduct","text":""},{"location":"code-of-conduct/#our-pledge","title":"Our Pledge","text":"We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
"},{"location":"code-of-conduct/#our-standards","title":"Our Standards","text":"Examples of behavior that contributes to a positive environment for our community include:
Examples of unacceptable behavior include:
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
"},{"location":"code-of-conduct/#scope","title":"Scope","text":"This Code of Conduct applies within all community spaces, community servers, code repositories, and also applies when an individual is officially representing the community in public spaces.
"},{"location":"code-of-conduct/#enforcement","title":"Enforcement","text":"Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement. You can contact Admin or Org Lead members directly via Discord or using an integrated report function on other platforms. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
"},{"location":"code-of-conduct/#enforcement-guidelines","title":"Enforcement Guidelines","text":"Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
"},{"location":"code-of-conduct/#warning","title":"Warning","text":"Offense: First time offence.
Consequence: A public or private written warning depending on the space where offense happened.
"},{"location":"code-of-conduct/#temporary-or-permanent-ban","title":"Temporary or Permanent Ban","text":"Offense: Second time offense.
Consequence: Temporary or permanent ban from any sort of public interaction within the community and removal of any previously given elevated permissions.
"},{"location":"code-of-conduct/#attribution","title":"Attribution","text":"This Code of Conduct is a modified and adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
"},{"location":"matrix/","title":"Matrix","text":""},{"location":"matrix/#what-is-matrix","title":"What is Matrix?","text":"Matrix is an open-source internet protocol for secure, decentralised, real-time communication. Unlike other popular platforms like Discord, Matrix is federated. It consists of many servers, each server hosts Matrix accounts and chats. You can create an account on any Matrix server and the join other servers without having to re-create your account. One common example of federated protocol everyone uses today is email.
On Matrix, usernames are referred to as MXIDs (Matrix IDs), chats as rooms, servers as homeservers. Think of homeserver as the domain that hosts the instance. You can also group rooms together to form spaces (similar to Discord server).
In comparison to Discord: Username = Matrix ID Channel = Room Server = Space1
1 Spaces are a collection of individual rooms.
"},{"location":"matrix/#registration-on-matrix","title":"Registration on Matrix","text":"There is no central place to register on. You can create an account on any homeserver and join spaces and rooms across all of them.
"},{"location":"matrix/#popular-homeservers","title":"Popular homeservers","text":"2 Redirects to element.io domain, which is affiliated with matrix.org.
"},{"location":"matrix/#clients","title":"Clients","text":"Matrix supports a variety of clients on web, desktop (Windows, Linux, and macOS), and mobile (Android, iOS). matrix.org maintains a list of clients on their website here.
TipWeb-based clients are great to start and register. Element (web) is feature-rich and easy to use client.
"},{"location":"matrix/#stash-space","title":"Stash space","text":"Our official space is located at #stashapp:unredacted.org. Alternative addresses are on matrix.im: #stashapp:matrix.im.
Tip
Rooms can be joined from inside the space. You can join one, or more rooms, or all rooms from the space. They are not directly tied to each other.
"},{"location":"matrix/#stash-rooms","title":"Stash rooms","text":"Info
We are using a bridge bot that relays Discord and Matrix messages both ways in some rooms. They will be marked (bridged). Some features doesn't translate through the bridge like reactions and threads.
Some rooms are designated as [NSFW]. Adult focused media is allowed to be posted in those rooms without /spoiler as long as they within space rules.
"},{"location":"matrix/#matrix-focused-rooms","title":"Matrix focused rooms","text":"The following is our recommended procedure for new Stash users who want to get info for their scenes as quickly, easily, and as accurately as possible. Pulling info directly from StashDB is still the best option, but unfortunately this will not always be possible. Alternative methods are also covered for when StashDB doesn't have what you need. This is an expanded version of @Scruffy's pinned post in the #stashdb-general channel in our Discord. Go there if you'd like something more succinct and direct. Hopefully this guide will reduce the pain and frustration for those who are lost and don't know where to start.
The following sections are in this particular order for a reason, so please follow this guide from the beginning.
"},{"location":"beginner-guides/guide-to-scraping/#generate-phashes","title":"Generate pHashes","text":"Navigate to the Settings page (\u2699 icon in top right), make sure you're on \"Tasks\" in the sidebar to the left, then find the first heading \"Library\" in the middle of the page. Make sure \"Generate perceptual hashes\" is turned on so pHashes will be created automatically each time you run a scan to add new scenes. This will slow down the scanning process, but for most users it's worth it. pHashes are the main way to match your scenes with our data on StashDB.
pHash generation is not turned on by default, so you'll need to generate them manually if you haven't already. This can be done on your entire library on the same Settings --> Tasks page, scroll down to the \"Generated Content\" heading. Make sure \"Perceptual hashes (for deduplication)\" is turned on and click the \"Generate\" button at the top. As long as \"Overwrite existing generated files\" is turned off, this will only generate missing files and hashes.
If you haven't set up StashDB in your Stash settings yet, now's the time to do it. The best way to do that is to follow this guide to Accessing StashDB. It includes step-by-step instructions for both signing up to StashDB and connecting your new account to Stash.
"},{"location":"beginner-guides/guide-to-scraping/#use-the-scene-tagger","title":"Use the Scene Tagger","text":"Go to your Scenes page on Stash and click the double \ud83d\udd16 icon to the far right of the search bar. This is your Scene Tagger view and should be your first choice for pulling data, not Identify / Autotag / Filename Parser / URL Scrapers / etc. Always use the Scene Tagger first, the rest are for users with more specific needs who understand the strengths and weaknesses of each tool.
Important
Tags are not created automatically. You need to click +
icon near the tag name to create it for you locally and attach it to the scene. Once it's created, it will match automatically in the future.
First, click the \"Scrape All\" button. This will use your pHashes to find matching scenes on StashDB for every scene on the current page. The \"Scrape by fragment\" buttons will do the same thing but just for one scene at a time. Also, you may want to change your Scene Tagger settings with the \u2699 icon next to \"Scrape All.\" You can tell it to Merge (keep all) tags, Overwrite (keep only new) tags, or ignore StashDB's tags entirely (leave box unchecked). If you plan on contributing to StashDB, you should have \"Show male performers\" turned on to better follow these guidelines.
If your fingerprint search doesn't return a correct result for your scene, you can try searching with the \"Query\" field using title, performer, release date, or studio. Try to use as little text as possible to find your scene. Otherwise, unnecessary words that do not match StashDB's info may block correct results. If you can find the matching scene on StashDB.org but can't find it using the Scene Tagger, you can use the scene's StashID as your Tagger query.
Be sure to double-check that each selected result matches your scene before clicking the \"Save\" button at the bottom of each card. If you're confident that all of your saved matches are accurate, you may click the \"Submit fingerprints\" button after you're done. This will add your files' hashes to StashDB to make them easier for other users to find. But again, make sure your files were matched correctly first. The button will appear right next to the \"Scrape All\" button.
{:style=\"counter-reset:none\"} 1. First step is to make an account at theporndb.net. With your account created, navigate to your API Tokens page. Type \"stash\" as your token's name (or whatever you'd prefer), make sure the \"read\" permission is checked (you don't need the others), and click the \"Create\" button. A pop-up will display your newly created token. Save your API token somewhere so you can find it later!. It will not be visible on ThePornDB's website after you close the pop-up. If you lose it, you may need to create a new one and repeat this entire setup process. This can be done in a password manager, notes app, or a well-placed text file.
![How to create an API token on ThePornDB](/assets/beginner-guides/create-tpdb-token.jpg)\n
{:style=\"counter-reset:none\"} 1. Click Add and fill out the form that pops up: paste in your API key you created earlier amd enter ThePornDB
(or anything else you'd like, like TPDB) for Name, and enter https://theporndb.net/graphql
as the GraphQL endpoint.
Click Test Credentials to make sure you've entered everything correctly, then click Confirm.
Finally, we can use the Scene Tagger to scrape from ThePornDB. First you'll need to switch to \"ThePornDB\" as the Tagger's source. It will always default to the first Stash-Box source, so you'll need to switch it every time you need something else. Use the same process here as we used with StashDB and the Scene Tagger. The \"Scrape All\" and \"Scrape by fragment\" buttons will match by using file hashes (pHash and oshash). If these don't give you the right results, you can try the \"Search\" button and customize your search terms as needed. Remember to use as few terms as possible in your search because unneccessary words that don't match ThePornDB's info may block correct results. You can also copy-paste additional terms from TPDB's page if you need to narrow down the Tagger's results more.
For those wanting to contribute to StashDB
As noted before, ThePornDB leans heavily on automated scrapers to pull all of their info. Often that data is incomplete or inaccurate compared to what we'd want on StashDB. Before you submit your scene to StashDB, you'll need to double-check your info, clean it up a bit first, and make sure you're following these guidelines. Submitting to StashDB is discussed further in the last step of this guide.
"},{"location":"beginner-guides/guide-to-scraping/#use-site-specific-scrapers","title":"Use Site-Specific Scrapers","text":"If you've already tried StashDB, you've already tried ThePornDB, and you still want to scrape a site directly, you can try using a site-specific scraper. However, every scraper is going to work differently. Some will need Python installed. Others will need you to set a user agent or a Chrome CDP path. A handful will need to be edited and configured first. Only a few can search a studio's website for the right scene. The entire process is much more advanced and is different for each scraper, which is why we recommend StashDB and TPDB first for new users. They can all be found in the same repo. You can download them individually, or you can download the entire repo as a zip archive.
First you'll want to search this page for your website to see if we have a scraper for it and to get an idea of what its requirements are. For most of these scrapers, you'll need to find and save a studio URL to your scene first. If you've managed to set up a fragment scraper, you can click on the \"Scrape with...\" button in the scene's edit tab to select your scraper. Typically fragment scrapers are better than URL scrapers. Otherwise, you'll need to click the button at the far right end of the URL field to run a URL scraper. It should light up when the field is filled with a URL that matches one of your installed scrapers. That's about as detailed as we can get in this guide for new users. If you've tried StashDB, tried TPDB, checked the relevant documentation, checked your logs, and still can't get one of these scrapers working, you can ask for help on Discord in the #help channel. More advanced discussions might be moved to the #scrapers channel
If you're certain a scene isn't on StashDB and you've found the info using ThePornDB or some other scraper, please consider submitting it to StashDB yourself. That way nobody else will have to duplicate the same work you've done for that particular scene if they can match their pHash with yours. You'll need to ask for edit privileges in our Discord and follow the guidelines on this website. In particular, please note that not every scene can be added to StashDB at this time. Some studios aren't allowed and full movies likely won't be eligible either.
Also, please don't blindly resubmit data gotten from ThePornDB. You should verify the data is correct and complete first, make sure the URL is right, check for any missing performers, and look up any relevant guidelines if something else seems funky to you. You should update your data within Stash before submitting a draft or you can edit the draft on StashDB itself before creating the edit. You should also have the studio URL now, so you should also compare with that page manually or even scrape again with a site-specific scraper as explained in the previous step of this guide. Also please note in your edit comment where your data is coming from.
Info
Please check your logs after migrating to this release. A log warning will be generated on startup if duplicate image checksums exist in your system. Search for the images using the logged checksums, and remove the unwanted ones.
Info
The system will now stop serving requests if authentication is not configured and it detects a connection from public internet. See this link for details.
"},{"location":"changelog/v0100/#new-features","title":"\u2728 New Features","text":"libvips
) and made optional. (#1655)The Stash developers would greatly appreciate if you take a short, anonymous survey. It would help us out a great deal to make yourself heard, let us know how you use Stash, and tell us what you'd like to see in the future.
"},{"location":"changelog/v0110/#new-features","title":"\u2728 New Features","text":"Auto Tag
scene scraper to match performers, studio and tags from filename - using AutoTag logic. (#1817)or
keywords and exclude keywords. See the Browsing
section of the manual for details. (#1982)Info
Image Slideshow Delay (in Interface Settings) is now in seconds rather than milliseconds and has not been converted. Please adjust your settings as needed.
"},{"location":"changelog/v0140/#new-features","title":"\u2728 New Features","text":"theme_color
property in config.yml
(#2365).
characters. (#2658)Info
After migrating, please run a scan on your entire library to populate missing data, and to ingest identical files which were previously ignored.
"},{"location":"changelog/v0170/#known-issues-and-other-changes","title":"\ud83d\udca5 Known issues and other changes","text":"Set name, date, details from embedded file metadata
scan flag is no longer supported. This functionality may be implemented as a built-in scraper in the future.Don't include file extension as part of the title
scan flag is no longer supported.parseDate
scraper post processor. (#2817)autostartVideoOnPlaySelected
option not applying when navigating from scene queue. (#2896)database is locked
errors when performing operations while running a scan. (#3153)index.html
not correctly served from custom mapped folders. (#3168)ffmpeg
during generation and live-transcoding. (#3216)r x x
keyboard shortcuts to set decimal ratings. (#3226)Info
After upgrading performance will be degraded until a full scan has been completed.
Info
Language has been set to `English (United States)` by default, which affects number and date formatting.
"},{"location":"changelog/v020/#new-features","title":"\u2728 New Features","text":"Info
The cache directory is now required if using HLS/DASH streaming. Please set the cache directory in the System Settings page.
Info
The image data subsystem has been reworked in this release. Existing systems will have their storage system set to Database
, which stores all image data in the database. This can be changed in the System Settings page.
A migration is required to change the storage system, and can be accessed from the Tasks page.
The Database
storage system is not recommended for large libraries, as it can cause performance issues. The Filesystem
storage system is recommended for large libraries, and is the default for new systems.
Info
The generated/screenshots
jpg files are now considered legacy. These files can be migrated into the blob storage system by running the Migrate Screenshots
task from the Tasks page.
Once migrated, these files can be deleted. The files can be optionally deleted during the migration.
"},{"location":"changelog/v0200/#new-features","title":"\u2728 New Features","text":"Is Missing Cover
scene filter criterion. (#3187)/stream
endpoint serving directory list. (#3541).forcegallery
to directory. (#3715).nogallery
to directory. (#3715)-v/--version
command line flag. (#3883)Mark as Organized on save
is false when saving a scene in the tagger. (#4213)Info
A number of settings and tasks are now only available when Advanced Mode
is set to true in the settings, including the Auto Tag
and Identify
tasks.
.forcegallery
file not being honoured when re-scanning after adding the file. (#4627)baseURL
not being applied to some links. (#4501)bmp
files being treated as video files in the lightbox. (#4653)Mousetrap
and MousetrapPause
to PluginApi.libraries
. (#4489)useToast
to PluginApi.hooks
. (#4546)PluginApi.components
. (#4546)task_name
parameter optional, added an optional description
parameter and deprecated args
for a generic map parameter args_map
in runPluginTask
. (#4603)runPluginOperation
to run synchronous plugin operations with a return value, without using the task manager. (#4603)PluginApi.Event.addEventListener
and stash:location
event dispatching.Info
The Enable Scene Play History
setting has been set to true for existing systems. This setting enables play counts and resuming scenes from where they were previously played. If you do not want this enabled, please disable it explicitly in Settings -> Interface -> Scene Player -> Enable Scene Play History
.
Settings -> System
, and can also be downloaded from this screen. (#4688)console
object in javascript runtime environment. (#4944)ErrUnauthorized
errors. (#4842)Info
The Movie concept has been renamed to Group.
Info
Tagger settings have been reset, but are now persisted between browser sessions. Show male performers
and Set Tags
are now defaulted to true. Please verify your settings before using the Tagger.
Groups
and now may contain orderable sub-groups with descriptions. (#5105)ffmpeg
instances while scrubbing. (#5340)STASH_BLOBS
. (#5345)Metadata Providers
page, and improved presentation. (#5040)Rescan
on the details pages will now properly recalculate file details. (#5043)career length
, measurements
and weight
. (#5129)path
column option to scene and gallery list tables. (#5005)Reload scrapers
option to top of Scrapers menus. (#5142)scene
filter criterion for Scene Marker queries. (#5097)movies
scene filter. (#5348)n
- prefixed version numbers. (#5102)PluginAPI.patch.instead
now allows for multiple plugins to hook into a single function. (#5125)Info
After upgrading, the next scan will populate all scenes with oshash hashes. MD5 calculation can be disabled after populating the oshash for all scenes. See `Hashing Algorithms` in the `Configuration` section of the manual for details.
"},{"location":"changelog/v030/#new-features","title":"\u2728 New Features","text":"Info
After upgrading, please verify your stash library settings and perform a scan to populate gallery images and the file modification times in the database.
"},{"location":"changelog/v040/#new-features","title":"\u2728 New Features","text":"STASH_STASH
environment variable if not already set.Info
After upgrading, all scene file sizes will be 0B until a new scan is run.
"},{"location":"changelog/v050/#new-features","title":"\u2728 New Features","text":"generated
directory from the library.downloads
directory when first run.python3
or python
for python script scrapers.url
field to URLReplace
, and make queryURLReplace
available when scraping by URL.cover.jpg
not being detected as cover image when in sub-directory.lbToKg
post-process action for performer scrapers.count
filter criteria and sort options./healthz
.tmp
and downloads
generated folders takes more than one second.today
and yesterday
for parseDate
in scrapers.Clear Image
button not updating image preview.Host
in input to plugins. (#1514)CreatedAt
and UpdatedAt
(and FileModTime
where applicable) to API objects. (#1421)subtractDays
post-process scraper action. (#1399)FAQ section is split into multiple categories for easier browsing, but if you have specific issue or question try using search. You can access search from the header or you can use keyboard shortcuts F , S , / to access it from any page.
"},{"location":"faq/#community-support","title":"Community support","text":"If you can't find an answer to your question here, you can always ask for help from the community.
Performer images uploaded in WebP format will not display on versions of Safari prior to version 13 or on anything earlier than MacOS Big Sur. This is a limitation of Safari. As a workaround, ensure you are uploading performer images in .jpg or .png format.
"},{"location":"faq/performers/","title":"Performers","text":""},{"location":"faq/performers/#how-can-i-add-performers-in-bulk","title":"How can I add performers in bulk?","text":"Info
You will need to have a stash-box attached as a source.
Info
You will need to have a stash-box attached as a source.
Stash tracks video files 2 ways:
Stash can still find the file even if one of them changes, all you need to do is run a scan task to trigger it. If both gets changed at the same time, Stash will create a new scene.
"},{"location":"faq/settings/","title":"Settings","text":""},{"location":"faq/settings/#how-can-i-move-my-library-from-one-location-to-another","title":"How can I move my library from one location to another?","text":"This will update all the paths for the existing objects without having to re-generate supported files.
Danger
Do not run a Clean task in between these steps, or you will lose the metadata from the affected objects. Your files will not be affected.
"},{"location":"faq/setup/","title":"Setup","text":""},{"location":"faq/setup/#how-do-i-recover-a-forgotten-username-or-password","title":"How do I recover a forgotten username or password?","text":"Stash saves login credentials in the config.yml
file. You must reset both login and password if you have forgotten your password by doing the following:
config.yml
file found in your Stash directory with a text editor;login
and password
lines from the file and save;Find the local IP address of your Stash Server (guides for Windows, MacOS, Linux). Then, on another device on your local network, open a browser to http://SERVER.IP.ADDRESS.HERE:9999
.
See this article for ideas on accessing your stash from outside your network.
"},{"location":"faq/setup/#how-do-i-serve-stash-over-ssltls-https","title":"How do I serve Stash over SSL/TLS (HTTPS)?","text":"This is typically accomplished by putting Stash behind a reverse proxy, such as Nginx or Caddy. Stash can also serve SSL directly. To use the built-in SSL:
First you must generate a SSL certificate and key combo.
Example using OpenSSLopenssl req -x509 -newkey rsa:4096 -sha256 -days 7300 -nodes -keyout stash.key -out stash.crt -extensions san -config <(echo \"[req]\"; echo distinguished_name=req; echo \"[san]\"; echo subjectAltName=DNS:stash.server,IP:127.0.0.1) -subj /CN=stash.server\n
This command would need customizing for your environment. This link might be useful.
Once you have a certificate and key file name them stash.crt
and stash.key
and place them in the same directory as the config.yml
file, or the ~/.stash
directory. Stash detects these and starts up using HTTPS rather than HTTP.
The basepath defaults to /
. When running stash via a reverse proxy in a subpath, the basepath can be changed by having the reverse proxy pass X-Forwarded-Prefix
(and optionally X-Forwarded-Port
) headers. When detects these headers, it alters the basepath URL of the UI.
config.yml
file. Usually located at %userprofile%/.stash
or $HOME/.stash
.generated:
line. generated: absolute_path_to_your_generated_folder
.If Stash is unable to find or download FFMPEG, then download and install it yourself.
The ffmpeg.exe
and ffprobe.exe
files should be placed in C:\\Users\\YourUsername\\.stash
on Windows. The ffmpeg
and ffprobe
files should be placed in ~/.stash
on macOS / Linux.
It can mean that you database got corrupted. You can verify that by running a few SQL statements. The easiest way to do so is to install a simple program called DB Browser for SQLite. Start the program and in the menu select File
> Open Database...
and select your Stash .sqlite database file. Then navigate to the Execute SQL
tab and run: - PRAGMA integrity_check;
- it should return ok
. - PRAGMA foreign_key_check;
- it should return nothing.
If you get something different it means there is an issue with your database. It's still possible that it can be recovered. You can ask for more help in one of the support channels. Another option would be to try using an older backup if you have one.
"},{"location":"faq/setup/#my-python-installation-is-not-detected","title":"My Python installation is not detected","text":"Make sure your Python version is added to environment variable PATH. This is a common issue with Python installed from Microsoft Store on Windows.
How to add Python to PATHA handy guide how you set a PATH on different operating systems: https://realpython.com/add-python-to-path/.
If you use multiple versions or have non standard configuration you can specify which version to use in Settings > System and under Applications Paths header set Python Executable Path.
Running multiple instances of Stash can be done by specifying both the -c
switch to denote an alternate config.yml
filepath, and the --p
switch to denote a unique port number.
Step-by-step Linux guide to running mutiple instances of Stash:
NEW_DIRECTORY_LOCATION
.NEW_PORT_NUMBER
../stash-linux --port NEW_PORT_NUMBER -c NEW_DIRECTORY_LOCATION/config.yml
.config.yml
to use NEW_PORT_NUMBER
. Find the line port: 9999
and replace with port: NEW_PORT_NUMBER
../stash-linux -c NEW_DIRECTORY_LOCATION/config.yml
Stash data is considered private, and Stash is not designed to be publicly exposed, except to trusted confidants. Stash has a built-in protection against accidentally exposing itself publicly outside of your network. If Stash receives a request from the public internet, and you do not have a password enabled, Stash will reject the request and stop handling requests to protect your privacy.
This often happens when you use the port-forwarding feature of your router or install Stash on a publicly accessible server, such as a VPS. When you do this, anybody in the world can access your Stash instance, so we enforce a password requirement. If your Stash instance has shutdown due to an insecure configuration, it will not handle requests again until you tell it that you have fixed the problem. After setting up either authentication, firewall, or removing your port forwarding rules, you can edit .stash/config/config.yml
and remove the key security_tripwire_accessed_from_public_internet
.
You may use several methods to safely access Stash from outside of your home network. In the most basic, you can enable authentication in Stash, and re-enable port forwarding. You can also use a VPN solution that allows you to securely access your home network, such as Tailscale, Zerotier, Wireguard, or others.
"},{"location":"faq/setup/#using-an-external-authentication-provider","title":"Using an external authentication provider","text":"If you are an advanced user, and have secured your Stash instance behind an authwall provided by a reverse proxy or hosting solution, you may continue to use that. You simply have to edit .stash/config/config.yml
and set dangerous_allow_public_without_auth
to true
. If you have already tripped the security feature, you will also have to remove the security_tripwire_accessed_from_public_internet
key in order to allow Stash to serve requests.
Info
Migrating between filesystems with different path separators (/
and \\
) is currently unsupported.
Danger
Use at your own risk. If you do this, make sure backup your database before starting.
It's possible to manually migrate the folders
table using SQL.
The following example query would replace \\
with /
and D:/
with /mnt/
.
UPDATE folders SET path = REPLACE(path, '\\', '/');\nUPDATE folders SET path = REPLACE(path, 'D:/', '/mnt/');\n
"},{"location":"faq/studios/","title":"Studios","text":""},{"location":"faq/studios/#how-can-i-add-studios-in-bulk","title":"How can I add studios in bulk?","text":"Info
You will need to have a stash-box attached as a source.
Info
You will need to have a stash-box attached as a source.
Info
If you decide to cancel the task in the queue, next time you will start the task, it will skip the files that were already scanned.
"},{"location":"guides/","title":"Guides","text":"In this section the community written guides will be published. You can submit your own via Stash-Docs repository.
If you find the guide has a typo or is outdated you can submit a pull request to fix it or make an issue on the GitHub. Thank you!
"},{"location":"guides/advanced-configuration-options/","title":"Advanced configuration options","text":"Some configuration options can not be edited through the UI and should only be used if needed.
Depending on the option they can be configured either by editing the config.yml
configuration file or by using an enviroment variable or in a few cases by using flags when running stash.
As an example the port
option can be changed from the default 9999
to 1234
by one of the below methods:
port: 1234
to the config.yml fileSTASH_PORT=1234 ./stash
./stash --port 1234
Always use the UI to create a backup of the database. As with all live databases DO NOT copy manually the database file as a means of backup.
Stash uses an sqlite database with WAL
mode enabled. This practically means that along with the main db file stash.go-sqlite
there can be a -shm
and a -wal
file present (more info). Even stopping Stash might leave some of these index files present so again DO NOT manually copy the database file.
The Backup or Download Backup tasks are the proper way to create a backup file.
Assuming you have properly created a backup file you can use it to restore your database if needed.
Info
The restore procedure uses the default stash-go.sqlite
filename, if you changed that when configuring Stash adjust accordingly.
The following steps are recommended when restoring a database file:
stash-go.sqlite
database file (along with the -shm
-wal
.journal
files if present).stash-go.sqlite
.stash-go.sqlite
file and that no -shm
-wal
.journal
files are present. You should now have Stash running with a working and restored database.
"},{"location":"guides/backup-and-restore-database/#advanced-troubleshooting","title":"Advanced troubleshooting","text":"If you get a database malformed message during upgrade or backup that probably means that the database is already corrupt. One way to get past that is to do a full export and check the error log. If there are not a lot of errors you can then try to do a full import and get a working db with minimal losses. As the full import is destructive proceed with caution. For cases like this it is better to ask for support.
"},{"location":"guides/importing-via-csv-using-gql-iterate/","title":"Bulk importing via CSV using gql-iterate","text":"If you want to add a collection of performers, tags, studios, etc, and you have a text/spreadsheet list of them, here's the walkthrough of how to do it via a simple CLI method.
"},{"location":"guides/importing-via-csv-using-gql-iterate/#step-1-install-gql-iterate","title":"Step 1: Install gql-iterate","text":"gql-iterate repository
npm install @efstajas/gql-iterate -g
or yarn add @efstajas/gql-iterate -g
For latest versions of NodeJS (14>) you need to go where you globally install your npm modules (AppData/Roaming/npm/node_modules/@efstajas/gql-iterate/bin) and add the following to the first line of the cli.js file.
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
See below for example versions of performers.gql and tags.gql samples that should work for you. Others can be figured out (with minor changes needeed) from stash/graphql/documents/mutations
These are NOT identical to the original files found above. Compare you'll see how they differ. This is very specific to be used for gql-iterate.
tags.gqlperformers.gql mutation TagCreate( \n $name: String!,\n $image: String) {\n tagCreate(input: { \n name: $name, \n image: $image \n }) {\n id\n }\n }\n
mutation PerformerCreate( \n $name: String!, \n $url: String, \n $gender: GenderEnum, \n $birthdate: String, \n $ethnicity: String, \n $country: String, \n $eye_color: String, \n $height: String, \n $measurements: String, \n $fake_tits: String, \n $career_length: String, \n $tattoos: String, \n $piercings: String, \n $aliases: String, \n $twitter: String, \n $instagram: String, \n $favorite: Boolean, \n $image: String) {\n performerCreate(input: { \n name: $name, \n url: $url, \n gender: $gender, \n birthdate: $birthdate, \n ethnicity: $ethnicity, \n country: $country, \n eye_color: $eye_color, \n height: $height, \n measurements: $measurements, \n fake_tits: $fake_tits, \n career_length: $career_length, \n tattoos: $tattoos,\n piercings: $piercings, \n aliases: $aliases, \n twitter: $twitter, \n instagram: $instagram, \n favorite: $favorite, \n image: $image }\n ) \n { id } \n }\n
If you have a suggested change, please add it below.
"},{"location":"guides/importing-via-csv-using-gql-iterate/#step-3-prepare-your-textfile-or-spreadsheet-into-a-csv","title":"Step 3: Prepare your textfile or spreadsheet into a CSV","text":"let's say you have a textfile with these performers (just names and eyecolors for a simple example) If you have a spreadsheet, add a first line with the column headers, you HAVE to provide all fields listed above in the first line, but you don't have to actually have data in them.
name,url,gender,birthdate,ethnicity,country,eye_color,height,measurements,fake_tits,career_length,tattoos,piercings,aliases,twitter,instagram,favorite,image
then add your data if text, or export as CSV if it's a spreadsheet (gender is not a string, see documentation in code, and favorite is a boolean, if you want to add those)
Alice,,,,,,blue\nBetty,,,,,,green\nCarter,,,,,,brown\n
the above lines all go into a file, like performerdata.csv
Gender is complicated due to Stash using GenderEnum.
For tags, you only need the tag title, and if desired, a url to a image
If you're unable to get this to work, then omit the favorite and image property from your CSV header, and from the performers.gql file.
"},{"location":"guides/importing-via-csv-using-gql-iterate/#step-4","title":"Step 4","text":"Note
Must use numerical IP instead of localhost.
Run this CLI command (assumes your files are in current directory and location for gql-interate is in your path)
gql-iterate --host http://_yourserverIP:portgoeshere_/graphql --input ./performerdata.csv --query ./performers.gql
It will run and add performers, it won't duplicate existing names, so you can run it multiple times if you want to add more names. Or delete something and readd it, if need be.
"},{"location":"guides/manually-editing-the-stash-sqlite3-database/","title":"Manually editing the Stash sqlite3 database","text":""},{"location":"guides/manually-editing-the-stash-sqlite3-database/#location","title":"Location","text":"The Stash Sqlite3 database file is located at ~/.stash/stash-go.sqlite
.
Before making changes to the Stash sqlite3 database - please make a backup first!
You can use the sqlite3
client to directly edit this file.
cd ~/.stash\nsqlite3 stash-go.sqlite\n
"},{"location":"guides/manually-editing-the-stash-sqlite3-database/#examples","title":"Examples","text":""},{"location":"guides/manually-editing-the-stash-sqlite3-database/#deleting-all-tags","title":"Deleting all tags","text":"If you need to delete all tags, you can use the following commands:
sqlite> DELETE FROM scenes_tags;\nsqlite> DELETE FROM tags;\n
Note
This will not work if you have Scene marker tags.
"},{"location":"guides/reverse-proxy/","title":"Reverse proxy","text":"The use of a reverse proxy for Stash is possible.
"},{"location":"guides/reverse-proxy/#general","title":"General","text":"Generally, the following headers will need to be set (check your proxy's documentation for how to configure).
See issue 134 for more information.
"},{"location":"guides/reverse-proxy/#using-a-url-prefix","title":"Using a URL prefix","text":"Stash also supports running under a URL prefix, in which case the the X-Forwarded-Prefix
header must also be set. The proxy also needs to remove the prefix from the requested URLs. For example, if you want your homepage to be accessible at http://example.domain.com/stash
, then you need to set X-Forwarded-Prefix: /stash
.
You can also set the host that will be served by Stash manually by adding an external_host:
setting in your Stash config.yml and assigning it the publicly accessible hostname, including the http://
or https://
. X-Forwarded-Prefix
will still need to be set if using a prefix.
external_host: http://example.domain.com\n
"},{"location":"guides/reverse-proxy/#server-configuration-examples","title":"Server Configuration Examples","text":""},{"location":"guides/reverse-proxy/#nginx","title":"Nginx","text":"location / {\n proxy_pass http://127.0.0.1:9999;\n\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_read_timeout 60000s;\n}\n
"},{"location":"guides/reverse-proxy/#nginx-docker-linuxserver-letsencrypt","title":"Nginx + Docker (Linuxserver Letsencrypt)","text":"If you are using the linuxserver letencrypt docker you can use create a stash.subdomain.conf
file in your proxy-confs
folder and use this as the config:
# make sure that your dns has a cname set for stash\n\nserver {\n listen 443 ssl;\n listen [::]:443 ssl;\n\n server_name stash.*;\n\n include /config/nginx/ssl.conf;\n\n client_max_body_size 0;\n\n # enable for ldap auth, fill in ldap details in ldap.conf\n #include /config/nginx/ldap.conf;\n\n location / {\n # enable the next two lines for http auth\n #auth_basic \"Restricted\";\n #auth_basic_user_file /config/nginx/.htpasswd;\n\n # enable the next two lines for ldap auth\n #auth_request /auth;\n #error_page 401 =200 /login;\n\n include /config/nginx/proxy.conf;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n resolver 127.0.0.11 valid=30s;\n set $upstream_app stash;\n set $upstream_port 9999;\n set $upstream_proto http;\n proxy_pass $upstream_proto://$upstream_app:$upstream_port;\n proxy_set_header Host $http_host;\n proxy_read_timeout 60000s;\n }\n}\n
"},{"location":"guides/reverse-proxy/#nginx-with-prefix","title":"Nginx with prefix","text":"An example for nginx
using the prefix /stash
:
location /stash/ {\n # Notice the trailing slash - this causes nginx to remove the /stash prefix from requested URLs\n proxy_pass http://192.168.0.1:9999/;\n\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Port $server_port;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_set_header X-Forwarded-Prefix /stash;\n proxy_read_timeout 60000s;\n}\n
"},{"location":"guides/reverse-proxy/#nginx-with-external_host","title":"Nginx with external_host","text":"Another example for nginx
:
In this case we are using stash.home
as our domain and 192.168.0.1
is stash's ip so edit acccordingly.
The external_host
configuration option should also be set, in this case external_host: http://stash.home
. Refer to external_host for more details.
server {\n listen 80;\n listen [::]:80;\n\n server_name stash.home;\n client_max_body_size 0;\n\n location / {\n proxy_pass http://192.168.0.1:9999;\n\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Port $server_port;\n proxy_set_header X-Forwarded-Proto $scheme;\n }\n}\n
"},{"location":"guides/reverse-proxy/#apache","title":"Apache","text":"# if using apache < 2.4.47, remove upgrade=websocket\nProxyPass \"/stash\" \"http://127.0.0.1:9999\" upgrade=websocket\nProxyPassReverse \"/stash\" \"http://127.0.0.1:9999\"\nRequestHeader setIfEmpty X-Forwarded-Prefix \"/stash\"\nProxyPreserveHost on\n\n# for name resolution\nServerAdmin admin@example.com\nServerName example.com\nServerAlias stash.example.com\n\n# to enable websockets for apache < 2.4.47\n#RewriteEngine on\n#RewriteCond %{HTTP:Upgrade} websocket [NC]\n#RewriteCond %{HTTP:Connection} upgrade [NC]\n#RewriteRule ^/?stash/(.*) \"ws://127.0.0.1:9999/$1\" [P,L]\n\n# to add SSL\nSSLEngine on\nSSLCertificateFile /path/to/cert.pem\nSSLCertificateKeyFile /path/to/cert.key\n
"},{"location":"guides/reverse-proxy/#prerequisites","title":"Prerequisites","text":"sudo a2enmod proxy\nsudo a2enmod proxy_http\nsudo a2enmod proxy_balancer\nsudo a2enmod lbmethod_byrequests\n\nsudo a2enmod rewrite\nsudo a2enmod headers\n\n# for SSL\nsudo a2enmod ssl\n
"},{"location":"guides/reverse-proxy/#caddy-v2","title":"Caddy v2","text":"stash.example.com {\n reverse_proxy 127.0.0.1:9999 {\n header_up Host {host}\n header_up X-Real-IP {remote_host}\n header_up X-Forwarded-Port {server_port}\n }\n}\n
The external_host
configuration option should also be set, in this case external_host: http://stash.home
. Refer to external_host for more details.
504
errors during stash db migration due to timeout. Adjusting the proxy_read_timeout
value ( proxy.conf
file in Letencrypt/Swag docker container)proxy.conf
file in the Letencrypt Unraid docker container for instance) as mentioned here should fix the issue.proxy_http_version 1.1;\nproxy_set_header Upgrade $http_upgrade;\nproxy_set_header Connection \"upgrade\";\n
"},{"location":"guides/reverse-proxy/#cloudflare-tunnel","title":"Cloudflare Tunnel","text":"Cloudflare Tunnels are not recommended since they throttle non-HTML traffic (which video falls under).
See Cloudflare blog post for more details.
"},{"location":"guides/run-cdp-on-truenas-scale/","title":"Run CDP on TrueNAS Scale","text":"Info
Written by WiiGe. Originally posted on stashapp/stash discussions1.
A way to use CDP scraper on TrueNAS Scale and install chromedp/headless-shell on TrueNAS Scale.
People using stash-app on TrueNAS Scale like me may face the problem that no supported CDP app by truecharts or truenas , and now I found a way to properly run chromedp/headless-shell.
This can be done by custom-app.
According to docker hub page of chromedp/headless-shell, we start container with docker run -d -p 9222:9222 --rm --name headless-shell --shm-size 2G chromedp/headless-shell
, but this's not enough for TrueNAS Scale which run everything with K3s.
In order to run a docker image on K3s, we need to warp docker image with custom-app, fill the Container Repository with chromedp/headless-shell
and Container Tag with latest
so that TrueNAS can pull the image for you.
As for the docker args docker run -d -p 9222:9222 --rm --name headless-shell --shm-size 2G chromedp/headless-shell
, we need to translate the args and env parameter into custom-app configuration. Under the Workload Settings section of custom-app configuration page, there will be a list of Extra Args, we put --name headless-shell --shm-size 2G
here in custom-app way.
But due to this issue, K3s will report an error of zygote: ERROR:zygote_host_impl_linux.cc(262)] Failed to adjust OOM score of renderer with pid 28: Permission denied (13)
, solution is simple - just offer extra args to disable it :--headless --disable-gpu --no-sandbox --no-zygote --disable-software-rasterizer --disable-dev-shm-usage
.
--remote-debugging-address=0.0.0.0 --remote-debugging-port=9222
is not needed because we will set port and ip on Networking and Services section for LoadBalancer (I am using 192.168.1.45 and 9222, change it for your own scenario).
The Networking section and the final Extra Args page should be like this:
and click Install button then your headless-shell will be good to go.
The last step: just fill stash's CDP setting with http://192.168.1.45:9222/json/version
(still, change ip:port for your own scenario), and now cdp should be running for you.
An extra note is Ingress section of custom-app, you may want to use chromedp/headless-shell remotely (e.g. accessing cdp by https://cdp.example.com/json/version), you need to modify the header of request with SetHeader function, see Host header is specified and is not an IP address or localhost. Obviously stash scraper do not support such operation, write your own scraper in this circumstances.
I just put the info I found together and share here, hope this page help more people who try to use CDP scraper on K3s-based OS.
https://github.com/stashapp/stash/discussions/4719 \u21a9
A regular scraper can only scrape information from webpages that are open to the public access. If you want to scrape a webpage that requires login or behind a paywall, you need to use the \"Visible CDP\" technique.
Normal CDP scraping will launch a headless chrome browser, which will not show up for any user interactions. \"Visible CDP\" turns the \"headless chrome\" into a \"visible\" instance.
driver:\n useCDP: true\n
chrome.exe --remote-debugging-port=9222
. This will launch a special Chrome instance that Stash Scrapers can control later on.http://localhost:9222/json/version
.stash-box is an open-source video indexing and metadata API server for porn developed by Stash team. It provides a crowdsourced database of metadata for adult performers, studios and scenes.
Stash has several ways to scrape from stash-box instances. From automatic to manual. Each has its own advantages and disadvantages.
Scan task and its options are applied when the content is being added to the database the first time.
Generate task and its options are applied when you want to generate additional things for content that is already in your database.
"},{"location":"guides/scraping-scenes-via-stash-box/#configure-stash-box-endpoint","title":"Configure stash-box endpoint","text":"Known stash-box instances
A list of public stash-box instances is available here.
Recommended to people that value accuracy the most. It can automatically go through scenes and match them based on perceptual hash, but object creation and verification is left to you and nothing is saved until you click Save.
Opposite the Source click on the to open configuration.
You can enable Mark as Organized on save which will apply Organized flag.
Organized flagOrganized flag has a technical purpose in addition to being able to be used in a filter. All objects marked as organized will be ignored by automatic tasks like Identify and Auto Tag.
Click on Scrape All and look through the results. Add missing objects and click Save.
For scenes that you clicked Save on, you can submit your file fingerprints (hashes) back to the instance to help improve the accuracy. Scroll to the top and click Submit x fingerprints.
FingerprintsAll fingerprints are tied to the user API key, no other information is sent to the stash-box instance. Privacy is paramount.
For people that want fully automatic option and don't mind some potential inaccuracies. The task will automatically go through all scenes and match them based on perceptual hash. You can also create all missing objects automatically. No manual verification is possible.
Warning
Task is irreversible, so it's a good idea to make a backup before running it.
Under Sources select a stash-box instance(s) you want to match against.
Info
Identify task iterates through sources until it finds a match, once it finds a match, it will ignore all other sources for that scene.
Configure default options that will apply to all sources (they can be overwritten for individual sources by clicking next to each source).
In addition to previous methods, there is also a completely manual way to match scenes individually.
You can use the ffprobe command to gather useful information about a video file:
ffprobe -show_format -show_streams big_buck_bunny.mkv\n
This can be useful for example, when filing bug reports, or discussing in chat.
"},{"location":"guides/troubleshooting-video-playback/#remuxing-files","title":"Remuxing files","text":"Another good test, is to see if remuxing the file into a new video file helps:
ffmpeg -i big_buck_bunny.mkv -c:v copy -c:a copy remuxed_file.mkv\n
"},{"location":"guides/troubleshooting-video-playback/#extracting-a-sample-of-a-video","title":"Extracting a sample of a video","text":"If you are asked for a sample of a video (e.g. for developers to analyse), you can use
ffmpeg -ss 120 -i big_buck_bunny.mkv -t 30 -c:v copy -c:a copy 30_second_sample.mkv\n
The above command starts at the 120-second marker, and takes a 30-second sample of the video file.
"},{"location":"in-app-manual/","title":"In-app manual","text":"Info
Stash internal help manual, mirrored from stashapp/stash/ui/v2.5/src/docs/en/Manual.
Internal links will be broken as a result, but will work correctly when browsing the Help section inside Stash.
"},{"location":"in-app-manual/browsing/","title":"Browsing","text":""},{"location":"in-app-manual/browsing/#querying-and-filtering","title":"Querying and Filtering","text":""},{"location":"in-app-manual/browsing/#keyword-searching","title":"Keyword searching","text":"The text field allows you to search using keywords. Keyword searching matches on different fields depending on the object type:
Type Fields searched Scene Title, Details, Path, OSHash, Checksum, Marker titles Image Title, Path, Checksum Group Title Marker Title, Scene title Gallery Title, Path, Checksum Performer Name, Aliases Studio Name, Aliases Tag Name, AliasesKeyword matching uses the following rules:
foo bar
matches scenes with both foo
and bar
in the title.or
keyword or symbol (|
) is used to match either fields. For example, foo or bar
(or foo | bar
) matches scenes with foo
or bar
in the title. Or sets can be combined. For example, foo or bar or baz xyz or zyx
matches scenes with one of foo
, bar
and baz
, and xyz
or zyx
.-
) is used to exclude terms. For example, foo -bar
matches scenes with foo
and excludes those with bar
. The not symbol cannot be combined with an or operand. That is, -foo or bar
will be interpreted to match -foo
or bar
. On the other hand, foo or bar -baz
will match foo
or bar
and exclude baz
.\"
) matches on that exact phrase. For example, \"foo bar\"
matches scenes with foo bar
in the title. Quotes may also be used to escape the keywords and symbols. For example, foo \"-bar\"
will match scenes with foo
and -bar
.\"foo bar\" or baz -\"xyz zyx\"
will match scenes with foo bar
or baz
, and exclude those with xyz zyx
.or
keywords or symbols at the start or end of a line will be treated literally. That is, or foo
will match scenes with or
and foo
.Filters can be accessed by clicking the filter button on the right side of the query text field.
Note that only one filter criterion per criterion type may be assigned.
"},{"location":"in-app-manual/browsing/#regex-modifiers","title":"Regex modifiers","text":"Some filters have regex modifier as an option. Regex modifiers are always case-sensitive.
"},{"location":"in-app-manual/browsing/#sorting-and-page-size","title":"Sorting and page size","text":"The current sorting field is shown next to the query text field, indicating the current sort field and order. The page size dropdown allows selecting from a standard set of objects per page, and allows setting a custom page size.
"},{"location":"in-app-manual/browsing/#saved-filters","title":"Saved filters","text":"Saved filters can be accessed with the bookmark button on the left of the query text field. The current filter can be saved by entering a filter name and clicking on the save button. Existing saved filters may be overwritten with the current filter by clicking on the save button next to the filter name. Saved filters may also be deleted by pressing the delete button next to the filter name.
Saved filters are sorted alphabetically by title with capitalized titles sorted first.
"},{"location":"in-app-manual/browsing/#default-filter","title":"Default filter","text":"The default filter for the top-level pages may be set to the current filter by clicking the Set as default
button in the saved filter menu.
Stash supports captioning with SRT and VTT files.
These files need to be named as follows:
"},{"location":"in-app-manual/captions/#scene","title":"Scene","text":"Where {language_code}
is defined by the ISO-6399-1 (2 letters) standard and ext
is the file extension. Captions files without a language code will be labeled as Unknown in the video player but will work fine.
Scenes with captions can be filtered with the captions
criterion.
Note: If the caption file was added after the scene was initially added during scan you will need to run a Selective Scan task for it to show up.
"},{"location":"in-app-manual/configuration/","title":"Configuration","text":""},{"location":"in-app-manual/configuration/#library","title":"Library","text":"This section allows you to add and remove directories from your library list. Files in these directories will be included when scanning. Files that are outside of these directories will be removed when running the Clean task.
\u26a0\ufe0f Note: Don't forget to click Save
after updating these directories!
Given a valid regex, files that match even partially are excluded during the Scan process and are not entered in the database. Also during the Clean task if these files exist in the DB they are removed from it and their generated files get deleted. Prior to matching both the filenames and patterns are converted to lower case so the match is case insensitive.
Regex patterns can be added in the config file or from the UI. If you add manually to the config file a restart is needed while from the UI you just need to click the Save button. When added through the config file directly special care must be given to double escape the \\
character.
There are 2 separate exclusion settings. One is for videos, another is for images/galleries.
Some examples:
\"sample\\.mp4$\"
will exclude all files ending in sample.mp4
. \"/\\.[[:word:]]+/\"
will exclude all hidden directories like /.directoryname/
.\"c:\\\\stash\\\\videos\\\\exclude\"
will exclude specific Windows directory c:\\stash\\videos\\exclude
.\"^/stash/videos/exclude/\"
will exclude all directories that match /stash/videos/exclude/
pattern.\"\\\\\\\\stash\\\\network\\\\share\\\\excl\\\\\"
will exclude specific Windows network path \\\\stash\\network\\share\\excl\\
.Note: If a directory is excluded for images and videos, then the directory will be excluded from scans completely.
There is a useful regex101 site that can help test and experiment with regexps.
"},{"location":"in-app-manual/configuration/#gallery-creation-from-folders","title":"Gallery creation from folders","text":"In the Library section you can find an option to create a gallery from each folder containing images. This will be applied on all libraries when activated, including the base folder of a library.
If you wish to apply this on a per folder basis, you can create a file called .nogallery or .forcegallery in a folder that should act different than this global setting.
This will either exclude the folder from becoming a gallery even if the setting is set, or create a gallery from the folder even if the setting is not set.
The file will only be recognized if written in lower case letters.
Files with a dot in front are handled as hidden in the Linux OS and Mac OS, so you will not see those files after creation on your system without setting your file manager accordingly.
"},{"location":"in-app-manual/configuration/#hashing-algorithms","title":"Hashing algorithms","text":"Stash identifies video files by calculating a hash of the file. There are two algorithms available for hashing: oshash
and MD5
. MD5
requires reading the entire file, and can therefore be slow, particularly when reading files over a network. oshash
(which uses OpenSubtitle's hashing algorithm) only reads 64k from each end of the file.
The hash is used to name the generated files such as preview images and videos, and sprite images.
By default, new systems have MD5 calculation disabled for optimal performance. Existing systems that are upgraded will have the oshash populated for each scene on the next scan.
"},{"location":"in-app-manual/configuration/#changing-the-hashing-algorithm","title":"Changing the hashing algorithm","text":"To change the file naming hash to oshash, all scenes must have their oshash values populated. oshash population is done automatically when scanning.
To change the file naming hash to MD5
, the MD5 must be populated for all scenes. To do this, Calculate MD5
for videos must be enabled and the library must be rescanned.
MD5 calculation may only be disabled if the file naming hash is set to oshash
.
After changing the file naming hash, any existing generated files will now be named incorrectly. This means that stash will not find them and may regenerate them if the Generate task
is used. To remedy this, run the Rename generated files
task, which will rename existing generated files to their correct names.
These instructions are for existing users whose systems will be defaulted to use and calculate MD5 checksums. Once completed, MD5 checksums will no longer be calculated when scanning, and oshash will be used for generated file naming. Existing calculated MD5 checksums will remain on scenes, but checksums will not be calculated for new scenes.
Calculate MD5
and select oshash
as file naming hash. Save the configuration.Rename generated files
migration button.This setting controls how many sub-tasks will be run in parallel during scanning and generation tasks. (See Tasks)
Auto-detection can be enabled by setting this to zero. This will calculate the number of parallel tasks to be logical cores/4 + 1.
This setting can be used to increase/decrease overall CPU utilisation in two scenarios:
Note: If this is set too high it will decrease overall performance and causes failures (out of memory).
"},{"location":"in-app-manual/configuration/#hardware-accelerated-live-transcoding","title":"Hardware accelerated live transcoding","text":"Hardware accelerated live transcoding can be enabled by setting the FFmpeg hardware encoding
setting. Stash outputs the supported hardware encoders to the log file on startup at the Info log level. If a given hardware encoder is not supported, it's error message is logged to the Debug log level for debugging purposes.
To stream using HLS (such as on Apple devices) or DASH, the Cache path must be set. This directory is used to store temporary files during the live-transcoding process. The Cache path can be set in the System settings page.
"},{"location":"in-app-manual/configuration/#ffmpeg-arguments","title":"ffmpeg arguments","text":"Additional arguments can be injected into ffmpeg when generating previews and sprites, and when live-transcoding videos.
The ffmpeg arguments configuration is split into Input
and Output
arguments. Input arguments are injected before the input file argument, and output arguments are injected before the output file argument.
Arguments are accepted as a list of strings. Each string is a separate argument. For example, a single argument of -foo bar
would be treated as a single argument \"-foo bar\"
. The correct way to pass this argument would be to split it into two separate arguments: \"-foo\", \"bar\"
.
Some websites require a legitimate User-Agent string when receiving requests, or they will be rejected. If entered, this string will be applied as the User-Agent
header value in http scrape requests.
Some scrapers require a Chrome instance to function correctly. If left empty, stash will attempt to find the Chrome executable in the path environment, and will fail if it cannot find one.
Chrome CDP path
can be set to a path to the chrome executable, or an http(s) address to remote chrome instance (for example: http://localhost:9222/json/version
).
By default, stash is not configured with any sort of password protection. To enable password protection, both Username
and Password
must be populated. Note that when entering a new username and password where none was set previously, the system will immediately request these credentials to log you in.
If password protection is enabled, you may also generate an API key. An API key is used by external systems to access your stash system without needing to login first.
External systems using the API key must set the ApiKey
header value to the configured API key in order to bypass the login requirement.
The logout button is situated in the upper-right part of the screen when you are logged in.
"},{"location":"in-app-manual/configuration/#recovering-from-a-forgotten-username-or-password","title":"Recovering from a forgotten username or password","text":"Stash saves login credentials in the config.yml file. You must reset both login and password if you have forgotten your password by doing the following: * Close your Stash process * Open the config.yml
file found in your Stash directory with a text editor * Delete the login
and password
lines from the file and save Stash authentication should now be reset with no authentication credentials.
These options are typically not exposed in the UI and must be changed manually in the config.yml
file.
custom_served_folders
A map of URLs to file system folders. See below. custom_ui_location
The file system folder where the UI files will be served from, instead of using the embedded UI. Empty to disable. Stash must be restarted to take effect. developer_options.extra_blob_paths
A list of alternative blob paths. These paths will be read for blob files. Blobs will not be written or deleted from these paths. Intended for developer use only. max_upload_size
Maximum file upload size for import files. Defaults to 1GB. theme_color
Sets the theme-color
property in the UI. gallery_cover_regex
The regex responsible for selecting images as gallery covers proxy
The url of a HTTP(S) proxy to be used when stash makes calls to online services Example: https://user:password@my.proxy:8080 no_proxy
A list of domains for which the proxy must not be used. Default is all local LAN: localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12 sequential_scanning
Modifies behaviour of the scanning functionality to generate support files (previews/sprites/phash) at the same time as fingerprinting/screenshotting. Useful when scanning cached remote files. The following environment variables are also supported:
Environment variable RemarksSTASH_SQLITE_CACHE_SIZE
Sets the SQLite cache size. See https://www.sqlite.org/pragma.html#pragma_cache_size. Default is -2000
which is 2MB."},{"location":"in-app-manual/configuration/#custom-served-folders","title":"Custom served folders","text":"Custom served folders are served when the server handles a request with the /custom
URL prefix. The following is an example configuration:
custom_served_folders:\n /: D:\\stash\\static\n /foo: D:\\bar\n
With the above configuration, a request for /custom/foo/bar.png
would serve D:\\bar\\bar.png
.
The /
entry matches anything that is not otherwise mapped by the other entries. For example, /custom/baz/xyz.png
would serve D:\\stash\\static\\baz\\xyz.png
.
Financial contributions are welcomed and are accepted using Open Collective.
"},{"location":"in-app-manual/contributing/#development-related","title":"Development-related","text":"The Stash backend is written in Go, using a SQLite database. The UI is written in Typescript, using React. Bug fixes, improvements and new features are welcomed. Please see the DEVELOPMENT.md file for details on how to get started. Assistance is available via our Discord.
"},{"location":"in-app-manual/contributing/#documentation","title":"Documentation","text":"Efforts to improve documentation in Stash helps new users and reduces the number of questions we have to field in Discord. Contributions to documentation are welcomed. While submitting documentation changes via GitHub pull requests is ideal, we will gladly accept submissions via GitHub issues or on Discord.
For those with web page experience, we also welcome contributions to our website (which as of writing is very undeveloped).
"},{"location":"in-app-manual/contributing/#testing-features-improvements-and-bug-fixes","title":"Testing features, improvements and bug fixes","text":"Testing is currently covered by a very small group, so new testers are welcomed. Being able to build Stash locally is ideal, but binaries for pull requests are also available.
First, you will need to be signed in to GitHub. Find and open the relevant pull request, and then click on the Checks
tab. On the right, there should be a button titled Artifacts
- click that, and you should get a dropdown with links to download binaries built from that pull request for Linux, Windows and macOS.
We welcome ideas for future improvements and features, and bug reports help everyone. These can all be found on GitHub.
"},{"location":"in-app-manual/contributing/#providing-support","title":"Providing support","text":"Offering support for new users on Discord is also welcomed.
"},{"location":"in-app-manual/deduplication/","title":"Dupe Checker","text":"The dupe checker searches your collection for scenes that are perceptually similar. This means that the files don't need to be identical, and will be identified even with different bitrates, resolutions, and intros/outros.
To achieve this stash needs to generate what's called a phash, or perceptual hash. Similar to sprite generation stash will generate a set of 25 images from fixed points in the scene. These images will be stitched together, and then hashed using the phash algorithm. The phash can then be used to find scenes that are the same or similar to others in the database. Phash generation can be run during scan, or as a separate task. Note that generation can take a while due to the work involved with extracting screenshots.
The dupe checker can be run with four different levels of accuracy. Exact
looks for scenes that have exactly the same phash. This is a fast and accurate operation that should not yield any false positives except in very rare cases. The other accuracy levels look for duplicate files within a set distance of each other. This means the scenes don't have exactly the same phash, but are very similar. High
and Medium
should still yield very good results with few or no false positives. Low
is likely to produce some false positives, but might still be useful for finding dupes.
Note that to generate a phash stash requires an uncorrupted file. If any errors are encountered during sprite generation the phash will not be generated. This is to prevent false positives.
"},{"location":"in-app-manual/images/","title":"Images and Galleries","text":"Images are the parts which make up galleries, but you can also have them be scanned independently. To declare an image part of a gallery, there are four ways:
You can add images to every gallery manually in the gallery detail page. Deleting can be done by selecting the according images in the same view and clicking on the minus next to the edit button.
For best results, images in zip file should be stored without compression (copy, store or no compression options depending on the software you use. Eg on linux: zip -0 -r gallery.zip foldertozip/
). This impacts heavily on the zip read performance.
If a filename of an image in the gallery zip file ends with cover.jpg
, it will be treated like a cover and presented first in the gallery view page and as a gallery cover in the gallery list view. If more than one images match the name the first one found in natural sort order is selected.
Images can also be clips/gifs. These are meant to be short video loops. Right now they are not possible in zipfiles. To declare video files to be images, there are two ways:
A clip/gif will be a stillframe in the wall and grid view by default. To view the loop, you can go into the Lightbox Carousel (e.g. by clicking on an image in the wall view) or the image detail page.
If you want the loop to be used as a preview on the wall and grid view, you will have to generate them. You can do this as you scan for the new clip file by activating Generate previews for image clips on the scan settings, or do it after by going to the Generated Content section in the task section of your settings, activating Image Clip Previews and clicking generate. This takes a while, as the files are transcoded.
"},{"location":"in-app-manual/interactive/","title":"Interactivity","text":"Stash currently supports syncing with Handy devices, using funscript files.
In order for stash to connect to your Handy device, the Handy Connection Key must be entered in Settings -> Interface.
Funscript files must be in the same directory as the matching video file and must have the same base name. For example, a funscript file for video.mp4
must be named video.funscript
. A scan must be run to update scenes with matching funscript files.
Scenes with funscript files can be filtered with the interactive
criterion.
Setting the language affects the formatting of numbers and dates.
"},{"location":"in-app-manual/interface/#scenemarker-wall-preview-type","title":"Scene/Marker Wall Preview Type","text":"The Scene Wall and Marker pages display scene preview videos (mp4) by default. This can be changed to animated image (webp) or static image.
\u26a0\ufe0f Note: scene/marker preview videos must be generated to see them in the applicable wall page if Video preview type is selected. Likewise, if Animated Image is selected, then Image Previews must be generated.
"},{"location":"in-app-manual/interface/#show-studios-as-text","title":"Show Studios as text","text":"By default, a scene's studio will be shown as an image overlay. Checking this option changes this to display studios as a text name instead.
"},{"location":"in-app-manual/interface/#scene-player-options","title":"Scene Player options","text":"By default, scene videos do not automatically start when navigating to the scenes page. Checking the \"Auto-start video\" option changes this to auto play scene videos.
The maximum loop duration option allows looping of shorter videos. Set this value to the maximum scene duration that scene videos should loop. Setting this to 0 disables this functionality.
"},{"location":"in-app-manual/interface/#activity-tracking","title":"Activity tracking","text":"The \"Track Activity\" option allows tracking of scene play count and duration, and sets the resume point when a scene video is not finished.
The \"Minimum Play Percent\" gives the minimum proportion of a video that must be played before the play count of the scene is incremented.
By default, when a scene has a resume point, the scene player will automatically seek to this point when the scene is played. Setting \"Always start video from beginning\" to true disables this behaviour.
"},{"location":"in-app-manual/interface/#custom-css","title":"Custom CSS","text":"The stash UI can be customised using custom CSS. See here for a community-curated set of CSS snippets to customise your UI.
Stash Plex Theme is a community created theme inspired by the popular Plex interface.
"},{"location":"in-app-manual/interface/#custom-javascript","title":"Custom Javascript","text":"Stash supports the injection of custom javascript to assist with theming or adding additional functionality. Be aware that bad Javascript could break the UI or worse.
"},{"location":"in-app-manual/interface/#custom-locales","title":"Custom Locales","text":"The localisation strings can be customised. The master list of default (en-GB) locale strings can be found here. The custom locale format is the same as this json file.
For example, to override the actions.add_directory
label (which is Add Directory
by default), you would have the following in the custom locale:
{\n \"actions\": {\n \"add_directory\": \"Some other description\"\n }\n}\n
"},{"location":"in-app-manual/interface/#custom-served-folders","title":"Custom served folders","text":"It is possible to expose specific folders to the UI. This configuration is performed manually in the config.yml
file only.
Custom served content is exposed via the /custom
URL path prefix.
For example, in the config.yml
file:
custom_served_folders:\n /: D:\\stash\\static\n /foo: D:\\bar\n
With the above configuration, a request for /custom/foo/bar.png
would return D:\\bar\\bar.png
. The /
entry matches anything that is not otherwise mapped by the other entries. For example, /custom/baz/xyz.png
would return D:\\stash\\static\\baz\\xyz.png
.
Applications for this include using static images in custom css, like the Plex theme. For example, using the following config:
custom_served_folders:\n /: <stash folder>\\custom\n
The background.png
and noise.png
files can be placed in the custom
folder, then in the custom css, the ./background.png
and ./noise.png
strings can be replaced with /custom/background.png
and /custom/noise.png
respectively.
Other applications are to add custom UIs to stash, accessible via /custom
.
Stash works by cataloging your media using the paths that you provide. Once you have configured the locations where your media is stored, you can click the Scan button in Settings -> Tasks
and stash will begin scanning and importing your media into its library.
For the best experience, it is recommended that after a scan is finished, that video previews and sprites are generated. You can do this in Settings -> Tasks
. Note that currently it is only possible to perform one task at a time and but there is a task queue, so the generate tasks should be performed after scan is complete.
Once your media is imported, you are ready to begin creating Performers, Studios and Tags, and curating your content!
"},{"location":"in-app-manual/keyboardshortcuts/","title":"Keyboard Shortcuts","text":""},{"location":"in-app-manual/keyboardshortcuts/#global-shortcuts","title":"Global shortcuts","text":"Keyboard sequence Action?
Display manual"},{"location":"in-app-manual/keyboardshortcuts/#global-navigation","title":"Global Navigation","text":"Keyboard sequence Target page g s
Scenes g i
Images g v
Groups g k
Markers g l
Galleries g p
Performers g u
Studios g t
Tags g z
Settings"},{"location":"in-app-manual/keyboardshortcuts/#query-page-shortcuts","title":"Query page shortcuts","text":"Keyboard sequence Action /
Focus search field / focus query field in filter dialog f
Show Add Filter dialog r
Reshuffle if sorted by random v g
Set view to grid v l
Set view to list v w
Set view to wall +
Increase zoom slider -
Decrease zoom slider \u2190
Previous page of results \u2192
Next page of results Shift + \u2190
Go to current results page -10 Shift + \u2192
Go to current results page +10 Ctrl + Home
Go to first page of results Ctrl + End
Go to last page of results s a
Select all on page s n
Unselect all e
Edit selected d d
Delete selected"},{"location":"in-app-manual/keyboardshortcuts/#scenes-page-shortcuts","title":"Scenes page shortcuts","text":"Keyboard sequence Action p r
Play random scene"},{"location":"in-app-manual/keyboardshortcuts/#scene-page-shortcuts","title":"Scene page shortcuts","text":"Keyboard sequence Action a
Details tab q
Queue tab k
Markers tab i
File info tab e
Edit tab h
History tab ,
Hide/Show sidebar .
Hide/Show scene scrubber o
Increment O-Counter p n
Play next scene in queue p p
Play previous scene in queue p r
Play random scene in queue Space
Play/pause player Enter
Play/pause player \u2190
Seek backwards by 10 seconds \u2192
Seek forwards by 10 seconds Shift + \u2190
Seek backwards by 5 seconds Shift + \u2192
Seek forwards by 5 seconds Ctrl/Alt + \u2190
Seek backwards by 1 minute Ctrl/Alt + \u2192
Seek forwards by 1 minute {1-9}
Seek to 10-90% duration [
Scrub backwards 10% duration ]
Scrub forwards 10% duration \u2191
Increase volume 10% \u2193
Decrease volume 10% m
Toggle mute l
A/B looping toggle. Press once to set start point. Press again to set end point. Press again to disable loop. Shift + l
Toggle looping of scene when it's over"},{"location":"in-app-manual/keyboardshortcuts/#scene-markers-tab-shortcuts","title":"Scene Markers tab shortcuts","text":"Keyboard sequence Action n
Display Create Markers dialog"},{"location":"in-app-manual/keyboardshortcuts/#edit-scene-tab-shortcuts","title":"Edit Scene tab shortcuts","text":"Keyboard sequence Action r {1-5}
Set rating (stars) r 0
Unset rating (stars) r {0-9} {0-9}
Set rating (decimal - 00
for 10.0
) r `
Unset rating (decimal) s s
Save Scene d d
Delete Scene Ctrl + v
Paste Scene cover"},{"location":"in-app-manual/keyboardshortcuts/#groups-page-shortcuts","title":"Groups Page shortcuts","text":"Keyboard sequence Action n
New Group"},{"location":"in-app-manual/keyboardshortcuts/#group-page-shortcuts","title":"Group Page shortcuts","text":"Keyboard sequence Action e
Edit Group s s
Save Group d d
Delete Group r {1-5}
[Edit mode] Set rating (stars) r 0
[Edit mode] Unset rating (stars) r {0-9} {0-9}
[Edit mode] Set rating (decimal - r 0 0
for 10.0
) r `
[Edit mode] Unset rating (decimal) ,
Expand/Collapse Details Ctrl + v
Paste Group image"},{"location":"in-app-manual/keyboardshortcuts/#markers-page-shortcuts","title":"Markers Page shortcuts","text":"Keyboard sequence Action p r
Play random marker"},{"location":"in-app-manual/keyboardshortcuts/#performers-page-shortcuts","title":"Performers Page shortcuts","text":"Keyboard sequence Action n
New Performer p r
Open random Performer"},{"location":"in-app-manual/keyboardshortcuts/#performer-page-shortcuts","title":"Performer Page shortcuts","text":"Keyboard sequence Action c
Scenes tab e
Edit tab o
Operations tab f
Toggle favourite ,
Expand/Collapse Details"},{"location":"in-app-manual/keyboardshortcuts/#edit-performer-tab-shortcuts","title":"Edit Performer tab shortcuts","text":"Keyboard sequence Action s s
Save Performer d d
Delete Performer Ctrl + v
Paste Performer image"},{"location":"in-app-manual/keyboardshortcuts/#studios-page-shortcuts","title":"Studios Page shortcuts","text":"Keyboard sequence Action n
New Studio"},{"location":"in-app-manual/keyboardshortcuts/#studio-page-shortcuts","title":"Studio Page shortcuts","text":"Keyboard sequence Action e
Edit Studio s s
Save Studio d d
Delete Studio ,
Expand/Collapse Details Ctrl + v
Paste Studio image"},{"location":"in-app-manual/keyboardshortcuts/#tags-page-shortcuts","title":"Tags Page shortcuts","text":"Keyboard sequence Action n
New Tag"},{"location":"in-app-manual/keyboardshortcuts/#tag-page-shortcuts","title":"Tag Page shortcuts","text":"Keyboard sequence Action e
Edit Tag s s
Save Tag d d
Delete Tag ,
Expand/Collapse Details Ctrl + v
Paste Tag image"},{"location":"in-app-manual/tagger/","title":"Scene Tagger","text":"Stash can be integrated with stash-box which acts as a centralized metadata database. This is in the early stages of development but can be used for fingerprint/keyword lookups and automated tagging of performers and scenes. The batch tagging interface can be accessed from the scene view. For more information join our Discord.
"},{"location":"in-app-manual/tagger/#searching","title":"Searching","text":"The fingerprint search matches your current selection of files against the remote stash-box instance. Any scenes with a matching fingerprint will be returned, although there is currently no validation of fingerprints so it\u2019s recommended to double-check the validity before saving.
If no fingerprint match is found it\u2019s possible to search by keywords. The search works by matching the query against a scene\u2019s title, release date, studio name, and performer names. By default the tagger uses metadata set on the file, or parses the filename, this can be changed in the config.
An important thing to note is that it only returns a match if all query terms are a match. As an example, if a scene is titled \"A Trip to the Mall\"
with the performer \"Jane Doe\"
, a search for \"Trip to the Mall 1080p\"
will not match, however \"trip mall doe\"
would. Usually a few pieces of info is enough, for instance performer name + release date or studio name. To avoid common non-related keywords you can add them to the blacklist in the tagger config. Any items in the blacklist are stripped out of the query.
When a scene is matched stash will try to match the studio and performers against your local studios and performers. If you have previously matched them, they will automatically be selected. If not you either have to select the correct performer/studio from the dropdown, choose create to create a new entity, or skip to ignore it.
Once a scene is saved the scene and the matched studio/performers will have the stash_id
saved which will then be used for future tagging.
By default male performers are not shown, this can be enabled in the tagger config. Likewise scene tags are by default not saved. They can be set to either merge with existing tags on the scene, or overwrite them. It is not recommended to set tags currently since they are hard to deduplicate and can litter your data.
"},{"location":"in-app-manual/tagger/#submitting-fingerprints","title":"Submitting fingerprints","text":"After a scene is saved you will prompted to submit the fingerprint back to the stash-box instance. This is optional, but can be helpful for other users who have an identical copy who will then be able to match via the fingerprint search. No other information than the stash_id
and file fingerprint is submitted.
Stash supports plugins that can do the following: - perform custom tasks when triggered by the user from the Tasks page - perform custom tasks when triggered from specific events - add custom CSS to the UI - add custom JavaScript to the UI
Plugin tasks can be implemented using embedded Javascript, or by calling an external binary.
\u26a0\ufe0f Note: Plugin support is still experimental and is likely to change.
"},{"location":"in-app-manual/plugins/#managing-plugins","title":"Managing Plugins","text":"Plugins can be installed and managed from the Settings > Plugins
page.
Scrapers are installed using the Available Plugins
section. This section allows configuring sources from which to install plugins. The Community (stable)
source is configured by default. This source contains plugins for the current stable version of stash.
These are the plugin sources maintained by the stashapp organisation:
Name Source URL Recommended Local Path Notes Community (stable)https://stashapp.github.io/CommunityScripts/stable/index.yml
stable
For the current stable version of stash. Community (develop) https://stashapp.github.io/CommunityScripts/develop/index.yml
develop
For the develop version of stash. Installed plugins can be updated or uninstalled from the Installed Plugins
section.
The source URL must return a yaml file containing all the available packages for the source. An example source yaml file looks like the following:
- id: <package id>\n name: <package name>\n version: <version>\n date: <date>\n requires:\n - <ids of packages required by this package (optional)>\n - ...\n path: <path to package zip file>\n sha256: <sha256 of zip>\n metadata:\n <optional key/value pairs for extra information>\n- ...\n
Path can be a relative path to the zip file or an external URL.
"},{"location":"in-app-manual/plugins/#adding-plugins-manually","title":"Adding plugins manually","text":"By default, Stash looks for plugin configurations in the plugins
sub-directory of the directory where the stash config.yml
is read. This will either be the $HOME/.stash
directory or the current working directory.
Plugins are added by adding configuration yaml files (format: pluginName.yml
) to the plugins
directory.
Loaded plugins can be viewed in the Plugins page of the Settings. After plugins are added, removed or edited while stash is running, they can be reloaded by clicking Reload Plugins
button.
Plugins provide tasks which can be run from the Tasks page.
"},{"location":"in-app-manual/plugins/#creating-plugins","title":"Creating plugins","text":""},{"location":"in-app-manual/plugins/#plugin-configuration-file-format","title":"Plugin configuration file format","text":"The basic structure of a plugin configuration file is as follows:
name: <plugin name>\ndescription: <optional description of the plugin>\nversion: <optional version tag>\nurl: <optional url>\n\nui:\n # optional list of css files to include in the UI\n css:\n - <path to css file>\n\n # optional list of js files to include in the UI\n javascript:\n - <path to javascript file>\n\n # optional list of plugin IDs to load prior to this plugin\n requires:\n - <plugin ID>\n\n # optional list of assets \n assets:\n urlPrefix: fsLocation\n ...\n\n # content-security policy overrides\n csp:\n script-src:\n - http://alloweddomain.com\n\n style-src:\n - http://alloweddomain.com\n\n connect-src:\n - http://alloweddomain.com\n\n # map of setting names to be displayed in the plugins page in the UI\n settings:\n # internal name\n foo:\n # name to display in the UI\n displayName: Foo\n # type of the attribute to show in the UI\n # can be BOOLEAN, NUMBER, or STRING\n type: BOOLEAN\n\n# the following are used for plugin tasks only\nexec:\n - ...\ninterface: [interface type]\nerrLog: [one of none trace, debug, info, warning, error]\ntasks:\n - ...\n
The name
, description
, version
and url
fields are displayed on the plugins page.
The exec
, interface
, errLog
and tasks
fields are used only for plugins with tasks.
The settings
field is used to display plugin settings on the plugins page. Plugin settings can also be set using the graphql mutation configurePlugin
- the settings set this way do not need to be specified in the settings
field unless they are to be displayed in the stock plugin settings UI.
The css
and javascript
field values may be relative paths to the plugin configuration file, or may be full external URLs.
The requires
field is a list of plugin IDs which must have their javascript/css files loaded before this plugins javascript/css files.
The assets
field is a map of URL prefixes to filesystem paths relative to the plugin configuration file. Assets are mounted to the /plugin/{pluginID}/assets
path.
As an example, for a plugin with id foo
with the following assets
value:
assets:\n foo: bar\n /: .\n
The following URLs will be mapped to these locations: /plugin/foo/assets/foo/file.txt
-> {pluginDir}/bar/file.txt
/plugin/foo/assets/file.txt
-> {pluginDir}/file.txt
/plugin/foo/assets/bar/file.txt
-> {pluginDir}/bar/file.txt
(via the /
entry) Mappings that try to go outside of the directory containing the plugin configuration file will be ignored.
The csp
field contains overrides to the content security policies. The URLs in script-src
, style-src
and connect-src
will be added to the applicable content security policy.
See External Plugins for details for making plugins with external tasks.
See Embedded Plugins for details for making plugins with embedded tasks.
"},{"location":"in-app-manual/plugins/#plugin-task-input","title":"Plugin task input","text":"Plugin tasks may accept an input from the stash server. This input is encoded according to the interface, and has the following structure (presented here in JSON format):
{\n \"server_connection\": {\n \"Scheme\": \"http\",\n \"Port\": 9999,\n \"SessionCookie\": {\n \"Name\":\"session\",\n \"Value\":\"cookie-value\",\n \"Path\":\"\",\n \"Domain\":\"\",\n \"Expires\":\"0001-01-01T00:00:00Z\",\n \"RawExpires\":\"\",\n \"MaxAge\":0,\n \"Secure\":false,\n \"HttpOnly\":false,\n \"SameSite\":0,\n \"Raw\":\"\",\n \"Unparsed\":null\n },\n \"Dir\": <path to stash config directory>,\n \"PluginDir\": <path to plugin config directory>,\n },\n \"args\": {\n \"argKey\": \"argValue\"\n }\n}\n
The server_connection
field contains all the information needed for a plugin to access the parent stash server, if necessary.
Plugin task output is expected in the following structure (presented here as JSON format):
{\n \"error\": <optional error string>\n \"output\": <anything>\n}\n
The error
field is logged in stash at the error
log level if present. The output
is written at the debug
log level.
Tasks are configured using the following structure:
tasks:\n - name: <operation name>\n description: <optional description>\n defaultArgs:\n argKey: argValue\n
A plugin configuration may contain multiple tasks.
The defaultArgs
field is used to add inputs to the plugin input sent to the plugin.
Stash supports executing plugin operations via triggering of a hook during a stash operation.
Hooks are configured using a similar structure to tasks:
hooks:\n - name: <operation name>\n description: <optional description>\n triggeredBy:\n - <trigger types>...\n defaultArgs:\n argKey: argValue\n
Note: it is possible for hooks to trigger eachother or themselves if they perform mutations. For safety, hooks will not be triggered if they have already been triggered in the context of the operation. Stash uses cookies to track this context, so it's important for plugins to send cookies when performing operations.
"},{"location":"in-app-manual/plugins/#trigger-types","title":"Trigger types","text":"Trigger types use the following format: <object type>.<operation>.<hook type>
For example, a post-hook on a scene create operation will be Scene.Create.Post
.
The following object types are supported:
Scene
SceneMarker
Image
Gallery
Group
Performer
Studio
Tag
The following operations are supported:
Create
Update
Destroy
Merge
(for Tag
only)Currently, only Post
hook types are supported. These are executed after the operation has completed and the transaction is committed.
Plugin tasks triggered by a hook include an argument named hookContext
in the args
object structure. The hookContext
is structured as follows:
{\n \"id\": <object id>,\n \"type\": <trigger type>,\n \"input\": <operation input>,\n \"inputFields\": <fields included in input>\n}\n
The input
field contains the JSON graphql input passed to the original operation. This will differ between operations. For hooks triggered by operations in a scan or clean, the input will be nil. inputFields
is populated in update operations to indicate which fields were passed to the operation, to differentiate between missing and empty fields.
For example, here is the args
values for a Scene update operation:
{\n \"hookContext\": {\n \"type\":\"Scene.Update.Post\",\n \"id\":45,\n \"input\":{\n \"clientMutationId\":null,\n \"id\":\"45\",\n \"title\":null,\n \"details\":null,\n \"url\":null,\n \"date\":null,\n \"rating\":null,\n \"organized\":null,\n \"studio_id\":null,\n \"gallery_ids\":null,\n \"performer_ids\":null,\n \"groups\":null,\n \"tag_ids\":[\"21\"],\n \"cover_image\":null,\n \"stash_ids\":null\n },\n \"inputFields\":[\n \"tag_ids\",\n \"id\"\n ]\n }\n}\n
"},{"location":"in-app-manual/plugins/embeddedplugins/","title":"Embedded Plugin Tasks","text":"Embedded plugin tasks are executed within the stash process using a scripting system.
"},{"location":"in-app-manual/plugins/embeddedplugins/#supported-script-languages","title":"Supported script languages","text":"Stash currently supports Javascript embedded plugin tasks using goja.
"},{"location":"in-app-manual/plugins/embeddedplugins/#javascript-plugins","title":"Javascript plugins","text":""},{"location":"in-app-manual/plugins/embeddedplugins/#plugin-input","title":"Plugin input","text":"The input is provided to Javascript plugin tasks using the input
global variable, and is an object based on the structure provided in the Plugin input
section of the Plugins page. Note that the server_connection
field should not be necessary in most embedded plugins.
The output of a Javascript plugin task is derived from the evaluated value of the script. The output should conform to the structure provided in the Plugin output
section of the Plugins page.
There are a number of ways to return the plugin output:
"},{"location":"in-app-manual/plugins/embeddedplugins/#example-1","title":"Example #1","text":"(function() {\n return {\n Output: \"ok\"\n };\n})();\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#example-2","title":"Example #2","text":"function main() {\n return {\n Output: \"ok\"\n };\n}\n\nmain();\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#example-3","title":"Example #3","text":"var output = {\n Output: \"ok\"\n};\n\noutput;\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#logging","title":"Logging","text":"See the Javascript API
section below on how to log with Javascript plugins.
For embedded plugins, the exec
field is a list with the first element being the path to the Javascript file that will be executed. It is expected that the path to the Javascript file is relative to the directory of the plugin configuration file.
For embedded plugins, the interface
field must be set to one of the following values: * js
Stash provides the following API for logging in Javascript plugins:
Method Descriptionlog.Trace(<string>)
Log with the trace
log level. log.Debug(<string>)
Log with the debug
log level. log.Info(<string>)
Log with the info
log level. log.Warn(<string>)
Log with the warn
log level. log.Error(<string>)
Log with the error
log level. log.Progress(<float between 0 and 1>)
Sets the progress of the plugin task, as a float, where 0
represents 0% and 1
represents 100%."},{"location":"in-app-manual/plugins/embeddedplugins/#gql","title":"GQL","text":"Stash provides the following API for communicating with stash using the graphql interface:
Method Descriptiongql.Do(<query/mutation string>, <variables object>)
Executes a graphql query/mutation on the stash server. Returns an object in the same way as a graphql query does."},{"location":"in-app-manual/plugins/embeddedplugins/#example","title":"Example","text":"// creates a tag\nvar mutation = \"\\\nmutation tagCreate($input: TagCreateInput!) {\\\n tagCreate(input: $input) {\\\n id\\\n }\\\n}\";\n\nvar variables = {\n input: {\n 'name': tagName\n }\n};\n\nresult = gql.Do(mutation, variables);\nlog.Info(\"tag id = \" + result.tagCreate.id);\n
"},{"location":"in-app-manual/plugins/embeddedplugins/#utility-functions","title":"Utility functions","text":"Stash provides the following API for utility functions:
Method Descriptionutil.Sleep(<milliseconds>)
Suspends the current thread for the specified duration."},{"location":"in-app-manual/plugins/externalplugins/","title":"External Plugin Tasks","text":"External plugin tasks are executed by running an external binary.
"},{"location":"in-app-manual/plugins/externalplugins/#plugin-interfaces","title":"Plugin interfaces","text":"Stash communicates with external plugin tasks using an interface. Stash currently supports RPC and raw interface types.
"},{"location":"in-app-manual/plugins/externalplugins/#rpc-interface","title":"RPC interface","text":"The RPC interface uses JSON-RPC to communicate with the plugin process. A golang plugin utilising the RPC interface is available in the stash source code under pkg/plugin/examples/gorpc
. RPC plugins are expected to provide an interface that fulfils the RPCRunner
interface in pkg/plugin/common
.
RPC plugins are expected to accept requests asynchronously.
When stopping an RPC plugin task, the stash server sends a stop request to the plugin and relies on the plugin to stop itself.
"},{"location":"in-app-manual/plugins/externalplugins/#raw-interface","title":"Raw interface","text":"Raw interface plugins are not required to conform to any particular interface. The stash server will send the plugin input to the plugin process via its stdin stream, encoded as JSON. Raw interface plugins are not required to read the input.
The stash server reads stdout for the plugin's output. If the output can be decoded as a JSON representation of the plugin output data structure then it will do so. If not, it will treat the entire stdout string as the plugin's output.
When stopping a raw plugin task, the stash server kills the spawned process without warning or signals.
"},{"location":"in-app-manual/plugins/externalplugins/#logging","title":"Logging","text":"External plugins may log to the stash server by writing to stderr. By default, data written to stderr will be logged by stash at the error
level. This default behaviour can be changed by setting the errLog
field in the plugin configuration file.
Plugins can log for specific levels or log progress by prefixing the output string with special control characters. See pkg/plugin/common/log
for how this is done in go.
For external plugin tasks, the exec
field is a list with the first element being the binary that will be executed, and the subsequent elements are the arguments passed. The execution process will search the path for the binary, then will attempt to find the program in the same directory as the plugin configuration file. The exe
extension is not necessary on Windows systems.
\u26a0\ufe0f Note: The plugin execution process sets the current working directory to that of the stash process.
Arguments can include the plugin's directory with the special string {pluginDir}
.
For example, if the plugin executable my_plugin
is placed in the plugins
subdirectory and requires arguments foo
and bar
, then the exec
part of the configuration would look like the following:
exec:\n - my_plugin\n - foo\n - bar\n
Another example might use a python script to execute the plugin. Assuming the python script foo.py
is placed in the same directory as the plugin config file, the exec
fragment would look like the following:
exec:\n - python\n - {pluginDir}/foo.py\n
"},{"location":"in-app-manual/plugins/externalplugins/#interface","title":"interface","text":"For external plugin tasks, the interface
field must be set to one of the following values: * rpc
* raw
See the Plugin interfaces
section above for details on these interface types.
The interface
field defaults to raw
if not provided.
The errLog
field tells stash what the default log level should be when the plugin outputs to stderr without encoding a log level. It defaults to the error
level if no provided. This field is not necessary if the plugin outputs logging with the appropriate encoding. See the Logging
section above for details.
In addition to the standard task configuration, external tasks may be configured with an optional execArgs
field to add extra parameters to the execution arguments for the task.
For example:
tasks:\n - name: <operation name>\n description: <optional description>\n execArgs:\n - <arg to add to the exec line>\n
"},{"location":"in-app-manual/plugins/uipluginapi/","title":"UI Plugin API","text":"The PluginApi
object is a global object in the window
object.
PluginApi
is considered experimental and is subject to change without notice. This documentation covers only the plugin-specific API. It does not necessarily cover the core UI API. Information on these methods should be referenced in the UI source code.
An example using various aspects of PluginApi
may be found in the source code under pkg/plugin/examples/react-component
.
React
","text":"An instance of the React library.
"},{"location":"in-app-manual/plugins/uipluginapi/#reactdom","title":"ReactDOM
","text":"An instance of the ReactDOM library.
"},{"location":"in-app-manual/plugins/uipluginapi/#gql","title":"GQL
","text":"This namespace contains the generated graphql client interface. This is a low-level interface. In many cases, StashService
should be used instead.
libraries
","text":"libraries
provides access to the following UI libraries: - ReactRouterDOM
- Bootstrap
- Apollo
- Intl
- FontAwesomeRegular
- FontAwesomeSolid
- Mousetrap
- MousetrapPause
register
","text":"This namespace contains methods used to register page routes and components.
"},{"location":"in-app-manual/plugins/uipluginapi/#pluginapiregisterroute","title":"PluginApi.register.route
","text":"Registers a route in the React Router.
Parameter Type Descriptionpath
string
The path to register. This should generally use the /plugin/
prefix. component
React.FC
A React function component that will be rendered when the route is loaded. Returns void
.
PluginApi.register.component
","text":"Registers a component to be used by plugins. The component will be available in the components
namespace.
name
string
The name of the component to register. This should be unique and should ideally be prefixed with plugin-
. component
React.FC
A React function component. Returns void
.
components
","text":"This namespace contains all of the components available to plugins. These include a selection of core components and components registered using PluginApi.register.component
.
utils
","text":"This namespace provides access to the NavUtils
and StashService
namespaces. It also provides access to the loadComponents
method.
PluginApi.utils.loadComponents
","text":"Due to code splitting, some components may not be loaded and available when a plugin page is rendered. loadComponents
loads all of the components that a plugin page may require.
In general, PluginApi.hooks.useLoadComponents
hook should be used instead.
components
Promise[]
The list of components to load. These values should come from the PluginApi.loadableComponents
namespace. Returns a Promise<void>
that resolves when all of the components have been loaded.
hooks
","text":"This namespace provides access to the following core utility hooks: - useSpriteInfo
- useToast
It also provides plugin-specific hooks.
"},{"location":"in-app-manual/plugins/uipluginapi/#pluginapihooksuseloadcomponents","title":"PluginApi.hooks.useLoadComponents
","text":"This is a hook used to load components, using the PluginApi.utils.loadComponents
method.
components
Promise[]
The list of components to load. These values should come from the PluginApi.loadableComponents
namespace. Returns a boolean
which will be true
if the components are loading.
loadableComponents
","text":"This namespace contains all of the components that may need to be loaded using the loadComponents
method. Components are added to this namespace as needed. Please make a development request if a required component is not in this namespace.
patch
","text":"This namespace provides methods to patch components to change their behaviour.
"},{"location":"in-app-manual/plugins/uipluginapi/#pluginapipatchbefore","title":"PluginApi.patch.before
","text":"Registers a before function. A before function is called prior to calling a component's render function. It accepts the same parameters as the component's render function, and is expected to return a list of new arguments that will be passed to the render.
Parameter Type Descriptioncomponent
string
The name of the component to patch. fn
Function
The before function. It accepts the same arguments as the component render function and is expected to return a list of arguments to pass to the render function. Returns void
.
PluginApi.patch.instead
","text":"Registers a replacement function for a component. The provided function will be called with the arguments passed to the original render function, plus the next render function as the last argument. Replacement functions will be called in the order that they are registered. If a replacement function does not call the next render function then the following replacement functions will not be called or applied.
Parameter Type Descriptioncomponent
string
The name of the component to patch. fn
Function
The replacement function. It accepts the same arguments as the original render function, plus the next render function, and is expected to return the replacement component. Returns void
.
PluginApi.patch.after
","text":"Registers an after function. An after function is called after the render function of the component. It accepts the arguments passed to the original render function, plus the result of the original render function. It is expected to return the rendered component.
Parameter Type Descriptioncomponent
string
The name of the component to patch. fn
Function
The after function. It accepts the same arguments as the original render function, plus the result of the original render function, and is expected to return the rendered component. Returns void
.
App
BooleanSetting
ChangeButtonSetting
CompressedPerformerDetailsPanel
ConstantSetting
CountrySelect
DateInput
FolderSelect
GalleryIDSelect
GallerySelect
GallerySelect.sort
Icon
ImageDetailPanel
ModalSetting
GroupIDSelect
GroupSelect
GroupSelect.sort
NumberSetting
PerformerDetailsPanel
PerformerDetailsPanel.DetailGroup
PerformerIDSelect
PerformerSelect
PerformerSelect.sort
PluginRoutes
SceneCard
SceneCard.Details
SceneCard.Image
SceneCard.Overlays
SceneCard.Popovers
SceneIDSelect
SceneSelect
SceneSelect.sort
SelectSetting
Setting
SettingModal
StringSetting
StringListSetting
StudioIDSelect
StudioSelect
StudioSelect.sort
TagIDSelect
TagSelect
TagSelect.sort
PluginSettings
Setting
SettingGroup
PluginApi.Event
","text":"Allows plugins to listen for Stash's events.
PluginApi.Event.addEventListener(\"stash:location\", (e) => console.log(\"Page Changed\", e.detail.data.location.pathname))\n
"},{"location":"in-app-manual/scraping/","title":"Metadata Scraping","text":"Stash supports scraping of metadata from various external sources.
"},{"location":"in-app-manual/scraping/#scraper-types","title":"Scraper Types","text":"Type Description Fragment Uses existing metadata for an Item and match it to a result from a metadata source. Search/By Name Uses a provided query string to search a metadata source for a list of matches for the user to pick from. URL Extracts metadata from a given URL."},{"location":"in-app-manual/scraping/#supported-scrapers","title":"Supported Scrapers","text":"Fragment Search URL gallery \u2714\ufe0f \u2714\ufe0f group \u2714\ufe0f performer \u2714\ufe0f \u2714\ufe0f scene \u2714\ufe0f \u2714\ufe0f \u2714\ufe0f"},{"location":"in-app-manual/scraping/#included-scrapers","title":"Included Scrapers","text":"Stash provides the following built-in scrapers:
Scraper Description Freeonessearch
Performer scraper for freeones.xxx. Auto Tag Scene fragment
scraper that matches existing performers, studio and tags using the filename."},{"location":"in-app-manual/scraping/#managing-scrapers","title":"Managing Scrapers","text":"Scrapers can be installed and managed from the Settings > Metadata Providers
page.
Scrapers are installed using the Available Scrapers
section. This section allows configuring sources from which to install scrapers. The Community (stable)
source is configured by default. This source contains scrapers for the current stable version of stash.
These are the scraper sources maintained by the stashapp organisation:
Name Source URL Recommended Local Path Notes Community (stable)https://stashapp.github.io/CommunityScrapers/stable/index.yml
stable
For the current stable version of stash. Community (develop) https://stashapp.github.io/CommunityScrapers/develop/index.yml
develop
For the develop version of stash. Installed scrapers can be updated or uninstalled from the Installed Scrapers
section.
The source URL must return a yaml file containing all the available packages for the source. An example source yaml file looks like the following:
- id: <package id>\n name: <package name>\n version: <version>\n date: <date>\n requires:\n - <ids of packages required by this package (optional)>\n - ...\n path: <path to package zip file>\n sha256: <sha256 of zip>\n metadata:\n <optional key/value pairs for extra information>\n- ...\n
Path can be a relative path to the zip file or an external URL.
"},{"location":"in-app-manual/scraping/#adding-scrapers-manually","title":"Adding Scrapers manually","text":"By default, Stash looks for scraper configurations in the scrapers
sub-directory of the directory where the stash config.yml
is read. This will either be the $HOME/.stash
directory or the current working directory.
Scrapers are added manually by placing yaml configuration files (format: scrapername.yml
) in the scrapers
directory.
\u26a0\ufe0f Note: Some scrapers may require more than just the yaml file, consult the individual scraper documentation
After the yaml files are added, removed or edited while stash is running, they can be reloaded going to Settings > Metadata Providers > Scrapers
and clicking Reload Scrapers
.
Click on the Scrape With...
button in the edit
tab of an item, then select the scraper you wish to use.
Click on the \ud83d\udd0d button in the edit
tab of an item. You will be presented with a search dialog with a pre-populated query to search for, after searching you will be presented with a list of results to pick from
Enter the URL in the edit
tab of an Item. If a scraper is installed that supports that url, then a button will appear to scrape the metadata.
The Tagger view is accessed from the scenes page. It allows the user to run scrapers on all items on the current page. The Tagger presents the user with potential matches for an item from a selected stash-box instance or metadata source if supported. The user needs to select the correct metadata information to save.
When used in combination with stash-box, the user can optionally submit scene fingerprints to contribute to a stash-box instance. A scene fingerprint consists of any generated hashes (phash
, oshash
, md5
) and the scene duration. Fingerprint submissions are associated with your stash-box account. Submitting fingerprints assists others in matching their files, because stash-box returns a count of matching user submitted fingerprints with every potential match.
This task iterates through your Scenes and attempts to identify the scene using a selection of scraping sources. This task can be found under Settings -> Tasks -> \"Identify...\" (Button)
. For more information see the Tasks > Identify page.
Scrapers can be contributed to the community by creating a PR in this repository.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scraper-configuration-file-format","title":"Scraper configuration file format","text":"name: <site>\nperformerByName:\n <single scraper config>\nperformerByFragment:\n <single scraper config>\nperformerByURL:\n <multiple scraper URL configs>\nsceneByName:\n <single scraper config>\nsceneByQueryFragment:\n <single scraper config>\nsceneByFragment:\n <single scraper config>\nsceneByURL:\n <multiple scraper URL configs>\ngroupByURL:\n <multiple scraper URL configs>\ngalleryByFragment:\n <single scraper config>\ngalleryByURL:\n <multiple scraper URL configs>\n<other configurations>\n
name
is mandatory, all other top-level fields are optional. The inclusion of each top-level field determines what capabilities the scraper has.
A scraper configuration in any of the top-level fields must at least have an action
field. The other fields are required based on the value of the action
field.
The scraping types and their required fields are outlined in the following table:
Behavior Required configuration Scraper inScrape...
dropdown button in Performer Edit page Valid performerByName
and performerByFragment
configurations. Scrape performer from URL Valid performerByURL
configuration with matching URL. Scraper in query dropdown button in Scene Edit page Valid sceneByName
and sceneByQueryFragment
configurations. Scraper in Scrape...
dropdown button in Scene Edit page Valid sceneByFragment
configuration. Scrape scene from URL Valid sceneByURL
configuration with matching URL. Scrape group from URL Valid groupByURL
configuration with matching URL. Note: movieByURL
is also supported but is deprecated. Scraper in Scrape...
dropdown button in Gallery Edit page Valid galleryByFragment
configuration. Scrape gallery from URL Valid galleryByURL
configuration with matching URL. URL-based scraping accepts multiple scrape configurations, and each configuration requires a url
field. stash iterates through these configurations, attempting to match the entered URL against the url
fields in the configuration. It executes the first scraping configuration where the entered URL contains the value of the url
field.
Executes a script to perform the scrape. The script
field is required for this action and accepts a list of string arguments. For example:
action: script\nscript:\n - python\n - iafdScrape.py\n - query\n
If the script specifies the python executable, Stash will find the correct python executable for your system, either python
or python3
. So for example. this configuration could execute python iafdScrape.py query
or python3 iafdScrape.py query
. python3
will be looked for first and if it's not found, we'll check for python
. In the case neither are found, you will get an error.
Stash sends data to the script process's stdin
stream and expects the output to be streamed to the stdout
stream. Any errors and progress messages should be output to stderr
.
The script is sent input and expects output based on the scraping type, as detailed in the following table:
Scrape type Input OutputperformerByName
{\"name\": \"<performer query string>\"}
Array of JSON-encoded performer fragments (including at least name
) performerByFragment
JSON-encoded performer fragment JSON-encoded performer fragment performerByURL
{\"url\": \"<url>\"}
JSON-encoded performer fragment sceneByName
{\"name\": \"<scene query string>\"}
Array of JSON-encoded scene fragments sceneByQueryFragment
, sceneByFragment
JSON-encoded scene fragment JSON-encoded scene fragment sceneByURL
{\"url\": \"<url>\"}
JSON-encoded scene fragment groupByURL
{\"url\": \"<url>\"}
JSON-encoded group fragment galleryByFragment
JSON-encoded gallery fragment JSON-encoded gallery fragment galleryByURL
{\"url\": \"<url>\"}
JSON-encoded gallery fragment For performerByName
, only name
is required in the returned performer fragments. One entire object is sent back to performerByFragment
to scrape a specific performer, so the other fields may be included to assist in scraping a performer. For example, the url
field may be filled in for the specific performer page, then performerByFragment
can extract by using its value.
Python example of a performer Scraper:
import json\nimport sys\nimport string\n\ndef readJSONInput():\n input = sys.stdin.read()\n return json.loads(input)\n\n\ndef searchPerformer(name):\n # perform scraping here - using name for the query\n\n # fill in the output\n ret = []\n\n # example shown for a single found performer \n p = {}\n p['name'] = \"some name\"\n p['url'] = \"performer url\"\n ret.append(p)\n\n return ret\n\ndef scrapePerformer(input):\n ret = []\n # get the url from the input\n url = input['url']\n return scrapePerformerURL(url)\n\ndef debugPrint(t):\n sys.stderr.write(t + \"\\n\")\n\ndef scrapePerformerURL(url):\n debugPrint(\"Reading url...\")\n debugPrint(\"Parsing html...\")\n\n # parse html\n\n # fill in performer details - single object\n ret = {}\n\n ret['name'] = \"fred\"\n ret['aliases'] = \"freddy\"\n ret['ethnicity'] = \"\"\n # and so on\n\n return ret\n\n# read the input \ni = readJSONInput()\n\nif sys.argv[1] == \"query\":\n ret = searchPerformer(i['name'])\n print(json.dumps(ret))\nelif sys.argv[1] == \"scrape\":\n ret = scrapePerformer(i)\n print(json.dumps(ret))\nelif sys.argv[1] == \"scrapeURL\":\n ret = scrapePerformerURL(i['url'])\n print(json.dumps(ret))\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapexpath","title":"scrapeXPath","text":"This action scrapes a web page using an xpath configuration to parse. This action is not valid for performerByFragment
.
This action requires that the top-level xPathScrapers
configuration is populated. The scraper
field is required and must match the name of a scraper name configured in xPathScrapers
. For example:
sceneByURL:\n- action: scrapeXPath\n url: \n - pornhub.com/view_video.php\n scraper: sceneScraper\n
The above configuration requires that sceneScraper
exists in the xPathScrapers
configuration.
XPath scraping configurations specify the mapping between object fields and an xpath selector. The xpath scraper scrapes the applicable URL and uses xpath to populate the object fields.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapejson","title":"scrapeJson","text":"This action works in the same way as scrapeXPath
, but uses a mapped json configuration to parse. It uses the top-level jsonScrapers
configuration. This action is not valid for performerByFragment
.
JSON scraping configurations specify the mapping between object fields and a GJSON selector. The JSON scraper scrapes the applicable URL and uses GJSON to parse the returned JSON object and populate the object fields.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapexpath-and-scrapejson-use-with-performerbyname","title":"scrapeXPath and scrapeJson use withperformerByName
","text":"For performerByName
, the queryURL
field must be present also. This field is used to perform a search query URL for performer names. The placeholder string sequence {}
is replaced with the performer name search string. For the subsequent performer scrape to work, the URL
field must be filled in with the URL of the performer page that matches a URL given in a performerByURL
scraping configuration. For example:
name: Boobpedia\nperformerByName:\n action: scrapeXPath\n queryURL: http://www.boobpedia.com/wiki/index.php?title=Special%3ASearch&search={}&fulltext=Search\n scraper: performerSearch\nperformerByURL:\n - action: scrapeXPath\n url: \n - boobpedia.com/boobs/\n scraper: performerScraper\nxPathScrapers:\n performerSearch:\n performer:\n Name: # name element\n URL: # URL element that matches the boobpedia.com/boobs/ URL above\n performerScraper:\n # ... performer scraper details ...\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#scrapexpath-and-scrapejson-use-with-scenebyfragment-and-scenebyqueryfragment","title":"scrapeXPath and scrapeJson use with sceneByFragment
and sceneByQueryFragment
","text":"For sceneByFragment
and sceneByQueryFragment
, the queryURL
field must also be present. This field is used to build a query URL for scenes. For sceneByFragment
, the queryURL
field supports the following placeholder fields:
{checksum}
- the MD5 checksum of the scene{oshash}
- the oshash of the scene{filename}
- the base filename of the scene{title}
- the title of the scene{url}
- the url of the sceneThese placeholder field values may be manipulated with regex replacements by adding a queryURLReplace
section, containing a map of placeholder field to regex configuration which uses the same format as the replace
post-process action covered below.
For example:
sceneByFragment:\n action: scrapeJson\n scraper: sceneQueryScraper\n queryURL: https://metadataapi.net/api/scenes?parse={filename}&limit=1\n queryURLReplace:\n filename:\n - regex: <some regex>\n with: <replacement>\n
The above configuration would scrape from the value of queryURL
, replacing {filename}
with the base filename of the scene, after it has been manipulated by the regex replacements.
<scene|performer|gallery|group>ByURL
","text":"For sceneByURL
, performerByURL
, galleryByURL
the queryURL
can also be present if we want to use queryURLReplace
. The functionality is the same as sceneByFragment
, the only placeholder field available though is the url
: * {url}
- the url of the scene/performer/gallery
sceneByURL:\n - action: scrapeJson\n url:\n - metartnetwork.com\n scraper: sceneScraper\n queryURL: \"{url}\"\n queryURLReplace:\n url:\n - regex: '^(?:.+\\.)?([^.]+)\\.com/.+movie/(\\d+)/(\\w+)/?$'\n with: https://www.$1.com/api/movie?name=$3&date=$2\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#stash","title":"Stash","text":"A different stash server can be configured as a scraping source. This action applies only to performerByName
, performerByFragment
, and sceneByFragment
types. This action requires that the top-level stashServer
field is configured.
stashServer
contains a single url
field for the remote stash server. The username and password can be embedded in this string using username:password@host
. Alternatively, the apiKey
field can be used to authenticate with the remote stash server.
An example stash scrape configuration is below:
name: stash\nperformerByName:\n action: stash\nperformerByFragment:\n action: stash\nsceneByFragment:\n action: stash\nstashServer:\n apiKey: <api key>\n url: http://stashserver.com:9999\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#xpath-and-json-scrapers-configuration","title":"Xpath and JSON scrapers configuration","text":"The top-level xPathScrapers
field contains xpath scraping configurations, freely named. These are referenced in the scraper
field for scrapeXPath
scrapers.
Likewise, the top-level jsonScrapers
field contains json scraping configurations.
Collectively, these configurations are known as mapped scraping configurations.
A mapped scraping configuration may contain a common
field, and must contain performer
, scene
, group
or gallery
depending on the scraping type it is configured for.
Within the performer
/scene
/group
/gallery
field are key/value pairs corresponding to the golang fields on the performer/scene object. These fields are case-sensitive.
The values of these may be either a simple selector value, which tells the system where to get the value of the field from, or a more advanced configuration (see below). For example, for an xpath configuration:
performer:\n Name: //h1[@itemprop=\"name\"]\n
This will set the Name
attribute of the returned performer to the text content of the element that matches <h1 itemprop=\"name\">...
.
For a json configuration:
performer:\n Name: data.name\n
The value may also be a sub-object. If it is a sub-object, then the selector must be set to the selector
key of the sub-object. For example, using the same xpath as above:
performer:\n Name: \n selector: //h1[@itemprop=\"name\"]\n postProcess:\n # post-processing config values\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#fixed-attribute-values","title":"Fixed attribute values","text":"Alternatively, an attribute value may be set to a fixed value, rather than scraping it from the webpage. This can be done by replacing selector
with fixed
. For example:
performer:\n Gender: \n fixed: Female\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#common-fragments","title":"Common fragments","text":"The common
field is used to configure selector fragments that can be referenced in the selector strings. These are key-value pairs where the key is the string to reference the fragment, and the value is the string that the fragment will be replaced with. For example:
common:\n $infoPiece: //div[@class=\"infoPiece\"]/span\nperformer:\n Measurements: $infoPiece[text() = 'Measurements:']/../span[@class=\"smallInfo\"]\n
The Measurements
xpath string will replace $infoPiece
with //div[@class=\"infoPiece\"]/span
, resulting in: //div[@class=\"infoPiece\"]/span[text() = 'Measurements:']/../span[@class=\"smallInfo\"]
.
\u26a0\ufe0f Note: Recursive common fragments are not supported. Referencing a common fragment within another common fragment will cause an error. For example:
common:\n $info: //div[@class=\"info\"]\n # Referencing $info in $models will cause an error\n $models: $info/a[@class=\"model\"]\nscene:\n Title: $info/h1\n Performers:\n Name: $models\n URL: $models/@href\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#post-processing-options","title":"Post-processing options","text":"Post-processing operations are contained in the postProcess
key. Post-processing operations are performed in the order they are specified. The following post-processing operations are available: * javascript
: accepts a javascript code block, that must return a string value. The input string is declared in the value
variable. If an error occurs while compiling or running the script, then the original value is returned. Example:
performer:\n Name:\n selector: //div[@class=\"example element\"]\n postProcess:\n - javascript: |\n // capitalise the first letter\n if (value && value.length) {\n return value[0].toUpperCase() + value.substring(1)\n }\n
Note that the otto
javascript engine is missing a few built-in methods and may not be consistent with other modern javascript implementations. * feetToCm
: converts a string containing feet and inches numbers into centimeters. Looks for up to two separate integers and interprets the first as the number of feet, and the second as the number of inches. The numbers can be separated by any non-numeric character including the .
character. It does not handle decimal numbers. For example 6.3
and 6ft3.3
would both be interpreted as 6 feet, 3 inches before converting into centimeters. * lbToKg
: converts a string containing lbs to kg. * map
: contains a map of input values to output values. Where a value matches one of the input values, it is replaced with the matching output value. If no value is matched, then value is unmodified. Example:
performer:\n Gender:\n selector: //div[@class=\"example element\"]\n postProcess:\n - map:\n F: Female\n M: Male\n Height:\n selector: //span[@id=\"height\"]\n postProcess:\n - feetToCm: true\n Weight:\n selector: //span[@id=\"weight\"]\n postProcess:\n - lbToKg: true\n
Gets the contents of the selected div element, and sets the returned value to Female
if the scraped value is F
; Male
if the scraped value is M
. Height and weight are extracted from the selected spans and converted to cm
and kg
. parseDate
: if present, the value is the date format using go's reference date (2006-01-02). For example, if an example date was 14-Mar-2003
, then the date format would be 02-Jan-2006
. See the time.Parse documentation for details. When present, the scraper will convert the input string into a date, then convert it to the string format used by stash (YYYY-MM-DD
). Strings \"Today\", \"Yesterday\" are matched (case insensitive) and converted by the scraper so you don't need to edit/replace them. Unix timestamps (example: 1660169451) can also be parsed by selecting unix
as the date format. Example:
Date:\n selector: //div[@class=\"value epoch\"]/text()\n postProcess:\n - parseDate: unix\n
subtractDays
: if set to true
it subtracts the value in days from the current date and returns the resulting date in stash's date format. Example:
Date:\n selector: //strong[contains(text(),\"Added:\")]/following-sibling::text()\n postProcess:\n - replace:\n - regex: (\\d+)\\sdays\\sago.+\n with: $1\n - subtractDays: true\n
replace
: contains an array of sub-objects. Each sub-object must have a regex
and with
field. The regex
field is the regex pattern to replace, and with
is the string to replace it with. $
is used to reference capture groups - $1
is the first capture group, $2
the second and so on. Replacements are performed in order of the array.
Example:
CareerLength: \n selector: $infoPiece[text() = 'Career Start and End:']/../span[@class=\"smallInfo\"]\n postProcess:\n - replace:\n - regex: \\s+to\\s+\n with: \"-\"\n
Replaces 2001 to 2003
with 2001-2003
. subScraper
: if present, the sub-scraper will be executed after all other post-processes are complete and before parseDate. It then takes the value and performs an http request, using the value as the URL. Within the subScraper
config is a nested scraping configuration. This allows you to traverse to other webpages to get the attribute value you are after. For more info and examples have a look at #370, #606Additionally, there are a number of fixed post-processing fields that are specified at the attribute level (not in postProcess
) that are performed after the postProcess
operations: * concat
: if an xpath matches multiple elements, and concat
is present, then all of the elements will be concatenated together * split
: the inverse of concat
. Splits a string to more elements using the separator given. For more info and examples have a look at PR #579
Example:
Tags:\n Name:\n selector: //span[@class=\"list_attributes\"]\n split: \",\"\n
Splits a comma separated list of tags located in the span and returns the tags. For backwards compatibility, replace
, subscraper
and parseDate
are also allowed as keys for the attribute.
Post-processing on attribute post-process is done in the following order: concat
, replace
, subscraper
, parseDate
and then split
.
To print the received html/json from a scraper request to the log file, add the following to your scraper yml file:
debug:\n printHTML: true\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#cdp-support","title":"CDP support","text":"Some websites deliver content that cannot be scraped using the raw html file alone. These websites use javascript to dynamically load the content. As such, direct xpath scraping will not work on these websites. There is an option to use Chrome DevTools Protocol to load the webpage using an instance of Chrome, then scrape the result.
Chrome CDP support can be enabled for a specific scraping configuration by adding the following to the root of the yml configuration:
driver:\n useCDP: true\n
Optionally, you can add a sleep
value under the driver
section. This specifies the amount of time (in seconds) that the scraper should wait after loading the website to perform the scrape. This is needed as some sites need more time for loading scripts to finish. If unset, this value defaults to 2 seconds.
When useCDP
is set to true, stash will execute or connect to an instance of Chrome. The behavior is dictated by the Chrome CDP path
setting in the user configuration. If left empty, stash will attempt to find the Chrome executable in the path environment, and will fail if it cannot find one.
Chrome CDP path
can be set to a path to the chrome executable, or an http(s) address to remote chrome instance (for example: http://localhost:9222/json/version
). As remote instance a docker container can also be used with the chromedp/headless-shell
image being highly recommended.
When using CDP you can use the clicks
part of the driver
section to do Mouse Clicks on elements you need to collapse or toggle. Each click element has an xpath
value that holds the XPath for the button/element you need to click and an optional sleep
value that is the time in seconds to wait for after clicking. If the sleep
value is not set it defaults to 2
seconds.
A demo scraper using clicks
follows.
name: clickDemo # demo only for a single URL\nsceneByURL:\n - action: scrapeXPath\n url:\n - https://getbootstrap.com/docs/4.3/components/collapse/\n scraper: sceneScraper\n\nxPathScrapers:\n sceneScraper:\n scene:\n Title: //head/title\n Details: # shows the id/s of the visible div/s for the Multiple targets example of the page\n selector: //div[@class=\"bd-example\"]//div[@class=\"multi-collapse collapse show\"]/@id\n concat: \"\\n\\n\"\n\ndriver:\n useCDP: true\n sleep: 1\n clicks: # demo usage toggle on off multiple times\n - xpath: //a[@href=\"#multiCollapseExample1\"] # toggle on first element\n - xpath: //button[@data-target=\"#multiCollapseExample2\"] # toggle on second element\n sleep: 4\n - xpath: //a[@href=\"#multiCollapseExample1\"] # toggle off fist element\n sleep: 1\n - xpath: //button[@data-target=\"#multiCollapseExample2\"] # toggle off second element\n - xpath: //button[@data-target=\"#multiCollapseExample2\"] # toggle on second element\n
\u26a0\ufe0f Note: each click
adds an extra delay of clicks sleep
seconds, so the above adds 2+4+1+2+2=11
seconds to the loading time of the page.
In some websites the use of cookies is needed to bypass a welcoming message or some other kind of protection. Stash supports the setting of cookies for the direct xpath scraper and the CDP based one. Due to implementation issues the usage varies a bit.
To use the cookie functionality a cookies
sub section needs to be added to the driver
section. Each cookie element can consist of a CookieURL
and a number of Cookies
.
CookieURL
is only needed if you are using the direct / native scraper method. It is the request url that we expect from the site we scrape. It must be in the same domain as the cookies we try to set otherwise all cookies in the same group will fail to set. If the CookieURL
is not a valid URL then again the cookies of that group will fail.
Cookies
are the actual cookies we set. When using CDP that's the only part required. They have Name
, Value
, Domain
, Path
values.
In the following example we use cookies for a site using the direct / native xpath scraper. We expect requests to come from https://www.example.com
and https://api.somewhere.com
that look for a _warning
and a _warn
cookie. A _test2
cookie is also set just as a demo.
driver:\n cookies:\n - CookieURL: \"https://www.example.com\"\n Cookies:\n - Name: \"_warning\"\n Domain: \".example.com\"\n Value: \"true\"\n Path: \"/\"\n - Name: \"_test2\"\n Value: \"123412\"\n Domain: \".example.com\"\n Path: \"/\"\n - CookieURL: \"https://api.somewhere.com\"\n Cookies:\n - Name: \"_warn\"\n Value: \"123\"\n Domain: \".somewhere.com\"\n
The same functionality when using CDP would look like this:
driver:\n useCDP: true\n cookies:\n - Cookies:\n - Name: \"_warning\"\n Domain: \".example.com\"\n Value: \"true\"\n Path: \"/\"\n - Name: \"_test2\"\n Value: \"123412\"\n Domain: \".example.com\"\n Path: \"/\"\n - Cookies:\n - Name: \"_warn\"\n Value: \"123\"\n Domain: \".somewhere.com\"\n
For some sites, the value of the cookie itself doesn't actually matter. In these cases, we can use the ValueRandom
property instead of Value
. Unlike Value
, ValueRandom
requires an integer value greater than 0
where the value indicates how long the cookie string should be.
In the following example, we will adapt the previous cookies to use ValueRandom
instead. We set the _test2
cookie to randomly generate a value with a length of 6 characters and the _warn
cookie to a length of 3.
driver:\n cookies:\n - CookieURL: \"https://www.example.com\"\n Cookies:\n - Name: \"_warning\"\n Domain: \".example.com\"\n Value: \"true\"\n Path: \"/\"\n - Name: \"_test2\"\n ValueRandom: 6\n Domain: \".example.com\"\n Path: \"/\"\n - CookieURL: \"https://api.somewhere.com\"\n Cookies:\n - Name: \"_warn\"\n ValueRandom: 3\n Domain: \".somewhere.com\"\n
When developing a scraper you can have a look at the cookies set by a site by adding
a CookieURL
if you use the direct xpath scraper
a Domain
if you use the CDP scraper
and having a look at the log / console in debug mode.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#headers","title":"Headers","text":"Sending request headers is possible when using a scraper. Headers can be set in the driver
section and are supported for plain, CDP enabled and JSON scrapers. They consist of a Key and a Value. If the Key is empty or not defined then the header is ignored.
driver:\n headers:\n - Key: User-Agent\n Value: My Stash Scraper\n - Key: Authorization\n Value: Bearer ds3sdfcFdfY17p4qBkTVF03zscUU2glSjWF17bZyoe8\n
User-Agent
configuration option is applied. This means setting a User-Agent
header from the scraper overrides the one in the configuration settings.A performer and scene xpath scraper is shown as an example below:
name: Pornhub\nperformerByURL:\n - action: scrapeXPath\n url: \n - pornhub.com\n scraper: performerScraper\nsceneByURL:\n - action: scrapeXPath\n url: \n - pornhub.com/view_video.php\n scraper: sceneScraper\nxPathScrapers:\n performerScraper:\n common:\n $infoPiece: //div[@class=\"infoPiece\"]/span\n performer:\n Name: //h1[@itemprop=\"name\"]\n Birthdate: \n selector: //span[@itemprop=\"birthDate\"]\n parseDate: Jan 2, 2006\n Twitter: //span[text() = 'Twitter']/../@href\n Instagram: //span[text() = 'Instagram']/../@href\n Measurements: $infoPiece[text() = 'Measurements:']/../span[@class=\"smallInfo\"]\n Height: \n selector: $infoPiece[text() = 'Height:']/../span[@class=\"smallInfo\"]\n postProcess:\n - replace: \n - regex: .*\\((\\d+) cm\\)\n with: $1\n Ethnicity: $infoPiece[text() = 'Ethnicity:']/../span[@class=\"smallInfo\"]\n FakeTits: $infoPiece[text() = 'Fake Boobs:']/../span[@class=\"smallInfo\"]\n Piercings: $infoPiece[text() = 'Piercings:']/../span[@class=\"smallInfo\"]\n Tattoos: $infoPiece[text() = 'Tattoos:']/../span[@class=\"smallInfo\"]\n CareerLength: \n selector: $infoPiece[text() = 'Career Start and End:']/../span[@class=\"smallInfo\"]\n postProcess:\n - replace:\n - regex: \\s+to\\s+\n with: \"-\"\n sceneScraper:\n common:\n $performer: //div[@class=\"pornstarsWrapper\"]/a[@data-mxptype=\"Pornstar\"]\n $studio: //div[@data-type=\"channel\"]/a\n scene:\n Title: //div[@id=\"main-container\"]/@data-video-title\n Tags: \n Name: //div[@class=\"categoriesWrapper\"]//a[not(@class=\"add-btn-small \")]\n Performers:\n Name: $performer/@data-mxptext\n URL: $performer/@href\n Studio:\n Name: $studio\n URL: $studio/@href \n
See also #333 for more examples.
"},{"location":"in-app-manual/scraping/scraperdevelopment/#json-scraper-example","title":"JSON scraper example","text":"A performer and scene scraper for ThePornDB is shown below:
name: ThePornDB\nperformerByName:\n action: scrapeJson\n queryURL: https://api.metadataapi.net/performers?q={}\n scraper: performerSearch\nperformerByURL:\n - action: scrapeJson\n url:\n - https://api.metadataapi.net/performers/\n scraper: performerScraper\nsceneByURL:\n - action: scrapeJson\n url:\n - https://api.metadataapi.net/scenes/\n scraper: sceneScraper\nsceneByFragment:\n action: scrapeJson\n queryURL: https://api.metadataapi.net/scenes?parse={filename}&hash={oshash}&limit=1\n scraper: sceneQueryScraper\n queryURLReplace:\n filename:\n - regex: \"[^a-zA-Z\\\\d\\\\-._~]\" # clean filename so that it can construct a valid url\n with: \".\" # \"%20\"\n - regex: HEVC\n with:\n - regex: x265\n with:\n - regex: \\.+\n with: \".\"\njsonScrapers:\n performerSearch:\n performer:\n Name: data.#.name\n URL:\n selector: data.#.id\n postProcess:\n - replace:\n - regex: ^\n with: https://api.metadataapi.net/performers/\n\n performerScraper:\n common:\n $extras: data.extras\n performer:\n Name: data.name\n Gender: $extras.gender\n Birthdate: $extras.birthday\n Ethnicity: $extras.ethnicity\n Height:\n selector: $extras.height\n postProcess:\n - replace:\n - regex: cm\n with:\n Measurements: $extras.measurements\n Tattoos: $extras.tattoos\n Piercings: $extras.piercings\n Aliases: data.aliases\n Image: data.image\n\n sceneScraper:\n common:\n $performers: data.performers\n scene:\n Title: data.title\n Details: data.description\n Date: data.date\n URL: data.url\n Image: data.background.small\n Performers:\n Name: data.performers.#.name\n Studio:\n Name: data.site.name\n Tags:\n Name: data.tags.#.tag\n\n sceneQueryScraper:\n common:\n $data: data.0\n $performers: data.0.performers\n scene:\n Title: $data.title\n Details: $data.description\n Date: $data.date\n URL: $data.url\n Image: $data.background.small\n Performers:\n Name: $data.performers.#.name\n Studio:\n Name: $data.site.name\n Tags:\n Name: $data.tags.#.tag\ndriver:\n headers:\n - Key: User-Agent\n Value: Stash JSON Scraper\n - Key: Authorization\n Value: Bearer lPdwFdfY17p4qBkTVF03zscUU2glSjdf17bZyoe # use an actual API Key here\n# Last Updated April 7, 2021\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#object-fields","title":"Object fields","text":""},{"location":"in-app-manual/scraping/scraperdevelopment/#performer","title":"Performer","text":"Name\nGender\nURL\nTwitter\nInstagram\nBirthdate\nDeathDate\nEthnicity\nCountry\nHairColor\nEyeColor\nHeight\nWeight\nMeasurements\nFakeTits\nCareerLength\nTattoos\nPiercings\nAliases\nTags (see Tag fields)\nImage\nDetails\n
Note: - Gender
must be one of male
, female
, transgender_male
, transgender_female
, intersex
, non_binary
(case insensitive).
Title\nDetails\nCode\nDirector\nURL\nDate\nImage\nStudio (see Studio Fields)\nGroups (see Group Fields)\nTags (see Tag fields)\nPerformers (list of Performer fields)\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#studio","title":"Studio","text":"Name\nURL\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#tag","title":"Tag","text":"Name\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#group","title":"Group","text":"Name\nAliases\nDuration\nDate\nRating\nDirector\nStudio\nSynopsis\nURL\nFrontImage\nBackImage\n
"},{"location":"in-app-manual/scraping/scraperdevelopment/#gallery","title":"Gallery","text":"Title\nDetails\nURL\nDate\nRating\nStudio (see Studio Fields)\nTags (see Tag fields)\nPerformers (list of Performer fields)\n
"},{"location":"in-app-manual/tasks/","title":"Tasks","text":"This page allows you to direct the stash server to perform a variety of tasks.
"},{"location":"in-app-manual/tasks/#scanning","title":"Scanning","text":"The scan function walks through the stash directories you have configured for new and moved files.
Stash currently identifies files by performing a quick file hash. This means that if the file is renamed for moved elsewhere within your configured stash directories, then the scan will detect this and update its database accordingly.
Stash currently ignores duplicate files. If two files contain identical content, only the first one it comes across is used.
The scan task accepts the following options:
Option Description Generate scene covers Generates scene covers for video files. Generate previews Generates video previews (mp4) which play when hovering over a scene. Generate animated image previews Also generate animated (webp) previews, only required when Scene/Marker Wall Preview Type is set to Animated Image. When browsing they use less CPU than the video previews, but are generated in addition to them and are larger files. Generate scrubber sprites The set of images displayed below the video player for easy navigation. Generate perceptual hashes Generates perceptual hashes for scene deduplication and identification. Generate thumbnails for images Generates thumbnails for image files. Generate previews for image clips Generates a gif/looping video as thumbnail for image clips/gifs. Rescan By default, Stash will only rescan existing files if the file's modified date has been updated since its previous scan. Stash will rescan files in the path when this option is enabled, regardless of the file modification time. Only required Stash needs to recalculate video/image metadata, or to rescan gallery zips."},{"location":"in-app-manual/tasks/#auto-tagging","title":"Auto Tagging","text":"See the Auto Tagging page.
"},{"location":"in-app-manual/tasks/#scene-filename-parser","title":"Scene Filename Parser","text":"See the Scene Filename Parser page.
"},{"location":"in-app-manual/tasks/#generated-content","title":"Generated Content","text":"The scanning function automatically generates a screenshot of each scene. The generated content provides the following:
The generate task accepts the following options:
Option Description Scene covers Generates scene covers for video files. Previews Generates video previews (mp4) which play when hovering over a scene. Animated image previews Generates animated previews (webp). Only required if the Preview Type is set to Animated Image. Requires Generate previews to be enabled. Scene Scrubber Sprites The set of images displayed below the video player for easy navigation. Markers Previews Generates 20 second video previews (mp4) which begin at the marker timecode. Marker Animated Image Previews Also generate animated (webp) previews, only required when Scene/Marker Wall Preview Type is set to Animated Image. When browsing they use less CPU than the video previews, but are generated in addition to them and are larger files. Marker Screenshots Generates static JPG images for markers. Only required if Preview Type is set to Static Image. Requires Marker Previews to be enabled. Transcodes MP4 conversions of unsupported video formats. Allows direct streaming instead of live transcoding. Perceptual hashes (for deduplication) Generates perceptual hashes for scene deduplication and identification. Generate heatmaps and speeds for interactive scenes Generates heatmaps and speeds for interactive scenes. Image Clip Previews Generates a gif/looping video as thumbnail for image clips/gifs. Overwrite existing generated files By default, where a generated file exists, it is not regenerated. When this flag is enabled, then the generated files are regenerated."},{"location":"in-app-manual/tasks/#transcodes","title":"Transcodes","text":"Web browsers support a limited number of video and audio codecs and containers. Stash will directly stream video files where the browser supports the codecs and container. Originally, stash did not support viewing scene videos where the browser did not support the codecs/container, and generating transcodes was a way of viewing these files.
Stash has since implemented live transcoding, so transcodes are essentially unnecessary now. Further, transcodes use up a significant amount of disk space and are not guaranteed to be lossless.
"},{"location":"in-app-manual/tasks/#image-gallery-thumbnails","title":"Image gallery thumbnails","text":"These are generated when the gallery is first viewed, so generating them beforehand is not necessary.
"},{"location":"in-app-manual/tasks/#cleaning","title":"Cleaning","text":"This task will walk through your configured media directories and remove any scene from the database that can no longer be found. It will also remove generated files for scenes that subsequently no longer exist.
Care should be taken with this task, especially where the configured media directories may be inaccessible due to network issues.
"},{"location":"in-app-manual/tasks/#exporting-and-importing","title":"Exporting and Importing","text":"The import and export tasks read and write JSON files to the configured metadata directory. Import from file will merge your database with a file.
\u26a0\ufe0f Note: The full import task wipes the current database completely before importing.
See the JSON Specification page for details on the exported JSON format.
"},{"location":"in-app-manual/tasks/autotagging/","title":"Auto Tagging","text":"When media filepaths or filenames contain a Performer, Studio, or Tag name, it is assigned those Performers, Studios, and Tags. It will only tag based on Performer, Studio, and Tag names that exist in your database.
When the Performer/Studio/Tag name has multiple words, the search will include paths/filenames where the Performer/Studio/Tag name is separated with .
, -
, _
, and whitespace characters.
For example, auto tagging for performer Jane Doe
will match the following filenames:
Jane.Doe.1.mp4
Jane_Doe.2.mp4
Jane-Doe.3.mp4
Jane Doe.4.mp4
Matching is case insensitive, and should only match exact wording within word boundaries. For example, the tag Jane Doe
will not match Maryjane-Doe
or Jane-Doen
, but will match Mary-Jane-Doe
, Jane-Doe_n
, and [OF]jane doe
.
Auto tagging for specific Performers, Studios, and Tags can be performed from the individual Performer/Studio/Tag page.
Note: Performer autotagging does not currently match on performer aliases.
"},{"location":"in-app-manual/tasks/identify/","title":"Identify","text":"This task iterates through your Scenes and attempts to identify the scene using a selection of scraping sources.
This task accepts one or more scraper sources. Valid scraper sources for the Identify task are stash-box instances, and scene scrapers which support scraping via Scene Fragment. The order of the sources may be rearranged.
For each Scene, the Identify task iterates through the scraper sources, in the order provided, and tries to identify the scene using each source. If a result is found in a source, then the Scene is updated, and no further sources are checked for that scene.
"},{"location":"in-app-manual/tasks/identify/#options","title":"Options","text":"The following options can be set:
Option Description Include male performers If false, then male performers will not be created or set on scenes. Set cover images If false, then scene cover images will not be modified. Set organised flag If true, the organised flag is set to true when a scene is organised. Skip matches that have more than one result If this is not enabled and more than one result is returned, one will be randomly chosen to match Tag skipped matches with If the above option is set and a scene is skipped, this will add the tag so that you can filter for it in the Scene Tagger view and choose the correct match by hand Skip single name performers with no disambiguation If this is not enabled, performers that are often generic like Samantha or Olga will be matched Tag skipped performers with If the above options is set and a performer is skipped, this will add the tag so that you can filter for in it the Scene Tagger view and choose how you want to handle those performersField specific options may be set as well. Each field may have a Strategy. The behaviour for each strategy value is as follows:
Strategy Description Ignore Not set. Overwrite Overwrite existing value. Merge (default) For multi-value fields, adds to existing values. For single-value fields, only sets if not already set.For Studio, Performers and Tags, an option is also available to Create Missing objects. This is enabled by default. When true, if a Studio/Performer/Tag is included during the identification process and does not exist in the system, then it will be created.
Default Options are applied to all sources unless overridden in specific source options.
The result of the identification process for each scene is output to the log.
"},{"location":"in-app-manual/tasks/jsonspec/","title":"Import/Export JSON Specification","text":"The metadata given to Stash can be exported into the JSON format. This structure can be modified, or replicated by other means. The resulting data can then be imported again, giving the possibility for automatic scraping of all kinds. The format of this metadata bulk is a folder structure, containing the following folders:
files
galleries
images
performers
scenes
studios
groups
When exported, files are named with different formats depending on the object type:
Type Format Files/Folders<path depth in hex, two character width>.<basename>.<hash>.json
Galleries <first zip filename>.<path hash>.json
or <folder basename>.<path hash>.json
or <title>.json
Images <title or first file basename>.<hash>.json
Performers <name>.json
Scenes <title or first file basename>.<hash>.json
Studios <name>.json
Groups <name>.json
Note that the file naming is not significant when importing. All json files will be read from the subdirectories.
"},{"location":"in-app-manual/tasks/jsonspec/#content-of-the-json-files","title":"Content of the json files","text":"In the following, the values of the according jsons will be shown. If the value should be a number, it is written with after comma values (like 29.98
or 50.0
), but still as a string. The meaning from most of them should be obvious due to the previous explanation or from the possible values stash offers when editing, otherwise a short comment will be added.
The json values are given as strings, if not stated otherwise. Every new line will stand for a new value in the json. If the value is a list of objects, the values of that object will be shown indented.
If a value is empty in any file, it can be left out of the file entirely. Many files have an created_at
and updated_at
, both are kept in the following format:
YYYY-MM-DDThh:mm:ssTZD \n
Example: \"created_at\": \"2019-05-03T21:36:58+01:00\"\n
"},{"location":"in-app-manual/tasks/jsonspec/#performer","title":"Performer","text":"name \nurl \ntwitter \ninstagram \nbirthdate \ndeath_date \nethnicity \ncountry \nhair_color \neye_color \nheight \nweight \nmeasurements \nfake_tits \ncareer_length \ntattoos \npiercings \nimage (base64 encoding of the image file) \ncreated_at \nupdated_at\nrating (integer)\ndetails\n
"},{"location":"in-app-manual/tasks/jsonspec/#studio","title":"Studio","text":"name \nurl \nimage (base64 encoding of the image file) \ncreated_at \nupdated_at\nrating (integer) \ndetails \n
"},{"location":"in-app-manual/tasks/jsonspec/#scene","title":"Scene","text":"title \nstudio \nurl \ndate \nrating (integer) \ndetails \nperformers (list of strings, performers name) \ntags (list of strings) \nmarkers \n title \n seconds \n primary_tag \n tags (list of strings) \n created_at \n updated_at \nfile (not a list, but a single object) \n size (in bytes, no after comma values) \n duration (in seconds) \n video_codec (example value: h264) \n audio_codec (example value: aac) \n width (integer, in pixel) \n height (integer, in pixel) \n framerate \n bitrate (integer, in Bit) \ncreated_at \nupdated_at \n
"},{"location":"in-app-manual/tasks/jsonspec/#image","title":"Image","text":"title \nstudio \nrating (integer) \nperformers (list of strings, performers name) \ntags (list of strings) \nfiles (list of path strings)\ngalleries\n zip_files (list of path strings)\n folder_path\n title (for user-created gallery)\ncreated_at \nupdated_at \n
"},{"location":"in-app-manual/tasks/jsonspec/#gallery","title":"Gallery","text":"title \nstudio \nurl \ndate \nrating (integer) \ndetails \nperformers (list of strings, performers name) \ntags (list of strings) \nzip_files (list of path strings)\nfolder_path \ncreated_at \nupdated_at \n
"},{"location":"in-app-manual/tasks/jsonspec/#files","title":"Files","text":""},{"location":"in-app-manual/tasks/jsonspec/#folder","title":"Folder","text":"zip_file (path to containing zip file)\nmod_time\ntype (= folder)\npath\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#video-file","title":"Video file","text":"zip_file (path to containing zip file)\nmod_time\ntype (= video)\npath\nfingerprints\n type\n fingerprint\nsize\nformat\nwidth\nheight\nduration\nvideo_codec\naudio_codec\nframe\nbitrate\ninteractive (bool)\ninteractive_speed (integer)\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#image-file","title":"Image file","text":"zip_file (path to containing zip file)\nmod_time\ntype (= image)\npath\nfingerprints\n type\n fingerprint\nsize\nformat\nwidth\nheight\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#other-files","title":"Other files","text":"zip_file (path to containing zip file)\nmod_time\ntype (= file)\npath\nfingerprints\n type\n fingerprint\nsize\ncreated_at\nupdated_at\n
"},{"location":"in-app-manual/tasks/jsonspec/#in-json-format","title":"In JSON format","text":"For those preferring the json-format, defined here, the following format may be more interesting:
"},{"location":"in-app-manual/tasks/jsonspec/#performerjson","title":"performer.json","text":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://docs.stashapp.cc/in-app-manual/tasks/jsonspec#performerjson\",\n \"title\": \"performer\",\n \"description\": \"A json file representing a performer. The file is named by a MD5 Code.\",\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"description\": \"Name of the performer\",\n \"type\": \"string\"\n },\n \"url\": {\n \"description\": \"URL to website of the performer\",\n \"type\": \"string\"\n },\n \"twitter\": {\n \"description\": \"Twitter name of the performer\",\n \"type\": \"string\"\n },\n \"instagram\": {\n \"description\": \"Instagram name of the performer\",\n \"type\": \"string\"\n },\n \"birthdate\": {\n \"description\": \"Birthdate of the performer. Format is YYYY-MM-DD\",\n \"type\": \"string\"\n },\n \"death_date\": {\n \"description\": \"Death date of the performer. Format is YYYY-MM-DD\",\n \"type\": \"string\"\n },\n \"ethnicity\": {\n \"description\": \"Ethnicity of the Performer. Possible values are black, white, asian or hispanic\",\n \"type\": \"string\"\n },\n \"country\": {\n \"description\": \"Country of the performer\",\n \"type\": \"string\"\n },\n \"hair_color\": {\n \"description\": \"Hair color of the performer\",\n \"type\": \"string\"\n },\n \"eye_color\": {\n \"description\": \"Eye color of the performer\",\n \"type\": \"string\"\n },\n \"height\": {\n \"description\": \"Height of the performer in centimeters\",\n \"type\": \"string\"\n },\n \"weight\": {\n \"description\": \"Weight of the performer in kilograms\",\n \"type\": \"string\"\n },\n \"measurements\": {\n \"description\": \"Measurements of the performer\",\n \"type\": \"string\"\n },\n \"fake_tits\": {\n \"description\": \"Whether performer has fake tits. Possible are Yes or No\",\n \"type\": \"string\"\n },\n \"career_length\": {\n \"description\": \"The time the performer has been in business. In the format YYYY-YYYY\",\n \"type\": \"string\"\n },\n \"tattoos\": {\n \"description\": \"Giving a description of Tattoos of the performer if any\",\n \"type\": \"string\"\n },\n \"piercings\": {\n \"description\": \"Giving a description of Piercings of the performer if any\",\n \"type\": \"string\"\n },\n \"image\": {\n \"description\": \"Image of the performer, parsed into base64\",\n \"type\": \"string\"\n },\n \"created_at\": {\n \"description\": \"The time this performers data was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this performers data was last changed in the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"details\": {\n \"description\": \"Description of the performer\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"name\", \"ethnicity\", \"image\", \"created_at\", \"updated_at\"]\n}\n
"},{"location":"in-app-manual/tasks/jsonspec/#studiojson","title":"studio.json","text":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://docs.stashapp.cc/in-app-manual/tasks/jsonspec#studiojson\",\n \"title\": \"studio\",\n \"description\": \"A json file representing a studio. The file is named by a MD5 Code.\",\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"description\": \"Name of the studio\",\n \"type\": \"string\"\n },\n \"url\": {\n \"description\": \"URL to the studios websites\",\n \"type\": \"string\"\n },\n \"image\": {\n \"description\": \"Logo of the studio, parsed into base64\",\n \"type\": \"string\"\n },\n \"created_at\": {\n \"description\": \"The time this studios data was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this studios data was last changed in the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"details\": {\n \"description\": \"Description of the studio\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"name\", \"image\", \"created_at\", \"updated_at\"]\n}\n
"},{"location":"in-app-manual/tasks/jsonspec/#scenejson","title":"scene.json","text":"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://docs.stashapp.cc/in-app-manual/tasks/jsonspec#scenejson\",\n \"title\": \"scene\",\n \"description\": \"A json file representing a scene. The file is named by the MD5 Code of the file its data is referring to.\",\n \"type\": \"object\",\n \"properties\": {\n \"title\": {\n \"description\": \"Title of the scene\",\n \"type\": \"string\"\n },\n \"studio\": {\n \"description\": \"The name of the studio that produced that scene\",\n \"type\": \"string\"\n },\n \"url\": {\n \"description\": \"The url to the scenes original source\",\n \"type\": \"string\"\n },\n \"date\": {\n \"description\": \"The release date of the scene. Its given in the format YYYY-MM-DD\",\n \"type\": \"string\"\n },\n \"rating\": {\n \"description\": \"The scenes Rating. Its given in stars, from 1 to 5\",\n \"type\": \"integer\"\n },\n \"details\": {\n \"description\": \"A description of the scene, containing things like the story arc\",\n \"type\": \"string\"\n },\n \"performers\": {\n \"description\": \"A list of names of the performers in this gallery\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"tags\": {\n \"description\": \"A list of the tags associated with this scene\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"markers\": {\n \"description\": \"Markers mark certain events in the scene, most often the change of the position. They are attributed with their own tags.\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"title\": {\n \"description\": \"Searchable name of the marker\",\n \"type\": \"string\"\n },\n \"seconds\": {\n \"description\": \"At what second the marker is set. It is given with after comma values, such as 10.0 or 17.5\",\n \"type\": \"string\"\n },\n \"primary_tag\": {\n \"description\": \"A tag identifying this marker. Multiple markers from the same scene with the same primary tag are concatenated, showing them as similar in nature\",\n \"type\": \"string\"\n },\n \"tags\": {\n \"description\": \"A list of the tags associated with this marker\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"created_at\": {\n \"description\": \"The time this marker was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this marker was updated the last time. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n }\n\n },\n \"required\": [\"seconds\", \"primary_tag\", \"created_at\", \"updated_at\"]\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"files\": {\n \"description\": \"A list of paths of the files for this scene\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"uniqueItems\": true\n },\n \"created_at\": {\n \"description\": \"The time this studios data was added to the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n },\n \"updated_at\": {\n \"description\": \"The time this studios data was last changed in the database. Format is YYYY-MM-DDThh:mm:ssTZD\",\n \"type\": \"string\"\n }\n },\n \"required\": [\"files\", \"created_at\", \"updated_at\"]\n}\n
"},{"location":"in-app-manual/tasks/scenefilenameparser/","title":"Scene Filename Parser","text":"This tool parses the scene filenames in your library and allows setting the metadata from those filenames.
"},{"location":"in-app-manual/tasks/scenefilenameparser/#parser-options","title":"Parser Options","text":"To use this tool, a filename pattern must be entered. The pattern accepts the following fields:
Field Remarktitle
Text captured within is set as the title of the scene. ext
Matches the end of the filename. It is not captured. Does not include the last .
character. d
Matches delimiter characters (-_.
). Not captured. i
Matches any ignored word entered in the Ignored words
field. Ignored words are entered as space-delimited words. Not captured. Use this to match release artifacts like DVDRip
or release groups. date
Matches yyyy-mm-dd
and sets the date of the scene. rating
Matches a single digit and sets the rating of the scene. performer
Sets the scene performer, based on the text captured. tag
Sets the scene tag, based on the text captured. studio
Sets the studio performer, based on the text captured. {}
Matches any characters. Not captured. \u26a0\ufe0f Note: performer
, tag
and studio
fields will only match against Performers/Tags/Studios that already exist in the system.
The performer
/tag
/studio
fields will remove any delimiter characters (.-_
) before querying. Name matching is case-insensitive.
The following partial date fields are also supported. The date will only be set on the scene if a date string can be built using the partial date components:
Field Remarkyyyy
Four digit year yy
Two digit year. Assumes the first two digits are 20
mm
Two digit month mmm
Three letter month, such as Jan
(case-insensitive) dd
Two digit date The following full date fields are supported, using the same partial date rules as above:
yyyymmdd
yymmdd
ddmmyyyy
ddmmyy
mmddyyyy
mmddyy
All of these fields are available from the Add Field
button.
Title generation also has the following options:
Option Remark Whitespace characters These characters are replaced with whitespace (defaults to._
, to handle filenames like three.word.title.avi
Capitalize title capitalises the first letter of each word The fields to display can be customised with the Display Fields
drop-down section. By default, any field with new/different values will be displayed.
Once the options are correct, click on the Find
button. The system will search for scenes that have filenames that match the given pattern.
The results are presented in a table showing the existing and generated values of the discovered fields, along with a checkbox to determine whether or not the field will be set on each scene. These fields can also be edited manually.
The Apply
button updates the scenes based on the set fields.
\u26a0\ufe0f Note: results are paged and the Apply
button only applies to scenes on the current page.
Stash offers native binaries for the following platforms:
All official binaries can be downloaded from our GitHub release page. Latest version is available here.
Official Discord image is hosted on Docker Hub. Latest version can be pulled from stashapp/stash:latest
.
Info
Before starting make sure your system has Docker installed. You can follow the instructions on how to install Docker from Docker Docs.
Info
Official Stash image is located at stashapp/stash
.
Note
Stash README on Docker installation is available here.
"},{"location":"installation/docker/#using-docker-compose","title":"Using Docker Compose","text":""},{"location":"installation/docker/#install","title":"Install","text":"docker-compose.yml
file from our GitHub.docker-compose.yml
or cd
to that directory.docker-compose up -d
If you are upgrading from older than v0.20 version make sure to re-download the docker-compose.yml
file from our GitHub as new volume was added. Alternatively you can edit the docker-compose.yml
to manually include new volume - ./blobs:/blobs
.
docker-compose.yml
is saved.docker-compose pull
. Pulls the new image.docker-compose down
. Removes old container.docker-compose up -d
. Creates and starts the new container. docker-compose.yml
file. docker-compose.yml
is saved.docker container kill
. Force stops the container.docker container rm
. Removes the container.docker-compose.yml
file.Info
The following step by step was tested using TrueNAS Scale Cobia (23.10.1.3).
"},{"location":"installation/freenas-truenas/#installation","title":"Installation","text":"To install the stashapp, we will use the TrueCharts app database. To install, we'll follow the official documentation at https://truecharts.org/manual/SCALE/guides/getting-started/
After the update is complete, use the search bar to search for \"stash\". When found, click Install.
"},{"location":"installation/freenas-truenas/#options","title":"Options","text":"The installation window will contain several customizable options, but the most important one is the storage option. Search for \"Additional App Storage\" on the page and click \"Add\".
In \"Type of Storage\", select \"Host Path\" if the desired folder is a Dataset. \"Host Path\" should be where your content will be. \"Mount Path\" is the name that appears in the stash for the selection. You can put anything here, like /stash-content for example. After that, click Install.
Installation will take a few minutes. After the stash appears as \"Running\", click \"Open\" on the right and continue with the stash configuration. When entering the folder that contains its contents, remember to search for the same name you entered previously. In the case of this guide, the name was /stash-content.
"},{"location":"installation/freenas-truenas/#truenas-core","title":"TrueNAS Core","text":"Info
We are now offering pre-compiled FreeBSD binary. You can grab it from release page.
Warning
The install guide below was reported as outdated.
"},{"location":"installation/freenas-truenas/#caveats-and-assumptions","title":"Caveats and assumptions","text":"In order for the stash-linux
binary to work in a FreeBSD system, Linux compatibility must be enabled both in the system and the jail. To enable Linux compatibility:
System -> Tunables
in the TrueNAS Web UIAdd
and enter the following:linux_enable
YES
rc.conf
/etc/rc.conf
to add: enable_linux=\"YES\"\n
Go into your iocage jail and install ffmpeg
pkg install ffmpeg\n
"},{"location":"installation/freenas-truenas/#create-user-and-group","title":"Create user and group","text":"It is recommended to not run services as root. Adjust this step to your system. in this example the user stash
will be created and set to run the service.
pw useradd -n stash -u 1069 -d /nonexistent -s /usr/sbin/nologin\n
"},{"location":"installation/freenas-truenas/#download-stash-linux","title":"Download stash-linux","text":"Choose where you would like to store the binary, in this example /usr/local/bin
is selected as this is where the ffmpeg binaries also reside. Check github for latest release. Also remember to fix permissions and ownership
cd /usr/local/bin\nfetch https://github.com/stashapp/stash/releases/download/v0.22.1/stash-linux\nchown stash:stash stash-linux\nchmod +x stash-linux\n
"},{"location":"installation/freenas-truenas/#create-configuration-directory","title":"Create configuration directory","text":"stash needs a directory for its config file, database and more. Remember to change ownership and permission for the folder you select. The script we will look at in the next step has this path as the default:
mkdir /usr/local/etc/stash\nchown stash:stash /usr/local/etc/stash\n
"},{"location":"installation/freenas-truenas/#rcd-startup-script","title":"rc.d startup script","text":"In order for stash to run as a daemon in the background, and also start at boot, you need a rc.d script.
mkdir /usr/local/etc/rc.d\nee /usr/local/etc/rc.d/stash\n
Enter the following in the editor: #!/bin/sh\n\n# PROVIDE: stash\n# REQUIRE: DAEMON\n# KEYWORD: shutdown\n\n\n. /etc/rc.subr\n\nname=stash\nrcvar=stash_enable\n\nload_rc_config $name\n\n: ${stash_enable:=\"NO\"}\n: ${stash_user:=\"stash\"}\n: ${stash_group:=\"stash\"}\n: ${stash_config_dir:=\"/usr/local/etc/stash/config.yml\"}\n: ${stash_exec_bin:=\"/usr/local/bin/stash-linux\"}\n\n#daemon\npidfile=\"/var/run/${name}.pid\"\ncommand=\"/usr/sbin/daemon\"\ncommand_args=\"-f -P ${pidfile} ${stash_exec_bin} --config ${stash_config_dir}\"\nstart_precmd=\"stash_precmd\"\n\nstash_precmd() {\n install -o ${stash_user} -g ${stash_group} /dev/null ${pidfile}\n}\n\nrun_rc_command $1\n
To save, press ESC + Enter
and confirm with a
and make it executable with chmod +x /usr/local/etc/rc.d/stash
"},{"location":"installation/freenas-truenas/#enable-the-service-at-boot","title":"Enable the service at boot","text":"If you want Stash to run when you start the jail, run the following command:
sysrc \"stash_enable=YES\"\n
And to start the service, reboot the jail or run this command: service stash start\n
Stash is now available at http://jail-IP:9999/ During setup you can leave all the paths for config, database and etc empty to use the default. They will then be stored in the config-folder we created earlier so you can easily backup the folder. Only add your media content.
"},{"location":"installation/freenas-truenas/#optional-steps","title":"Optional steps","text":"You can change the location where stash stores the configuration files and database. Please note that the path needs to end with config.yml
even if it does not exist yet. Stash will create it for you. Remember to fix ownership and permissions of the location you choose.
sysrc \"stash_config_dir=path/to/location/config.yml\"\n
You can change the user and group that Stash runs as. Remember that the config_dir needs to be owned by the user that Stash runs as, aswell as the stash-linux binary
sysrc \"stash_user=usernamegoeshere\"\nsysrc \"stash_group=groupnamegoeshere\"\n
Its also possible to change the location of the stash-linux binary ``` sysrc \"stash_exec_bin=/path/to/stash-linux\"
"},{"location":"installation/linux/","title":"Linux","text":"Info
It is recommended that you install ffmpeg
from your distribution's package manager. In case you don't, Stash will prompt you to download a copy during setup.
Note
Stash offers different binaries for different architectures. You can find your processor architecture by running a simple command uname -p
in a terminal. Replace <binary-name>
in the following tutorial accordingly.
stash-linux
= amd64 (x86_64) stash-linux-arm32v6
= arm32v6 (armel) stash-linux-arm32v7
= arm32v7 (armhf) stash-linux-arm64v8
= arm64v8 (arm64)
<binary-name>
binary from GitHub repository depending on your architecture. ./<binary-name>
from the terminal.chmod u+x <binary-name>
to make the file executable.<binary-name>
binary from GitHub repository.<binary-name>
binary and replace it with the newly downloaded one. ./<binary-name>
from the terminal.chmod u+x <binary-name>
to make the file executable.<binary-name>
binary file.$HOME/.stash
folder.On macOS, Stash can be run as either a packaged app (Stash.app
) or as a command-line app (stash-macos
). Both are universal apps, and will therefore run natively on both Apple silicon and Intel-based Macs.
Note
The packaged app is recommended for most users.
It supports desktop notifications, displays a menu bar icon, and does not need to be launched from the terminal.
However, due to app restrictions, it only supports setting up in $HOME/.stash
. If you would like to use a different folder, then you will need to use the command-line app.
Stash.app.zip
from GitHub repository.Stash.app.zip
archive and drag the Stash
app to your Applications folder.Stash
app.Stash.app.zip
from GitHub repository.Stash
app. Stash.app.zip
archive and drag the Stash
app to your Applications folder. Stash
app.Stash
app.$HOME/.stash
.Note
The command-line app is only recommended for users who are familiar with the terminal, or for those who do not want to set up in $HOME/.stash
.
It does not support desktop notifications and does not display a menu bar icon. It must be launched from the terminal.
"},{"location":"installation/macos/#install_1","title":"Install","text":"stash-macos
binary from GitHub repository.Run ./stash-macos
from the terminal.
If you have trouble, try running chmod u+x stash-macos
to make the file executable.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-macos
binary from GitHub repository.stash-macos
binary and replace it with the newly downloaded one. Run ./stash-macos
from the terminal.
If you have trouble, try running chmod u+x stash-macos
to make the file executable.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-macos
.$HOME/.stash
.Info
Written by Muldec.
"},{"location":"installation/synology/#foreword","title":"Foreword","text":"Synology devices comes in two categories : those who support containerization through Docker, and those who don't. To see in which category you stand, refer to the \"Applied Models\" section of the Docker Package page.
Now, follow the installation instructions based on whether you can use Docker or you cannot use Docker.
"},{"location":"installation/synology/#to-install-stash-with-docker","title":"To install Stash with Docker","text":"Note
Running Stash without Docker is possible even if your NAS is Docker ready. It offers more control on your Stash instance startup. As an example, it allows you to store your porn collection in an Encrypted Shared Folder, and only run Stash when the Encrypted folder is Mounted (Decrypted).
(These will need to be the same as the Volumes you created in the \"Volume\" tab.)
variable Value PATH (keep as is) STASH_CACHE /cache STASH_METADATA /metadata STASH_GENERATED /generated STASH_STASH /data"},{"location":"installation/synology/#port-tab","title":"\"Port\" tab","text":"You will need to set a default port in the \"Port\" tab, otherwise Docker will assign a different port every time Stash is launched. Leave the container port as-is.
"},{"location":"installation/synology/#network-tab","title":"\"Network\" tab","text":"Make sure that \"Use The Same Network As Docker Host\" is checked.
(thanks to backer Herelam80 for these instructions)
"},{"location":"installation/synology/#to-install-stash-without-docker","title":"To install Stash without Docker","text":"Warning
This method uses SSH to run command lines on the NAS. If you are unfamiliar with SSH or linux command lines, I suggest you not to go further, as making a mistake in the SSH session can really screw your NAS.
This is intended to work on DSM 7.0 and later. It will not work on any version prior to 7.0.
"},{"location":"installation/synology/#install-prerequisites","title":"Install Prerequisites","text":"In DSM, navigate to Package Center > Settings
. In the Package Sources
tab, click Add
, type SynoCommunity as Name and https://packages.synocommunity.com/ as Location and then press OK
to validate.
Go back to the Package Center and look for Python 3.11
in the Community tab. Click on \u00ccnstall
and agree to the Third-Party Package warning.
Then look for Ffmpeg 6
in the Community tab. Click on \u00ccnstall
and agree to the Third-Party Package warning.
In DSM, navigate to Control Panel > Connectivity > Terminal & SNMP
and check the Enable SSH service
box.
Control Panel > File Sharing > User & Group
Create
buttonNext
until you are on the \"Join groups\" screenNext
until you are on the \"Assign shared folders permissions\" screenNext
until you are on the \"Assign application permissions\" screenDeny
for all applicationsNext
until you can click on Done
With your terminal, connect to your NAS using the newly created account that is part of the administrators group.
ssh stash@your_nas_hostname\n
"},{"location":"installation/synology/#link-ffprobe-ffmpeg","title":"Link ffprobe & ffmpeg","text":"ffmpeg has been installed earlier, but is missing a link to ffprobe (also installed) and the new version of ffmpeg. Run the following command.
sudo ln -s /var/packages/ffmpeg6/target/bin/ffprobe /usr/local/bin/ffprobe\nsudo ln -s /var/packages/ffmpeg6/target/bin/ffmpeg /usr/local/bin/ffmpeg\n
"},{"location":"installation/synology/#download-stash","title":"Download Stash","text":"Download the lastest version of Stash and its checksum from GitHub
# find what architecture your synology is running on\nuname -m\n\n# depending on the architecture, you'll have to download the right version of stash\n\n# x86_64\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux\n# armv6l\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux-arm32v6\n# armv7l\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux-arm32v7\n# aarch64\nwget https://github.com/stashapp/stash/releases/latest/download/stash-linux-arm64v8\n\n# Download the CHECKSUM\nwget https://github.com/stashapp/stash/releases/latest/download/CHECKSUMS_SHA1\n\n# Perform the checksum validation\nsha1sum -c --ignore-missing CHECKSUMS_SHA1\n\n# you should see a line that says `stash-linux: OK`\n# if not, something went wrong during the download\n\n# Clean up the now unnecessary file\nrm CHECKSUMS_SHA1\n
Danger
DO NOT run stash yet or it will generate a bunch of files/folders where we don't want them.
"},{"location":"installation/synology/#python","title":"Python","text":"Prepare a python environment (for scrapers and plugins)
python3.11 -m ensurepip --Update\npython3.11 -m venv stash-env\nsource stash-env/bin/activate\npip3 install pipreqs\n
"},{"location":"installation/synology/#configure-your-nas-to-run-stash","title":"Configure your NAS to run Stash","text":"Create a profile file
echo 'PATH=/usr/local/bin:$PATH' > .profile\necho 'source stash-env/bin/activate' >> .profile\n
Create the service file by running cat > stash.service
, copy/pasting the following, and hitting CTRL+D when it's done to save the file (hit again if you are not back to the prompt) :
[Unit]\nDescription=Run Stash at startup\nAfter=network.target\n\n[Service]\nWorkingDirectory=/var/services/homes/stash\nType=simple\nUser=stash\nExecStart=/bin/bash -c -l '\\\n exec ./stash-linux'\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target\n
Note
Change the ExecStart
line by providing the exact name of the stash executable that you downloaded previously.
Start and activate the service
sudo systemctl enable \"$(pwd)/stash.service\"\nsudo systemctl start stash.service\n
"},{"location":"installation/synology/#verify-that-it-is-working","title":"Verify that it is working","text":"You can now access to stash by navigating to your NAS url on port 9999 : http://nas-hostname:9999
Whenever you install a new python scraper or plugin, do the following from the stash user home directory
pipreqs .stash/.\npip3 install -r .stash/requirements.txt\n
Note
Using pipreqs allows to scan all scrapers and plugins installed and find dependencies that they require. You can do the same thing without pipreqs by going into each individual directory and run pip3 install -r requirements.txt
Control Panel > File Sharing > User & Group
Edit
User Groups
tab, uncheck \"administrators\" and click on Save
Info
Unraid app is maintained by a 3rd party. For Unraid specific support you can go to support thread by CorneliousJD.
Note
For users that want to try the development branch of Stash you can change the repository to stashapp/stash:development
.
Apps
tab.Stash
.Stash
.Info
binarygeek119/stash-cuda:latest
repository is not maintained by Stash core team.
First off you need the unraid Nvidia plugin for this to work. On Unraid go to apps and do a search for nvidia driver
and install, this will take some time to install. When the dialog is done it is still installing in the background. When it has finshed you will get a popup saying it is safe to reboot now.
Warning
Do not restart Unraid server until the plugin is done installing itself!
After getting the popup, reboot your server. After it back online you may continue to the next steps.
"},{"location":"installation/unraid/#container-configuration","title":"Container configuration","text":"
Now we can change some thing to have Stash work with a Nvidia GPU.
stashapp/stash:development
to binarygeek119/stash-cuda:latest
. --runtime=nvidia
. Add another Path, Port, Variable, Label or Device
. path
to Variable
and add the following: Name:
enter NVIDIA_DRIVER_CAPABILITIES
Key:
enter NVIDIA_DRIVER_CAPABILITIES
Value:
enter all
and click save. Add another Path, Port, Variable, Label or Device
. path
to Variable
and add the following:Name:
enter NVIDIA_VISIBLE_DEVICES
Key:
enter NVIDIA_VISIBLE_DEVICES
Value:
enter GPU-xxxx-xxxx-xxx-xxxx-xxxx-xxx-xxxxxxxxxxxx
Where GPU-xxxx-xxxx-xxx-xxxx-xxxx-xxx-xxxxxxxxxxxx
you must enter your own GPUID. To find it do the folowing:
Variable
called Value
.Note
Some Windows 11 versions might open Stash via Terminal instead of going to notification area. You can bypass that by running the program as administrator or use a shortcut to run it via conhost.exe. As a result of running as administrator Stash might fail to detect your Python installtion in PATH, so you need point it the correct way yourself after installation. In Settings > System and under Applications Paths header set Python Executable Path.
"},{"location":"installation/windows/#install","title":"Install","text":"stash-win.exe
binary from GitHub repository.Run the executable (typically stash-win.exe
).
Running the executable might present a security prompt since the binary isn't signed yet. Just click more info and then the run anyway
button.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-win.exe
binary from GitHub repository.stash-win.exe
binary and replace it with the newly downloaded one. Run the executable (typically stash-win.exe
).
Running the executable might present a security prompt since the binary isn't signed yet. Just click more info and then the run anyway
button.
If everything went well, it should open a browser tab http://localhost:9999 to get started.
stash-win.exe
binary file.%userprofile%/.stash
folder.Info
Integrations are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Integrations are ways to integrate Stash into other programs.
To install follow the provided install instructions.
"},{"location":"integrations/list/","title":"List of integrations","text":"stash-git-indexExhaustive list of git repositories related to Stash Google Sheets document.
Integration no longer worksIf you found that integration is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"integrations/list/#jellyfinpluginstash","title":"Jellyfin.Plugin.Stash","text":"DescriptionAuthorScreenshotsPulls data from your Stash using the filename to query on.
DirtyRacer1337
"},{"location":"integrations/list/#pluginvideostash","title":"plugin.video.stash","text":"DescriptionAuthorScreenshotsplugin.video.stash is an add-on for the Kodi home theater center software to incorporate Stash, an organizer for your porn.
gitgiggety
"},{"location":"integrations/list/#stashplexagentbundle","title":"StashPlexAgent.bundle","text":"DescriptionAuthorScreenshotsA very simplistic Plex agent to pull metadata from Stash.
Darklyter
"},{"location":"metadata-sources/","title":"Metadata sources","text":"There are several ways to get metadata into Stash.
You can configure your metadata sources under Settings > Metadata Providers. See sections below for more details.
Scrapers are the way to retrieve information from websites for your scenes/groups/galleries/performers. Using scrapers wisely, you can avoid typing information manually and repetitively. They can help you quickly establish links between groups/scenes and performers/studios, add relative tags, then download covers/posters for easy recognition. It's a great feature to organize your video or image collections.
"},{"location":"metadata-sources/scrapers/#managing-scrapers","title":"Managing scrapers","text":"Scrapers can be installed and managed from the Settings > Metadata Providers page.
Scrapers are installed using the Available Scrapers section. The Community (stable) source is configured by default.
Installed plugins can be updated or uninstalled from the Installed Scrapers section.
"},{"location":"metadata-sources/scrapers/#adding-sources","title":"Adding sources","text":"Anyone can create their own source index for scrapers. To add a new source go to Settings > Metadata Providers page and under Available Scrapers click Add Source.
"},{"location":"metadata-sources/scrapers/#installing-scrapers-manually","title":"Installing scrapers manually","text":"By default, Stash looks for scrapers configurations in the scrapers sub-directory of the directory where the stash config.yml
is read. This will either be the %USERPROFILE%\\.stash\\scrapers
on Windows or /root/.stash/scrapers
on Unix systems (Mac, Linux, etc.) or the current working directory.
Scrapers are added by adding configuration yaml files (format: scraperName.yml
) to the scrapers
directory.
Loaded scrapers can be viewed in the Settings > Metadata Providers page. After scrapers are added, removed or edited while Stash is running, they can be reloaded by clicking Reload scrapers button.
CommunityScrapers repository is the source for community maintained scrapers.
"},{"location":"metadata-sources/scrapers/#scraper-types","title":"Scraper types","text":""},{"location":"metadata-sources/scrapers/#by-searching-type","title":"By searching type","text":""},{"location":"metadata-sources/scrapers/#fragment","title":"Fragment","text":"This kind of scrapers will fetch the metadata from a website, by using existing data from Stash, like a scene's file name, performer's name...etc. Fragment scrapers will get all the data Stash knows about that scene/performer/gallery, so it's quite flexible when fetching information.
"},{"location":"metadata-sources/scrapers/#search-by-name","title":"Search by name","text":"A Search-By-Name scraper will get only \"name\" input from a scene or performer, then it will search a website with that name, and return a list of results.
Scrapers includes: Babepedia.yml, FreeonesCommunity.yml, IAFD.yml
"},{"location":"metadata-sources/scrapers/#search-by-url","title":"Search by URL","text":"Most scrapers fetch metadata from a given URL, either by using XPath, JSON, or scripts. For this kind of scrapers you need to know the URL for that scene/performer/gallery/group so they can extract information from it.
Scrapers includes: All other scrapers.
"},{"location":"metadata-sources/scrapers/#by-implementation","title":"By implementation","text":""},{"location":"metadata-sources/scrapers/#xpath-and-json-scrapers","title":"XPath and JSON scrapers","text":"This is the most common type of scrapers, which use either XPath parser to pin-point the information and retrieve them, or send out JSON requests to get the information. xpathScraper and jsonScraper can be mixed in the same .yml file.
"},{"location":"metadata-sources/scrapers/#cdp-scrapers","title":"CDP scrapers","text":"This type of scrapers is mostly the same as XPath/JSON scrapers, except it will launch a headless Chrome browser to retrieve the information from websites. It can also get cookies, simulate a mouse click and other actions. These scrapers have useCDP: true
setting in them.
This type of scrapers will launch Python, Ruby to retrieve information from websites. Script scrapers are powerful, versatile and cross-platform. So they usually can do much more than regular scrapers. To install this kind of scrapers, you need to copy not only the .yml file, but also all the script files like .py, .rb that associated with it.
"},{"location":"metadata-sources/scrapers/#more-details","title":"More details","text":"You can view the detailed information about scrapers here or CommunityScrapers README.
"},{"location":"metadata-sources/scrapers/#create-your-own","title":"Create your own","text":"To create your own scraper, there is detailed information about that as well. Best way to start is to read the simple ones and understand how xpath works. The XPath Cheetsheet is quite useful in creating a .yml file. In Firefox you can use xpath search in \"Web Developer Tools (F12)\". The \"search HTML\" bar actually accepts xpath searches. You can use it to verify your xpath queries.
"},{"location":"metadata-sources/scrapers/#contribution","title":"Contribution","text":"The Scraper community always welcome new members. If you create a nice scraper and find it stable and useful, you can share it via the GitHub repository. Create a pull request, and let the mod review your work. The mods are busy, so it will probably take a few days, or a couple of weeks, but it will be a great feeling once your contribution is accepted by the community.
"},{"location":"metadata-sources/stash-box-instances/","title":"stash-box instances","text":""},{"location":"metadata-sources/stash-box-instances/#fansdb","title":"FansDB","text":"FansDB is a community-driven metadata database focused on adult content platforms (OnlyFans, Fansly, ManyVids, etc.) where the independent creators are the primary focus.
Website | Guidelines | Discord | Endpoint https://fansdb.cc/graphql
| Join
JAVStash is a community-driven metadata database focused on Japanese Adult Video content and their original metadata in Japanese.
Website | Guidelines1 | Discord | Endpoint https://javstash.org/graphql
| Join2
PMV Stash is a community-driven metadata database focused on remixed pornographic art such as Porn Music Videos, Cock Hero, Hypno Vids, Compilations.
Website | Guidelines | Discord | Endpoint https://pmvstash.org/graphql
| Join
StashDB is a community-driven metadata database focused on digital scenes of all orientations.
Website | Guidelines | Discord | Matrix | Endpoint https://stashdb.org/graphql
| Join
ThePornDB is a metadata database focused on digital scenes and movies, relying on automated scrapers.
Website | Discord | Endpoint https://theporndb.net/graphql
| Join3
Link leads to a private Discord server.\u00a0\u21a9
Link leads to a private Discord server.\u00a0\u21a9
Requires registration to access the site.\u00a0\u21a9
Stash data is considered private, and Stash is not designed to be publicly exposed, except to trusted confidants. Stash has a built-in protection against accidentally exposing itself publicly outside of your network. If Stash receives a request from the public internet, and you do not have a password enabled, Stash will reject the request and stop handling requests to protect your privacy.
This often happens when you use the port-forwarding feature of your router or install Stash on a publicly accessible server, such as a VPS. When you do this, anybody in the world can access your Stash instance, so we enforce a password requirement. If your Stash instance has shutdown due to an insecure configuration, it will not handle requests again until you tell it that you have fixed the problem. After setting up either authentication, firewall, or removing your port forwarding rules, you can edit .stash/config/config.yml
and remove the key security_tripwire_accessed_from_public_internet
.
You may use several methods to safely access Stash from outside of your home network. In the most basic, you can enable authentication in Stash, and re-enable port forwarding. You can also use a VPN solution that allows you to securely access your home network, such as Tailscale, Zerotier, Wireguard, or others.
"},{"location":"networking/authentication-required-when-accessing-stash-from-the-internet/#using-an-external-authentication-provider","title":"Using an external authentication provider","text":"If you are an advanced user, and have secured your Stash instance behind an authwall provided by a reverse proxy or hosting solution, you may continue to use that. You simply have to edit .stash/config/config.yml
and set dangerous_allow_public_without_auth
to true
. If you have already tripped the security feature, you will also have to remove the security_tripwire_accessed_from_public_internet
key in order to allow Stash to serve requests.
Info
Plugins are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Plugins adds further features that Stash doesn't itself provide.
"},{"location":"plugins/#managing-plugins","title":"Managing plugins","text":"Plugins can be installed and managed from the Settings > Plugins page.
Plugins are installed using the Available Plugins section. The Community (stable) source is configured by default.
Installed plugins can be updated or uninstalled from the Installed Plugins section.
"},{"location":"plugins/#adding-sources","title":"Adding sources","text":"Anyone can create their own source index for plugins. To add a new source go to Settings > Plugins page and under Available Plugins click Add Source.
"},{"location":"plugins/#installing-plugins-manually","title":"Installing plugins manually","text":"By default, Stash looks for plugin configurations in the plugins sub-directory of the directory where the stash config.yml
is read. This will either be the %USERPROFILE%\\.stash\\plugins
on Windows or /root/.stash/plugins
on Unix systems (Mac, Linux, etc.) or the current working directory.
Plugins are added by adding configuration yaml files (format: pluginName.yml
) to the plugins
directory.
Loaded plugins can be viewed in the Settings > Plugins page. After plugins are added, removed or edited while Stash is running, they can be reloaded by clicking Reload plugins button.
"},{"location":"plugins/list/","title":"List of plugins","text":""},{"location":"plugins/list/#add-images-to-tags","title":"Add Images to Tags","text":"DescriptionSource URLREADMEAuthorScreenshotsAuto add images to tags using first found image from Google API. Requires modifying the .py file to provide your own API key and CSE ID
https://rosa-umineko.github.io/CommunityScripts/stable/index.yml\n
No README available
rosa-umineko
"},{"location":"plugins/list/#adulttime-interactive-downloader","title":"Adulttime Interactive Downloader","text":"DescriptionSource URLREADMEAuthorScreenshotsDownload Interactive Files for Adulttime Scenes
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
tooliload
"},{"location":"plugins/list/#ai-tagger","title":"AI Tagger","text":"DescriptionSource URLREADMEAuthorScreenshotsTag videos and Images with Locally hosted AI using Skier's Free and Patreon AI models
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
skier233
"},{"location":"plugins/list/#audio-transcodes","title":"audio-transcodes","text":"DescriptionSource URLREADMEAuthorScreenshotsGenerate a transcode video from an audio file
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#auto-select-updatable-plugins-and-scrapers","title":"Auto Select Updatable Plugins and Scrapers","text":"DescriptionSource URLREADMEAuthorScreenshotsAuto selects updatable Plugins and Scrapers when Check for Updates is clicked
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#auto-update-plugins-and-scrapers","title":"Auto Update Plugins and Scrapers","text":"DescriptionSource URLREADMEAuthorScreenshots
Automatically updates Plugins and Scrappers on website Startup
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#autovr","title":"autovr","text":"DescriptionSource URLREADMEAuthorScreenshotsautomatically toggle VR mode
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#average-rating","title":"Average Rating","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds average rating to performers and studios
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#backup-plugins","title":"Backup Plugins","text":"DescriptionSource URLREADMEAuthorScreenshotsCreates a backup of the 'plugins' directory.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#bulk-import-performers","title":"Bulk Import Performers","text":"DescriptionSource URLREADMEAuthorScreenshotsBulk Import Performers based on names from a text file.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#cjs-card-tweaks","title":"CJ's Card Tweaks.","text":"DescriptionSource URLREADMEAuthorScreenshotsProvides various tweaks for the Stash Cards.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
No Author
"},{"location":"plugins/list/#cleanupui","title":"CleanupUI","text":"DescriptionSource URLREADMEAuthorScreenshots
UI plugin to hide features you don't want
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
View README
S3L3CT3DLoves
"},{"location":"plugins/list/#comic-info-extractor","title":"Comic Info Extractor","text":"DescriptionSource URLREADMEAuthorScreenshotsExtract the metadata from cbz with the Comicrack standard (ComicInfo.xml)
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
yoshnopa
"},{"location":"plugins/list/#communityscriptsuilibrary","title":"CommunityScriptsUILibrary","text":"DescriptionSource URLREADMEAuthorScreenshotsCommunityScripts UI helper library
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
No Author
"},{"location":"plugins/list/#completethestash","title":"CompleteTheStash","text":"DescriptionSource URLREADMEAuthorScreenshotsFinds missing scenes for selected performers and creates missing scene metadata to another missing Stash instance. You can use either StashDB or TPDB or both as a source for missing scenes.
https://minasukihikimuna.github.io/MidnightRider-Stash/index.yml\n
View README
MinasukiHikimuna
"},{"location":"plugins/list/#cuptag","title":"cuptag","text":"DescriptionSource URLREADMEAuthorScreenshotsTag performers with cup sizes
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#date-parser","title":"Date Parser","text":"DescriptionSource URLREADMEAuthorScreenshotsFind date in path or filename and add it
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
HijackHornet
"},{"location":"plugins/list/#default-data-for-path","title":"Default Data For Path","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds configured Tags, Performers and/or Studio to all newly scanned Scenes, Images and Galleries.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
TheSinfulKing
"},{"location":"plugins/list/#deletefp","title":"deletefp","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a button to delete fingerprints
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#discord-presence","title":"Discord Presence","text":"DescriptionSource URLREADMEAuthorScreenshotsSets currently playing scene data as your Discord status. See README for prerequisites and config options (blue hyperlink next to enable/disable button)
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
NotForMyCV
"},{"location":"plugins/list/#dupe-marker-detector","title":"Dupe Marker Detector","text":"DescriptionSource URLREADMEAuthorScreenshotsFinds and marks duplicate markers
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#dupfilemanager","title":"DupFileManager","text":"DescriptionSource URLREADMEAuthorScreenshotsManages duplicate files.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
No Author
"},{"location":"plugins/list/#duplicate-scene-marker-cleaner","title":"Duplicate Scene Marker Cleaner","text":"DescriptionSource URLREADMEAuthorScreenshotsAutomatically detects and removes duplicate scene markers based on scene ID, seconds, and title upon scene updates or via manual trigger.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#easytag","title":"EasyTag","text":"DescriptionSource URLREADMEAuthorScreenshotsUI plugin to add shortcuts for commonly used tags
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
View README
S3L3CT3DLoves
"},{"location":"plugins/list/#edit-unorganized","title":"edit-unorganized","text":"DescriptionSource URLREADMEAuthorScreenshotsDefault to edit tab on unorganized scenes
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#extended-stats","title":"Extended Stats","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds new stats to the stats page
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#filemonitor","title":"FileMonitor","text":"DescriptionSource URLREADMEAuthorScreenshotsMonitors the Stash library folders, and updates Stash if any changes occurs in the Stash library paths.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
David-Maisonave
"},{"location":"plugins/list/#filename-parser","title":"Filename parser","text":"DescriptionSource URLREADMEAuthorScreenshots
Parses filename into studio, date, performers and title
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
gitgiggety
"},{"location":"plugins/list/#filepath-copy","title":"filepath-copy","text":"DescriptionSource URLREADMEAuthorScreenshotsCopy file path to clipboard when selected
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#find-file-errors","title":"Find File Errors","text":"DescriptionSource URLREADMEAuthorScreenshotsfind files that stash has previously errored on from the log file
https://stg-annon.github.io/StashScripts/stable/index.yml\n
No README available
stg-annon
"},{"location":"plugins/list/#find-marker-tag-images","title":"Find Marker Tag Images","text":"DescriptionSource URLREADMEAuthorScreenshotsScript to update tag images based on scene markers
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#foldersort","title":"folderSort","text":"DescriptionSource URLREADMEAuthorScreenshotsOrganise your PMV folder(s) based on Stash info
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
View README
S3L3CT3DLoves
"},{"location":"plugins/list/#fontawesome-js","title":"fontawesome-js","text":"DescriptionSource URLREADMEAuthorScreenshotsUse fontawesome icons from React libraries
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#funscript-markers","title":"Funscript Markers","text":"DescriptionSource URLREADMEAuthorScreenshotsCreate markers if there is a funscript with \"chapters\" included in the metadata of the script
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#glassy-branding","title":"Glassy - Branding","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#hashthestash","title":"HashTheStash","text":"DescriptionSource URLREADMEAuthorScreenshotsCalculates additional fingerprints for scenes.
https://minasukihikimuna.github.io/MidnightRider-Stash/index.yml\n
No README available
MinasukiHikimuna
"},{"location":"plugins/list/#hot-cards","title":"Hot Cards","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds custom styling to card elements that match a Tag ID or a Rating Threshold.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
HandyRandyx
"},{"location":"plugins/list/#image2scene","title":"image2Scene","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd a mechanism to link images to scenes in the Image Edit Panel.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#lightbox-visual-novel","title":"Lightbox Visual Novel","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplay the image description with Typewriter effect on the footer.
https://w0lfiew0lf.github.io/StashApp-Tools/index.yml\n
View README
W0lfieW0lf
"},{"location":"plugins/list/#log-console","title":"log-console","text":"DescriptionSource URLREADMEAuthorScreenshots
display log messages in console
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#log-toast","title":"log-toast","text":"DescriptionSource URLREADMEAuthorScreenshotsdisplay log messages as toasts
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#marker-delete-button","title":"Marker Delete Button","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a delete button to entries on the Markers page and on the Scene page.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
[WeedLordVegeta420](https://github.com/WeedLordVegeta420]
"},{"location":"plugins/list/#markergen","title":"markergen","text":"DescriptionSource URLREADMEAuthorScreenshotsGenerate markers on save
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#mcmetadata","title":"mcMetadata","text":"DescriptionSource URLREADMEAuthorScreenshotsGenerates metadata for use with other media servers like Emby and Jellyfin, and optionally organizes/renames your tagged scenes.
https://carrotwaxr.github.io/stash-plugins/stable/index.yml\n
View README
carrotwaxr
"},{"location":"plugins/list/#misc-tags","title":"Misc Tags","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd extra tags for VR and other ues
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Tweeticoats
"},{"location":"plugins/list/#movie-duration-from-scenes","title":"Movie Duration from Scenes","text":"DescriptionSource URLREADMEAuthorScreenshotsMore accurately reflect your movie's duration with the sum of durations of its scenes.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy","title":"Movie-Fy","text":"DescriptionSource URLREADMEAuthorScreenshotsMovie-Fy meta-package
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-bulk-movie-scraper","title":"Movie-Fy Bulk Movie Scraper","text":"DescriptionSource URLREADMEAuthorScreenshotsUpdate your movie metadata in bulk.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-check-and-update-scene-titles","title":"Movie-Fy Check and Update Scene Titles","text":"DescriptionSource URLREADMEAuthorScreenshotsCheck and update titles for scenes in the Movie studio
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-create-movie-studio","title":"Movie-Fy Create Movie Studio","text":"DescriptionSource URLREADMEAuthorScreenshotsCreates a new Movie Studio to be used with Mass_Movie_Create
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-scene-studio-bulk-update","title":"Movie-Fy Scene Studio Bulk Update","text":"DescriptionSource URLREADMEAuthorScreenshotsBulk update scene studios based on movie studios.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#movie-fy-update-movie-scene-covers","title":"Movie-Fy Update Movie Scene Covers","text":"DescriptionSource URLREADMEAuthorScreenshotsUpdate scene cover images with movie cover images.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#path-parser","title":"Path Parser","text":"DescriptionSource URLREADMEAuthorScreenshotsUpdates scene info based on the file path.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
ImJustMatt
"},{"location":"plugins/list/#performer-body-calculator","title":"Performer Body Calculator","text":"DescriptionSource URLREADMEAuthorScreenshotsTags performers based on existing metadata, with tags matching the performers body type
https://stg-annon.github.io/StashScripts/stable/index.yml\n
View README
stg-annon
"},{"location":"plugins/list/#performer-details-extended","title":"Performer Details Extended","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplays additional metadata on performer pages, such as their most regular scene partners, top studio, and total play duration. Requires Stash v0.27.0 or higher.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#performer-gallery-scraper-plugin","title":"Performer Gallery Scraper Plugin","text":"DescriptionSource URLREADMEAuthorScreenshotsA plugin to scrape galleries from porngals4.com for specific performers and create zip archives.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#performer-scene-compare","title":"Performer Scene Compare","text":"DescriptionSource URLREADMEAuthorScreenshotsCompares local performer scenes with StashDB and updates the local database.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#phash-duplicate-tagger","title":"PHash Duplicate Tagger","text":"DescriptionSource URLREADMEAuthorScreenshotsPHash Duplicate Tagger (PDT) Will tag scenes based on duplicate PHashes for easier/safer removal.
https://stg-annon.github.io/StashScripts/stable/index.yml\n
View README
stg-annon
"},{"location":"plugins/list/#play-video-if-preview-not-found","title":"Play Video If Preview Not Found","text":"DescriptionSource URLREADMEAuthorScreenshotsPlays video on scene card hover if preview is not found
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#public-ip","title":"Public IP","text":"DescriptionSource URLREADMEAuthorScreenshots
Query ident.me to check my current IP (ensure VPN is working)
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
No README available
S3L3CT3DLoves
"},{"location":"plugins/list/#python-tools-installer","title":"Python Tools Installer","text":"DescriptionSource URLREADMEAuthorScreenshotsDownload stashapp-tools for DockerEnv
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
tooliload
"},{"location":"plugins/list/#quickrating","title":"QuickRating","text":"DescriptionSource URLREADMEAuthorScreenshotsMore rating UI options (only enable one)
https://s3l3ct3dloves.github.io/stashPlugins/stable/index.yml\n
No README available
S3L3CT3DLoves
"},{"location":"plugins/list/#qx-scene-card","title":"Qx Scene Card","text":"DescriptionSource URLREADMEAuthorScreenshotsRedesigns the scene card.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Qx
"},{"location":"plugins/list/#rebrand","title":"Rebrand","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a name override of your choice in Stash
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#renamefile","title":"RenameFile","text":"DescriptionSource URLREADMEAuthorScreenshotsRenames video (scene) file names when the user edits the [Title] field located in the scene [Edit] tab.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
David-Maisonave
"},{"location":"plugins/list/#renamer","title":"Renamer","text":"DescriptionSource URLREADMEAuthorScreenshotsRenames scene files based on scene details and updates associated scenes with a \"Renamed\" tag.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#renamer-dev","title":"Renamer-Dev","text":"DescriptionSource URLREADMEAuthorScreenshotsRenames scene files based on scene details and updates associated scenes with a \"Renamed\" tag.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#renameronupdate","title":"renamerOnUpdate","text":"DescriptionSource URLREADMEAuthorScreenshotsRename/move filename based on a template.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Belleyy
"},{"location":"plugins/list/#replace-thumbnails-with-high-res-images","title":"Replace Thumbnails With High-Res Images","text":"DescriptionSource URLREADMEAuthorScreenshots
Replaces thumbnails with original high res images
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#scene-cover-cropper","title":"Scene Cover Cropper","text":"DescriptionSource URLREADMEAuthorScreenshotsCrop Scene Cover Images
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#scene-marker-tags-to-scene","title":"Scene Marker Tags to Scene","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds primary tag of Scene Marker to the Scene on marker create/update.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
WithoutPants
"},{"location":"plugins/list/#scene-page-remember-states","title":"Scene Page Remember States","text":"DescriptionSource URLREADMEAuthorScreenshotsUses local storage to remember the state of the scene page detail panel nav bar and activate it on page load. Remembers collapse state of the divider.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#scenehub","title":"SceneHub","text":"DescriptionSource URLREADMEAuthorScreenshotsCollects the latest scenes from popular network sites and displays them all in one page.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#serechopsscenecard","title":"SerechopsSceneCard","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom scene card via the Plugin API.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#set-scene-cover","title":"Set Scene Cover","text":"DescriptionSource URLREADMEAuthorScreenshotssearches Stash for Scenes with a cover image in the same folder and sets the cover image in stash to that image
https://rosa-umineko.github.io/CommunityScripts/stable/index.yml\n
No README available
rosa-umineko
"},{"location":"plugins/list/#set-scene-cover_1","title":"Set Scene Cover","text":"DescriptionSource URLREADMEAuthorScreenshotssearches Stash for Scenes with a cover image in the same folder and sets the cover image in stash to that image
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
stg-annon
"},{"location":"plugins/list/#skip-intro","title":"skip-intro","text":"DescriptionSource URLREADMEAuthorScreenshotsSkips static duration intros
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stash-accessibility","title":"Stash Accessibility","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an Accessibility button in the top right navbar that offers various accessibility features.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-ai","title":"Stash AI","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd Tags or Markers to a video using AI
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cc1234475
"},{"location":"plugins/list/#stash-batch-create-all","title":"Stash Batch Create All","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a 'Create All' button to the scene tagger view. It will target all 'Create' buttons and add new tags as well.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-batch-query-edit","title":"Stash Batch Query Edit","text":"DescriptionSource URLREADMEAuthorScreenshotsBatch modify scene tagger search query
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-batch-result-toggle","title":"Stash Batch Result Toggle","text":"DescriptionSource URLREADMEAuthorScreenshots
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
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-batch-save","title":"Stash Batch Save","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a batch save button to scenes tagger
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-batch-search","title":"Stash Batch Search","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a batch search button to scenes and performers tagger
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-disable-all","title":"Stash Disable All","text":"DescriptionSource URLREADMEAuthorScreenshots
Disables all UI configs and plugins. Saves the current config to a JSON file so that it can be restored to original state.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-dynamic-groups","title":"Stash Dynamic Groups","text":"DescriptionSource URLREADMEAuthorScreenshotsDesignate dynamic groups that can be populated simply by assigning a tag.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-enable-all","title":"Stash Enable All","text":"DescriptionSource URLREADMEAuthorScreenshotsRestores the UI to its original state via a saved JSON config.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-fps-overlay","title":"Stash FPS Overlay","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an FPS overlay on the scene cards.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-jellyfin-exporter","title":"Stash Jellyfin Exporter","text":"DescriptionSource URLREADMEAuthorScreenshotsRestructures your Stash library to be Jellyfin compliant to better serve and populate metadata within your Jellyfin server.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-markdown","title":"Stash Markdown","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds markdown parsing to tag description fields
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-markers-autoscroll","title":"Stash Markers Autoscroll","text":"DescriptionSource URLREADMEAuthorScreenshots
Automatically scrolls markers page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-matched-performer-scrape","title":"Stash Matched Performer Scrape","text":"DescriptionSource URLREADMEAuthorScreenshots
Scrapes performers in bulk from ThePornDB and StashDB on exact name matches only.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-mergers","title":"Stash Mergers","text":"DescriptionSource URLREADMEAuthorScreenshotsA plugin for selectively merging data between performers in Stash.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#stash-new-performer-filter-button","title":"Stash New Performer Filter Button","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a customizable button to the performers page. Links to a new performers filter by default.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-notes","title":"Stash Notes","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a button to the navigation bar which opens a small window for writing notes to your browser's local storage.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
QxxxGit
"},{"location":"plugins/list/#stash-open-media-player","title":"Stash Open Media Player","text":"DescriptionSource URLREADMEAuthorScreenshotsOpen scene filepath links in an external media player
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-audit-task-button","title":"Stash Performer Audit Task Button","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a button to the performers page to run the audit plugin task
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-custom-fields","title":"Stash Performer Custom Fields","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds custom fields to performers that are stored in performer details as JSON.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
View README
7dJx1qP
"},{"location":"plugins/list/#stash-performer-favicons","title":"Stash Performer Favicons","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds the performer URL favicons as a new line item in the performer details.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-performer-image-cropper","title":"Stash Performer Image Cropper","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an image cropper to performer page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-image-extractor","title":"Stash Performer Image Extractor","text":"DescriptionSource URLREADMEAuthorScreenshots
Extracts all performers from your localdb to a local directory for easy editing.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-performer-markers-tab","title":"Stash Performer Markers Tab","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a Markers link to performer pages
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-tagger-additions","title":"Stash Performer Tagger Additions","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds performer birthdate and url to tagger view. Makes clicking performer name open stash profile in new tab instead of current tab.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-performer-url-searchbox","title":"Stash Performer URL Searchbox","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a search by performer url textbox to the performers page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-realbooru","title":"Stash Realbooru","text":"DescriptionSource URLREADMEAuthorScreenshots
Add tags based on the realbooru model, This works on individual images.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cc1234475
"},{"location":"plugins/list/#stash-reels","title":"Stash Reels","text":"DescriptionSource URLREADMEAuthorScreenshotsTikTok for Stash.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#stash-right-click-galleries","title":"Stash Right Click Galleries","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the gallery cards to perform various quick tasks related to galleries.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-images","title":"Stash Right Click Images","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the image cards to perform various quick tasks related to images.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-performer-merge","title":"Stash Right Click Performer Merge","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the to perform various quick tasks related to settings.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-performers","title":"Stash Right Click Performers","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the performer cards to perform various quick tasks related to performers.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-scenes","title":"Stash Right Click Scenes","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the scene cards to perform various quick tasks related to scenes.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-settings","title":"Stash Right Click Settings","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the settings icon to perform various quick tasks related to settings.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-right-click-suite","title":"Stash Right Click Suite","text":"DescriptionSource URLREADMEAuthorScreenshotsMeta-package installer for the Stash Right-Click Suite tools.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-right-click-tags","title":"Stash Right Click Tags","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom right-click menu to the tag cards to perform various quick tasks related to tags.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-scene-file-size","title":"Stash Scene File Size","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplay file size on scene cards.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-scene-specs-overlay","title":"Stash Scene Specs Overlay","text":"DescriptionSource URLREADMEAuthorScreenshotsHides all the scene specs overlay within the scene card and reveals them on hover.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-scene-tagger-additions","title":"Stash Scene Tagger Additions","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds scene duration and filepath to tagger view.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-scene-tagger-colorizer","title":"Stash Scene Tagger Colorizer","text":"DescriptionSource URLREADMEAuthorScreenshots
Colorize scene tagger match results to show matching and mismatching scene data.
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-scene-tagger-draft-submit","title":"Stash Scene Tagger Draft Submit","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds button to Scene Tagger to submit draft to stashdb
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-set-stashbox-favorite-performers","title":"Stash Set Stashbox Favorite Performers","text":"DescriptionSource URLREADMEAuthorScreenshots
Set Stashbox favorite performers according to stash favorites
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stashbox-scene-count","title":"Stash Stashbox Scene Count","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds stashbox scene counts to performers and studios
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stashid-icon","title":"Stash StashID Icon","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds checkmark icon to performer and studio cards that have a stashid
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stashid-input","title":"Stash StashID Input","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds input for entering new stash id to performer details page and studio page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-stats","title":"Stash Stats","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds stats to stats page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
View README
7dJx1qP
"},{"location":"plugins/list/#stash-studio-logo-wall-view","title":"Stash Studio Logo Wall View","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds the studio logo on the scene cards in Wall view.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-tag-custom-colors","title":"Stash Tag Custom Colors","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom button in the navbar to stylize tag chips based on CSS snippets, regex patterns, or basic color-coding.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stash-tag-image-cropper","title":"Stash Tag Image Cropper","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an image cropper to tag page
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-timestamps","title":"Stash TimeStamps","text":"DescriptionSource URLREADMEAuthorScreenshots
Create timestamps from pre-existing markers within the scene's details.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-toggle-scene-sprites","title":"Stash Toggle Scene Sprites","text":"DescriptionSource URLREADMEAuthorScreenshotsToggles scene sprites to replace static preview image of all scenes on the current index page.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-ui-plugin-example","title":"Stash UI Plugin Example","text":"DescriptionSource URLREADMEAuthorScreenshotsAn attempt to simplify the process of building UI plugins.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stash-video-player-ab-loop-time-input","title":"Stash Video Player AB Loop Time Input","text":"DescriptionSource URLREADMEAuthorScreenshotsReplaces the video player AB loop start and end buttons with time inputs
https://7djx1qp.github.io/stash-plugins/main/index.yml\n
No README available
7dJx1qP
"},{"location":"plugins/list/#stash-omnisearch","title":"stash-omnisearch","text":"DescriptionSource URLREADMEAuthorScreenshots
search all the things on stash
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stash-open","title":"stash-open","text":"DescriptionSource URLREADMEAuthorScreenshotsOpens media files in local media player
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stash-s6-helper","title":"stash-s6 helper","text":"DescriptionSource URLREADMEAuthorScreenshotsstash-s6 helper plugin
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stashappandroidtv-companion","title":"StashAppAndroidTV Companion","text":"DescriptionSource URLREADMEAuthorScreenshotsA companion plugin for StashAppAndroidTV
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
damontecres
"},{"location":"plugins/list/#stashaudioplayer","title":"StashAudioPlayer","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd an audio-only toggle button and support for audio files in the Stash player through hls transcoder.
https://raw.githubusercontent.com/d0t-d0t-d0t/stash-repo/refs/heads/dist/index.yml\n
View README
d0t-d0t-d0t
"},{"location":"plugins/list/#stashdb-performer-gallery","title":"stashdb performer gallery","text":"DescriptionSource URLREADMEAuthorScreenshotsAutomatically download performer images from stashdb or other stash-boxes. Add the [Stashbox Performer Gallery] tag to a performer and it will create a gallery of images from that stash-box database. Apply the tag [Set Profile Image] to an image to set it as the profile image of that performer. Note you will need to configure the download path and add this as a path under settings > library
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Tweeticoats
"},{"location":"plugins/list/#stashdb-tag-import","title":"StashDB Tag Import","text":"DescriptionSource URLREADMEAuthorScreenshotsImport StashDB's list of Tags for your Stash.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stashdb-fullimg","title":"stashdb-fullimg","text":"DescriptionSource URLREADMEAuthorScreenshotsDownload full-size images from StashDB
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stashdisable","title":"stashDisable","text":"DescriptionSource URLREADMEAuthorScreenshotsstashDisable meta-package
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#stashlist-sync","title":"stashlist-sync","text":"DescriptionSource URLREADMEAuthorScreenshotsSync stashIDs to stashlist history
https://feederbox826.github.io/stashlist/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#stashnewperformerscenes","title":"stashNewPerformerScenes","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds a custom icon in the performer card should they have a new scene released within the specified date range from the navbar button.
https://serechops.github.io/Serechops-Stash/index.yml\n
No README available
serechops
"},{"location":"plugins/list/#stashtagperformerimage","title":"stashTagPerformerImage","text":"DescriptionSource URLREADMEAuthorScreenshotsChecks parent directory of image on Image.Update.Post and compares to any existing performers in the db. Updates that image with the related performer.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#studio-background-shadow","title":"Studio background shadow","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd drop shadows to studio icons for visibility
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#studio-top-performer","title":"Studio Top Performer","text":"DescriptionSource URLREADMEAuthorScreenshots
Adds a Queen icon with the top performer listed in the studio cards as determined by most scenes starred in from that particular studio.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"plugins/list/#tag-graph","title":"Tag Graph","text":"DescriptionSource URLREADMEAuthorScreenshotsInteractive tag graph with vis.js, to view go to http://localhost:9999/plugin/tagGraph/assets/graph/
https://stg-annon.github.io/StashScripts/stable/index.yml\n
View README
stg-annon
"},{"location":"plugins/list/#tag-scenes-from-performer-tags","title":"Tag Scenes From Performer Tags","text":"DescriptionSource URLREADMEAuthorScreenshotstags scenes with performer tags.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Dankonite
"},{"location":"plugins/list/#tag-filter","title":"tag-filter","text":"DescriptionSource URLREADMEAuthorScreenshotsFilter out and hide meta-tags
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#tag-import","title":"tag-import","text":"DescriptionSource URLREADMEAuthorScreenshots
feederbox opinionated tag import
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#tag-video","title":"tag-video","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd <video> support to tag images
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#tagger-img-res","title":"tagger-img-res","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds resolutions to all tagger images
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#tetrax-userscript-library","title":"Tetrax Userscript Library","text":"DescriptionSource URLREADMEAuthorScreenshotsUtility library for Tetrax userscripts
https://tetrax-10.github.io/stash-stuffs/index.yml\n
No README available
tetrax-10
"},{"location":"plugins/list/#the-porn-db-markers","title":"The Porn DB Markers","text":"DescriptionSource URLREADMEAuthorScreenshotsSync Markers from The Porn DB aka theporndb.net
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Tweeticoats
"},{"location":"plugins/list/#theme-colorpalette","title":"Theme - colorPalette","text":"DescriptionSource URLREADMEAuthorScreenshotsBased on the default theme, change the overall color of the page by setting the hue value. Make minor changes to the remaining styles.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"plugins/list/#theme-switch","title":"Theme Switch","text":"DescriptionSource URLREADMEAuthorScreenshotsTheme and CSS script manager located in main menu bar top right.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
elkorol
"},{"location":"plugins/list/#timestamp-trade","title":"Timestamp Trade","text":"DescriptionSource URLREADMEAuthorScreenshots
Sync Markers with timestamp.trade, a new database for sharing markers.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Tweeticoats
"},{"location":"plugins/list/#titlefromfilename","title":"titleFromFilename","text":"DescriptionSource URLREADMEAuthorScreenshotsSet a scene's title from it's filename
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
bnkai
"},{"location":"plugins/list/#titleobserver","title":"titleobserver","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds an event listener for title changes
https://feederbox826.github.io/plugins/main/index.yml\n
No README available
feederbox826
"},{"location":"plugins/list/#valkyr-scene-cards","title":"Valkyr Scene Cards","text":"DescriptionSource URLREADMEAuthorScreenshotsA customisable rework of the scene card component for Stash.
https://valkyr-js.github.io/stash-plugins/index.yml\n
View README
Valkyr-JS
"},{"location":"plugins/list/#videoscrollwheel","title":"VideoScrollWheel","text":"DescriptionSource URLREADMEAuthorScreenshots
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.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
WeedLordVegeta420
"},{"location":"plugins/list/#visage","title":"Visage","text":"DescriptionSource URLREADMEAuthorScreenshotsUse facial Recognition To Lookup Performers.
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cc1234475
"},{"location":"plugins/list/#vjs-mmb-fullscreen","title":"vjs-mmb-fullscreen","text":"DescriptionSource URLREADMEAuthorScreenshotsVideoJS middle mouse button fullscreen
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#vjs-shortcut","title":"vjs-shortcut","text":"DescriptionSource URLREADMEAuthorScreenshotsAdd YouTube keyboard shortcuts to VideoJS
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#vjs-vr-zoom","title":"vjs-vr-zoom","text":"DescriptionSource URLREADMEAuthorScreenshotsVideoJS VR zoom controls
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"plugins/list/#watched-video-icon","title":"Watched Video Icon","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds icon and css class to watched videos
https://feederbox826.github.io/plugins/main/index.yml\n
View README
feederbox826
"},{"location":"scripts/","title":"Scripts","text":"
Info
Scripts are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Scripts are standalone programs that can interact with Stash either through GraphQL queries, custom Javascript or by directly editing Stash database or external files.
To install a script follow the script's install instructions.
"},{"location":"scripts/list/","title":"List of scripts","text":"stash-git-indexExhaustive list of git repositories related to Stash Google Sheets document.
Script no longer worksIf you found that script is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"scripts/list/#addmarkerono","title":"AddMarkerOnO","text":"DescriptionAuthorScreenshotsWill auto-generate a marker when the SceneAddO event is trigger
rosa-umineko
"},{"location":"scripts/list/#blurrycardbackground","title":"blurryCardBackground","text":"DescriptionAuthorScreenshotsAdd blurry background to scene/movie/gallery/image/studio.
philpw99
"},{"location":"scripts/list/#filenameperformerstocsv","title":"FilenamePerformersToCSV","text":"DescriptionAuthorScreenshotsParse performer names from your media filenames into CSV files for batch import into Stash!
ALonelyJuicebox
"},{"location":"scripts/list/#get-profilepictures","title":"Get-ProfilePictures","text":"DescriptionAuthorScreenshotsGet-ProfilePictures
MinasukiHikimuna
"},{"location":"scripts/list/#kodi-helper","title":"Kodi helper","text":"DescriptionAuthorScreenshotsGenerates nfo and strm for use with Kodi.
WithoutPants
"},{"location":"scripts/list/#ofmetadatatostash","title":"OFMetadataToStash","text":"DescriptionAuthorScreenshotsOnlyFans metadata import tool for Stash, written in Powershell.
ALonelyJuicebox
"},{"location":"scripts/list/#plex-to-stash-ratings","title":"plex-to-stash-ratings","text":"DescriptionAuthorScreenshots
Transfer scene rating and view count from Plex to Stash.
oikmeg
"},{"location":"scripts/list/#pwplayerjs-scene-card-quick-player","title":"pwPlayer.js - Scene Card Quick Player","text":"DescriptionAuthorScreenshotsThis Javascript will create a \"Play\" button in each scene card. You can click on it and the video for that scene will be played right away. Click on the video again, then you are back to the scene list.
philpw99
"},{"location":"scripts/list/#sqlite-renamer-for-stash","title":"SQLITE Renamer for Stash","text":"DescriptionAuthorScreenshotsUsing metadata from your database (SQLITE) to rename your file.
Belleyy
"},{"location":"scripts/list/#stash-watcher","title":"Stash Watcher","text":"DescriptionAuthorScreenshotsStash Watcher is a service that watches your Stash library directories for changes and then triggers a Metadata Scan when new files are added to those directories. It then waits a period of time before triggering another scan to keep Stash from constantly scanning if you're making many changes. Note that updates are watched during that window; the update is merely delayed.
DuctTape42
"},{"location":"scripts/list/#stashapp-tag-importer","title":"stashapp-tag-importer","text":"DescriptionAuthorScreenshotsCreates tags and aliases, resolves tag conflicts, and updates tag titles and descriptions from Stashbox (StashDB) to your local Stash instance. It can be run periodically to perform a one way sync to keep your Stash instance up to date with Stashbox (StashDB).
soundchaser128
"},{"location":"scripts/list/#stashgalleryupdate","title":"StashGalleryUpdate","text":"DescriptionAuthorScreenshotsDumb little script to match and update Stash galleries from scenes
Darklyter
"},{"location":"scripts/list/#stashstudiosync","title":"StashStudioSync","text":"DescriptionAuthorScreenshotsAn easy way to query a stashbox GQL endpoint and import any unknown studio IDs.
Stash-KennyG
"},{"location":"scripts/list/#stashtagskins","title":"StashTagSkins","text":"DescriptionAuthorScreenshotsUsed to quickly apply and change themes of tags for Stash.
Stash-KennyG
"},{"location":"scripts/list/#stashvideohashernode","title":"StashVideohasherNode","text":"DescriptionAuthorScreenshots
This is a very simple script that can be run on multiple systems to process a large Stash import of scenes. Instead of running cover and phash generation tasks on the Stash server itself, this script will allow you to do the same thing on as many computers as you would like, with all of the nodes contributing back to the Stash server.
Darklyter
"},{"location":"themes/","title":"Themes","text":"Info
Themes are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Stash supports CSS themes to adjust the look-and-feel of the interface. There are several that have been created by the maintainers and users.
Themes can be installed either via plugin or as Custom CSS.
"},{"location":"themes/#installing-via-plugin","title":"Installing via plugin","text":"Plugins can be installed and managed from the Settings > Plugins page.
Plugins are installed using the Available Plugins section. The Community (stable) source is configured by default that has several themes.
Installed plugins can be updated or uninstalled from the Installed Plugins section.
"},{"location":"themes/#adding-sources","title":"Adding sources","text":"Anyone can create their own source index for plugins. To add a new source go to Settings > Plugins page and under Available Plugins click Add Source.
"},{"location":"themes/#installing-via-custom-css","title":"Installing via Custom CSS","text":"Custom CSS allows you to modify Stash stock stylesheets.
The following is a list of some useful CSS snippets. You may use them by copying-and-pasting them into the Custom CSS editor found in the Settings > Interface panel or by navigating to localhost:9999/settings?tab=interface
Warning
Reduce left and right padding on Scene and Performer grid pages allowing for more thumbnails on each row.
/* [Scenes tab] Fit more thumbnails on each row */\n\n.grid { padding: 0px !important; }\n
"},{"location":"themes/custom-css-snippets/#allow-for-longer-string-when-displaying-studio-as-text-on-scene-thumbnails","title":"Allow for longer string when displaying \"Studio as Text\" on scene thumbnails","text":"DescriptionAuthorScreenshotsCSS code Allow for longer string when displaying \"Studio as Text\" on scene thumbnails.
/* [Scenes tab] Allow for longer string when displaying \"Studio as Text\" on scene thumbnails */\n\n.scene-studio-overlay {\n font-weight: 600 !important;\n opacity: 1 !important;\n width: 60% !important;\n text-overflow: ellipsis !important;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-scene-specs-resolution-duration-from-scene-card","title":"Hide scene specs (resolution, duration) from scene card","text":"DescriptionAuthorScreenshotsCSS code Hide scene specs (resolution, duration) from scene card.
/* [Scenes tab] Hide scene specs (resolution, duration) from scene card */\n\n.scene-specs-overlay {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-studio-logotext-from-scene-card","title":"Hide studio logo/text from scene card","text":"DescriptionAuthorScreenshotsCSS code Hide studio logo/text from scene card.
/* [Scenes tab] Hide studio logo/text from scene card */\n\n.scene-studio-overlay {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#make-the-list-of-tags-take-up-less-width","title":"Make the list of tags take up less width","text":"DescriptionAuthorScreenshotsCSS code Make the list of tags take up less width.
/* [Scenes tab] Make the list of tags take up less width */\n\n.bs-popover-bottom {\nmax-width: 500px\n}\n
"},{"location":"themes/custom-css-snippets/#swap-studio-and-resolutionduration-positions","title":"Swap studio and resolution/duration positions","text":"DescriptionAuthorScreenshotsCSS code Swap studio and resolution/duration positions.
/* [Scenes tab] Swap studio and resolution/duration positions */\n\n.scene-studio-overlay {\nbottom: 1rem;\nright: 0.7rem;\nheight: inherit;\ntop: inherit;\n}\n\n.scene-specs-overlay {\nright: 0.7rem;\ntop: 0.7rem;\nbottom: inherit;\n}\n
"},{"location":"themes/custom-css-snippets/#adjust-the-mouse-over-behaviour-in-wall-mode","title":"Adjust the mouse over behaviour in wall mode","text":"DescriptionAuthorScreenshotsCSS code Adjust the mouse over behaviour in wall mode.
/* [Scenes tab] Adjust the mouse over behaviour in wall mode */\n\n@media (min-width: 576px) {\n.wall-item:hover::before {\nopacity: 0; \n}\n\n.wall-item:hover .wall-item-container {\ntransform: scale(1.5);\n}\n}\n
"},{"location":"themes/custom-css-snippets/#disable-zoom-on-hover-in-wall-mode","title":"Disable zoom on hover in wall mode","text":"DescriptionAuthorScreenshotsCSS code Disable zoom on hover in wall mode.
/* [Scenes tab] Disable zoom on hover in wall mode */\n\n.wall-item:hover .wall-item-container {\n transform: none;\n}\n.wall-item:before {\n opacity: 0 !important;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-scene-scrubber","title":"Hide the scene scrubber","text":"DescriptionAuthorScreenshotsCSS code This will hide the large scene scrubber under the video player and max out the player's height.
/* [Scenes tab] Hide the scene scrubber and max out the player's height */\n.scrubber-wrapper {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-truncated-text","title":"Hide the truncated text","text":"DescriptionAuthorScreenshotsCSS code This will hide the truncated text that appears under the tile and date.
/* [Scenes Tab] - Hide the truncated text on scene card */\n\n.TruncatedText.scene-card__description { \ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#images","title":"Images","text":""},{"location":"themes/custom-css-snippets/#disable-lightbox-animation","title":"Disable lightbox animation","text":"DescriptionAuthorScreenshotsCSS code Disable lightbox animation.
/* [Images tab] Disable lightbox animation */\n\n.Lightbox-carousel {\ntransition: none;\n}\n
"},{"location":"themes/custom-css-snippets/#dont-crop-preview-thumbnails","title":"Don't crop preview thumbnails","text":"DescriptionAuthorScreenshotsCSS code Don't crop preview thumbnails.
/* [Images tab] Don't crop preview thumbnails */\n\n.flexbin > * > img {\nobject-fit: inherit;\nmax-width: none;\nmin-width: initial;\n}\n
"},{"location":"themes/custom-css-snippets/#groups","title":"Groups","text":""},{"location":"themes/custom-css-snippets/#better-group-layout-for-desktops-regular-size-poster","title":"Better Group layout for desktops, regular size poster","text":"DescriptionAuthorScreenshotsCSS code Making the front and back image much bigger. Left panel uses 70% while the right uses 30%.
/* [Groups tab] Better Group layout for desktops: Regular size poster */\n\n.group-details.mb-3.col.col-xl-4.col-lg-6 {\nflex-basis: 70%\n}\n.col-xl-8.col-lg-6{\nflex-basis: 30% \n}\n.group-images{\nflex-wrap: wrap\n}\n.group-image-container {\nflex: 0 0 500px\n}\n
"},{"location":"themes/custom-css-snippets/#better-group-layout-for-desktops-larger-size-poster","title":"Better Group layout for desktops, larger size poster","text":"DescriptionAuthorScreenshotsCSS code Making the front and back image much bigger. Left panel uses 70% while the right uses 30%.
/* [Groups tab] Better Group layout for desktops: Larger size poster */\n\n.group-details.mb-3.col.col-xl-4.col-lg-6 {\nflex-basis: 70%\n}\n.col-xl-8.col-lg-6{\nflex-basis: 30% \n}\n.group-images{\nflex-direction: column;\nflex-wrap: wrap\n}\n.group-image-container {\nflex: 1 1 700px\n}\n
"},{"location":"themes/custom-css-snippets/#galleries","title":"Galleries","text":""},{"location":"themes/custom-css-snippets/#grid-view-for-galleries","title":"Grid view for galleries","text":"DescriptionAuthorScreenshotsCSS code Grid view for galleries.
/* [Galleries tab] Grid view for galleries */\n\n.col.col-sm-6.mx-auto.table .d-none.d-sm-block {\n display: none !important;\n}\n.col.col-sm-6.mx-auto.table .w-100.w-sm-auto {\n width: 175px !important;\n background-color: rgba(0, 0, 0, .45);\n box-shadow: 0 0 2px rgba(0, 0, 0, .35);\n}\n.col.col-sm-6.mx-auto.table tr {\n display: inline-table;\n}\n
"},{"location":"themes/custom-css-snippets/#disable-lightbox-image-transition","title":"Disable lightbox image transition","text":"DescriptionAuthorScreenshotsCSS code Disable lightbox image transition.
/* [Gallery tab] Disable lightbox image transition */\n.Lightbox-carousel {\ntransition: unset;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-lightbox-header-and-footer","title":"Hide the lightbox header and footer","text":"DescriptionAuthorScreenshotsCSS code Hides the lightbox header and footer to make the image area larger. Mouse reveals them as an overlay to the image.
peresabcod
/* [Gallery tab] Hides the lightbox header and footer to make the image area larger. Mouse reveals them as an overlay to the image*/\n\n.Lightbox-header,\n.Lightbox-footer{\nz-index:9999;\nposition:absolute;\nwidth:100%;\nopacity:0;\nbackground-color:#0008;\ntransition: opacity 0.5s ease;\n}\n\n.Lightbox-footer{\nbottom:0;}\n\n.Lightbox-navbutton{\nopacity:0;\ntransition: opacity 0.5s ease;\n}\n\n\n.Lightbox-navbutton:hover,\n.Lightbox-header:hover,\n.Lightbox-footer:hover{\nopacity:1;\n}\n
"},{"location":"themes/custom-css-snippets/#performers","title":"Performers","text":""},{"location":"themes/custom-css-snippets/#show-entire-performer-image-in-performer-card","title":"Show entire performer image in performer card","text":"DescriptionAuthorScreenshotsCSS code Show entire performer image in performer card.
/* [Performers tab] Show entire performer image in performer card */\n\n.performer.image {\nbackground-size: contain !important;\n}\n
"},{"location":"themes/custom-css-snippets/#show-a-larger-image-in-performers-page-for-desktop","title":"Show a larger image in performer's page for desktop","text":"DescriptionAuthorScreenshotsCSS code Show a larger image in performer's page for desktop.
/* [Performers tab] Show a larger image in performer's page for desktop */\n.performer-image-container{\nflex: 0 0 50%;\nmax-width: 50%;\n}\n/* Changing .col-md-8 settings also affects studios and tags display. 50% should be good enough. */\n.col-md-8 {\nflex: 0 0 50%;\nmax-width: 50%;\n}\n
"},{"location":"themes/custom-css-snippets/#place-performer-image-in-the-background-on-performer-page","title":"Place performer image in the background on performer page","text":"DescriptionAuthorScreenshotsCSS code Place performer image in the background on performer page.
/* [Performers tab] Place performer image in the background on performer page */\n\n.performer-image-container.col-md-4.text-center {\n flex: 0 0 0%;\n max-width: 0%;\n}\n\n#performer-page .performer-image-container .btn.btn-link {\n position: fixed;\n width: 100%;\n top: 0;\n left: 0;\n padding: 0;\n}\n\n#performer-page .performer-image-container .btn.btn-link:before {\n content: '';\n position:absolute;\n top:0;\n left: 0;\n right: 0;\n bottom: 0;\n background: linear-gradient(to left, rgba(0,0,0,0) 0%,rgb(0 0 0 / 75%) 100%);\n z-index: 1;\n}\n\n#performer-page .performer-image-container .performer {\n max-height: none;\n max-width: none;\n width: 100%;\n}\n
"},{"location":"themes/custom-css-snippets/#show-larger-performer-images-in-performers-list","title":"Show larger performer images in performers list","text":"DescriptionAuthorScreenshotsCSS code Show larger performer images in performers list.
/* [Performers tab] Show larger performer images in performers list */\n/* original value: height: 30rem; min-width:13.25rem; */\n.performer-card-image{\nheight: 45rem;\nmin-width: 20rem;\n}\n
"},{"location":"themes/custom-css-snippets/#move-the-buttons-in-the-performers-edit-panel-to-the-top-instead-of-bottom","title":"Move the buttons in the Performer's edit panel to the top instead of bottom","text":"DescriptionAuthorScreenshotsCSS code Move the buttons in the Performer's edit panel to the top instead of bottom (in newer version of Stash, the buttons are already positioned both at top and bottom.
/* [Performers tab] Move the buttons in the Performer's edit panel to the top instead of bottom (in newer version of Stash, the buttons are already positioned both at top and bottom. */\n\nform#performer-edit {\n display: flex;\n flex-direction: column;\n}\n#performer-edit > .row {\n order: 1;\n}\n#performer-edit > .row:last-child {\n order: 0;\n margin-bottom: 1rem;\n}\n
"},{"location":"themes/custom-css-snippets/#move-the-tags-row-in-the-performers-edit-panel-to-the-second-position-just-after-name","title":"Move the tags row in the Performer's edit panel to the second position (just after name)","text":"DescriptionAuthorScreenshotsCSS code Move the tags row in the Performer's edit panel to the second position (just after name).
/* [Performers tab] Move the tags row in the Performer's edit panel to the second position (just after name). */\n\nform#performer-edit {\n display: flex;\n flex-direction: column;\n}\n#performer-edit > .row:nth-child(24) {\n order: -1;\n}\n#performer-edit > .row:first-child {\n order: -2;\n}\n
"},{"location":"themes/custom-css-snippets/#studios","title":"Studios","text":""},{"location":"themes/custom-css-snippets/#different-studio-cards-layout","title":"Different studio cards layout","text":"DescriptionAuthorScreenshotsCSS code Changes the layout of studio cards.
Qx#1573
/* [Studios tab] Changes the layout of studio cards */\n.studio-card.grid-card.card div.card-section div.rating-banner { display: none; }\n.slick-slide .studio-card-image { height: 300px; }\n\n.studio-card, .recommendation-row .studio-card {\n padding: 0;\n width: 500px;\n height: 300px;\n}\n\n.studio-card-image, .recommendation-row .studio-card .studio-card-image {\n max-height: 300px;\n width: 500px;\n}\n\n.studio-card.grid-card.card div.card-section {\n position: absolute;\n bottom: 0em;\n width: inherit;\n background-color: rgba(0, 0, 0, 0.7);\n overflow: hidden;\n height: 2.5em;\n transition: 0.5s ease-in-out;\n}\n\n.studio-card.grid-card.card div.card-section:hover {\n height: 7em;\n}\n
"},{"location":"themes/custom-css-snippets/#more-studio-per-row","title":"More studio per row","text":"DescriptionAuthorScreenshotsCSS code Display more studio per row
hijack_hornet
/* [Studios tab] Show more item per row */\n:not(.recommendation-row .studio-card).studio-card {\n width: 15%\n}\n:not(.recommendation-row .studio-card-image).studio-card-image {\n width: 100%\n}\n.studio-card h5 {\n text-align: center !important;\n display: block;\n}\n
"},{"location":"themes/custom-css-snippets/#tags","title":"Tags","text":""},{"location":"themes/custom-css-snippets/#different-tag-cards-layout","title":"Different tag cards layout","text":"DescriptionAuthorScreenshotsCSS code Changes the layout of tag cards on tags tab and when hovering on tags in different content.
Qx#1573
/* [Tags changes] changes the layout of tag cards on tags page and hover */\n.tag-parent-tags, .tag-sub-tags { display: none;}\n.tag-card.zoom-0.grid-card.card div.card-section div.card-popovers.btn-group { margin-top: 1em; }\n.tag-card.zoom-0.grid-card.card div.thumbnail-section a.tag-card-header img.tag-card-image { object-fit: cover; }\n.tag-card.zoom-0.grid-card.card div.card-section hr { display: none; }\n\n.tag-card.zoom-0.grid-card.card {\n padding: 0;\n width: 300px;\n height: 180px;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section {\n position: absolute;\n text-shadow: 2px 2px 2px #000;\n width: 100%;\n background-color: rgba(0, 0, 0, 0.3);\n height: 3em;\n overflow: hidden;\n transition: 0.8s ease-in-out;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section a {\n text-decoration: none;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section:hover {\n height: 22em;\n}\n\n.tag-card.zoom-0.grid-card.card \n div.card-section a \n h5.card-section-title.flex-aligned \n div.TruncatedText {\n white-space: nowrap;\n text-overflow: ellipsis;\n width: 300px;\n overflow: hidden;\n display: block;\n}\n\n.tag-card.zoom-0.grid-card.card div.card-section div.TruncatedText.tag-description {\n position: relative;\n top: 0.5em;\n -webkit-text-stroke-width: 1px;\n font-size: 16px;\n}\n\n.tag-card .card-popovers .btn {\n text-shadow: 1px 1px 1px #000;\n stroke: black;\n stroke-width: 15;\n}\n
"},{"location":"themes/custom-css-snippets/#alternative-tag-layout","title":"Alternative tag layout","text":"DescriptionAuthorScreenshotsCSS code Changes the tags layout to show more images, and details on hover.
hijack_hornet
/*Tag layout changes*/\n.tag-card {\n width: 16rem;\n padding: 0;\n}\n\n.tag-card .card-section {\n height: 2.5rem;\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: #0000007a;\n line-height: none;\n}\n.tag-card .card-section .TruncatedText {\n -webkit-line-clamp: 1 !important;\n}\n.tag-card h1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n line-height: normal;\n}\n.tag-card hr,\n.tag-description {\n display: none;\n}\n.tag-card .btn-group {\n position: absolute;\n width: 100%;\n bottom: 2.5rem;\n margin-bottom: 0;\n opacity: 0;\n transition: ease 0.2s;\n}\n.tag-card .btn-group:hover {\n opacity: 1;\n transition: ease 0.2s;\n background: #0000007a;\n}\n\n.tag-card-image {\n object-fit: cover;\n object-position: center;\n}\n\n.zoom-0 .tag-card-image {\n max-height: none;\n height: 16rem;\n width: 12rem;\n}\n\n.zoom-1 .tag-card-image {\n max-height: none;\n height: 20rem;\n width: 15rem;\n}\n\n.zoom-2 .tag-card-image {\n max-height: none;\n height: 24rem;\n width: 18rem;\n}\n\n.zoom-3 .tag-card-image {\n max-height: none;\n height: 28rem;\n width: 21rem;\n}\n\n.zoom-0.tag-card,\n.zoom-1.tag-card,\n.zoom-2.tag-card,\n.zoom-3.tag-card {\n width: initial;\n}\n\n.tag-card .card-section > a {\n position: absolute;\n width: 100%;\n height: 100%;\n display: block;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n padding: 7px 14px 0px 14px;\n}\n.tag-card .card-section .tag-sub-tags {\n position: relative;\n margin-top: 2rem;\n z-index: 1;\n}\n.tag-sub-tags {\n font-size: 0;\n}\n.tag-parent-tags {\n display: none;\n}\n
"},{"location":"themes/custom-css-snippets/#subtag-explorer","title":"Subtag explorer","text":"DescriptionAuthorScreenshotsCSS code This snipset includes the above tag layout snipset with a twist. Its meant to be used for people who use subtags as a hierachy. For example Watermelon is a subtag of Fruits, so when i click Fruits i want to see both oranges and watermelons, but i might want to get into the list of fruits subtags more easily. That what this snipset is used for. Any tag that has a subtag will show a (...) icon. When clicking its name you will show all subtags of this tag. if you click its image, it will instead open the tag itself normaly. You can change '137cbd' in the icon url to any color you want to match you theme.
hijack_hornet
/*Tag layout changes*/\n.tag-card {\n width: 16rem;\n padding: 0;\n}\n\n.tag-card .card-section {\n height: 2.5rem;\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: #0000007a;\n line-height: none;\n}\n.tag-card .card-section .TruncatedText {\n -webkit-line-clamp: 1 !important;\n}\n.tag-card h1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n line-height: normal;\n}\n.tag-card hr,\n.tag-description {\n display: none;\n}\n.tag-card .btn-group {\n position: absolute;\n width: 100%;\n bottom: 2.5rem;\n margin-bottom: 0;\n opacity: 0;\n transition: ease 0.2s;\n}\n.tag-card .btn-group:hover {\n opacity: 1;\n transition: ease 0.2s;\n background: #0000007a;\n}\n\n.tag-card-image {\n object-fit: cover;\n object-position: center;\n}\n\n.zoom-0 .tag-card-image {\n max-height: none;\n height: 16rem;\n width: 12rem;\n}\n\n.zoom-1 .tag-card-image {\n max-height: none;\n height: 20rem;\n width: 15rem;\n}\n\n.zoom-2 .tag-card-image {\n max-height: none;\n height: 24rem;\n width: 18rem;\n}\n\n.zoom-3 .tag-card-image {\n max-height: none;\n height: 28rem;\n width: 21rem;\n}\n\n.zoom-0.tag-card,\n.zoom-1.tag-card,\n.zoom-2.tag-card,\n.zoom-3.tag-card {\n width: initial;\n}\n\n.tag-card .card-section > a {\n position: absolute;\n width: 100%;\n height: 100%;\n display: block;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n padding: 7px 14px 0px 14px;\n}\n.tag-card .card-section .tag-sub-tags {\n position: relative;\n margin-top: 2rem;\n z-index: 1;\n}\n.tag-sub-tags {\n font-size: 0;\n}\n.tag-parent-tags {\n display: none;\n}\n/*Tag subtag exploration snipset*/\n.tag-card .card-section > a {\n cursor: default;\n pointer-events: none;\n}\n.tag-card .card-section > hr {\n margin-top: 2rem;\n}\n.tag-card .card-section .tag-sub-tags {\n position: absolute !important;\n margin-top: 0 !important;\n width: 100%;\n height: 100%;\n display: block;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n padding: 0;\n}\n.tag-sub-tags::before {\n content: \"\";\n display: block;\n background: url(\"https://img.icons8.com/material-outlined/24/137cbd/connection-status-off.png\")\n no-repeat;\n background-size: 1.5rem 1.5rem;\n width: 1.5rem;\n height: 1.5rem;\n float: right;\n margin: 0.5rem 0.5rem 0 0;\n}\n.tag-sub-tags > a {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.tag-card .btn-group a {\n z-index: 10;\n}\n.tag-sub-tags {\n font-size: 0;\n}\n.tag-parent-tags {\n display: none;\n}\n
"},{"location":"themes/custom-css-snippets/#global","title":"Global","text":""},{"location":"themes/custom-css-snippets/#change-the-order-of-navigation-bar-buttons","title":"Change the order of navigation bar buttons","text":"DescriptionAuthorScreenshotsCSS code Use order
values below 0 to move specific buttons to the left of the non-ordered buttons, and values above 1 to move them to the right of the non-ordered buttons.
/* [Global changes] Change the order of navigation bar buttons */\n\nnav .navbar-nav:first-child {\ndisplay: flex;\nflex-direction: row;\n}\ndiv.nav-link[data-rb-event-key=\"/tags\"] {\norder: -2;\n}\ndiv.nav-link[data-rb-event-key=\"/groups\"] {\norder: -1;\n}\ndiv.nav-link[data-rb-event-key=\"/scenes\"] {\norder: 1;\n}\n
"},{"location":"themes/custom-css-snippets/#hide-the-donate-button","title":"Hide the Donate button","text":"DescriptionAuthorScreenshotsCSS code Hide the Donate button.
/* [Global changes] Hide the Donate button */\n\n.btn-primary.btn.donate.minimal {\ndisplay: none;\n}\n
"},{"location":"themes/custom-css-snippets/#blur-nsfw-images","title":"Blur NSFW images","text":"DescriptionAuthorScreenshotsCSS code Use for when working on stash but don't want to expose NSFW images and text. May not be exhaustive.
/* [Global changes] Blur NSFW images */\n\n.scene-card-preview-video,\n.scene-card-preview-image,\n.image-card-preview-image,\n.image-thumbnail,\n.gallery-card-image,\n.performer-card-image,\n.tag-card-image,\nimg.performer,\n.group-card-image,\n.gallery .flexbin img,\n.wall-item-media,\n.scene-studio-overlay .image-thumbnail,\n.image-card-preview-image,\n#scene-details-container .text-input,\n#scene-details-container .scene-header,\n#scene-details-container .react-select__single-value,\n.scene-details .pre,\n#scene-tabs-tabpane-scene-file-info-panel span.col-8.text-truncate > a,\n.gallery .flexbin img,\n.group-details .logo {\nfilter: blur(12px);\n}\n\n.scene-card-video {\nfilter: blur(13px);\n}\n\n.jw-video,\n.jw-preview,\n.jw-flag-floating,\n.image-container,\n.studio-logo,\n.scene-cover {\nfilter: blur(20px);\n}\n\n.group-card .text-truncate,\n.scene-card .card-section {\nfilter: blur(4px);\n}\n
"},{"location":"themes/custom-css-snippets/#blur-nsfw-images-and-unblur-on-mouse-over","title":"Blur NSFW images and unblur on mouse over","text":"DescriptionAuthorScreenshotsCSS code Blur NSFW images and unblur on mouse over.
fl0w#9497
/* [Global changes] Blur NSFW images and unblur on mouse over */\n/* === MORE BLUR === */\n/* scene */\n.scene-card-preview,\n.vjs-poster,\nvideo,\n.scene-cover,\n.scrubber-item,\n\n/* image */\n.image-card-preview,\n.image-image,\n.gallery-image,\n\n/* group */\n.group-card-image,\n.group-images,\n\n/* gallery */\n.gallery-card-image,\ntable > tbody > tr > td > a > img.w-100,\n\n/* performer */\n.performer-card-image,\nimg.performer,\n\n/* studio */\n.studio-card-image,\n\n/* tag */\n.tag-card-image\n\n{\nfilter: blur(30px);\n}\n\n/* === LESS BLUR === */\n/* common */\n.card-section-title,\n\n/* scene */\n.scene-studio-overlay,\n.scene-header > h3,\nh3.scene-header,\n.studio-logo,\n.image-thumbnail,\n\n/* image */\nh3.image-header,\n\n/* group */\n.group-details > div > h2,\n\n/* gallery */\nh3.gallery-header,\n\n/* studio */\n.studio-details .logo,\n.studio-details > div > h2,\n\n/* tag */\n.logo-container > .logo,\n.logo-container > h2\n\n{\nfilter: blur(2px);\n}\n\n/* === UNBLUR ON HOVER === */\n/* common */\n.thumbnail-section:hover *,\n.card:hover .card-section-title,\n\n/* scene */\n.card:hover .scene-studio-overlay,\n.video-js:hover .vjs-poster,\nvideo:hover,\n.scene-header:hover > h3,\ndiv:hover > .scene-header,\n.studio-logo:hover,\n.scene-cover:hover,\n.image-thumbnail:hover,\n.scene-card-preview:hover,\n.scrubber-item:hover,\n\n/* image */\n.image-image:hover,\ndiv:hover > .image-header,\n.gallery-image:hover,\n\n/* group */\n.group-images:hover,\n.group-details > div > h2:hover,\n\n/* gallery */\ndiv:hover > .gallery-header,\ntable > tbody > tr > td:hover > a > img.w-100,\n\n/* performer */\nimg.performer:hover,\n\n/* studio */ \n.studio-details .logo:hover,\n.studio-details:hover > div > h2,\n\n/* tag */\n.logo-container > .logo:hover,\n.logo-container:hover > h2\n{\nfilter: blur(0px);\n}\n
"},{"location":"themes/custom-css-snippets/#hide-0-count-badges","title":"Hide 0 count badges","text":"DescriptionAuthorScreenshotsCSS code Hide 0 count badges.
echo6ix
/* [Global changes] Hide 0 count badges */\nspan.badge[data-value=\"0\"] {\n display: none;\n}\n
"},{"location":"themes/custom-css-snippets/#border-around-cards-activated-with-checkbox-selection","title":"Border around cards activated with checkbox selection","text":"DescriptionAuthorScreenshotsCSS code Add a noticeable border around any cards that have been selected using the checkbox selection. Border color uses Stash's --primary
color variable to maintain consistency with any theme that uses Stash's color variables.
echo6ix
/* [Global changes] Modify card when checkbox is selected */\n.grid-card.card:has(input:checked) {\nbox-shadow: 0 0 0 1px var(--primary,rgba(255, 255, 255, 0.30));\n}\n
"},{"location":"themes/list/","title":"List of themes","text":""},{"location":"themes/list/#alternative-tag-layout","title":"alternative-tag-layout","text":"DescriptionSource URLREADMEAuthorScreenshots Changes the tags layout to show more images, and details on hover
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#direct-stream","title":"direct-stream","text":"DescriptionSource URLREADMEAuthorScreenshotsAdds styling to settings to indicate direct stream
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#dracula-theme","title":"Dracula Theme","text":"DescriptionSource URLREADMEAuthorScreenshotsA dark theme for Stash based on the popular Dracula theme.
https://uncertainmongoose.github.io/dracula-for-stash/index.yml\n
No README available
UncertainMongoose
"},{"location":"themes/list/#glassy-a-window-to-your-collection","title":"Glassy - A Window to Your Collection","text":"DescriptionSource URLREADMEAuthorScreenshotsA Stash Theme
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-font-overhaul","title":"Glassy - Font Overhaul","text":"DescriptionSource URLREADMEAuthorScreenshotsA Stash Theme
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-front-page-animations-and-blur","title":"Glassy - Front Page Animations and Blur","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-marker-wall-redesign","title":"Glassy - Marker Wall Redesign","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-performer-scene-card-details-redesign","title":"Glassy - Performer Scene Card Details Redesign","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-and-movie-card-redesign","title":"Glassy - Scene and Movie Card Redesign","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-and-movie-card-redesign-no-animated-titles","title":"Glassy - Scene and Movie Card Redesign - No Animated Titles","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-player-details-6040","title":"Glassy - Scene Player-Details 60/40","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-player-details-reversed","title":"Glassy - Scene Player-Details Reversed","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-scene-player-details-reversed-6040","title":"Glassy - Scene Player-Details Reversed 60/40","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-smaller-performer-cards-on-main-page","title":"Glassy - Smaller Performer Cards on Main Page","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-smaller-performer-image-cards","title":"Glassy - Smaller Performer Image Cards","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-video-res-icons","title":"Glassy - Video-Res Icons","text":"DescriptionSource URLREADMEAuthorScreenshotsA Glassy Add-On Module.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-images","title":"Glassy Images","text":"DescriptionSource URLREADMEAuthorScreenshotsImages for A Stash Theme
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#glassy-installer","title":"Glassy Installer","text":"DescriptionSource URLREADMEAuthorScreenshotsGlassy meta-package for requirements.
https://serechops.github.io/Serechops-Stash/index.yml\n
View README
serechops
"},{"location":"themes/list/#hide-donate","title":"hide-donate","text":"DescriptionSource URLREADMEAuthorScreenshotsHide the Donate button.
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#hide-ocount","title":"hide-ocount","text":"DescriptionSource URLREADMEAuthorScreenshotsHide O-Count and O-Count trakcers
https://feederbox826.github.io/themes/main/index.yml\n
No README available
feederbox826
"},{"location":"themes/list/#more-studio-row","title":"more-studio-row","text":"DescriptionSource URLREADMEAuthorScreenshotsDisplay more studio per row
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#performer-grid","title":"performer-grid","text":"DescriptionSource URLREADMEAuthorScreenshotsAligns performer details in a grid
https://feederbox826.github.io/themes/main/index.yml\n
View README
feederbox826
"},{"location":"themes/list/#theme-blackhole","title":"Theme - BlackHole","text":"DescriptionSource URLREADMEAuthorScreenshotsBlackHole Theme for Stash by BViking78
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
BViking78
"},{"location":"themes/list/#theme-moderndark","title":"Theme - ModernDark","text":"DescriptionSource URLREADMEAuthorScreenshotsModernDark Theme for Stash by cj13
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
cj13
"},{"location":"themes/list/#theme-neondark","title":"Theme - NeonDark","text":"DescriptionSource URLREADMEAuthorScreenshotsNeonDark Theme for Stash by Dankonite
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Dankonite
"},{"location":"themes/list/#theme-night","title":"Theme - Night","text":"DescriptionSource URLREADMEAuthorScreenshotsNight Theme for Stash (unknown author)
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
No Author
"},{"location":"themes/list/#theme-plex","title":"Theme - Plex","text":"DescriptionSource URLREADMEAuthorScreenshotsPlex Theme for Stash by Fidelio 2020
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Fidelio
"},{"location":"themes/list/#theme-plex-better-styles","title":"Theme - Plex Better Styles","text":"DescriptionSource URLREADMEAuthorScreenshots
A modified version of Stash-Plex theme
https://tetrax-10.github.io/stash-stuffs/index.yml\n
View README
tetrax-10
"},{"location":"themes/list/#theme-pornhub","title":"Theme - Pornhub","text":"DescriptionSource URLREADMEAuthorScreenshots
PornHub Theme for Stash by neurokinin
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
ronilaukkarinen
"},{"location":"themes/list/#theme-pulsar","title":"Theme - Pulsar","text":"DescriptionSource URLREADMEAuthorScreenshotsPlex Theme for Stash by Fonzie 2020-21
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Fonzie
"},{"location":"themes/list/#theme-pulsarlight","title":"Theme - PulsarLight","text":"DescriptionSource URLREADMEAuthorScreenshotsPlex Theme for Stash by Fonzie 2021
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
No README available
Fonzie
"},{"location":"themes/list/#theme-rounded-yellow","title":"Theme - Rounded Yellow","text":"DescriptionSource URLREADMEAuthorScreenshotsTheme with rounded corners and yellow accents
https://stashapp.github.io/CommunityScripts/stable/index.yml\n
View README
Fonzie
"},{"location":"themes/list/#wrap-subtag","title":"wrap-subtag","text":"DescriptionSource URLREADMEAuthorScreenshotsWraps detail values (subtags)
https://feederbox826.github.io/themes/main/index.yml\n
No README available
feederbox826
"},{"location":"userscripts/","title":"Userscripts","text":"Info
Userscripts are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Userscripts are programs written in Javascript that modifies web pages to improve browsing with new features, formatting and more.
"},{"location":"userscripts/#install","title":"Install","text":"To install the userscript you will need a browser extension such as:
Exhaustive list of git repositories related to Stash Google Sheets document.
Userscript no longer worksIf you found that userscript is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"userscripts/list/#stash-userscripts","title":"Stash userscripts","text":"CompatabilityMake sure your instance URL is declared in @match
.
Automate batch creation and tagging
Serechops
"},{"location":"userscripts/list/#performer-image-carousel","title":"Performer Image Carousel","text":"DescriptionAuthorScreenshotsDisplays a carousel of performer images in the header.
Serechops
"},{"location":"userscripts/list/#stash-box-userscripts","title":"stash-box userscripts","text":"stash-box compatabilitySometimes just updating @match
is enough to make the userscript to work on a different stash-box instance. But it's not a guarantee.
Adds Noto Color Emoji to stash-box instances
feederbox826
"},{"location":"userscripts/list/#fansdb-submission-helper","title":"FansDB Submission Helper","text":"DescriptionREADMEAuthorScreenshotsView README
mmenanno, DogmaDragon
"},{"location":"userscripts/list/#stashdb-submission-helper","title":"StashDB Submission Helper","text":"DescriptionREADMEAuthorScreenshots
View README
mmenanno
"},{"location":"userscripts/list/#stashdb-diff","title":"stashdb-diff","text":"DescriptionAuthorScreenshots
add character-by-character diff for stashdb
feederbox826
"},{"location":"userscripts/list/#stashdb-link-chip","title":"stashdb-link-chip","text":"DescriptionAuthorScreenshotsadd chips to links in edit queue
feederbox826
"},{"location":"userscripts/list/#stashdb-relative-date","title":"stashdb-relative-date","text":"DescriptionAuthorScreenshotsadds relative dates to stashdb
feederbox826
"},{"location":"userscripts/list/#stashdb-rm","title":"stashdb-rm","text":"DescriptionAuthorScreenshotsRemove scenes from loaded studios on stashdb.org
feederbox826
"},{"location":"userscripts/list/#stashbox-notifications","title":"StashBox Notifications","text":"DescriptionAuthorScreenshotsNotifications for StashBox !
S3L3CT3DLoves
"},{"location":"userscripts/list/#studio-image-blur-for-stashdb","title":"Studio Image Blur for StashDB","text":"DescriptionAuthorScreenshotsBlurs images from specific studios on StashDB scene cards, based on studio name and img src
Serechops
"},{"location":"userscripts/list/#utility-userscripts","title":"Utility userscripts","text":"There are some userscripts that might be useful to Stash users, but does not directly involve Stash or stash-box instances.
"},{"location":"userscripts/list/#twitter-media-unblur","title":"twitter-media-unblur","text":"DescriptionAuthorScreenshotsunblur all twitter sensitive media post
feederbox826
"},{"location":"userscripts/list/#pmvhaven-autodl","title":"PMVHaven AutoDL","text":"DescriptionAuthorScreenshotsDashboard to simplify PMV downloading on PMVHaven
S3L3CT3DLoves
"},{"location":"userscripts/list/#spankbang-autodl","title":"SpankBang AutoDL","text":"DescriptionAuthorScreenshotsDashboard to download all a user's videos on SpankBang
S3L3CT3DLoves
"},{"location":"userscripts/list/#spankbang-frontend-scraper","title":"SpankBang Frontend Scraper","text":"DescriptionAuthorScreenshotsUse in Stash to scrape Spankbang from the browser, bypassing cloudflare issues
S3L3CT3DLoves
"},{"location":"userscripts/list/#lifeselector-unblur","title":"LifeSelector unblur","text":"DescriptionAuthorScreenshotsUnblur LifeSelector website
feederbox826
"},{"location":"userscripts/list/#redgifs-autosettings","title":"redgifs autosettings","text":"DescriptionAuthorScreenshotsAuto Unmute / Play / HD redgifs
feederbox826
"},{"location":"userscripts/list/#stash-tmdb-syncscraper","title":"Stash-TMDB Sync/Scraper","text":"DescriptionAuthorScreenshotsSync Button in TMDB Site.to Create Movie/Performer in Stash and Update performer missing info.
W0lfieW0lf
"},{"location":"utilities/","title":"Utilities","text":"
Info
Utilities are created by third parties and not officially affiliated or supported by the core Stash team. If you have issues, please reach out to the original creators.
Utilities are other external applications that utilise or interact with Stash in some way.
To install follow the utilities install instructions.
"},{"location":"utilities/list/","title":"List of utilities","text":"stash-git-indexExhaustive list of git repositories related to Stash Google Sheets document.
Utility no longer worksIf you found that utility is no longer working you can try contacting the author directly or create an issue on their Git platform. You can also create a GitHub issue on Stash-Docs for it to be removed from the list.
"},{"location":"utilities/list/#clip-mash","title":"clip-mash","text":"DescriptionAuthorScreenshotsVideo editing app that allows you to automate creating compilations from multiple videos. It runs in your browser. It's mostly made for, ahem, adult content, which is why it can connect to Stash and fetch videos and scene markers from there to guide the video creation process. You can also use local files and set the markers in ClipMash itself and then generate a compilation based on that.
soundchaser128
"},{"location":"utilities/list/#stash-app-for-android-tv","title":"Stash App for Android TV","text":"DescriptionAuthorScreenshotsA basic Android TV app for browsing and playing videos from a Stash server. Not all features of Stash are supported, but the basics for browsing, searching, and playing scenes should work. The app is not intended to perform administrative functions such as scanning, scraping, or editing details.
damontecres
"},{"location":"utilities/list/#stash-compilation-maker","title":"stash-compilation-maker","text":"DescriptionAuthorScreenshots
Connects to your Stash instance and creates simple compilation videos from scene markers. You select one or more tags, or one or more performers and it will take (currently) the first 15 seconds of video after the marker start and compile all of the markers into one video.
soundchaser128
"},{"location":"utilities/list/#stash-qmt","title":"stash-qmt","text":"DescriptionAuthorScreenshotsstash-qmt (quick manual tagger) is a simple GUI tool designed to help with cases of manually tagging multiple similar scenes (manually, as in, with having to actually watch them) in Stash.
PokerFacowaty
"},{"location":"utilities/list/#stash-vr-companion","title":"stash-vr-companion","text":"DescriptionAuthorScreenshots
Similar to stash-deovr as above but designed as a web app that sits in a docker container next to stash to make it easier to use and add more functionality.
Tweeticoats
"},{"location":"utilities/list/#stash-vr","title":"stash-vr","text":"DescriptionAuthorScreenshotsWatch your Stash library in VR for that full immersion effect.
Stash-VR bridges your Stash instance and VR video player allowing you to browse, play and manage your scenes using the video players native VR UI.
o-fl0w
"},{"location":"utilities/list/#stash-webvr","title":"stash-webvr","text":"DescriptionAuthorScreenshotsWebVR friendly Stash client that displays only videos tagged with \"Virtual Reality\" tag.
stishadmin
"},{"location":"utilities/list/#stash_helper","title":"Stash_helper","text":"DescriptionAuthorScreenshotsAdds some helping features to Stash (Bookmarks, playlist, external player, etc). Windows only.
philpw99
"},{"location":"utilities/list/#stashbox-performer-bot","title":"StashBox Performer Bot","text":"DescriptionAuthorScreenshotsThis program is designed to help automate the creation and updating of Performers on StashBox instances. It is designed to copy Performer info from one StashBox to another, to avoid having to maintain the information in both sources manually.
S3L3CT3DLoves
"}]} \ No newline at end of file