Skip to main content

VideoJoin - Join two local videos with FFmpeg (stream-copy first)

Version License CIAO Stars Python

VideoJoin is a lightweight interactive command-line tool that concatenates two video files from the current directory using FFmpeg. It prefers stream copy (no re-encode when possible) and fail-closed re-encode fallback when copy fails. Intermediate files are staged next to the output path when possible and published with shutil.move for multi-mount safety (for example USB).

Features

  • Interactive pick of first and second video (same file cannot be chosen twice)
  • Discovers .mp4, .mov, .mkv, .avi, .m4v in the current working directory (sorted case-insensitively)
  • Stream-copy join first (ffmpeg concat demuxer); re-encode fallback (libx264 CRF 18, AAC 192k)
  • Fail-closed: no success message if both paths fail
  • Unique temp list + media intermediates; cleanup on success and failure
  • Publish intermediates with shutil.move (same FS rename; cross-mount copy+delete)
  • FFmpeg on PATH checked before joining
  • Console script video-join and module entry python -m VideoJoin

Quick Installation

System requirement: FFmpeg must be installed and available as ffmpeg on your PATH. The package does not install FFmpeg via pip.

Local install (primary)

From a checkout:

git clone https://github.com/Wilgat/VideoJoin.git
cd VideoJoin
python3 -m venv venv
source venv/bin/activate   # Windows: venv\Scripts\activate
pip install -e .

This installs the console entry video-join and the package VideoJoin.

Optional dependency declared in packaging: ChronicleLogger (not required for the current interactive console paths).

PyPI

A future pip install VideoJoin channel may appear when the project is published to PyPI. Today, install from source as above. Do not assume a live PyPI release without checking the project page.

Usage

After install:

# ensure videos are in the current directory
cd /path/to/folder/with/clips
video-join

Or:

python -m VideoJoin

Session steps:

  1. Lists eligible videos in the current directory
  2. Choose first video (number)
  3. Choose second video from the remaining list
  4. Confirm or edit output name (default: {stem1} + {stem2}.mp4)
  5. FFmpeg stream-copy → on failure, re-encode → publish result

Exit codes: non-zero if fewer than two videos, FFmpeg missing, or join fails.

Examples

$ video-join
Video Joiner – WITH ORIGINAL AUDIO (using ffmpeg)

VideoJoin 1.0.3

Found video files:
   1. clip1.mp4
   2. clip2.mkv

Choose FIRST video → 1

Found video files:
   1. clip2.mkv

Choose SECOND video → 1

Output filename [clip1 + clip2.mp4]: joined.mp4

Joining with perfect audio sync:
   clip1.mp4
 + clip2.mkv
 → joined.mp4
   Staging dir → .

Running ffmpeg (stream copy – no quality loss)…
SUCCESS! Perfectly joined with original sound → joined.mp4

Import for scripts (thin entry):

from VideoJoin import main
# interactive session; expects cwd videos + TTY stdin

Platform Compatibility

Platform Status
Linux Primary; tested development path
macOS Supported when Python + FFmpeg on PATH
Windows Supported when Python + FFmpeg on PATH (venv activate differs)
Architectures Any with CPython + FFmpeg binary

Interactive prompts need a terminal (or fed stdin). Non-interactive automation flags are not implemented yet.

Related Projects

  • VideoJoin on GitHub — this repository
  • Sibling media tooling (same author ecosystem) may include other FFmpeg CLIs; this product is two-file join only, not cut/speed/boomerang editing

Contributing

  1. Keep product law under docs/requirements/ in sync when behavior changes.
  2. Prefer small, CIAO-safe changes; do not remove Protection Zones in cli.py (staging / shutil.move publish) without explicit design.
  3. Version dual SSOT: bump pyproject.toml and src/VideoJoin/__init__.__version__ together.
  4. Open issues and pull requests on GitHub.

License

MIT — see LICENSE.md. Also declared in pyproject.toml.

Last Update

2026-08-09 — README aligned with 1.0.3 (fail-closed join, unique temps, shutil.move promote, honest install/runtime docs).

Download files

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

Source Distribution

videojoin-1.0.3.tar.gz (10.4 kB view details)

Uploaded Source

Built Distribution

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

videojoin-1.0.3-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file videojoin-1.0.3.tar.gz.

File metadata

  • Download URL: videojoin-1.0.3.tar.gz
  • Upload date:
  • Size: 10.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for videojoin-1.0.3.tar.gz
Algorithm Hash digest
SHA256 93d5a2794ca3b6edcb6ac222030410f782ff98d92e92e510cebd22995f01ea7d
MD5 908d1a2faeb2b8a039a65a5b4038f873
BLAKE2b-256 5d35023805ae6c15cd31304b4d7179c2f43940d1e40051e10d0d1d0987ae1e0b

See more details on using hashes here.

File details

Details for the file videojoin-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: videojoin-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 9.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for videojoin-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7d4724632edd94995e1539f52fcb686fe345aa6f2b5feb18a82700d404f945d5
MD5 98f36cdf61f18575568feb2aa5a9fd1a
BLAKE2b-256 e6fe1fc7b098820df8fe0baadab82cc43290c65d63797b963813ba7e1347b760

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page