Cleanup
The Cleanup page (Settings → Cleanup) provides five fixed automated operations that remove unnecessary subtitle files and database entries from your library, plus two opt-in rules covering embedded video tracks.
Operations
Section titled “Operations”Each operation has the same shape: a config card, a dry-run preview, and a Run Now button. None of them touch the database or filesystem until you confirm.
Language Filter
Section titled “Language Filter”What it does. Walks every video folder in your library and deletes subtitle sidecars whose language token isn’t in your keep-list.
What signals deletion. The language token in the sidecar filename
must not appear in the configured list. Filenames are parsed by the
same grammar Sublarr uses elsewhere — Episode.S01E01.de.ass is
recognised as de, Episode.S01E01.de.hi.ass is recognised as de
with the hi modifier, and the whole sidecar is dropped if de isn’t
on the keep-list.
Example. Keep-list de,en. The folder contains *.de.ass,
*.en.srt, *.ja.ass, *.fr.srt → the .ja.ass and .fr.srt
sidecars get moved to the trash directory. und (undetermined
language) sidecars are kept by default; toggle the Drop und sidecars
config flag to remove those too.
Config. Comma-separated language codes (de,en). Order doesn’t
matter; the comparison is case-insensitive. An empty keep-list aborts
the run instead of deleting everything — Sublarr refuses to nuke every
sidecar in the library on a misconfiguration.
Format Upgrade
Section titled “Format Upgrade”What it does. When the same logical subtitle exists as both .srt
and .ass, deletes the .srt copy.
What signals deletion. Two sidecars share the same (language, modifiers) token grammar but different containers. The richer
container (.ass / .ssa) wins; the plain .srt is trashed. The
file pair must live in the same folder — Sublarr won’t compare across
directories.
Example. Episode.S01E01.de.srt and Episode.S01E01.de.ass exist
side-by-side → .srt goes to trash, .ass stays. If only one of the
two exists, nothing happens.
Orphan Files
Section titled “Orphan Files”What it does. Deletes subtitle sidecars whose video file is gone.
What signals deletion. A sidecar’s parent video can’t be found.
Sublarr looks for any video file in the same folder with a matching
basename (modulo language token), e.g. Episode.S01E01.de.ass
expects Episode.S01E01.<videoExt> in the same directory. If no
candidate exists in any of the supported video extensions
(.mkv, .mp4, .avi, …) the sidecar is treated as orphaned.
Why this happens. The user moved or renamed media outside Sublarr, the *arr replaced a file with a different episode-number scheme, or a manual rsync left old subs behind.
Orphan DB Entries
Section titled “Orphan DB Entries”What it does. Removes rows from the wanted_items and
subtitle_history tables when the file they reference no longer
exists on disk.
What signals deletion. os.path.exists() returns False for the
recorded file_path. The database row is removed regardless of how
old it is — there’s no retention window.
When you’d run it. After a bulk filesystem reorganisation, after restoring a backup that’s older than the database, or as a pre-deduplication housekeeping pass.
Old Backups
Section titled “Old Backups”What it does. Deletes remux backup files (*.mkv.bak) older than
the retention window.
What signals deletion. File mtime is older than
remux_backup_retention_days (default 7). The
Subtitle Backups section below
manages a different fleet (*.bak.<ext> next to subtitles); this
operation only touches container-level remux backups created by the
remux to add subtitle stream path.
Additional Opt-In Rules
Section titled “Additional Opt-In Rules”Beyond the five fixed operations above, Sublarr ships three rules that are off by default. Signs & Forced Removal strips non-dialogue (signs / forced / songs) tracks, Foreign-Track Removal (covered in detail below) removes embedded tracks in other languages, and Duplicate language codes removes doubled sidecars. All of them move removals to the trash and stay recoverable — nothing here is a hard delete.
Duplicate Language Codes
Section titled “Duplicate Language Codes”What it does. Moves a sidecar spelled with an ISO 639-2 code
(X.deu.srt) to the sidecar trash when it holds the same subtitle as the
X.de.srt beside it, so Emby and other media servers no longer list two
German tracks.
Rules. The rule is created disabled; enable it under Settings → Cleanup. Forced and HI variants only pair with their own kind. If the content differs, both files stay. An alias file without a canonical one beside it stays.
Foreign-Track Removal
Section titled “Foreign-Track Removal”What it does. Strips embedded subtitle streams from a video container whose language isn’t in the keep-set. Audio streams are never touched — only subtitle tracks are ever removed, so a Russian/Polish/Japanese audio track stays exactly where it is even after its subtitle counterpart is stripped.
How it works. Sublarr probes the container with ffprobe, then
remuxes it with mkvmerge (falling back to ffmpeg if mkvmerge isn’t
installed) into a temporary file, verifies the result, and atomically
swaps it in. The original file is never overwritten in place — it’s
moved to the trash directory as <file>.<timestamp>.bak, fully
restorable.
Two independent triggers, one engine. Both paths below call the same stripping engine, but resolve the keep-set differently:
| Trigger | Where to configure | Keep-set |
|---|---|---|
| Automatic, shortly after a subtitle download or an embedded-subtitle extract — queued as a separate task in the automation queue, which refreshes the media server once the strip is done | Settings → Subtitle Automation → Foreign-Track Cleanup — Strip by default toggle | The item’s own target/missing languages ∪ the global always-keep list (cleanup_foreign_tracks_keep_languages, default de,en — not exposed in the UI, only via the config API). This means a download for just de still preserves English tracks. |
| Manual / scheduled, against your whole library at once | Settings → Cleanup → Foreign-Track Removal card on this page | A fixed list you set on the rule itself (Behalten tags), applied identically to every video the scan finds, regardless of what was originally downloaded for it. A series whose Foreign-Track Cleanup override is Off is left untouched. |
Config (both surfaces).
| Setting | Default | Effect |
|---|---|---|
| Keep languages | de,en | Comma-separated (or tag-picker) list of languages whose subtitle tracks survive. Expanded to every known variant of a tag, so de also matches deu/ger as reported by ffprobe. |
| Keep undetermined (und) | on (automatic hook) / configurable per rule (manual) | Whether tracks tagged und (undetermined language) are preserved. Many releases tag the original-language track as und, so keeping it avoids stripping the one subtitle a re-encode actually needs. |
Per-series override. The automatic trigger can be forced on or off for an individual series from Library → series detail → Cleanup foreign tracks (Inherit / On / Off) — useful for a show where the container carries a rare-language commentary track you want to keep regardless of the global default. The scheduled sweep honours Off as well and leaves that series’ files untouched.
Track variant policy. By default, every track of a kept language survives — a video with English Forced, English, English SDH and German subtitle tracks keeps all four once English and German are both in the keep-set. Four settings change that. They live only on Settings → Subtitle Automation → Foreign-Track Cleanup — the Cleanup rule has no controls of its own for them — and apply to the cleanup after a download and to the scheduled sweep alike:
| Setting | Values | Effect |
|---|---|---|
| Track variant mode | Keep all (default) · One main track per language | Keep all is the language-only decision. One main track per language keeps a single best track per kept language — preferring ASS over SRT/VTT over an image track, then the default flag, then whichever has more dialogue lines — and strips the rest, subject to the two toggles below. |
| Keep forced | on/off (default on) | In one main track per language, also keep one forced (or Signs & Songs) track per kept language. |
| Keep SDH | on/off (default off) | In one main track per language, also keep one hearing-impaired (SDH) track per kept language. Has no effect in Keep all. |
| Sidecar policy | Keep embedded (default) · Drop if a real sidecar covers the language | With the second option, the embedded main track for a language is removed once a genuine subtitle file for that language already sits next to the video. Forced and SDH tracks still follow their own toggles. |
A kept language never loses its last subtitle track through this policy, even under One main track per language or the sidecar-drop option — if a language has no full or SDH track to promote, every track of it is kept.
What counts as a “real” sidecar. The sidecar-drop option only removes an embedded track when the sidecar it defers to was downloaded from a provider, uploaded by hand in Sublarr, or extracted by Sublarr — and only while the file on disk is still that subtitle: same format, not rewritten since by anything but a Sublarr sync, and not a forced track. A machine translation next to the video, or a sidecar file of unknown origin, never counts as “real” — so a provisional translation can never cause a genuine embedded track to be stripped. Syncing a real sidecar (auto-sync after download, or a manual sync) keeps it real. A sidecar put back from a backup, rolled back from the history or restored from the subtitle trash counts as unknown origin until it is downloaded again.
Per-series and per-movie overrides. All four settings can be overridden individually. For a series, from Library → series detail, in the series settings panel next to the existing Foreign-Track Cleanup on/off override. For a movie, from the movie’s detail page, in the subtitle-settings card — movies have no separate on/off switch for the cleanup itself, only these four overrides; the global setting decides whether cleanup runs at all. Each override is Inherit / value; leaving it on Inherit follows the global setting above.
Per-track preview. Before anything is rewritten, you can see exactly what the cleanup would do to a file’s tracks: the Cleanup rule’s example files (in its dry-run preview) list every subtitle track with its language, format, kind and verdict, and the series detail page offers a live preview for a single episode that runs the same decision read-only against the current file on disk.
Running it over a large library. A first pass over tens of thousands of files is not something you want as one long job: it would run for hours, hold its lock the whole time, and start from the beginning if anything interrupted it. The scheduled sweep is therefore batched and resumable — it works through the library in slices, records how far it got, and picks up there on the next tick.
It is off by default. Enable it in the Automatic sweep section of the
foreign-track card under Settings → Cleanup, and the foreign_track_sweep
job takes it from there. The same section sets how often it runs — every 6
hours (default), hourly, or only at night (01:00–06:59, in your time zone) —
shows how many files are left and has a Run now button. A schedule edited
on the Scheduler page shows here as
Custom schedule, with a link back to the scheduler to change it.
| Setting | Default | Effect |
|---|---|---|
| Sweep enabled | off | Whether the scheduled sweep runs at all. The manual Run now on the rule is unaffected. |
| Budget per run | 30 min | Wall-clock limit (5–60 min), checked after each completed file — so a run can overshoot by at most the time the slowest single file takes, which for a large remux is minutes. Nothing is left half-written. |
| Rescan after | 7 days | How long the sweep idles once it has been through the whole library before starting a fresh generation. |
| Minimum file age | 10 min | Files modified more recently than this are skipped, so an import that is still being written is never probed or rewritten mid-write. |
| Keep free (GB) | 0 (off) | Stops the sweep before free disk space on the target drops below this. A remux needs room for the temporary copy; set this if the volume is tight. |
| Largest file (GB) | 0 (no limit) | Files above this size are left alone. A rewrite costs time in proportion to the file, while the tracks it removes weigh a few hundred kilobytes — one 2160p film took 49 minutes to remux and 47 more to move its 70 GB original to the trash. Something like 20 keeps episodes in scope and leaves films out. |
Going back. Every file the sweep rewrites keeps its original in the
trash (.sublarr/trash) for the backup retention — Backup Retention (days)
under Settings → Subtitles → Stream Management, 7 days by default; within that time it can be restored from the remux backups. With a
fast pace this needs room — the sweep pauses on its own when free space would
drop below Keep free.
Delete the original right after a verified rewrite is an explicit opt-in on the rule. Then the original is deleted immediately — but only after the new file has been checked against it: every video and audio stream kept, and exactly the subtitle tracks your settings keep (same language, format, title, forced and hearing-impaired flags). Anything that does not match keeps the backup. There is no way back through the trash for a file deleted this way.
The statistics page has a Track cleanup section with the files cleaned, tracks removed, space freed and the sweep’s current phase, and every run appears in the cleanup history.
The rule also takes include and exclude paths, so you can point a first run at one subfolder and see how it behaves before letting it loose on everything. Scoping makes a run cheaper, but not free: the sweep still walks the library to find what is in scope.
Changing the paths or Largest file takes effect on the next run: the sweep walks the library again for the new scope, and every file is checked against the current scope right before it is probed or rewritten, so nothing found under an older, wider scope is touched afterwards.
Progress, the current generation and what the last tick did are visible on the
rule’s card and in the foreign_track_sweep row under
Scheduler.
Using Cleanup Operations
Section titled “Using Cleanup Operations”Each operation is an expandable card with:
- Toggle — enable or disable the operation
- Configuration — operation-specific settings (e.g. language list)
- Schedule — manual / daily / weekly / after scan
- Preview — dry run showing up to 20 example files that would be affected, with reason
- Run Now — execute immediately
Dry-Run Preview
Section titled “Dry-Run Preview”Before running any operation, use Preview to see which files would be affected. The preview shows:
- File path
- File size (or track count, for Foreign-Track Removal)
- Reason for deletion (e.g.
lang:ja,replaced by Episode.S01E01.de.ass,no video in folder)
No files are deleted during preview.
Deduplication
Section titled “Deduplication”The Deduplication section below the five operations uses SHA-256 hashing to find identical subtitle files across your library. Run a scan, then choose which copy to keep for each duplicate group.
Subtitle Backups
Section titled “Subtitle Backups”Whenever Sublarr modifies a subtitle in place (HI removal, common-fixes
pipeline, credit-region trim, timing shift, common-fix presets, etc.) it
first writes a .bak.<ext> snapshot of the original next to the active
sub. The dedicated admin page at
Settings → Cleanup → Subtitle Backups is where you see and manage
that fleet of .bak files.
What the page shows
Section titled “What the page shows”For every .bak.srt / .bak.ass on disk:
- Language pill (parsed from the filename —
.de.bak.ass→DE) - Modifier badges (HI / FORCED / SDH / CC) reconstructed from the same filename token grammar the live subs use
- Parent video (with deep-link to the series / movie detail page, if Sublarr can match it)
- Age (relative timestamp — 3d ago, 2 mo ago)
- Orphan flag when no live sibling subtitle exists for that language/modifier combination
Bulk actions
Section titled “Bulk actions”| Action | Effect |
|---|---|
| Purge orphans | Deletes every .bak whose live sibling no longer exists. Useful after a foreign-track cleanup or a Library-wide re-translation pass — the backups become unreachable, so this collects them in one click. |
| Purge aged | Deletes every .bak older than the configured subtitle_bak_retention_days window (default 30 days, set per-instance in Settings → Media Management → Subtitle Trash). |
Per-row actions
Section titled “Per-row actions”| Action | Effect |
|---|---|
| Restore | Atomic three-step swap-rename: live sub → temporary file, .bak → live name, temp file → new .bak. Fully reversible — clicking Restore again brings back the previous active version. |
| Delete | Hard-deletes the .bak only. Live sub is untouched. |
Configuration
Section titled “Configuration”| Setting | Default | Description |
|---|---|---|
| Subtitle Bak Retention (days) | 30 | Maximum age for .bak files before Purge aged is allowed to delete them. 0 means keep forever. |
Cleanup History
Section titled “Cleanup History”Past cleanup runs appear in the History table at the bottom of the page, showing files processed, files deleted, and bytes freed for each run.