Skip to main content

A utility to merge downloaded TV episodes into organized series directories using TVDB metadata

Project description

merge-into-series

A Python utility to merge downloaded TV episodes into organized series directories using TVDB metadata.

Overview

merge-into-series helps you organize downloaded TV show episodes by automatically matching them with episode information from The TV Database (TVDB) and moving/copying them to appropriately structured directories for media servers like Plex.

This is particularly useful for long-running series like BBC's "Storyville" (1997-present) and "Arena" (1975-present) where episodes often don't follow standard sNNeNN naming conventions.

Features

  • Fuzzy matching: Intelligently matches filenames to episode titles, even with typos or formatting differences
  • Interactive confirmation: Review matches before processing with options to manually correct or skip files
  • Flexible operations: Choose between moving or copying files to preserve originals
  • Season organization: Automatically creates season directories (e.g., "Season 01", "Season 2024")
  • Plex metadata: Generates .nfo sidecar files so Plex displays episode titles, summaries, and air dates
  • Safe processing: Dry-run mode and confirmation prompts prevent accidental operations
  • Configuration-based: Simple text file configuration for series definitions

Installation

Recommended: Using pipx

# Install pipx if you don't have it
pip install --user pipx
pipx ensurepath

# Install merge-into-series
pipx install merge-into-series

From PyPI

pip install merge-into-series

From Source

git clone https://github.com/lorenzowood/merge-into-series.git
cd merge-into-series
pipx install .

Why pipx? It installs the tool in an isolated environment while making it globally available. This prevents conflicts with your system Python packages and is the recommended way to install CLI tools.

Configuration

Create a configuration file at ~/.merge-into-series.conf with the following format:

# Series Name, Target Path, TVDB URL
# This assumes your TV shows are organized in /Media/TV/
# Adjust the paths below to match your setup.
Storyville, /Media/TV/Storyville (1997) {tvdb-82300}, https://thetvdb.com/series/storyville/allseasons/official
Arena, /Media/TV/Arena (1975) {tvdb-80379}, https://thetvdb.com/series/arena/allseasons/official

Create Example Configuration

merge-into-series --create-config

Usage

Basic Usage

merge-into-series <series_name> <source_pattern> [source_pattern ...]

Examples

Process files in a directory:

cd "/Volumes/TV shows/Downloads"
merge-into-series storyville Storyville

Process specific files with glob pattern:

merge-into-series storyville "/path/to/downloads/Storyville*.mkv"

Process multiple files directly (shell-expands the glob):

merge-into-series upstart_crow Upstart_Crow_*

Process a mix of files and directories:

merge-into-series storyville /downloads/ep1.mkv /downloads/ep2.mkv /other/downloads/

Dry run to see what would happen:

merge-into-series --dry-run storyville Storyville

Retroactively generate missing NFO files for an existing library:

merge-into-series --update-nfo=missing storyville

Regenerate all NFO files, overwriting existing ones:

merge-into-series --update-nfo=all storyville

Command Options

  • --config, -c: Path to configuration file (default: ~/.merge-into-series.conf)
  • --dry-run, -n: Show what would be done without actually doing it
  • --threshold, -t: Fuzzy matching threshold 0-100 (default: 80)
  • --generate-nfo: Generate .nfo metadata sidecar files alongside video files (default: true). Use --generate-nfo=false to disable.
  • --update-nfo=missing|all: Scan the target directory and generate NFO files for already-merged episodes, without touching video files. missing adds NFOs only where absent; all overwrites existing ones too. Cannot be combined with SOURCE_PATTERN.
  • --overwrite, -o: Overwrite existing files without prompting
  • --create-config: Create example configuration file and exit
  • --help: Show help message

Interactive Workflow Example

$ merge-into-series storyville Storyville
Found 7 files
Storyville - Praying for Armageddon ((dashfhd)).mkv -> S2024E06 Praying For Armageddon
Storyville - The Contestant ((dashfhd)).mkv -> S2025E11 The Contestant
Storyville - The Fire Within ((dashfhd)).mkv -> S2022E19 The Fire Within
Storyville - ERROR ERROR Speaks ((dashfhd)).mkv ->
1. S2005E20 Dr. Geobbels Speaks
2. S2025E09 The Jackal Speaks
3. Manual entry
4. Skip
Choice: 2
...

Ready to process:
Storyville - Praying for Armageddon ((dashfhd)).mkv -> S2024E06 Praying For Armageddon
Storyville - The Contestant ((dashfhd)).mkv -> S2025E11 The Contestant
...

Process to target /Media/TV/Storyville (1997) {tvdb-82300} by
1. Moving
2. Copying
Choice: 1

Moving Storyville - Praying for Armageddon ((dashfhd)).mkv -> S2024E06 Praying For Armageddon
...
All operations completed successfully!

How It Works

  1. Configuration Loading: Reads series configuration from ~/.merge-into-series.conf
  2. Episode Data Fetching: Scrapes episode information from the configured TVDB URL
  3. File Discovery: Finds all video files (.mp4, .mkv, .avi, etc.) matching the source pattern
  4. Fuzzy Matching: Uses intelligent text matching to pair filenames with episode titles
  5. Interactive Review: Presents matches for user confirmation and allows manual corrections
  6. File Operations: Moves or copies files to organized season directories with proper naming
  7. NFO Generation: Writes a .nfo metadata sidecar alongside each video file for Plex

Supported File Formats

Video files with extensions: .mp4, .mkv, .avi, .mov, .mpg, .mpeg, .m4v, .wmv

File Naming Convention

Files are renamed using the format: S{YYYY}E{NN} {Episode Title}.{extension}

Examples:

  • S2024E06 Praying for Armageddon.mkv
  • S2025E11 The Contestant.mp4

Directory Structure

Target Directory/
├── Season 2022/
│   ├── S2022E01 Episode Title.mkv
│   ├── S2022E01 Episode Title.nfo
│   └── S2022E19 The Fire Within.mkv
│   └── S2022E19 The Fire Within.nfo
├── Season 2024/
│   ├── S2024E06 Praying for Armageddon.mkv
│   └── S2024E06 Praying for Armageddon.nfo
└── Season 2025/
    ├── S2025E11 The Contestant.mkv
    └── S2025E11 The Contestant.nfo

NFO Sidecar Files

Each video file is accompanied by a .nfo file containing episode metadata in a format Plex understands:

<?xml version="1.0" encoding="UTF-8"?>
<episodedetails>
  <title>Praying for Armageddon</title>
  <plot>A documentary following evangelical Christians...</plot>
  <aired>2024-03-15</aired>
  <season>2024</season>
  <episode>6</episode>
</episodedetails>

This is particularly useful for long-running series where Plex cannot identify episodes from the season number alone (e.g. year-based seasons like S1964E04). Use --generate-nfo=false to skip NFO generation.

Error Handling

  • Network Issues: Gracefully handles TVDB connection problems
  • Missing Files: Validates source files exist before processing
  • Permission Issues: Checks target directory permissions
  • Duplicate Files: Prompts before overwriting existing files
  • Malformed Configuration: Reports configuration file errors

Development

Running Tests

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=merge_into_series

Code Style

# Format code
black src/ tests/

# Sort imports
isort src/ tests/

# Lint code
flake8 src/ tests/

Requirements

  • Python 3.8+
  • Internet connection (for TVDB data fetching)
  • Dependencies: requests, beautifulsoup4, fuzzywuzzy, python-levenshtein, click

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

License

MIT License - see LICENSE file for details.

Changelog

v0.1.11

  • Accept multiple source patterns (files, directories, or globs) as arguments. Shell-expanding globs like Upstart_Crow_* now work without quoting. Duplicate files from overlapping patterns are silently deduplicated.
  • Document --update-nfo usage examples in README

v0.1.9

  • Fix --update-nfo failing to parse episode codes in filenames that start with a series name prefix (e.g. Series - S01E01 - Title.mkv)

v0.1.8

  • Add --update-nfo=missing/all to retroactively generate NFO files in an existing library

v0.1.7

  • Generate .nfo sidecar files for Plex episode metadata (title, summary, air date)
  • Normalise TVDB date format to ISO 8601 in NFO output

v0.1.0

  • Initial release
  • TVDB scraping and episode matching
  • Interactive file processing
  • Move/copy operations
  • Configuration file support
  • Comprehensive test suite

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

merge_into_series-0.1.11.tar.gz (28.1 kB view details)

Uploaded Source

Built Distribution

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

merge_into_series-0.1.11-py3-none-any.whl (19.2 kB view details)

Uploaded Python 3

File details

Details for the file merge_into_series-0.1.11.tar.gz.

File metadata

  • Download URL: merge_into_series-0.1.11.tar.gz
  • Upload date:
  • Size: 28.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for merge_into_series-0.1.11.tar.gz
Algorithm Hash digest
SHA256 e33ea7b7974ee3e316c1f94c553d6eeee3fa4f61c848446aa0a0eb7a64e88813
MD5 2b80697758c2ca807c6df265f8f792fa
BLAKE2b-256 6669c66f0e0e297d6db63996136f6c49f598d25b09cfd677cfd752fddaa00a7b

See more details on using hashes here.

File details

Details for the file merge_into_series-0.1.11-py3-none-any.whl.

File metadata

File hashes

Hashes for merge_into_series-0.1.11-py3-none-any.whl
Algorithm Hash digest
SHA256 b219eb173e1eb10f3fd739ba460ba2c29facbbf8181636a2b7cceb681cad74e8
MD5 b8ed65d99a2fea90288701fa055ef7dd
BLAKE2b-256 88f5d5a77d05f803a645b552f9fd581dbf77751b309a0a9bba348f016896774e

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