mcMetadata

:placard: Summary Generates metadata for use with other media servers like Emby and Jellyfin, and optionally organizes/renames your tagged scenes.
:link: Repository https://github.com/carrotwaxr/stash-plugins/tree/main/plugins/mcMetadata
:information_source: Source URL https://carrotwaxr.github.io/stash-plugins/stable/index.yml
:open_book: Install How to install a plugin?

mcMetadata

Generate Jellyfin/Emby-compatible metadata from your Stash database. Create NFO files, rename/organize video files, and export performer images - all without relying on external scrapers.

:link: Links

:package: Installation

  1. Go to Settings → Plugins → Available Plugins
  2. Add source: https://carrotwaxr.github.io/stash-plugins/stable/index.yml
  3. Find “mcMetadata” under “Carrot Waxxer” and click Install
  4. Reload plugins

:sparkles: Features

  • NFO Generation - Creates metadata files with title, performers, studio, tags, date, rating
  • File Organization - Rename and move files using customizable templates
  • Performer Images - Export performer photos to Jellyfin/Emby’s People folder
  • Dry Run Mode - Preview all changes before committing (enabled by default)
  • Bulk Operations - Process your entire library or individual scenes via hooks

:gear: Configuration

Configure in Settings → Plugins → mcMetadata:

General

Setting Default Description
Dry Run Mode On Preview changes without making them
Enable Scene Update Hook Off Auto-process scenes when updated
Require StashDB Link (Hook) Off Only process StashDB-linked scenes

File Renamer

Setting Description
Enable File Renamer Move/rename files based on template
Renamer Base Path Destination directory (must be in a Stash library)
Path Template e.g., $Studio/$Title - $Performers $ReleaseDate [$Resolution]

Template Variables: $Studio, $Studios, $Title, $StashID, $ReleaseDate, $ReleaseYear, $Resolution, $Quality, $Performers, $FemalePerformers, $MalePerformers, $Tags

Actor Images

Setting Description
Enable Actor Images Export performer images
Media Server Type jellyfin or emby
Actor Metadata Path Path to People metadata folder

:rocket: Usage

Recommended Workflow

  1. Enable Dry Run Mode, configure settings
  2. Run “Bulk Update Scenes” task
  3. Check logs at Settings → Logs (Debug level)
  4. Disable Dry Run Mode, run task again
  5. Enable hook for ongoing automatic updates

Media Server Paths

  • Jellyfin: <config>/data/metadata/People/
  • Emby: <config>/metadata/People/

:warning: Requirements

  • Stash v0.24.0 or later
  • Scenes should have StashIDs for best results

:beetle: Troubleshooting

Files not moving? Ensure destination is within a Stash library path.

NFO not parsing? Check your media server is configured to read local NFO files.

Performer images not showing? Verify the actor metadata path matches your media server config.

Issues? Report them at GitHub · Where software is built

:clipboard: Changelog

v1.2.2

  • Added “Require StashDB Link” setting for hook processing
  • NFO files now generated for locally edited scenes by default

v1.2.1

  • Dry Run Mode now correctly defaults to ON

v1.2.0

  • Fixed Emby actor folder structure
  • Fixed XML escaping for special characters

v1.1.0

  • Migrated to Stash’s native plugin settings UI
  • Added scene update hook

v1.0.0

  • Initial release with NFO, renamer, and actor image support
1 Like

mcMetadata v1.2.1 Released

What’s New in v1.2.1:

  • Added explicit defaults to all settings - Dry Run Mode now correctly defaults to ON for new installations

v1.2.0 Changes:

  • Fixed: XML escaping for special characters in titles (ampersands, quotes, etc.) - Issue #9

  • Fixed: Emby actor folder structure now correctly uses People/Actor Name/ instead of People/A/Actor Name/ - Issue #11

  • Added: Comprehensive unit tests

Breaking Change - Settings Migration:

Settings have moved from settings.ini to Stash’s native plugin settings UI. After updating:

  1. Go to Settings → Plugins → mcMetadata

  2. Re-enter your settings in the GUI

  3. Delete the old settings.ini file (no longer used)

The new settings UI is easier to use and doesn’t require restarting Stash when you make changes.

Reminder - Dry Run Mode:

Dry Run Mode is ON by default. Run “Bulk Update Scenes” first to preview changes in Settings → Logs (Debug level), then disable Dry Run Mode to execute for real.

Installation:

If you haven’t already, add the plugin source:

https://carrotwaxr.github.io/stash-plugins/stable/index.yml

Then install/update mcMetadata from Settings → Plugins → Available Plugins.

Note for Docker users:

If you get ModuleNotFoundError: No module named 'stashapi', you may need to install the dependency in Stash’s venv:

/root/.stash/venv/bin/python -m ensurepip --upgrade
/root/.stash/venv/bin/pip install stashapp-tools

无法适应最新版,问题好像是在
scene.py里「一行fingerprint 都没写」,
但 mcMetadata 仍然会在 Stash v0.30 报 fingerprint(type)错,
原因是:stash.find_scenes()/ stash.find_scene()使用了 StashInterface的「默认GraphQL
fragment」,而这个 fragment 在v0.30已经变更。

I like what this is doing. Anything that can make my library “portable” with metadata stored next to the files is a good thing in my opinion. I have a few comments.

  • Can this be configured to run for targeted directories? I have a large library and I get nervous about doing a large update which will move and rename all files at once. To test this plugin I had to setup a new stash instance and only loaded in one directory.
  • Dry run did not default to on for me with new install like your changelog says it should.
  • I do not see it mentioned but this copies the cover to be stored next to the nfo file. This is good but it didn’t work for me. It created a jpg file but the file was corrupted and wouldn’t open. I didn’t see any messages in log so I’m not sure what happened.

Interesting. The image issue I’ll have to look into. Target directory, no you can’t do that yet but good idea. The DRY RUN thing I’d be curious - was DRY RUN actually not enabled, or just appeared to be in the Plugin Settings? Because Stash will not allow you to provide a default value that reflects properly in the UI, so even if that Boolean is set to “true” by default in the code, the Plugin settings will show it as “false” or off until you actually toggle it on via the UI, then it will be “synced” to the correct value. A weird little shortcoming of Stash’s that is sometimes confusing. I will investigate all of these bugs against my own Stash though. Thanks for the report!

I wasn’t aware of that quirk in the UI with default values so it may have been assigned correctly as you describe. I didn’t run it before setting the toggle in the UI so I don’t know if that was the case.

Regarding images, I wonder if it’s because it’s missing API key in string? I set log to debug and I see messages like the one below, there should be string after apikey= shouldn’t there?

[Plugin / mcMetadata] Downloading image http://127.0.0.1:9999/scene/35/screenshot?t=1766837811&apikey= to /path/filename.jpg

I wasn’t seeing the “No module named ‘stashapi’” error you mentioned but since I spun up a new instance for testing this and I use docker I realized I’m probably missing this. After install, the apikey= is still blank.

I’ve investigated and created a fix: fix(mcMetadata): validate images before saving to prevent corrupted files by carrotwaxr · Pull Request #62 · carrotwaxr/stash-plugins · GitHub

Issue 1 (Dry run default): This is a Stash UI quirk - boolean settings show as “off” visually until you toggle them, even though the code defaults to true. Once you toggle the setting once, it persists correctly.

Issues 2 & 3 (Corrupted images / blank API key): These are related. The download_image function had no error handling - if the download failed (e.g., auth error from missing API key), it would save whatever it received (often an HTML error page) as the image file, with no logging.

The fix:

  • Downloads to a temp file first, validates before saving
  • Checks HTTP status code and Content-Type header
  • Validates the file is actually a JPEG/PNG/WebP by checking magic bytes
  • Adds comprehensive error logging so you can see what went wrong
  • Sanitizes API key from logs for security

Once merged, if you still see image download failures, you’ll now get clear error messages in the Stash logs explaining why.

1 Like

Looks a bit better. I’m still having issues with api key but for now I’ve just disabled security credentials to my test instance so that an api key isn’t needed.

Now I get this:

Error downloading image from http://127.0.0.1:9999/path…: [Errno 18] Cross-device link: ‘/tmp/tmp1mwanket.tmp’ → ‘/data/file.jpg’

Some searching online and this appears to be because /tmp and /data are different filesystems. The /data path is default path for docker to point to your library files. Looks like shutil.move() might be better option?

I’m also experiencing the corrupted image issue. Current version 1.2.3-f22a4e3 on Stash v0.30.1 (build b23b0267).

This is what I’m seeing in the logs. Only bit changed its the path and filename before the hyphen. The outputted file’s checksums, when checked on CX Explorer on Android, all show Error.

[16:59:53] [DEBUG] Downloading image from http://127.0.0.1:9999/scene/9572/screenshot?t=1770674391&apikey=***

[16:59:53] [DEBUG] Saved image to /data/my/path/scene_file_,name-poster.jpg

Rename option is disabled, Scene update hook enabled.

I’ll take a look - sorry about the delays on updates recently

1 Like

I see you updated this recently. The nfo and image creation is working great for me now, thank you. If I may make some more minor suggestions.

  • Would it be possible to have more control over the triggers on hook? I often make make updates when adding a new scene, and usually not all at once. It would be good to have the option to only write and rename the files when the scene is marked as organized instead of after every save.
  • Any chance of conditional tests in the rename so that text is only included if data exists for a field? For example, if you used curly brackets, {$ReleaseDate - }$Title would only include the “ - “ if a release date is set on the scene. If no release date on the scene then it only writes $Title.
  • This is minor but any chance of control over what fields get written to the nfo? I don’t think I need “uniqueid type” and I might choose to omit one or more of the rating fields as well.
2 Likes

Thanks for the plugin!
Can you make this plugin also export the scene covers as poster.jpg files for Jellyfin to pick up?
THANKS!

@fellfast

Currently it’s exported as [scene title]-poster.jpg which will get recognized by Jellyfin. It may be nice to be able to customize the output filenames though.

@carrotwaxr

I noticed you implemented the other changes I suggested in a previous post and they’ve been working great. I haven’t figured out how to use hookTriggerMode though to have it fire only on organized. Probably I’m missing something obvious.

@carrotwaxr I’m running into errors like this:
26-03-20 17:45:07Error [Plugin / mcMetadata] Invalid content type ‘text/html’ from http://127.0.0.1:30198/scene/513/screenshot?t=1773919676&apikey=*** (expected image/*)
No scene covers are therefore created…

I’ve generated an API key and it seems to have worked

If I am thinking of using the plugin rename function, is it okay and how to set it up

First, thank you for this plugin, it works well and is great for jellyfin integrations. I have 3 requests and I was wondering if you’d be interested in adding any of these onto this plugin:

  1. Ability to exclude thumbs. Specifically this tag: <thumb aspect="poster"></thumb>. I tried to put this into the exclude field in the Plugin Settings but it didn’t work. Or maybe I’m doing it wrong? I put in thumb aspect, thumb in the NFO Exclude Fields.
  2. Ability to use <stashid></stashid> for the stashID instead of <uniqueid type="stash"></uniqueid>
  3. ThePornDB ID integration, which for scenes looks like this: <theporndbid>scenes/25e1418b-897c-4aa1-854b-5673a1211d96</theporndbid>. You can grab the UUID from the tpdb scraped endpoint.

Thanks!! :heart_hands:t4:

Any possibility of getting something like a tag that’s required for moving/generating nfo/renaming? Or being able to restrict it to specific directories? Basically, something that would let us only generate nfo/etc when we know the files are in their final location without micro managing disabling/enabling features in the settings. Just something to cut down on manual work.

Even just an option to somehow choose a folder to run ‘Bulk Update Scenes’ on would be awesome. Sorry that I missed it if there is already something for this. Appreciate your work!