# 05 — File & Folder Structure Rules (arrflix.s8n.ru)
Last updated: 2026-05-08
Server: Jellyfin 10.10.3 on nullstone, container `jellyfin`
Library root inside container: `/media`
Library root on host: `/home/user/media`
This document is the authoritative ruleset for laying media out on disk so
Jellyfin scrapes it correctly the first time, every time. Cross-linked to:
- [`01-artwork-and-images.md`](01-artwork-and-images.md) — image scrapers and on-disk override files
- [`02-metadata-and-titles.md`](02-metadata-and-titles.md) — filename parsing, `RemoteSearch/Apply`, the lock-the-series flow
- [`03-subtitles.md`](03-subtitles.md) — sidecar `.srt` / `.ass` naming and the OpenSubtitles plugin
- [`04-theming-and-users.md`](04-theming-and-users.md) — multi-user policies and library access
Sources of truth (check these BEFORE this doc — they update):
-
-
-
-
-
-
- Source: `Emby.Naming.dll` ships in the container at `/jellyfin/Emby.Naming.dll`. Rules below match the Emby.Naming regex chain referenced by the docs.
- `CollectionType.cs` (master): `unknown, movies, tvshows, music, musicvideos, trailers, homevideos, boxsets, books, photos, livetv, playlists, folders` (enum int values 0–12).
---
## 0. Top-level rules (apply to everything)
These are non-negotiable. Most "Jellyfin won't match my file" tickets are
caused by violating one of these:
1. **One library = one `CollectionType`.** Never mix Movies and TV in the same
library. Mixed libraries technically exist (`mixed`) but lose half the
scrapers and most edge-case parsing — do not use.
2. **One folder per item.** A movie lives in its own folder. A series lives in
its own folder. A music album lives in its own folder. Loose files in the
library root will scrape, but extras / NFO / artwork sidecars cannot attach
to a loose file.
3. **Forbidden filename characters:** `< > : " / \ | ? *`
These are illegal on Windows and Jellyfin's parser refuses to canonicalise
them. Use `--` for `:`, drop quotes entirely.
4. **No accents/non-ASCII in folder names** unless you are sure the underlying
filesystem (`ext4` here) and SMB/NFS clients all support UTF-8. We're on
`ext4` + LAN-only HTTP, so accents are safe — but avoid them where the
ASCII title is well-known (e.g. `Amelie (2001)` not `Amélie (2001)`).
5. **Always include the year** for movies/series whose title is not unique:
`The Office (2005)` vs `The Office (2001)` (UK), `It (2017)` vs `It (1990)`.
Year goes in parentheses immediately after the title with a single space.
6. **Year is parsed only when in `( )`** — `Movie 2005.mkv` does NOT bind 2005
as the year, it becomes part of the title. `Movie (2005).mkv` does.
7. **Provider-ID overrides win over filename guessing.** If a title is
ambiguous or the scraper repeatedly picks the wrong show, embed the ID:
`Series Name (2023) [tmdbid-12345]/`. Doc 02 covers the `RemoteSearch/Apply`
path for fixing this after-the-fact via API.
8. **`SeriesName/Season XX/SeriesName SXXEYY.ext` is the canonical TV layout.**
Anything flatter or deeper has corner cases. Stick to it.
9. **Dots, dashes, underscores, and spaces are interchangeable** between tokens
for the parser. `Futurama.s01e01.pl.mkv` parses identically to
`Futurama - S01E01 - pl.mkv`. Pick one and be consistent inside a library.
10. **Refresh after a rename.** Renaming a file on disk does NOT auto-refresh
the existing Jellyfin item — it creates a new "missing" record. Either
rename BEFORE first scan, or `POST /Library/Refresh` after.
---
## 1. Movies
### 1.1 Folder structure
```
/media/movies/
├── Blade Runner (1982)/
│ └── Blade Runner (1982).mkv
├── Blade Runner 2049 (2017)/
│ ├── Blade Runner 2049 (2017) - 2160p.mkv
│ ├── Blade Runner 2049 (2017) - 1080p.mkv
│ └── Blade Runner 2049 (2017) - Theatrical.mkv
├── Dune (1984)/
│ └── Dune (1984) [imdbid-tt0087182].mkv
├── Dune (2021)/
│ └── Dune (2021).mkv
└── Lord of the Rings - Fellowship (2001)/
├── Lord of the Rings - Fellowship (2001) - cd1.mkv
└── Lord of the Rings - Fellowship (2001) - cd2.mkv
```
One folder per movie. Folder name = movie name.
### 1.2 Filename pattern
- **Pattern:** `^
\((?\d{4})\)( \[(imdbid|tmdbid|tvdbid)-[^\]]+\])?( - )?\.$`
- **Title** is whatever you put — but it must **byte-for-byte match** the
parent folder name when using multi-version naming.
- **Year** in `(YYYY)` is technically optional but **required for this deploy**.
- **Provider-ID block** `[imdbid-ttNNNNNNN]` / `[tmdbid-NNNN]` / `[tvdbid-NNNN]`
is optional; use it when the title is ambiguous or scraper picks wrong.
- **Label** for multi-version movies: ` - ` or ` - []`.
Resolution labels ending in `p` or `i` (`2160p`, `1080p`, `720i`) sort
descending by resolution; everything else sorts alphabetically.
#### Examples that WORK
```
Blade Runner (1982).mkv
Blade Runner (1982) [imdbid-tt0083658].mkv
Blade Runner 2049 (2017) - 2160p.mkv
Blade Runner 2049 (2017) - Directors Cut.mkv
Blade Runner 2049 (2017) - [Extended].mkv
Lord of the Rings - Fellowship (2001) - cd1.mkv
Lord of the Rings - Fellowship (2001) - part 1.mkv
Lord of the Rings - Fellowship (2001).part.1.mkv
```
#### Examples that BREAK
```
Blade Runner.1982.mkv ← year not in parens; title becomes "Blade Runner 1982"
Blade.Runner.(1982).mkv ← parses but folder/file mismatch will void multi-version
BR (1982).mkv ← title too cryptic, scraper guesses wrong
Blade Runner (1982) - Directors Cut.mkv ← in folder "BladeRunner1982" → mismatch
LOTR: Fellowship (2001).mkv ← `:` is illegal
Movies/Blade Runner (1982).mkv ← no per-movie folder; extras/NFO can't attach
```
### 1.3 Multi-disc / multi-part rips
Use part separators `cd|dvd|part|pt|disc|disk` followed by a number, optionally
preceded by space/`.`/`-`/`_`:
```
Lord of the Rings - Fellowship (2001) - cd1.mkv
Lord of the Rings - Fellowship (2001) - cd2.mkv
```
**Limitation (from upstream docs, verbatim):** "This does not work with
multiple versions or merging." → if you have a 2-disc 2160p AND a 2-disc 1080p
of the same movie, you must remux into single files; the parser cannot encode
both axes.
### 1.4 Foreign-language audio dubs
Jellyfin matches on the original title (English/release-language) regardless
of audio. Polish-dubbed `Futurama` would be:
```
/media/movies/Futurama - Bender's Big Score (2007)/
└── Futurama - Bender's Big Score (2007).mkv ← Polish audio inside
```
Do NOT put `.pl` in the filename — the audio language tag is a track-level
attribute (read from the mkv stream), not a filename token. If you must
distinguish two language rips of the same film, use the multi-version pattern:
```
Movie (2020) - PL Dub.mkv
Movie (2020) - Original.mkv
```
### 1.5 Year disambiguation
When two films share a title, year alone is what the scraper uses. If both
are 1980, fall back to provider IDs:
```
/media/movies/Bad Movie (1980) [imdbid-tt0080000]/
/media/movies/Bad Movie (1980) [imdbid-tt0080001]/
```
### 1.6 Scrapers
- **Primary:** TheMovieDb (TMDb) — bundled, on by default.
- **Fallback / cross-reference:** OMDb (IMDb-backed; ships with Jellyfin core).
- **Image-only:** TheMovieDb covers most posters/backdrops. Add the
**Fanart.tv** plugin if you need clearart, disc, logo overrides — see
`01-artwork-and-images.md` § 4.
- **Trailers:** TheMovieDb attaches YouTube trailer links automatically; the
**AniList** / **TheTVDB** plugins do not apply here.
### 1.7 Edge cases
- **`VIDEO_TS` / `BDMV` rips** are supported but **lose multi-version, multi-part,
and external subtitles**. Avoid for new rips; remux to mkv.
- **Pre-release / unofficial cuts** (Snyder Cut, Final Cut Pro, etc.) → use the
multi-version label, not a separate folder.
- **Movies that became series** (e.g. Fargo) — the original film goes in
`/media/movies/`, the show in `/media/tv/`. Provider IDs prevent cross-match.
- **Anime films that are part of a TV show** (One Piece: Stampede) — see § 3.6.
---
## 2. TV shows
### 2.1 Folder structure (canonical)
```
/media/tv/
├── Futurama (1999)/
│ ├── Season 00/ ← specials live here
│ │ └── Futurama (1999) S00E01 - Christmas Special.mkv
│ ├── Season 01/
│ │ ├── Futurama (1999) S01E01.mkv
│ │ ├── Futurama (1999) S01E02.mkv
│ │ └── Futurama (1999) S01E03-E04.mkv ← multi-episode file
│ ├── Season 02/
│ └── tvshow.nfo ← optional, doc § 11
└── The Office (2005)/
└── Season 01/
└── The Office (2005) S01E01.mkv
```
**Per-season folders are mandatory** for this deploy. Flat (no season folders)
parses but loses the per-season-poster override path (§ 10) and breaks for
shows >2 seasons.
### 2.2 Filename pattern
- **Pattern:** `^.*?[Ss](?\d{1,2})[Ee](?\d{1,3})(-[Ee]?(?\d{1,3}))?(\s.*)?\.$`
- Season + episode tokens recognised by the parser (case-insensitive, dots
and dashes equivalent to spaces — verified in doc 02 § 2):
| Pattern | Example | Result |
|---|---|---|
| `S##E##` | `Futurama S01E01.mkv` | s1e1 |
| `s##e##` | `Futurama.s01e01.pl.mkv` | s1e1 (current Futurama) |
| `Season ## Episode ##` | `Futurama Season 1 Episode 1.mkv` | s1e1 |
| `##x##` | `Futurama 1x01.mkv` | s1e1 |
| `S##E##-E##` | `Futurama S01E01-E02.mkv` | one file, eps 1+2 |
| `S##E## - S##E##` | `Futurama S01E01 - S01E02.mkv` | multi range |
Series name comes from the **parent folder** (preferred) or the filename
prefix before the `S##E##` token. If both are present, folder wins.
#### Examples that WORK
```
Futurama (1999)/Season 01/Futurama (1999) S01E01.mkv
Futurama (1999)/Season 01/Futurama.s01e01.pl.mkv
Futurama (1999)/Season 01/Futurama 1x01 Space Pilot 3000.mkv
Futurama (1999)/Season 01/Futurama S01E01-E02.mkv
Futurama (1999)/Season 00/Futurama (1999) S00E01 - Bender Big Score.mkv
```
#### Examples that BREAK
```
Futurama/Futurama-Pilot.mkv ← no S##E## token, ungrabbable as episode
Futurama/Season1/... ← "Season1" — needs space: "Season 1" or "Season 01"
Futurama/Specials/... ← "Specials" doesn't match; use "Season 00"
Futurama/Season 01/01.mkv ← parser sees no season+episode token, only "01"
Futurama/S01/Futurama_S01E01.mkv ← top-level folder is "S01", series name = "S01"
Futurama (1999) S01E01.mkv ← in /media/tv/ root; no series folder
```
### 2.3 Specials (Season 0)
- Folder: `Season 00` (zero-padded). `Specials/`, `Season 0/`, `Season Specials/`
do **not** match the parser.
- Filename: `Series (year) S00E01 - Title.mkv` — `S00` is required; without
it the file falls into "no season" and is ignored.
- For specials that should appear inside a regular season (e.g. between S03E04
and S03E05), use NFO `` / `` /
`` tags AND enable "Display specials within their
series" in library settings.
### 2.4 Multi-episode files
Two formats accepted:
```
Futurama (1999) S01E01-E02.mkv ← preferred
Futurama (1999) S01E01 - S01E02.mkv ← also accepted
```
Both tag the file as "stacked" — Jellyfin shows it as one entry on the
episode list and plays the entire file when either episode is clicked.
### 2.5 Date-based / daily shows
The official docs do not define a date-based pattern as of 2026-05. The
practical workaround for daily shows (talk shows, news) is to fake them
into seasonal numbering by year:
```
The Daily Show/
├── Season 2024/
│ ├── The Daily Show S2024E001 - 2024-01-02.mkv
│ └── The Daily Show S2024E002 - 2024-01-03.mkv
```
Episode number = day-of-year (001–366). Ugly but parser-clean. If the
metadata provider (TVDB) supports the date-based show, NFO sidecars can
override the episode title to the actual airdate.
### 2.6 Scrapers
- **Primary:** TheTVDB.
- **Secondary:** TheMovieDb (TMDb has good TV coverage too).
- **Order matters:** Library options → Metadata Fetchers → drag the order.
For Futurama on this deploy we used TMDB primary because TVDB had stale
episode-still URLs.
- **Image:** TVDB ships posters and episode stills; TMDB has higher-resolution
backdrops; Fanart.tv has clearart + clearlogo.
### 2.7 Edge cases
- **Series whose name STARTS with a year** (e.g. "1923") — wrap in folder
`1923 (2022)/` so the parser doesn't confuse the series-name year with
the disambiguation year.
- **Shows that re-run/reboot** (`Doctor Who`, `Battlestar Galactica`) — keep
reboots in separate folders, year disambiguation is mandatory:
`Doctor Who (1963)/` and `Doctor Who (2005)/`.
- **Mini-series / limited series** — treat as TV, single season is fine
(`Chernobyl (2019)/Season 01/...`).
- **Episode title inside filename is ignored** once the series is identified;
TMDB/TVDB title overwrites it (see doc 02 § 4).
- **`(year)` is required only at the series level**, not on every episode.
Including it on every episode is harmless but verbose.
---
## 3. Anime
Anime is the area with the highest "scraper picks the wrong thing" risk
because TVDB / TMDB / AniDB / AniList disagree on how to slice multi-cours
shows into seasons. Two distinct strategies — pick **one per show**, never
mix.
### 3.1 Strategy A — TVDB seasonal numbering (default for this deploy)
Use this when:
- Show has ≤ 100 episodes.
- TVDB's season split matches the official Blu-ray / streaming split.
- You're not running Shoko.
#### Folder structure
```
/media/anime/
├── Cowboy Bebop (1998)/
│ └── Season 01/
│ ├── Cowboy Bebop (1998) S01E01.mkv
│ └── Cowboy Bebop (1998) S01E02.mkv
└── Mushishi (2005)/
├── Season 01/
└── Season 02/ ← Mushishi Zoku Shou maps to S02 on TVDB
```
#### Filename pattern
Identical to TV shows § 2.2. Include `(year)` of first broadcast.
#### Edge case — episodes >99 in a season
`S01E100` works for the parser. `S01E001` (3-digit) also works — see [Issue
#17 in jellyfin-plugin-anime](https://github.com/jellyfin-archive/jellyfin-plugin-anime/issues/17).
But **absolute numbering across multiple seasons** (where the show has 1099
episodes spanning many "seasons" on disk) breaks the seasonal model. Use
Strategy B.
### 3.2 Strategy B — Absolute numbering with Shoko Server
Use this when:
- Show has > 100 episodes (One Piece, Naruto, Detective Conan).
- You want AniDB matching, MAL/AniList sync, exact tag accuracy.
- You don't mind running an extra container.
Shoko hashes files by content (ED2K) and identifies them regardless of
filename. With Shoko + the Jellyfin Shoko plugin, **filenames don't matter**.
```
/media/anime-shoko/
└── (any layout you like; Shoko walks the tree and hashes everything)
```
This deploy does **not currently run Shoko**. If/when added, it lives at
`/opt/docker/shoko/` and exposes `/media/anime-shoko/` to Jellyfin via the
plugin, separate from `/media/anime/`.
### 3.3 Strategy C — Absolute numbering with naive Jellyfin (avoid)
Naming files `One Piece - 1099.mkv` with no season folders works for the
**very first 99 episodes** then breaks: the parser sees ep 100+ as "ep 1
of S00 (Specials)" and shuffles. Documented in upstream issue #17. Don't.
### 3.4 Sub vs Dub
Two acceptable patterns:
**Pattern 1 — separate libraries** (recommended, clean):
```
/media/anime/Death Note (2006)/Season 01/Death Note (2006) S01E01.mkv ← original Japanese w/ subs
/media/anime-dub/Death Note (2006)/Season 01/Death Note (2006) S01E01.mkv ← English dub
```
Two libraries; user picks which to browse.
**Pattern 2 — multi-version filenames** (single library, may confuse scraper):
```
/media/anime/Death Note (2006)/Season 01/
├── Death Note (2006) S01E01.mkv ← default (sub)
└── Death Note (2006) S01E01 - Dub.mkv ← extra version, label "Dub"
```
Beware: multi-version on TV episodes (vs movies) is partial in Jellyfin
10.10 — the dub version may not be selectable from all clients. Pattern 1
is safer.
### 3.5 OVAs / OADs / specials
OVAs go in `Season 00` of the parent series, with descriptive titles:
```
Mushishi (2005)/
├── Season 00/
│ ├── Mushishi (2005) S00E01 - Hihamukage OVA.mkv
│ └── Mushishi (2005) S00E02 - Bell of Stillness OVA.mkv
└── Season 01/
```
### 3.6 Anime films that are "part of" a show
Two camps:
- **Canon to plot, watch-order matters** (e.g. *Code Geass: Lelouch of the
Re;surrection*) → put in `Season 00` of the show as a special.
- **Standalone film**, parallel universe (most One Piece movies, Pokémon
films) → put in `/media/movies/` with year. Provider IDs prevent
cross-matching with the parent series.
### 3.7 Japanese vs English titles
Folder name uses the title that matches your **primary metadata provider's
preferred display language**. On this deploy, library `MetadataLanguage` is
`pl` for Futurama; if you add an Anime library set it to `en` or `ja-JP`.
Practical rule: use **the romaji or English title that the show's English
Wikipedia article uses as its primary heading**. That's what TVDB/TMDB
search will resolve. Set provider ID to lock if both titles match
something:
```
/media/anime/Steins;Gate (2011) [tvdbid-244061]/
```
(Note `;` is illegal on Windows but allowed on `ext4`. Avoid for portability.)
### 3.8 Scrapers
- **Primary (sub library):** TheTVDB (anime detection enabled).
- **Optional plugin:** **AniDB** + **AniList** plugins — install via
Dashboard → Plugins → Catalog. Enable per-library. AniDB has better
episode-level metadata for older shows; AniList has better
current-airing data.
- **With Shoko:** Shoko replaces all of the above; AniDB IDs are canonical.
### 3.9 Library type
For this deploy, the Anime library uses `CollectionType: tvshows` (NOT a
separate "anime" type — Jellyfin doesn't have one). Set
`PreferredMetadataLanguage` and the metadata-provider order at library
creation. See § 12 for the API call.
---
## 4. Stand-up comedy specials
### 4.1 Folder structure
Treat as **movies** (one folder per special). Each comedian's specials are
peers — do not nest by performer.
```
/media/movies/
├── Bo Burnham - Inside (2021)/
│ └── Bo Burnham - Inside (2021).mkv
├── Bo Burnham - Make Happy (2016)/
│ └── Bo Burnham - Make Happy (2016).mkv
└── Norm Macdonald - Nothing Special (2022)/
└── Norm Macdonald - Nothing Special (2022).mkv
```
### 4.2 Filename pattern
Same as Movies (§ 1.2). Convention: ` - (year)`.
#### Examples that WORK
```
Bo Burnham - Inside (2021).mkv
Hannah Gadsby - Nanette (2018) [imdbid-tt8465676].mkv
```
#### Examples that BREAK
```
Bo Burnham/Inside (2021).mkv ← no per-movie folder
Inside (2021).mkv ← title too generic; TMDB picks horror film "Inside"
Bo Burnham: Inside (2021).mkv ← `:` is illegal
```
### 4.3 Scrapers
- **Primary:** TheMovieDb (TMDb has stand-up special listings under "Movies").
- TVDB has a Stand-Up category but the Jellyfin TVDB integration treats
everything in a movies library as a movie — leave it.
### 4.4 Edge cases
- **Specials that aren't on TMDB** (small comedians, festival recordings) →
write a `movie.nfo` (§ 11) and let it stand alone. Jellyfin won't fetch
remote data without an ID.
- **Optional separate library:** if you want stand-up out of the main movies
grid, create a second library with `CollectionType: movies` rooted at
`/media/standup/` — same scrapers, just a different shelf.
- **Tagging:** add `Stand-up ` to the NFO or use a Jellyfin
Collection (BoxSet) called "Stand-up Specials" to group them.
---
## 5. Concerts / music videos
### 5.1 Folder structure
```
/media/musicvideos/
├── Daft Punk/
│ ├── Get Lucky/
│ │ └── Daft Punk - Get Lucky.mp4
│ └── Around the World/
│ └── Daft Punk - Around the World.mp4
└── Pink Floyd/
└── Pulse Concert (1995)/
├── Pink Floyd - Pulse (1995).mkv
└── poster.jpg
```
The library can nest as deep as you like — verbatim from upstream:
"The folders and video files can be named however you want, since no
metadata fetching is performed."
### 5.2 Filename pattern
- **Pattern:** anything. Free-form. The display name is the literal filename
minus extension.
- **Convention for this deploy:** ` - .` (or
` - (year).` for full concerts).
#### Examples that WORK
Anything not containing `< > : " / \ | ? *`.
#### Examples that BREAK (parser-wise — none, but UX-wise)
```
01.mp4 ← display name "01", useless
videoplayback (1).mp4 ← yt-dlp default; rename before scan
```
### 5.3 Scrapers
- **None by default.** `musicvideos` library type has no built-in remote
metadata fetcher — Jellyfin uses filenames + folder structure.
- Embedded ID3-style tags in `mp4` (artist, title) ARE read.
- Plugins: there is no first-party music-video scraper. Some users use
the **MusicBrainz** plugin to cross-reference, but coverage is poor.
### 5.4 Edge cases
- **Full live concerts** are sometimes better as `tvshows` (one episode per
song) or `movies` (single file). For this deploy use **movies** for
full concert recordings, **musicvideos** for individual song clips.
- **Fan-made / unofficial videos** — fine here, since no scraper to
mismatch.
- **Music VIDEOS attached to a music album** — Jellyfin doesn't link a
music-video item to a music-album item natively. Live with the
separation.
---
## 6. Documentaries
Documentaries split on form:
### 6.1 Single-film documentaries → Movies library
```
/media/movies/
└── Free Solo (2018)/
└── Free Solo (2018).mkv
```
Same rules as § 1. TMDB classifies most documentary films as "Movies".
### 6.2 Multi-episode documentary series → TV library
```
/media/tv/
└── Planet Earth II (2016)/
└── Season 01/
├── Planet Earth II (2016) S01E01.mkv
└── Planet Earth II (2016) S01E02.mkv
```
Same rules as § 2. TVDB classifies most documentary series as "Series".
### 6.3 Optional separate libraries
For users who want documentaries off the main Movies/TV shelves:
- `/media/docs-movies/` with `CollectionType: movies`
- `/media/docs-tv/` with `CollectionType: tvshows`
Same scrapers as the parent type — the tag is purely UI.
### 6.4 Scrapers
- **Films:** TMDb (primary), OMDb (fallback).
- **Series:** TVDB (primary), TMDb (secondary).
- The same NFO override rules apply (§ 11) for obscure docs that aren't on
any provider.
### 6.5 Edge cases
- **Mini-series in 1 long file** (e.g. *The Vietnam War* PBS, 18 hours, one
rip) — treat as a movie or split into episodes. Jellyfin does not chapter-
split a single file into N episode entries.
- **Lecture series** (Crash Course, Khan Academy) — treat as TV. Use
`Crash Course (2011)/Season 01/` etc.
---
## 7. Home videos / personal media
The goal: keep Jellyfin from "fixing" your wedding videos by pulling the
poster of an unrelated 2015 movie called *Wedding*.
### 7.1 Folder structure
```
/media/home/
├── 2024/
│ ├── 2024-06-15 Berlin Trip/
│ │ ├── 2024-06-15 Berlin Trip - clip01.mp4
│ │ └── 2024-06-15 Berlin Trip - clip02.mp4
│ └── 2024-12-25 Christmas/
│ └── 2024-12-25 Christmas.mp4
└── 2025/
└── 2025-08-30 Wedding/
└── 2025-08-30 Wedding.mp4
```
### 7.2 Filename pattern
Free-form. Date-prefix recommended (`YYYY-MM-DD `) — Jellyfin will
parse the date and use it as the item's date.
### 7.3 Library type
`CollectionType: homevideos` — **critical**. This is the only collection
type that disables all remote metadata fetchers. With `homevideos`:
- No TMDB / TVDB / OMDb scrapers run.
- Image fetchers are off (use sidecar `.jpg` if you want a thumb).
- The library shows up under "Photos & home videos" in the UI sidebar.
### 7.4 Scrapers
**None.** Local-only. NFO sidecars (§ 11) work if you want to label
individual clips, but no remote lookups.
### 7.5 Edge cases
- **Photos in the same folder as videos** — `homevideos` library accepts
both. Use `.jpg`/`.png`/`.heic` sidecars; they appear in the slideshow.
- **Don't drop home videos in `/media/movies/`.** Even with no provider IDs,
Jellyfin will scan and try to match titles against TMDB. The
`homevideos` library is the only safe place.
- **Smart phone clips** named `IMG_1234.MOV` are fine; they display by
filename. Bulk-rename to `2024-06-15 - IMG_1234.mov` if you want them
sorted by event date.
---
## 8. Extras / special features
Extras attach to a parent item (movie or series) via two mechanisms:
filename suffix, or named subfolder. Either works; mixing is fine.
### 8.1 Suffix method
Append one of these tokens to the filename **before** the extension:
| Suffix | Type | Example |
|---|---|---|
| `-trailer` `.trailer` `_trailer` ` trailer` | Trailer | `Blade Runner (1982) - 1982 Theatrical-trailer.mp4` |
| `-sample` `.sample` `_sample` ` sample` | Sample | `Movie-sample.mp4` |
| `-scene` | Deleted scene / vignette | `Inception (2010) - Hallway-scene.mp4` |
| `-clip` | Promo clip | `Movie - TV Spot-clip.mp4` |
| `-interview` | Interview | `Movie - Director Interview-interview.mp4` |
| `-behindthescenes` | BTS featurette | `Movie - VFX Breakdown-behindthescenes.mp4` |
| `-deleted` `-deletedscene` | Deleted scene | `Movie - Cut Diner Scene-deleted.mp4` |
| `-featurette` | Featurette | `Movie - Anatomy of a Stunt-featurette.mp4` |
| `-short` | Short film | `Movie - Prequel Short-short.mp4` |
| `-other` `-extra` | Catch-all | `Movie - Ephemera-other.mp4` |
A lone trailer/sample file can also be named just `trailer.mp4` or
`sample.mp4` and dropped in the parent item folder.
### 8.2 Folder method
Inside the parent item folder, any of these named subfolders are picked up
and the files inside are tagged with the matching extra type:
```
Inception (2010)/
├── Inception (2010).mkv
├── behind the scenes/
│ └── VFX Breakdown.mp4
├── deleted scenes/
│ ├── Diner Cut.mp4
│ └── Hotel Hallway Cut.mp4
├── featurettes/
│ └── Dreams Within Dreams.mp4
├── interviews/
│ └── Christopher Nolan.mp4
├── scenes/
├── shorts/
├── samples/
├── trailers/
│ └── Theatrical Trailer.mp4
├── clips/
├── theme-music/
│ └── theme.mp3 ← see § 8.3
├── backdrops/
│ └── 2.mp4 ← rotating video backdrops
├── other/
└── extras/ ← generic catch-all
```
Subfolder names **must match exactly** (case-insensitive on `ext4`+Jellyfin):
`Behind the Scenes/` works; `BTS/` does not; `behind-the-scenes/` does not.
### 8.3 Theme music
`theme-music/theme.mp3` plays a track on hover/auto in supported clients
(Swiftfin, JellyfinMediaPlayer). One file per item.
### 8.4 Backdrops
Video backdrops (rotating background loops) go in `backdrops/` as numbered
mp4s. Falls back to image backdrops if not present.
### 8.5 Edge cases
- **Extras attached to a series vs a season vs an episode** — folder method
works at any level: drop `behind the scenes/` inside `Futurama (1999)/`
for series-wide extras, inside `Season 01/` for season extras, or
use suffix on a sibling file for episode extras.
- **Show-level trailers** — Jellyfin's TV scraper auto-attaches trailer
YouTube links from TMDB. You don't need to download them.
---
## 9. Subtitles (sidecar)
See [`03-subtitles.md`](03-subtitles.md) for the full rules. Quick reference:
```
.[.flag].
```
- `` = the video filename minus extension.
- `` = ISO-639-1 (`en`, `pl`) or ISO-639-2 (`eng`, `pol`).
- `` = optional, any combination of `forced`, `default`, `sdh`, `cc`.
- `` = `srt`, `ass`, `ssa`, `vtt`, `sub` (+ `.idx` for VobSub).
Examples next to `Futurama.s01e01.pl.mkv`:
```
Futurama.s01e01.pl.eng.srt ← English regular
Futurama.s01e01.pl.en.forced.srt ← English forced (foreign-scene captions)
Futurama.s01e01.pl.en.sdh.srt ← English SDH
Futurama.s01e01.pl.en.default.srt ← marked default, auto-selects
Futurama.s01e01.pl.pl.srt ← Polish (matches the language of the audio)
```
After dropping subs on disk, run `POST /Library/Refresh` (or wait for the
nightly scan) — Jellyfin discovers them and attaches.
---
## 10. Artwork override files
Jellyfin scrapes artwork from TMDB/TVDB/Fanart by default (see doc 01).
Override per-item by dropping a sidecar image with one of these recognised
filenames in the item's folder.
### 10.1 Movie / generic item folder
| Filename | ImageType | Notes |
|---|---|---|
| `poster.jpg` / `poster.png` | Primary | Main poster (vertical 2:3). |
| `folder.jpg` | Primary | Alias of poster (Windows / Plex compat). |
| `cover.jpg` | Primary | Alias of poster (also used in music). |
| `default.jpg` | Primary | Alias. |
| `movie.jpg` | Primary | Alias. |
| `backdrop.jpg` | Backdrop | Hero image (16:9 fanart). |
| `backdrop1.jpg`, `backdrop2.jpg`, ... | Backdrop | Multiple backdrops, numbered. |
| `fanart.jpg` | Backdrop | Plex/Kodi compat alias. |
| `logo.png` | Logo | Transparent text-logo overlay. |
| `clearlogo.png` | Logo | Alias. |
| `banner.jpg` | Banner | Wide ~758×140 strip. |
| `thumb.jpg` | Thumb | 16:9 still. Used as episode thumbnail at item level. |
| `landscape.jpg` | Thumb | Alias. |
| `disc.png` | Disc | DVD/Blu-ray hub icon. |
| `clearart.png` | Art | Transparent character cutout. |
### 10.2 TV series folder (additional)
```
Futurama (1999)/
├── poster.jpg
├── backdrop.jpg
├── logo.png
├── banner.jpg
├── season-all-poster.jpg ← shared across all seasons
├── season01-poster.jpg ← Season 01 specific
├── season02-poster.jpg
├── season-specials-poster.jpg ← Season 00
├── Season 01/
│ ├── Futurama (1999) S01E01.mkv
│ ├── Futurama (1999) S01E01.jpg ← episode thumb (basename match)
│ └── poster.jpg ← also valid as season poster
└── tvshow.nfo
```
The two season-poster paths are equivalent; pick one style. Episode-level
thumbs use `.jpg` (i.e. drop a `.jpg` next to the `.mkv` with
matching name).
### 10.3 When to override
- Use sidecar files when the scraper's choice is wrong AND you don't want
to upload via the Web UI (which writes into `/config/metadata/library/...`
— wiped on container rebuild).
- Sidecars in the media folder **survive `docker rm`** because they live on
the user's data volume.
- Sidecars take precedence over remote scraper images on next refresh
ONLY if "Save artwork into media folders" is enabled in Dashboard →
Libraries → (each library) → Library options. This deploy has it ON.
### 10.4 Edge cases
- `.png` and `.jpg` are both accepted; `.webp` works for backdrops but
not all clients render it — prefer `.jpg`.
- Image larger than 4K is downscaled by the API on serve. Don't bother with
>2160p source images.
- **Don't put `poster.jpg` in `/media/movies/`** (the library root) — it
becomes the library's primary image, often unwanted.
---
## 11. NFO sidecars
NFO files are XML metadata, written next to the media. They override remote
scrapers entirely. From upstream: "Local metadata will always be fetched and
has priority over remote metadata providers like TMDb."
### 11.1 Filenames
| Item type | Required filename |
|---|---|
| Movie | `movie.nfo` (in the movie folder), OR `.nfo` next to the file, OR `VIDEO_TS.nfo` for DVD rips |
| TV series | `tvshow.nfo` in the series folder |
| TV season | `season.nfo` in the season folder |
| TV episode | `.nfo` (e.g. `Futurama (1999) S01E01.nfo`) |
| Music artist | `artist.nfo` |
| Music album | `album.nfo` |
### 11.2 When to write one
- Obscure indie film not on TMDB / IMDB → `movie.nfo` lets you fill the
metadata yourself.
- Show whose IDs scrape wrong every time → `tvshow.nfo` with locked
`` / `` is faster than the API `RemoteSearch/Apply`
workflow (doc 02 § 5).
- Home videos / personal — usually not needed (homevideos lib doesn't
scrape) but useful for nice titles.
### 11.3 Minimal `movie.nfo` example
```xml
The Obscure Film
Niejasny film
2014
A short description that overrides whatever TMDB returns.
Drama
97
Jane Director
Lead Actor
Protagonist
tt12345678
```
### 11.4 Minimal `tvshow.nfo` example
```xml
Futurama
1999
...
615
73871
```
### 11.5 NFO Saver (write-back)
Enable Dashboard → Libraries → (each) → Metadata Savers → "Nfo". Jellyfin
will write `*.nfo` next to media files whenever metadata changes. This is
how you survive container rebuilds without losing manual fixes — the NFO
on disk is canonical, the SQLite DB is regenerable.
### 11.6 Edge cases
- **Empty/malformed NFO** stops the scraper from running on that item AT
ALL. Either write valid XML or delete the file.
- **NFO + provider ID conflict** — local always wins. If you set
`615 ` and the filename has `[tmdbid-9999]`, NFO wins.
- **Episode `.nfo` per file is verbose.** Most people only write `tvshow.nfo`
and let the episode metadata come from the provider.
---
## 12. CollectionType-to-scraper mapping (library creation)
Verbatim values from `Jellyfin.Data/Enums/CollectionType.cs` (master,
verified 2026-05). These are the strings to pass when creating a library
via API. (`unknown` is reserved; `tvshowseries`+ are virtual aggregates not
used at library creation.)
| `CollectionType` | UI name | Default scrapers (10.10.x) | Use for |
|---|---|---|---|
| `movies` | Movies | TMDb, OMDb, Fanart.tv (plugin) | Films, stand-up, doc films |
| `tvshows` | Shows | TVDB, TMDb, Fanart.tv, OMDb | TV, anime, doc series, kids' shows |
| `music` | Music | MusicBrainz, AudioDB | Albums, tracks |
| `musicvideos` | Music Videos | none (filename only) | Music videos, short concerts |
| `homevideos` | Home Videos & Photos | none | Personal recordings, photo albums |
| `boxsets` | Collections | TMDb collections | Manually-curated cross-library box sets |
| `books` | Books | requires "Bookshelf" plugin | epub, mobi, pdf, comics |
| `photos` | Photos | none | Photo-only library |
| `livetv` | Live TV | tuner-driven | Real-time TV (HDHomeRun etc.) |
| `trailers` | Trailers | bundled | Standalone trailers library (rare) |
| `playlists` | Playlists | n/a | Internal Jellyfin construct |
| `folders` | Folders | n/a | Internal Jellyfin construct |
| `mixed` (no enum, legacy) | Mixed | TMDb + TVDB | Don't use — drops most parsing rules |
### 12.1 Creating libraries via API
```bash
TOKEN=*redacted*
H="-H \"X-Emby-Token: ${TOKEN}\""
B="https://arrflix.s8n.ru"
# Movies library
curl -s -X POST $H "$B/Library/VirtualFolders?name=Movies&collectionType=movies" \
-H "Content-Type: application/json" \
-d '{"LibraryOptions":{"PathInfos":[{"Path":"/media/movies"}],"EnableInternetProviders":true,"PreferredMetadataLanguage":"en","MetadataCountryCode":"US","SaveLocalMetadata":true,"SubtitleDownloadLanguages":["eng"]}}'
# TV library
curl -s -X POST $H "$B/Library/VirtualFolders?name=Shows&collectionType=tvshows" \
-H "Content-Type: application/json" \
-d '{"LibraryOptions":{"PathInfos":[{"Path":"/media/tv"}],"EnableInternetProviders":true,"PreferredMetadataLanguage":"en","SaveLocalMetadata":true,"SubtitleDownloadLanguages":["eng"]}}'
# Anime library (still tvshows type)
curl -s -X POST $H "$B/Library/VirtualFolders?name=Anime&collectionType=tvshows" \
-H "Content-Type: application/json" \
-d '{"LibraryOptions":{"PathInfos":[{"Path":"/media/anime"}],"EnableInternetProviders":true,"PreferredMetadataLanguage":"en","SaveLocalMetadata":true,"SubtitleDownloadLanguages":["eng"]}}'
# Music videos
curl -s -X POST $H "$B/Library/VirtualFolders?name=Music%20Videos&collectionType=musicvideos" \
-H "Content-Type: application/json" \
-d '{"LibraryOptions":{"PathInfos":[{"Path":"/media/musicvideos"}]}}'
```
After creation, trigger an initial scan: `POST /Library/Refresh`.
---
## 13. Canonical layout for THIS deploy
### 13.1 Architecture decision
**Adopted: Architecture A** — flat by category at `/home/user/media/`, one
Jellyfin library per category.
```
/home/user/media/
├── movies/ ← collectionType: movies
└── tv/ ← collectionType: tvshows
```
> ARRFLIX scope locked 2026-05-08: TV Shows + Movies only. `anime/`,
> `musicvideos/`, `home/`, `music/`, `docs-*/` libraries removed. Sections in
> this doc covering anime/music/etc. remain as reference for the day scope is
> revisited — just `mkdir` + add library via API when needed.
### 13.2 Why Architecture A (not B or C)
**B (nested, `media/video/{movies,tv,anime}/...`)** — rejected. Adds a
useless directory level. Jellyfin's library config takes a path; nesting
buys nothing on the client side. Increases the chance of a typo in the
container's bind-mount.
**C (split disks: `/media-fast/` NVMe + `/media-slow/` HDD)** — rejected
**for now**. Nullstone has a single 2 TB NVMe and 4 TB HDD. Total media
today is ~50 GB (Futurama + future). When the library exceeds 1 TB, we'll
revisit and migrate cold catalogue (older movies, finished anime) to the
HDD, mounted as a second library path:
```
LibraryOptions.PathInfos = [
{"Path": "/media/movies"}, ← /home/user/media/movies on NVMe
{"Path": "/media-archive/movies"} ← /mnt/hdd/media/movies
]
```
Jellyfin natively merges multiple paths into one logical library. No URL
or client-facing change needed at migration time.
**A wins because:**
- One library per `collectionType` is the simplest correct mapping.
### 13.3 Concrete mkdir commands
Run on nullstone as `user` (not root — the existing tree is already owned
by `user:user`):
```bash
ssh user@192.168.0.100 'mkdir -p \
/home/user/media/movies \
/home/user/media/tv'
```
Verify:
```bash
ssh user@192.168.0.100 'ls -la /home/user/media/'
```
### 13.4 Container bind mounts
`/opt/docker/jellyfin/docker-compose.yml` should mount each as read-only
under `/media/`:
```yaml
volumes:
- /home/user/media/movies:/media/movies:ro
- /home/user/media/tv:/media/tv:ro
```
### 13.5 Initial state after applying
```
Movies library → /media/movies (empty, ready)
TV Shows library → /media/tv (Futurama 1999, S01-S04, 72 eps + 9 featurettes)
```
---
## 14. Verification checklist
Before declaring a new addition "done":
1. Filename matches the regex anchor for the category (§ 1–7).
2. Year is in `(YYYY)` and matches the actual release year.
3. Folder name byte-for-byte matches the filename prefix (movies multi-version).
4. No forbidden chars (`< > : " / \ | ? *`).
5. Per-item folder exists (no loose files in library root, except music videos).
6. `tvshow.nfo` / `movie.nfo` exists IFF you needed to override the scraper.
7. Subtitles use `..srt` (doc 03).
8. Scan: `curl -s -X POST -H "X-Emby-Token: $TOKEN" https://arrflix.s8n.ru/Library/Refresh`.
9. Wait ~30 s, check item via `/Items?searchTerm=...` — verify `ProviderIds`
is populated. Empty `ProviderIds` = filename didn't disambiguate; doc 02
§ 5 has the manual-lock recipe.
10. Refresh (`Items/{id}/Refresh?ReplaceAllMetadata=true`) AFTER fixing the
provider ID — otherwise the wrong cached metadata sticks.
---
## 15. Quick reference card
| Category | Folder | Filename | CollectionType | Scraper |
|---|---|---|---|---|
| Movie | `movies/Title (year)/` | `Title (year).mkv` | `movies` | TMDb |
| Movie multi-version | `movies/Title (year)/` | `Title (year) - 1080p.mkv` | `movies` | TMDb |
| Movie multi-disc | `movies/Title (year)/` | `Title (year) - cd1.mkv` | `movies` | TMDb |
| TV episode | `tv/Show (year)/Season 01/` | `Show (year) S01E01.mkv` | `tvshows` | TVDB |
| TV multi-ep | `tv/Show (year)/Season 01/` | `Show (year) S01E01-E02.mkv` | `tvshows` | TVDB |
| TV special | `tv/Show (year)/Season 00/` | `Show (year) S00E01.mkv` | `tvshows` | TVDB |
| Anime (seasonal) | `anime/Show (year)/Season 01/` | `Show (year) S01E01.mkv` | `tvshows` | TVDB+AniDB plugin |
| Anime (Shoko) | `anime-shoko/` | any | `tvshows` | Shoko |
| Stand-up | `movies/Comedian - Title (year)/` | `Comedian - Title (year).mkv` | `movies` | TMDb |
| Music video | `musicvideos/Artist/Track/` | `Artist - Track.mp4` | `musicvideos` | none |
| Doc film | `movies/Title (year)/` | `Title (year).mkv` | `movies` | TMDb |
| Doc series | `tv/Show (year)/Season 01/` | `Show (year) S01E01.mkv` | `tvshows` | TVDB |
| Extra (suffix) | `movies/Title (year)/` | `Anything-behindthescenes.mp4` | (parent) | n/a |
| Extra (folder) | `movies/Title (year)/behind the scenes/` | any | (parent) | n/a |
---
## 16. Top three gotchas (in order of frequency)
1. **No per-item folder.** Loose `Movie (2020).mkv` directly in `/media/movies/`
parses, but extras / NFO / artwork sidecars cannot attach. Always make a
folder.
2. **Year not in parens.** `Movie 2020.mkv` → year is part of the title;
scraper search for "Movie 2020" returns wrong results. Always
`Movie (2020).mkv`.
3. **Anime absolute numbering > 99 episodes** without Shoko, mixed with
season folders → episodes shuffle into Season 0. Either split by
TVDB seasons OR run Shoko. Never half-and-half.
---
End of doc 05. For questions about parsing edge cases not covered here,
read `Emby.Naming.xml` inside the container (`docker exec jellyfin cat
/jellyfin/Emby.Naming.xml`) — it has the canonical regex chain.