Skip to content

Movies Library Setup

Since: 0.14.0

TL;DR

A movies library turns your video collection into a browsable, searchable catalog with posters, synopses, and cast info pulled from online databases. Drop your video files into a folder, add that folder to Phlix as a Movies library, and Phlix handles the rest — matching titles, fetching artwork, and tracking your watch progress across devices.

bash
# Add your movies folder, scan, and you're ready
# Libraries → Add Library → Type: Movies → point to /path/to/movies → Scan

1. Supported Formats

FormatExtensionPlayback Notes
Matroska.mkvMost common; supports many codecs
MPEG-4.mp4, .m4vWide device compatibility
AVI.aviLegacy format; some files may need transcoding
QuickTime.movCommon for iTunes content
Windows Media.wmvMay require transcoding on non-Windows clients
MPEG Transport Stream.tsUsed for broadcast recordings

Container format matters less than the codec inside. Phlix streams directly when your player supports the codec; transcoding falls back automatically when needed.

2. Naming Conventions

2a. Flat-File Naming (Simplest)

Avatar (2009).mkv
The Matrix (1999).mp4
  • Movie Name (Year).ext — Phlix uses the year in parentheses as the primary identifier for metadata matching
  • Year range accepted by the scanner: 1900 through 5 years in the future

2b. Folder-Based Naming

/Movies/
  The Matrix (1999)/
    Matrix, The.mp4
  Avatar (2009)/
    Avatar.mkv
  • Folder name follows Movie Name (Year)/ — the article ("The", "A", "An") sorts to the end of the folder name: The Matrix becomes Matrix, The
  • The video file inside can be named anything; the folder name is what matters

2c. Multi-Version Movies

Avatar (2009) - directors-cut.mkv
Avatar (2009) - extended.mkv
Avatar (2009) - 4k-restored.mkv
  • A version tag ( - directors-cut, - extended, - 4k-restored) after the year creates a separate library entry per version
  • Each version has its own playback state and resume position

2d. Disc Folder Structure

Movie Name (2020)/
  movie.mkv
  trailer.mkv
  extras/
    Behind the Scenes.mkv
  • movie.mkv is the main feature; files named -trailer or -sample are excluded from the main library count but associated with the item
  • The extras/ subfolder is scanned as associated extras; naming inside is free-form

3. NFO Sidecar Files

Kodi-style NFO files let you lock metadata to a specific online record or add custom local data.

Per-Movie NFO

Place movie.nfo alongside the video file:

xml
<movie>
  <title>Avatar</title>
  <year>2009</year>
  <tmdbid>241</tmdbid>
  <plot>Jake Sully lives with the Na'vi on Pandora...</plot>
</movie>
  • tmdbid is the primary lookup key — when present, Phlix fetches metadata directly from TMDB without title/year matching
  • Local NFO always takes priority when metadata_source is set to local in the library configuration
  • The filename is case-sensitive on Linux: must be exactly movie.nfo, not Movie.nfo or MOVIE.NFO

What Goes in an NFO

FieldDescription
titleMovie title
yearRelease year (4 digits)
tmdbidTMDB movie ID (e.g., 241 for Avatar)
tvdbidTVDB ID (fallback)
plotSynopsis text
genreGenre tags
directorDirector name
ratingContent rating (MPAA or custom)

4. Metadata Sources and Priority

PrioritySourceNotes
1 (highest)Local NFOmovie.nfo in the same folder
2TMDBPrimary online metadata; free account at themoviedb.org
3TVDBFallback when TMDB has no match
4Filename parsingYear and title extracted from file/folder name as last resort

To re-fetch an item's metadata, click Match metadata on it in the UI (admins only) and pick a result — see Fixing a single item's match.

Provider responses are cached in memory for one hour. Every TMDB, TVDB and Fanart.tv call goes through a shared HTTP client that stores each successful 2xx JSON body against the endpoint and its query parameters, with a 1-hour TTL (MetadataHttpClient::CACHE_TTL_MS) and LRU eviction at 4096 entries. The provider objects are container singletons, so that cache lives for the life of the worker process — it spans requests and jobs. A re-match issued within the hour can therefore return byte-identical data without any HTTP request being made; restarting the server clears it.

There is no item-level freshness window on this path: the library match visits whichever items you ask it to and calls the resolver each time. (The 24-hour rule that exists elsewhere in the tree, MetadataManager::hasRecentMetadata(), is a per-provider gate on a different refresh path that movie items do not take.)

5. Scanner Behavior

How Phlix Distinguishes Movies from TV Episodes

Pattern in FilenameClassificationExample
(Year) only, no episode codeMovieAvatar (2009).mkv
S01E01 or 1x01TV episodeShow Name S01E01.mkv
Season 00/ or Specials/ folderTV (specials)Season 00/
Both episode code AND yearTV (episode number wins)Show (2020) S01E01.mkv

Scan Triggering

  • Manual: Click Scan (or Rescan) on the library's row in Admin → Libraries, or POST /api/v1/libraries/{id}/scan, or php bin/phlix library:scan {libraryId}
  • First add: Creating a library queues a full recursive scan of its roots in the background

There is no scheduled or filesystem-triggered scan. Creating a library registers its roots with FolderWatcher, but the method that would actually compare directory checksums and act on a change — FolderWatcher::checkForChanges() — has no production caller, so it never runs. Nothing polls the filesystem, nothing queues a scan from a change on disk, and the LibraryUpdated event that would refresh smart playlists is never dispatched. New files appear after you scan.

What a rescan does — and does not — do

The movie scanner has no per-file skip index and does not look at mtime at all. It decides by path: a file whose path is already in the catalogue takes the existing-item branch, which backfills any missing source technical metadata (duration, the metadata_json['source'] summary, media_streams rows) and then moves on. A file whose path is new is parsed, probed and inserted. Afterwards the prune pass removes items whose source file has disappeared.

The --rescan / Rescan "re-read every file" flag is consumed by the music scanner only; on a movie library it is inert. So a rescan is the right tool after files are added or deleted, and the wrong tool for a wrong or missing match — it will not re-parse the filename or re-fetch metadata for a row that already exists.

A rescan handles a MOVED file, but not a RENAMED one (S158)

Renaming a movie file inserts a new row (new UUID, no watch state) and the prune removes the old one — the new name is a different canonical key, so nothing links the two. Moving a movie file without renaming it is safe: the scanner matches it to the existing row by a canonical key built from title and year alone, and the prune in the same rescan re-points that row at the new path instead of deleting it, keeping the UUID, watch history and resume position. Episodes were never affected.

After reorganising storage run a Rescan, not a standalone Prune — a prune does not scan and so deletes the rows it cannot match. See Moving a file.

For a match problem, which remedy you want depends on which problem it is:

  • Never matched (no metadata at all) — match-metadata, which visits exactly the items carrying no metadata_refreshed_at stamp.
  • Matched to the wrong film — the per-item match action. refresh-metadata will not correct it: it re-seeds the resolve from the item's own stored external_ids and the resolver skips its title search whenever an IMDb id is present, so the same wrong film comes back. See Fixing a wrong match.

6. Content Rating and Parental Controls

Each user profile has a rating filter set in Settings → Profiles: G / PG / PG-13 / R / NC-17 / X / UNRATED. Movies rated above the profile's filter are hidden from that profile's library view.

  • Ratings are pulled from TMDB or TVDB metadata
  • Items sourced from NFO without a rating default to UNRATED (visible to all profiles)
  • You can manually set a content rating on any item from the item detail page

What Can Go Wrong

Duplicate Entries or Split Library

Symptom: The same movie appears 2–4 times in the library after a rescan.

Cause: Mixing flat-file and folder-based naming for the same movie; inconsistent year in filenames.

Fix: Pick one naming style per library. Run Empty Library from library settings, then re-scan. For multi-version movies, keep all versions in the same folder with distinct version tags.


Metadata Not Found or Wrong Match

Symptom: Movie shows as "Unknown Title" or matches a different film.

Cause: Year mismatch between your filename and the TMDB record; special characters or non-English titles break parsing.

Fix: Rename the file to Movie Name (Year).ext with the exact year from TMDB. Or create a movie.nfo with the correct tmdbid to bypass title/year matching entirely.


NFO File Ignored

Symptom: Custom poster, plot, or genre tags from your NFO are not appearing in Phlix.

Cause: NFO filename is not exactly movie.nfo (Linux is case-sensitive), or the NFO file contains malformed XML.

Fix: Rename to movie.nfo with a lowercase m. Validate your XML at xmlvalidation.com. Ensure the root element is <movie>.


Metadata Fetch Failure or Rate Limit

Symptom: Newly scanned movies show "No metadata" despite correct filenames.

Cause: TMDB API rate limit exceeded, or the server cannot reach TMDB.

Fix: Wait 10 seconds and click Match metadata on the item. For large initial scans, add a TMDB API key in library settings. Check server network connectivity to api.themoviedb.org.


Parental Control Content Leaking Through

Symptom: Restricted content is visible on a child profile.

Cause: Profile rating filter set too high; or the media item has UNRATED metadata and is not filtered.

Fix: Lower the profile's rating filter in Settings → Profiles. From the item's detail page, manually set the content rating if it shows as UNRATED.

Next Steps

BSD-3-Clause