Rename File on Update

This is a very simple version of other file renaming tools, made specifically for my needs. It is all configured through the Stash Plugins UI, no messing with configuration files is required. It also does not reach into the database internals at all and instead uses the built-in file renaming capabilities of Stash.

Note that this plugin is tested daily on a Linux machine running the bleeding edge version of Stash. I have no reason to believe it wouldn’t work elsewhere, but just know that I personally don’t test it elsewhere.

Plugin options

  • Allow unsafe characters: Enable this option if you want to allow the potentially unsafe characters for Windows filesystems. This option should fairly safe to enable with macOS and Linux.
  • Default directory path format: Formatted string to be used for the default directory to store files after they are moved. Note that this must be a directory that is contained within the directories for your Stash library, but it does not have to be the same root path as the original file. This can use any of the format specifiers mentioned below. Keep this blank in order to keep the file in the same directory.
  • Default file name format: Formatted string to be used for the default file name to rename the moved scene to. This can use any of the format specifiers mentioned below. Keep this blank in order to keep the original file name.
  • Dry Run: This controls if the files should be renamed or if they should just be indicated in the logs what they would be renamed to.
  • Duplicate file suffix: The suffix to append to the scene file names when a duplicate is found.
  • Remove extra spaces from file name: Should repeated spaces be removed from file names?
  • Rename unorganized scenes: Should this rename both organized and unorganized scenes, or only organized scenes?

File and directory formatting

This plugin offers a variety of format specifiers that can be used to customize the directory paths and file names which are generated.

Scene information

  • $director$: The director of the scene.
  • $title$: The title of the scene.
  • $scene_id$: The Stash scene ID for the scene.
  • $parent_studio_chain$: The name of the studio and the chain of parent studios of the studio attached to the scene.
  • $studio_code$: The studio code associated with the scene.
  • $studio_name$: The name of the studio directly attached to the scene.

Scene date

  • $date$: The scene date in yyyy-mm-dd format.
  • $month$: The month in mm format.
  • $year$: The year in yyyy format.

File information

  • $audio_codec$: The auto codec detected by ffmpeg.
  • $ext$: The extension of the file.
  • $height$: The height of the video.
  • $index$: The index of the file if it is a duplicate. This is empty for unique files and incremented by 1 for every duplicate file it detects.
  • $video_codec$: The video codec detected by ffmpeg.
  • $width$: The width of the video.

Optional parts of the path

There may be cases where you want the formatted value to be included if it’s present on the scene, but you don’t if it is not present. In these cases, you can wrap the section in curly braces ({ and }) to indicate that they should only be included if all of the format specifiers within it are filled in. If you do not indicate that it is optional, the format specifier will be replaced with an empty string instead.

Examples


If you run into an issue when using this plugin or have any questions, leave a message in this thread.

1 Like

Hello, I love the idea of this plugin, but unfortunatlly, its not working for me. Do you know why?

Misisng Python dependancy. If you already have Python on your system just run pip install stashapp-tools, otherwise install Python from Download Python | Python.org and then run the command in your command line interface.

This is awesome. The first renamer plugin I’ve found that does what I need it to do really. I know you built this for your needs but if you decide to muck with it again I’d love to be able to add performer to the filename. The first female performer found would be fine with me. If none are found, field is not used. Something like that. Either way, thanks for this. :saluting_face:

Ditto this request to be able to add a performer to the name.

I’m new to Stash (and its respective plugins). Is the only way to run the plugin via the “Tasks”, and it’s renames everything? (“Rename all of your scene’s files based on your configuration.”). Is there a way to batch a selection of files/scenes?

You can force an edit to scenes in order to re-trigger it. For example, adding a dummy tag or marking them as organized (bonus if you have it set to only move them when they’re organized). This works both in the scene details interface when editing an individual scene along with in the scene list page when performing a bulk edit.

1 Like

Did you ever get this fixed? I’m running into the exact same errors and @DogmaDragon’s instructions did not work for me. It returns the exact same error.

1 Like

Personally i use Whisparr for downloading / renaming before moving to stash
Probably a good alternative to this, especially if you get a lot of your content from Usenet/Torrents

So far I couldn’t make it run. I use Stash in Windows. I installed Python and set the Python Executable Path (in System) to G:\Program Files\Python\python.exe
But I still get an error:

025-10-27 22:58:11Error Scene.Update.Post [Rename File on Update]: returned error: exit status 1
2025-10-27 22:58:11Error [Plugin / Rename File on Update] ModuleNotFoundError: No module named ‘stashapi’
2025-10-27 22:58:11Error [Plugin / Rename File on Update] from stashapi.stashapp import StashInterface
2025-10-27 22:58:11Error [Plugin / Rename File on Update] File “C:\Users\xxxxxx.stash\plugins\Renaming\rename-file-on-update/rename_file_on_update.py”, line 1, in

pip install stashapp-tools

This is a great tool and love that it’s configured in the Stash UI.

Would be helpful if $title$ would use the filename whenever the Title field is blank, similar to how some of the other renamer apps have functioned. Otherwise it renames the file as “$title$”, and you have to go into the log files to recover the actual name.

Hope you continue to enhance this. Really good work.

Sent a pull request to add a feature and fix a bug:

Can you please add Performer as a tag? thanks :slight_smile:

Stash doesn’t store filenames of generated content in the database. Generated content is named based on the hash value of the object. Renaming it to something else will make Stash lose track of it.

The renamer plugin updates the file location with the API. I’ve been using it and it’s great. I just had some additions to it that fixed some issues for me so I figured I’d share the wealth.

I feel like an idiot. I can’t get this to work. It must be something obvious I’m overlooking as a newbie.

I set up stash. I registered on StashDB and connected to the metadata provider. I created a directory for the library and add the path to it. I can do a Scan, then Identify, and the scenes is organized in Stash. No change to the actual files at this point, of course.

I installed the Rename File on Update plug, I change the Default directory path format and Default file name format. I go to Task, Plugin Task, and click Rename scene under Rename File on Update. No change to the actual files in the directory. I’ve tried to remove the files, clean up the DB, re-add the files and scan and identify. I’ve tried to Edit an identified scene and hit save. When I click rename scene it would always complete without error under 100ms, but nothing happens. I tried to use the exact variables as the examples above and still nothing.

I feel like it is something super basic about how Stash works that I’m missing. Anyone?

Read the log. It’s likely you don’t have python or the dependencies (stashapi)

pip install stash-tools will install it.

I encounter the following error when using it:

INFO[2025-11-16 23:29:02] [Plugin / Rename File on Update] Renaming file from /data/Media/Porn/video/west/factory/Defloration/Hardcore Defloration - Chloe Minou.mp4 to /Defloration/Hardcore Defloration | Chloe Minou/Hardcore Defloration | Chloe Minou.mp4 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update] Traceback (most recent call last): 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/root/.stash/plugins/rename-file-on-update/rename_file_on_update.py", line 23, in <module> 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     rename_scene(stash, config, ARGS) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/root/.stash/plugins/rename-file-on-update/renamer.py", line 50, in rename_scene 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     stash_file.rename_file() 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/root/.stash/plugins/rename-file-on-update/file_manager.py", line 209, in rename_file 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     moved_file = self.stash.call_GQL( 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]                  ^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/stashapi/stashapp.py", line 221, in call_GQL 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     return self._GQL(query, variables) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/stashapi/classes.py", line 224, in _GQL 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     response = self.s.post(self.url, json=json_request) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/requests/sessions.py", line 637, in post 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     return self.request("POST", url, data=data, json=json, **kwargs) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/requests/sessions.py", line 575, in request 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     prep = self.prepare_request(req) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]            ^^^^^^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/requests/sessions.py", line 484, in prepare_request 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     p.prepare( 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/requests/models.py", line 370, in prepare 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     self.prepare_body(data, files, json) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/site-packages/requests/models.py", line 510, in prepare_body 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     body = complexjson.dumps(json, allow_nan=False) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/json/__init__.py", line 238, in dumps 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     **kw).encode(obj) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]           ^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/json/encoder.py", line 200, in encode 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     chunks = self.iterencode(o, _one_shot=True) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/json/encoder.py", line 258, in iterencode 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     return _iterencode(o, 0) 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]            ^^^^^^^^^^^^^^^^^ 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]   File "/usr/lib/python3.12/json/encoder.py", line 180, in default 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update]     raise TypeError(f'Object of type {o.__class__.__name__} ' 
ERRO[2025-11-16 23:29:02] [Plugin / Rename File on Update] TypeError: Object of type PosixPath is not JSON serializable 
ERRO[2025-11-16 23:29:02] Scene.Update.Post [Rename File on Update]: returned error: exit status 1

To start, I apologize if this is not the method this should be handled.

I noticed that every (almost every?) time rename on file ran, I would get an error, even though it was running fine after I made sure I gave it all the variables it wanted for a rename.

2025-11-20 21:41:18 Info
[Plugin / Rename File on Update] File paths are the same, no renaming needed.
2025-11-20 21:41:03 Error
Scene.Update.Post [Rename File on Update]: returned error: exit status 1
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] NameError: name ‘oldpath’ is not defined. Did you mean: ‘old_path’?
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] ^^^^^^^
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] self.rename_related_files(oldpath, new_path, dry_run=False)
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] stash_file.rename_file()
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] File “/stash/plugins/rename-file-on-update/file_manager.py”, line 220, in rename_file
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] File “/stash/plugins/rename-file-on-update/renamer.py”, line 50, in rename_scene
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] File “/stash/plugins/rename-file-on-update/rename_file_on_update.py”, line 23, in
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] Traceback (most recent call last):
2025-11-20 21:41:03 Info
[Plugin / Rename File on Update] File renamed successfully: {‘moveFiles’: True}
2025-11-20 21:41:03 Error
[Plugin / Rename File on Update] rename_scene(stash, config, ARGS)

So I thought, okay, oldpath is definitely not a variable I configured and most of the two word entries used _ to separate them AND it did say “did you mean old_path”. So I did some digging through the python files on the git hub repository for the plugin and saw that in file_manager.py what looked like a ‘write to log’ function (I’m the furthest thing from a programmer) had ‘oldpath’

220: self.rename_related_files(oldpath, new_path, dry_run=False)

I didn’t see any issues logged about the issue, so maybe it was just me, but just in case, I went and found that line in my local stashapp plugin for this, changed it to old_path

220: self.rename_related_files(old_path, new_path, dry_run=False)

Reloaded my plugins and the problem went away.

So, I don’t want to sign up for a new github account to make an issue post about a porn cataloging application, this seemed like a less public place to mention this weirdness and how I fixed it for me. I do not suggest my way was the right way, I may somehow have made a much larger problem for myself in 3 months. :slight_smile:

2 Likes

Yeah this is a known issue that I haven’t gotten around to patching. In theory it only causes problems if your scene has multiple files attached to it.