Dedupe TV episodes by quality. Keep best (resolution + PROPER/REPACK), delete worse + sidecar files.
Project description
dedupe-episodes
Scan a TV show library, detect duplicate episodes at different qualities,
keep the best, delete the rest (and their sidecar .nfo / -thumb.jpg /
.srt files).
Quality ranking
- Resolution: 2160p > 1080p > 720p > 480p
- Same resolution: PROPER / REPACK beats plain
- Tied (same resolution AND same proper flag): WARN + skip — manual review
Resolution always outranks proper. So a 2160p plain release beats a
1080p Proper, but a 1080p Proper beats a plain 1080p.
Install
CLI app — recommended way is to install it isolated from your system Python:
# isolated install with uv (recommended)
uv tool install dedupe-episodes
# isolated install with pipx
pipx install dedupe-episodes
# run once without installing
uvx dedupe-episodes /path/to/shows
pipx run dedupe-episodes /path/to/shows
# or plain pip (into current env)
pip install dedupe-episodes
Standalone binary (no Python required)
Each release ships pre-built binaries on GitHub Releases:
| Platform | Asset |
|---|---|
| Linux x86_64 | dedupe-episodes-linux-x86_64 |
| macOS Apple Silicon | dedupe-episodes-macos-arm64 |
| Windows x86_64 | dedupe-episodes-windows-x86_64.exe |
# Linux / macOS — download, mark executable, run
curl -LO https://github.com/asm0dey/dedupe-episodes/releases/latest/download/dedupe-episodes-linux-x86_64
chmod +x dedupe-episodes-linux-x86_64
./dedupe-episodes-linux-x86_64 /path/to/shows
Binaries are built with Nuitka (real C-compiled, single-file, ~12 MB) — bundle Python interpreter + all deps.
Usage
dedupe-episodes /path/to/shows # dry-run (default — prints plan, deletes nothing)
dedupe-episodes /path/to/shows --delete # actually delete losers + their sidecars
dedupe-episodes /path/to/shows --ext mkv --ext mp4 # restrict scanned extensions
Episodes are grouped by (parent directory, season, episode), parsed via
guessit. Sidecars are siblings whose
filename starts with the video stem followed by ., -, or _.
Develop locally
git clone https://github.com/asm0dey/dedupe-episodes
cd dedupe-episodes
uv sync
uv run dedupe-episodes /path/to/shows
Tests
uv run pytest
53 tests, all run on an in-memory fake filesystem via
pyfakefs — no real disk I/O,
no host pollution.
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 dedupe_episodes-0.1.2.tar.gz.
File metadata
- Download URL: dedupe_episodes-0.1.2.tar.gz
- Upload date:
- Size: 21.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e76a7ae576f4e5c264adf5608d60fe69953313a58b226bdad13893066c8a21ca
|
|
| MD5 |
72d77666f304943efc2b5dd5028c98b0
|
|
| BLAKE2b-256 |
17acf63aeae4fee9204442c1d44281d3fbcad13804a688b0322fb4083ae20fda
|
Provenance
The following attestation bundles were made for dedupe_episodes-0.1.2.tar.gz:
Publisher:
publish.yml on asm0dey/dedupe-episodes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dedupe_episodes-0.1.2.tar.gz -
Subject digest:
e76a7ae576f4e5c264adf5608d60fe69953313a58b226bdad13893066c8a21ca - Sigstore transparency entry: 1409439206
- Sigstore integration time:
-
Permalink:
asm0dey/dedupe-episodes@ff91f3ab83a5ac5192af6561e604ca0cc154bf66 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/asm0dey
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff91f3ab83a5ac5192af6561e604ca0cc154bf66 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dedupe_episodes-0.1.2-py3-none-any.whl.
File metadata
- Download URL: dedupe_episodes-0.1.2-py3-none-any.whl
- Upload date:
- Size: 7.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c0e915f20b2e4d50ceb1d1fdd8cd61c68a8a7756ce1dd52843161321dbfdfeb
|
|
| MD5 |
6d1331dd61d59c17f8dba6c69342d72f
|
|
| BLAKE2b-256 |
288189774fd913d4266c1d082d718e8a38c5efbc068ba0ea4d1e7cb9e3f2400f
|
Provenance
The following attestation bundles were made for dedupe_episodes-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on asm0dey/dedupe-episodes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dedupe_episodes-0.1.2-py3-none-any.whl -
Subject digest:
1c0e915f20b2e4d50ceb1d1fdd8cd61c68a8a7756ce1dd52843161321dbfdfeb - Sigstore transparency entry: 1409439217
- Sigstore integration time:
-
Permalink:
asm0dey/dedupe-episodes@ff91f3ab83a5ac5192af6561e604ca0cc154bf66 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/asm0dey
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff91f3ab83a5ac5192af6561e604ca0cc154bf66 -
Trigger Event:
push
-
Statement type: