VideoJoin - Join two local videos with FFmpeg (stream-copy first)
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,.m4vin the current working directory (sorted case-insensitively) - Stream-copy join first (
ffmpegconcat demuxer); re-encode fallback (libx264CRF 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
PATHchecked before joining - Console script
video-joinand module entrypython -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:
- Lists eligible videos in the current directory
- Choose first video (number)
- Choose second video from the remaining list
- Confirm or edit output name (default:
{stem1} + {stem2}.mp4) - 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
- Keep product law under
docs/requirements/in sync when behavior changes. - Prefer small, CIAO-safe changes; do not remove Protection Zones in
cli.py(staging /shutil.movepublish) without explicit design. - Version dual SSOT: bump
pyproject.tomlandsrc/VideoJoin/__init__.__version__together. - 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
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93d5a2794ca3b6edcb6ac222030410f782ff98d92e92e510cebd22995f01ea7d
|
|
| MD5 |
908d1a2faeb2b8a039a65a5b4038f873
|
|
| BLAKE2b-256 |
5d35023805ae6c15cd31304b4d7179c2f43940d1e40051e10d0d1d0987ae1e0b
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d4724632edd94995e1539f52fcb686fe345aa6f2b5feb18a82700d404f945d5
|
|
| MD5 |
98f36cdf61f18575568feb2aa5a9fd1a
|
|
| BLAKE2b-256 |
e6fe1fc7b098820df8fe0baadab82cc43290c65d63797b963813ba7e1347b760
|