Jellyfin Format Media Organizer
Project description
Automatically organizes and renames media files according to Jellyfin's naming conventions. Detects movies vs TV shows, fetches TMDB metadata, and handles transliteration of non-Latin filenames.
Features
- Smart movie vs TV show detection
- TMDB integration for IDs and metadata
- Configurable naming via tokens
- Russian transliteration detection and conversion
- Daemon mode for continuous monitoring
Installation
1. Create a system user and add it to the media group:
sudo groupadd media
sudo useradd --system --no-create-home --shell /usr/sbin/nologin jfmo
sudo usermod -aG media jfmo
Make sure your media directories are owned or readable by the media group:
sudo chown -R :media /data/media
sudo chmod -R g+rw /data/media
2. Set up the config:
Default config path: /etc/jfmo/config.yaml. See config.template.yaml for all options.
sudo mkdir -p /etc/jfmo
sudo vim /etc/jfmo/config.yaml
sudo chown -R jfmo:jfmo /etc/jfmo
Option 1 — pip / pipx
3. Install the package:
sudo pipx install jfmo --global
4. Create the systemd unit /etc/systemd/system/jfmo.service:
[Unit]
Description=Jellyfin Format Media Organizer
After=network.target
[Service]
Type=simple
User=jfmo
Group=media
ExecStart=/usr/local/bin/jfmo daemon
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
5. Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now jfmo
sudo systemctl status jfmo
Run once manually (without stopping the daemon):
sudo -u jfmo -g media jfmo run --apply
Option 2 — Docker
See example of docker compose file in docker-compose.template.yaml.
Set user in docker-compose.yaml to the uid:gid of jfmo:media (created above):
id jfmo # get uid
getent group media # get gid
1. Set up files:
sudo mkdir -p /opt/jfmo
cd /opt/jfmo
sudo vim docker-compose.yaml
Start as a background daemon (restarts automatically on reboot):
sudo docker compose up -d
Run once manually (e.g. to process a backlog):
# Dry-run preview — no files moved
sudo docker compose run --rm jfmo run
# Apply changes
sudo docker compose run --rm jfmo run --apply
Update
pipx
sudo pipx upgrade jfmo --global
sudo systemctl restart jfmo
Docker
sudo docker compose pull
sudo docker compose up -d
Usage
jfmo run # dry-run preview (no files moved)
jfmo run --apply # apply changes
jfmo daemon # watch downloads directory continuously
jfmo --version
Naming
Available tokens
| Token | Description | Example |
|---|---|---|
{title} |
Media title | Inception |
{year} |
Release year | 2010 |
{tmdb_id} |
TMDB numeric ID | 27205 |
{quality} |
Resolution label | [1080p] |
{season} |
Season number, zero-padded | 01 |
{episode} |
Episode number, zero-padded | 04 |
{source} |
Release source | WEB-DL, BluRay, BDRip |
{codec} |
Video codec | x265, HEVC, AV1 |
{hdr} |
HDR format | HDR10, DV, DoVi |
{service} |
Streaming service | NF, AMZN, DSNP |
{release_group} |
Release group name | LostFilm, NOOBDL |
Each pattern only accepts a specific subset of tokens:
Pattern (naming.) |
Allowed tokens |
|---|---|
movie.file |
title, year, tmdb_id, quality, source, codec, hdr, service, release_group |
tv.folder |
title, year, tmdb_id |
tv.season |
season |
tv.file |
title, season, episode, quality, source, codec, hdr, service, release_group |
Example: before → after
downloads/
├── Severance.S02E02.1080p.mkv
├── The.Accountant.2.2024.2160p.mkv
├── Podslushano.v.Rybinske.S01E01.2160p.mkv ← Russian transliteration
└── La Casa de Papel 3 - LostFilm [1080p]/
films/
└── The Accountant 2 (2024) [tmdbid-717559] - 2160p.mkv
tv/
├── Severance (2022) [tmdbid-95396]/
│ └── Season 02/
│ └── Severance S02E02 - 1080p.mkv
├── Подслушано в Рыбинске (2024) [tmdbid-245083]/ ← converted to Cyrillic
│ └── Season 01/
│ └── Подслушано в Рыбинске S01E01 - 2160p.mkv
└── La Casa de Papel (2017) [tmdbid-71446]/
└── Season 03/
└── La Casa de Papel S03E01 - 1080p.mkv
Transliteration Detection
Most media organizers (Radarr, Sonarr, etc.) cannot handle files where the title is written in Latin-script transliteration of Russian — e.g. Podslushano.v.Rybinske.S01.mkv looks like English but is actually «Подслушано в Рыбинске».
JFMO detects this automatically using a custom character n-gram language model trained to distinguish genuine English titles from Russian titles written in transliteration. When a transliterated title is detected, JFMO converts it back to Cyrillic before searching TMDB — resulting in a correct match instead of a failed lookup.
Podslushano.v.Rybinske.S01E01.mkv
detected: Russian transliteration
converted: Подслушано в Рыбинске
TMDB match: tmdbid-XXXXXX
→ Подслушано в Рыбинске (2024) [tmdbid-XXXXXX]/Season 01/...
The model was trained on a custom dataset of ~2.5M titles (165k Russian + 2.4M English) built specifically for this project, achieving 93% accuracy on a diverse test set of 334 cases.
- Dataset: stafloker/media-transliterated (Kaggle)
- Inspired by: Language Identification for Texts Written in Transliteration
Acknowledgments
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jfmo-3.0.0.tar.gz.
File metadata
- Download URL: jfmo-3.0.0.tar.gz
- Upload date:
- Size: 4.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e83642e8cf340be00d68eb40aed1c30988d1347bbd61fb60f9f7787ee89ad9b2
|
|
| MD5 |
95f8f7a801b8d6c99e3f3d0b19948f1c
|
|
| BLAKE2b-256 |
7b3042d3939ec3d13bd18e0290cb060e606183b87ad00f3893ee0878d741674f
|
File details
Details for the file jfmo-3.0.0-py3-none-any.whl.
File metadata
- Download URL: jfmo-3.0.0-py3-none-any.whl
- Upload date:
- Size: 4.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
667e4726919e23aed9f941905d79d3e9da327abe6701f19f2870e0702634dead
|
|
| MD5 |
d364ff250ea90592c111e1bdfe788258
|
|
| BLAKE2b-256 |
e4cf46164f3b9e616f619d63cc95bb70c3cc155a714efc1e75cab3799e4be3d9
|