Skip to main content

A fast, local video duplicate detector

Project description

VidDup ๐ŸŽฌ

A fast, local video duplicate detector โ€” finds re-encoded, re-scaled, and compressed copies that other tools miss.

CI PyPI Python License: MIT


Demo

VidDup terminal scan demo

ๆ‰ซๆๅฎŒๆˆๅŽ่‡ชๅŠจ็”Ÿๆˆไบคไบ’ๅผ HTML ๆŠฅๅ‘Š โ†“

HTML report โ€” exact duplicates HTML report โ€” near duplicates


Why VidDup?

Most duplicate detectors only find byte-for-byte identical files. VidDup goes further:

Scenario dupeGuru Czkawka VidDup
Exact copy (same file) โœ… โœ… โœ…
Re-encoded (H.264 โ†’ HEVC) โŒ โŒ โœ…
Re-scaled (1080p โ†’ 720p) โŒ โŒ โœ…
Compressed (high โ†’ low bitrate) โŒ โŒ โœ…
Incremental cache (skip unchanged files) โŒ โŒ โœ…
Interactive HTML report with thumbnails โŒ โŒ โœ…

VidDup uses perceptual frame hashing (pHash) across multiple sampled frames per video, with a low-variance frame filter to ignore black/fade frames that cause false positives.


Quick Start

# Install VidDup (FFmpeg is bundled automatically โ€” no extra steps!)
pip install viddup

# Scan a directory
viddup scan ~/Movies

That's it. A terminal report is printed and an interactive HTML report (with video thumbnails) is automatically saved to the scanned directory and opened in your browser.

๐Ÿ’ก Zero external dependencies โ€” VidDup bundles a static FFmpeg binary via imageio-ffmpeg. No need to brew install ffmpeg or apt install ffmpeg.


Features

  • Three-layer detection
    • L1: xxHash3-128 โ€” instant exact-copy detection
    • L2: Duration metadata โ€” groups candidates, skips impossible pairs
    • L3: 10-frame pHash โ€” perceptual similarity across re-encodes and re-scales
  • Robust pHash comparison โ€” uses median Hamming distance (not average), resistant to black frames, fade-outs, and title cards
  • Smart frame selection โ€” automatically skips solid-color frames and retries with alternate timestamps
  • Ultra-short video handling โ€” graceful degradation for clips under 3 seconds
  • Incremental SQLite cache โ€” fingerprints are cached; re-scanning a library of 500 videos takes seconds after the first run
  • Multi-directory scan โ€” finds duplicates across multiple folders in one pass
  • .viddup_ignore โ€” exclude directories and files with glob patterns, like .gitignore
  • Hardware acceleration โ€” automatically uses VideoToolbox on macOS (Apple Silicon & Intel)
  • Interactive HTML report โ€” embedded thumbnails, one-click delete-script generation, copy to clipboard

Installation

Requirements

  • Python 3.11+
  • FFmpeg โ€” bundled automatically (or use your own system install)
# Recommended: one command, everything included
pip install viddup

# Or run directly without installing (via uvx)
uvx viddup scan ~/Movies

# From source (development)
git clone https://github.com/Pengfei-Kou/viddup.git
cd viddup
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

๐Ÿ”ง Already have FFmpeg installed? VidDup will automatically prefer your system ffmpeg over the bundled one. No configuration needed.


Supported Video Formats

VidDup scans files with the following extensions:

Format Extension
MPEG-4 .mp4, .m4v
Matroska .mkv
AVI .avi
QuickTime .mov
WebM .webm
Flash Video .flv
Windows Media .wmv
MPEG Transport Stream .ts
MPEG .mpeg, .mpg
3GPP .3gp

Other formats can be decoded if FFmpeg supports them โ€” contributions to extend the list are welcome!


Usage

viddup scan โ€” find duplicates

# Basic scan
viddup scan ~/Movies

# Scan multiple directories (finds cross-folder duplicates)
viddup scan ~/Movies ~/Downloads/Videos

# Stricter threshold (only report very similar videos)
viddup scan ~/Movies --threshold 0.92

# Looser duration filter (catches clips with trimmed intros)
viddup scan ~/Movies --duration-tol 0.15

# Preview what would be scanned (no DB writes)
viddup scan ~/Movies --dry-run

# Save report to a specific directory
viddup scan ~/Movies --output ~/Desktop

# Don't auto-open the browser
viddup scan ~/Movies --no-open

# Force re-fingerprint everything (ignore cache)
viddup scan ~/Movies --no-cache

Full options:

Options:
  -t, --threshold FLOAT         Similarity threshold (0โ€“1). Default: 0.85
  -f, --frames INTEGER          Frames sampled per video. Default: 10
  --duration-tol FLOAT          Duration tolerance for pre-filter. Default: 0.05 (ยฑ5%)
  --db PATH                     Fingerprint database path. Default: ~/.viddup/fingerprints.db
  -w, --workers INTEGER         Parallel worker processes. Default: CPU count
  -o, --output PATH             Report output directory. Default: first scanned directory
  --no-cache                    Ignore cache, recompute all fingerprints
  --recursive / --no-recursive  Recurse into subdirectories. Default: on
  --dry-run                     List files to be processed without writing DB
  --html / --no-html            Generate interactive HTML report. Default: on
  --open / --no-open            Auto-open HTML report in browser. Default: on
  -v, --verbose                 Show per-file progress

viddup status โ€” cache info

viddup status
# Shows: cached video count, orphan records, database size, last scan time

viddup clear โ€” clean up cache

# Remove records whose files no longer exist
viddup clear --orphans-only

# Wipe the entire cache
viddup clear --confirm

.viddup_ignore

Place a .viddup_ignore file in any scan directory to exclude files or subdirectories:

# Lines starting with # are comments

# Exclude directories (trailing slash required)
BRaw/
ๅŽŸๅง‹็ด ๆ/
proxies/

# Exclude by filename glob
temp_*
*.tmp
._*

# Exclude by relative path glob
Backups/**
archive/2020/**

VidDup reports how many files were filtered when an ignore file is active.


How It Works

Each video goes through three layers:

 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚  L1 โ€” File Hash (xxHash3-128)                    โ”‚
 โ”‚  Identical bytes โ†’ immediate match, skip L2/L3  โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                            โ”‚ not exact
 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚  L2 โ€” Metadata Pre-filter (ffprobe)              โ”‚
 โ”‚  Duration difference > 5% โ†’ skip pair            โ”‚
 โ”‚  Reduces O(nยฒ) comparisons to small groups       โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                            โ”‚ duration match
 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚  L3 โ€” Perceptual Frame Hash (pHash)              โ”‚
 โ”‚  Sample 10 frames at 5%, 15%, ..., 95%           โ”‚
 โ”‚  Skip low-variance frames (black/solid color)    โ”‚
 โ”‚  Compute pHash per frame โ†’ compare sequences     โ”‚
 โ”‚  Median Hamming distance < threshold โ†’ duplicate โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

"Suggest keep" priority (shown in HTML report):

  1. Highest resolution (width ร— height)
  2. Largest file size (less compression loss)
  3. Alphabetical path (deterministic tiebreak)

HTML Report

After scanning, VidDup generates a self-contained viddup_report_*.html file saved directly in the scanned directory. No server required โ€” open it with any browser.

The report includes:

  • Video thumbnails (extracted from the middle of each file, embedded as base64)
  • Grouped duplicate cards sorted by reclaimable space
  • "Suggest keep" badge for the recommended file in each group
  • Checkboxes to select files for deletion (non-suggested files pre-selected)
  • Generate delete script โ†’ shell commands you can review and execute in your terminal
  • Copy to clipboard button

โš ๏ธ VidDup never deletes files automatically. You always review the generated rm commands before executing them.


Performance

Fingerprinting speed is limited by ffmpeg frame extraction (I/O + decode) and scales linearly with video count. The main bottleneck is the first scan of a new library โ€” subsequent scans reuse the SQLite cache and complete in seconds regardless of library size.

Tips for faster scans:

  • macOS: VideoToolbox hardware decoding is enabled automatically โ€” no action needed.
  • Reduce --frames (e.g. --frames 6) for a 40% speedup with minimal accuracy loss on long videos.
  • Increase --workers on machines with many CPU cores.
  • Use --duration-tol conservatively โ€” a tighter window means fewer L3 comparisons.

Configuration Reference

Setting Default Notes
--threshold 0.85 Lower = more matches (more false positives). Try 0.90โ€“0.95 for stricter.
--frames 10 More frames = slower but more accurate. 6 is usually sufficient for short clips.
--duration-tol 0.05 Increase to 0.10โ€“0.15 if you expect trimmed intros/outros.
--workers CPU count Reduce if your system slows down during scanning.

Limitations

  • No semantic understanding: VidDup cannot detect if two videos are "about" the same topic but visually different (e.g., two different recordings of the same lecture).
  • Duration pre-filter: Videos differing by more than --duration-tol will not be compared at L3, even if they are perceptually similar. Increase the tolerance if needed.
  • Corrupt files: Videos that ffprobe cannot parse are skipped and reported in the terminal output.

Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

git clone https://github.com/Pengfei-Kou/viddup.git
cd viddup
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest          # run tests
ruff check .    # lint

Roadmap

  • v0.2: Demo GIF and HTML report screenshots in README
  • v0.3: BK-tree for large libraries (10,000+ videos), audio fingerprint verification, .viddup_ignore negation patterns
  • v0.4: Standalone binaries via PyInstaller + GitHub Actions (macOS, Windows, Linux)
  • v1.0: PyQt desktop GUI option, Windows full testing

License

MIT ยฉ VidDup Contributors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

viddup-0.2.1.tar.gz (3.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

viddup-0.2.1-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

Details for the file viddup-0.2.1.tar.gz.

File metadata

  • Download URL: viddup-0.2.1.tar.gz
  • Upload date:
  • Size: 3.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for viddup-0.2.1.tar.gz
Algorithm Hash digest
SHA256 124d00e0a403206f31f53765b231c41d7be05a3bc268cf38dedecdfbaec4b0cb
MD5 27cfe0a07fe5e9b362bb2f5fbf0c8456
BLAKE2b-256 ffb5bc32c9abc502ef076889a52c02d038533678dcc1164c4704344d843a6f45

See more details on using hashes here.

File details

Details for the file viddup-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: viddup-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 33.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for viddup-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c3579fdb0f0c56142d840779b41a8298ecf12da88d6efb1da648183ffdc24f06
MD5 a378416a55446f35520b29808c516855
BLAKE2b-256 f13082306ac5fc8a4af8aed1cde9f6f8345f42c5f60797607173b176211d36ec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page