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.0.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.0-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: viddup-0.2.0.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.0.tar.gz
Algorithm Hash digest
SHA256 4469e1d8595fe97d2d303d13d726d394498c962771f219a99b21ecf1bfa2ec90
MD5 6e594218bf6e236f81a2d1dee8bed4c8
BLAKE2b-256 3acaade0c1c7517f140b2cbc8029cc4b6cb31f780d877e8397e394c4e70d3ffb

See more details on using hashes here.

File details

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

File metadata

  • Download URL: viddup-0.2.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2f87dda1879e2a1ba637cc111ed092402bee8791719ba59f01ae6f06aa180c03
MD5 f2d1b592b83462be6b6eb274b6d7e4c3
BLAKE2b-256 c744af9797931ba23e54634378e42f171749ce87b12840ff491e1b27952f842e

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