Hardlink TV/anime Season-00 specials that are really movies into Plex movie folders
Find a file
xenarathon db3e962192 Map 142 more Season-0 films found by a full Sonarr specials scan
Films only: theatrical, direct-to-video and TV movies with a verified TMDB
match (title, year, runtime). TV episodes, holiday specials, documentaries,
concerts and episode recaps are left to Sonarr.
2026-09-30 18:08:14 -04:00
.agents/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.clinerules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.codex Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.cursor/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.github Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.kilo/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.kilocode/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.kiro/steering Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.qoder/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.roo/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.windsurf/rules Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
skills/procoder Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
.gitignore Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
AGENTS.md Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
LICENSE Initial commit: show-movie-linker 2026-06-14 18:50:04 -04:00
link_specials.py Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
movie_map.py Map 142 more Season-0 films found by a full Sonarr specials scan 2026-09-30 18:08:14 -04:00
README.md Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
run.sh Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
show-movie-linker.service Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00
show-movie-linker.timer Reverse direction: Radarr owns the films, Sonarr's Season 00 gets the hardlink 2026-09-30 15:29:29 -04:00

show-movie-linker

Some TV shows have feature films filed away as Season 00 "specials": the Stargate movies, the Pokémon movies, Psych: The Movie, Cowboy Bebop: The Movie, and so on. Sonarr is unreliable at finding specials, but Radarr is good at finding films. So this tool lets Radarr own each film and gives Sonarr the same file:

  1. Every film in the map is added to Radarr (if it isn't there) and monitored, so Radarr searches for it, grabs it, and upgrades it like any other movie.
  2. Radarr's file is hardlinked into the show's Season 00 folder, so Sonarr (and the TV library in Plex) has the special too. If Sonarr had its own separate copy, that copy is replaced by the link.
  3. If only Sonarr has the film so far, its file is hardlinked into Radarr's movie folder instead, so Radarr adopts it without downloading it again.
  4. The special is unmonitored in Sonarr, so Sonarr never goes looking for it again.

Afterwards it asks Sonarr/Radarr to rescan and rename the files it touched. The rename also triggers their Plex/Jellyfin notifications.

One copy on disk, two library entries. Run it nightly: when Radarr upgrades a film (or Tdarr re-encodes it), the Season 00 name still points at the old data until the next run relinks it.

What's a hardlink, and why does that mean "no extra disk space"?

A normal file is a name that points at the actual data on your disk. A hardlink is a second name for that same data. There's still only one copy of the movie. It just answers to two names: one in the movie library and one in the TV library's Season 00.

Delete one name and the other still works. The data only goes away when the last name is gone. Both names have to be on the same filesystem (or the same mergerfs pool).


Quick start

On the machine that holds your media (it must run as root, see Good to know):

git clone https://git.ourserver.party/xenarathon/show-movie-linker.git /opt/show-movie-linker

Create /etc/show-movie-linker.env (mode 600, it holds API keys):

SONARR_URL=http://sonarr-host:8989
SONARR_API_KEY=...
RADARR_URL=http://radarr-host:7878
RADARR_API_KEY=...

Edit the settings at the top of movie_map.py (see Personalize it), then preview. With no flags nothing is changed; it only prints what it would do:

/opt/show-movie-linker/run.sh

If the preview looks right, do it for real:

/opt/show-movie-linker/run.sh --apply
What does run.sh do?

It loads the API keys from /etc/show-movie-linker.env into the environment and runs link_specials.py with whatever flags you gave it. The systemd unit below reads the same file, so manual runs and scheduled runs behave the same.


Personalize it

Everything lives in movie_map.py:

Setting What it's for
ARR_PREFIX / HOST_PREFIX Where your arrs see the media vs. where this machine sees it. E.g. the arrs see /data/r520/media, and the pool host sees /srv/mergerfs/pool/media.
RADARR_ROOT Radarr root folder for films the tool has to add: one for normal films, one for anime.
RADARR_PROFILE Radarr quality profile id for those adds (see Radarr → Settings → Profiles, or /api/v3/qualityprofile).
RADARR_MIN_AVAILABILITY Radarr minimum availability for adds.
MIN_RUNTIME_RATIO Safety check: a file shorter than this fraction of the film's TMDB runtime is treated as the wrong file and never linked from.
MAP The list of films.

Each MAP line is one film:

(72449, 7, 13001, False),  # Stargate: The Ark of Truth (2008)
#  |    |    |      '-- anime? (picks RADARR_ROOT / RADARR_PROFILE for new adds)
#  |    |    '-- TMDB movie id
#  |    '-- Season 00 episode number on TheTVDB
#  '-- TheTVDB series id (the {tvdb-...} in the show's folder name)
How do I find the numbers?
  • TVDB series id: it's in your Sonarr show folder name (Stargate SG-1 {tvdb-72449}), or on the show's page at thetvdb.com.
  • Season 00 episode number: open the show's Specials season in Sonarr or on TheTVDB. The film's row shows its episode number.
  • TMDB id: search the film on themoviedb.org; the id is the number in the page URL. Check that the year and runtime match the special, because remakes share titles.

Run without --apply after adding lines: the preview says which files it would link or adopt.


Keep it running on a schedule

show-movie-linker.service and show-movie-linker.timer run it nightly at 06:00:

cp show-movie-linker.service show-movie-linker.timer /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now show-movie-linker.timer

Logs: journalctl -u show-movie-linker.service. Run it right now with systemctl start show-movie-linker.service.


Good to know

  • Run as root. The kernel setting fs.protected_hardlinks=1 stops ordinary users from hardlinking files they don't own. Folders the tool creates get the owner and permissions of their parent folder, so the arrs can still write into them.
  • Same pool/filesystem required, and on mergerfs the create policy must not be path-preserving (mfs, not mspmfs). Otherwise a link can't be made across disks.
  • mergerfs quirks it handles: the pool reports path-hashed inode numbers, so "same file?" is checked on the underlying disks. It also bumps folder timestamps after creating entries, so the arrs' NFS view notices them.
  • Existing movie folders are reused. If Radarr's stored path doesn't exist but a ... {tmdb-N} folder does, Radarr is pointed at that folder instead of getting a second one.
  • Sidecars aren't linked. Subtitles etc. stay with each library; Bazarr handles subtitles per library.
  • Non-video files are never deleted. If Sonarr is tracking a sidecar (for example a Dolby Vision .dvrpu.bin) as the episode, the tool leaves it alone.
  • Films Radarr can't find (no TMDB entry) don't belong in the map. Leave those to Sonarr.

License

MIT: see LICENSE. Do what you like with it.

Built with help from Claude (Anthropic).