VideoJoin 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- videojoin-1.0.0/PKG-INFO +193 -0
- videojoin-1.0.0/README.md +179 -0
- videojoin-1.0.0/pyproject.toml +29 -0
- videojoin-1.0.0/setup.cfg +4 -0
- videojoin-1.0.0/src/VideoJoin/__init__.py +4 -0
- videojoin-1.0.0/src/VideoJoin/__main__.py +4 -0
- videojoin-1.0.0/src/VideoJoin/cli.py +113 -0
- videojoin-1.0.0/src/VideoJoin.egg-info/PKG-INFO +193 -0
- videojoin-1.0.0/src/VideoJoin.egg-info/SOURCES.txt +11 -0
- videojoin-1.0.0/src/VideoJoin.egg-info/dependency_links.txt +1 -0
- videojoin-1.0.0/src/VideoJoin.egg-info/entry_points.txt +2 -0
- videojoin-1.0.0/src/VideoJoin.egg-info/requires.txt +1 -0
- videojoin-1.0.0/src/VideoJoin.egg-info/top_level.txt +1 -0
videojoin-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: VideoJoin
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A logging example application with sudo detection and log rotation
|
|
5
|
+
Author-email: Wilgat Wong <wilgat.wong@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Wilgat/VideoJoin
|
|
8
|
+
Project-URL: Repository, https://github.com/Wilgat/VideoJoin
|
|
9
|
+
Project-URL: Issues, https://github.com/Wilgat/VideoJoin/issues
|
|
10
|
+
Keywords: logging,sudo,chronicle,example
|
|
11
|
+
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: ChronicleLogger>=1.0.0
|
|
14
|
+
|
|
15
|
+
# VideoJoin
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
|
|
19
|
+
VideoJoin is a lightweight command-line tool for concatenating two video files (MP4, MOV, MKV, AVI, M4V) while preserving original audio and video quality using FFmpeg. It supports fast stream copying for compatible files and falls back to re-encoding for mismatches, making it ideal for quick edits without quality loss. As a Cython-optimized project, it leverages compiled extensions for efficient file scanning and subprocess handling, suitable for developers and users in media workflows .
|
|
20
|
+
|
|
21
|
+
This project follows a modular structure with source code in `src/VideoJoin/`, documentation in `docs/`, and build automation via `pyproject.toml` and `build.sh` for cross-platform compatibility (Linux, macOS, Windows with adjustments) .
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- Interactive selection of video files from the current directory.
|
|
26
|
+
- Automatic sorting and listing of eligible videos by name (case-insensitive).
|
|
27
|
+
- Lossless joining via FFmpeg concat (no re-encoding when possible).
|
|
28
|
+
- Fallback to high-quality re-encoding (libx264 CRF 18, AAC 192k) for incompatible formats.
|
|
29
|
+
- Temporary file handling with cleanup.
|
|
30
|
+
- FFmpeg dependency check on startup.
|
|
31
|
+
- Cython compilation for performance boosts in I/O operations .
|
|
32
|
+
|
|
33
|
+
## Prerequisites
|
|
34
|
+
|
|
35
|
+
- Python 3.6+ (recommend 3.12 for Cython compatibility; use pyenv for isolation: `curl https://pyenv.run | bash`, then `pyenv install 3.12.0` and `pyenv shell 3.12.0`) .
|
|
36
|
+
- FFmpeg installed and in your PATH (download from https://ffmpeg.org/download.html).
|
|
37
|
+
- C compiler (e.g., gcc on Linux/macOS, Visual Studio on Windows) for Cython builds.
|
|
38
|
+
- Git for version control (recommended to initialize a repository and use `.gitignore` to exclude `__pycache__/`, `build/`, `*.so`, `.env`) .
|
|
39
|
+
|
|
40
|
+
No additional pip packages are required beyond the standard library, but for development, consider `cython` via `pip install cython` in an isolated environment .
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### From Source (Recommended for Development)
|
|
45
|
+
|
|
46
|
+
1. Clone or download the repository:
|
|
47
|
+
```
|
|
48
|
+
git clone <repo-url>
|
|
49
|
+
cd VideoJoin
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. Initialize Git if starting fresh (optional but recommended):
|
|
53
|
+
```
|
|
54
|
+
git init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
3. Set up `.gitignore` to exclude build artifacts and caches:
|
|
58
|
+
```
|
|
59
|
+
# .gitignore content
|
|
60
|
+
.env
|
|
61
|
+
__pycache__/
|
|
62
|
+
*.pyc
|
|
63
|
+
*.pyo
|
|
64
|
+
*.so
|
|
65
|
+
build/
|
|
66
|
+
```
|
|
67
|
+
.
|
|
68
|
+
|
|
69
|
+
4. Build and install in editable mode (handles Cython compilation):
|
|
70
|
+
```
|
|
71
|
+
# Ensure pyenv or virtualenv for isolation
|
|
72
|
+
python3 -m venv venv
|
|
73
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
74
|
+
|
|
75
|
+
# Install Cython if needed
|
|
76
|
+
pip install cython
|
|
77
|
+
|
|
78
|
+
# Build extensions
|
|
79
|
+
chmod +x build.sh
|
|
80
|
+
./build.sh # Or python setup.py build_ext --inplace if using setup.py
|
|
81
|
+
|
|
82
|
+
# Editable install
|
|
83
|
+
pip install -e .
|
|
84
|
+
```
|
|
85
|
+
This compiles Cython files (e.g., `cli.pyx` if converted) into `.so` binaries in `build/lib/` and makes the package available as `VideoJoin` .
|
|
86
|
+
|
|
87
|
+
### Via pip (Packaged Release)
|
|
88
|
+
|
|
89
|
+
Once published to PyPI (future), install directly:
|
|
90
|
+
```
|
|
91
|
+
pip3 install VideoJoin
|
|
92
|
+
```
|
|
93
|
+
This pulls from PyPI, installs dependencies (none beyond stdlib), and sets up the entry point for `videojoin` command or `python -m VideoJoin` .
|
|
94
|
+
|
|
95
|
+
For requirements management, create `requirements.txt` with any dev tools:
|
|
96
|
+
```
|
|
97
|
+
cython
|
|
98
|
+
pytest # For tests
|
|
99
|
+
```
|
|
100
|
+
Then `pip3 install -r requirements.txt` .
|
|
101
|
+
|
|
102
|
+
## Usage
|
|
103
|
+
|
|
104
|
+
### Command-Line Execution
|
|
105
|
+
|
|
106
|
+
Run the tool directly from the source directory:
|
|
107
|
+
```
|
|
108
|
+
python -m src.VideoJoin
|
|
109
|
+
```
|
|
110
|
+
Or after installation:
|
|
111
|
+
```
|
|
112
|
+
python -m VideoJoin
|
|
113
|
+
```
|
|
114
|
+
(If entry point is configured in `pyproject.toml`, use `videojoin` as a script.)
|
|
115
|
+
|
|
116
|
+
The tool will:
|
|
117
|
+
1. Scan the current folder for video files.
|
|
118
|
+
2. Prompt for selection of first and second video (prevents duplicates).
|
|
119
|
+
3. Ask for output filename (defaults to `{file1} + {file2}.mp4`).
|
|
120
|
+
4. Execute FFmpeg and report success/failure.
|
|
121
|
+
|
|
122
|
+
Example session:
|
|
123
|
+
```
|
|
124
|
+
Video Joiner – WITH ORIGINAL AUDIO (using ffmpeg)
|
|
125
|
+
|
|
126
|
+
Found video files:
|
|
127
|
+
1. clip1.mp4
|
|
128
|
+
2. clip2.mkv
|
|
129
|
+
|
|
130
|
+
Choose FIRST video → 1
|
|
131
|
+
|
|
132
|
+
Found video files:
|
|
133
|
+
1. clip2.mkv
|
|
134
|
+
|
|
135
|
+
Choose SECOND video → 1
|
|
136
|
+
|
|
137
|
+
Output filename [clip1 + clip2.mp4]: joined.mp4
|
|
138
|
+
|
|
139
|
+
Joining with perfect audio sync:
|
|
140
|
+
clip1.mp4
|
|
141
|
+
+ clip2.mkv
|
|
142
|
+
→ joined.mp4
|
|
143
|
+
|
|
144
|
+
Running ffmpeg (stream copy – no quality loss)…
|
|
145
|
+
SUCCESS! Perfectly joined with original sound → joined.mp4
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
For batch or advanced use, extend via importing `from VideoJoin.cli import main` in scripts .
|
|
149
|
+
|
|
150
|
+
### Building for Distribution
|
|
151
|
+
|
|
152
|
+
- Use `python -m build` to create wheels/sdists (configured in `pyproject.toml`).
|
|
153
|
+
- Cython outputs like `VideoJoin.cpython-312-x86_64-linux-gnu.so` go to `build/lib/` (gitignore them for clean repos) .
|
|
154
|
+
|
|
155
|
+
## Project Structure
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
VideoJoin/
|
|
159
|
+
├── build.sh # POSIX build script for Cython
|
|
160
|
+
├── docs/ # Documentation
|
|
161
|
+
│ ├── CHANGELOG.md
|
|
162
|
+
│ ├── folder-structure.md
|
|
163
|
+
│ └── VideoClip-spec.md
|
|
164
|
+
├── pyproject.toml # Build config (setuptools/Cython)
|
|
165
|
+
├── README.md # This file
|
|
166
|
+
└── src/
|
|
167
|
+
└── VideoJoin/
|
|
168
|
+
├── cli.py # Core logic (Cython-compatible)
|
|
169
|
+
├── __init__.py # Package init and version
|
|
170
|
+
└── __main__.py # Entry point
|
|
171
|
+
```
|
|
172
|
+
Add `tests/` for unit tests (e.g., `test_cli.py`) and `requirements-dev.txt` for tools like pytest .
|
|
173
|
+
|
|
174
|
+
## Development
|
|
175
|
+
|
|
176
|
+
- **Folder Creation**: Use `mkdir -p src/VideoJoin docs tests` for extensions .
|
|
177
|
+
- **Logging/History**: The CLI uses print statements; extend with `inspect` for traceable calls if needed .
|
|
178
|
+
- **Testing**: Run `pytest tests/` after setup.
|
|
179
|
+
- **Versioning**: Update `__version__` in `__init__.py` and `CHANGELOG.md` per semantic rules .
|
|
180
|
+
- **License**: Add `LICENSE` (e.g., MIT) for open-source use .
|
|
181
|
+
|
|
182
|
+
## Troubleshooting
|
|
183
|
+
|
|
184
|
+
- **FFmpeg Not Found**: Install via package manager (e.g., `apt install ffmpeg` on Ubuntu) or download binaries.
|
|
185
|
+
- **Cython Build Errors**: Verify Python version with `which python3` and ensure C compiler; use `language_level=3` in directives .
|
|
186
|
+
- **Permission Issues**: On Unix, `chmod +x` scripts; use virtualenv to avoid global installs.
|
|
187
|
+
- **Cross-Platform**: Test paths with `pathlib`; avoid OS-specific assumptions .
|
|
188
|
+
|
|
189
|
+
For issues, check `CHANGELOG.md` or open a Git issue. Contributions welcome via pull requests after Git setup .
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT License (add `LICENSE` file with standard text) .
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# VideoJoin
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
VideoJoin is a lightweight command-line tool for concatenating two video files (MP4, MOV, MKV, AVI, M4V) while preserving original audio and video quality using FFmpeg. It supports fast stream copying for compatible files and falls back to re-encoding for mismatches, making it ideal for quick edits without quality loss. As a Cython-optimized project, it leverages compiled extensions for efficient file scanning and subprocess handling, suitable for developers and users in media workflows .
|
|
6
|
+
|
|
7
|
+
This project follows a modular structure with source code in `src/VideoJoin/`, documentation in `docs/`, and build automation via `pyproject.toml` and `build.sh` for cross-platform compatibility (Linux, macOS, Windows with adjustments) .
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Interactive selection of video files from the current directory.
|
|
12
|
+
- Automatic sorting and listing of eligible videos by name (case-insensitive).
|
|
13
|
+
- Lossless joining via FFmpeg concat (no re-encoding when possible).
|
|
14
|
+
- Fallback to high-quality re-encoding (libx264 CRF 18, AAC 192k) for incompatible formats.
|
|
15
|
+
- Temporary file handling with cleanup.
|
|
16
|
+
- FFmpeg dependency check on startup.
|
|
17
|
+
- Cython compilation for performance boosts in I/O operations .
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- Python 3.6+ (recommend 3.12 for Cython compatibility; use pyenv for isolation: `curl https://pyenv.run | bash`, then `pyenv install 3.12.0` and `pyenv shell 3.12.0`) .
|
|
22
|
+
- FFmpeg installed and in your PATH (download from https://ffmpeg.org/download.html).
|
|
23
|
+
- C compiler (e.g., gcc on Linux/macOS, Visual Studio on Windows) for Cython builds.
|
|
24
|
+
- Git for version control (recommended to initialize a repository and use `.gitignore` to exclude `__pycache__/`, `build/`, `*.so`, `.env`) .
|
|
25
|
+
|
|
26
|
+
No additional pip packages are required beyond the standard library, but for development, consider `cython` via `pip install cython` in an isolated environment .
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
### From Source (Recommended for Development)
|
|
31
|
+
|
|
32
|
+
1. Clone or download the repository:
|
|
33
|
+
```
|
|
34
|
+
git clone <repo-url>
|
|
35
|
+
cd VideoJoin
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. Initialize Git if starting fresh (optional but recommended):
|
|
39
|
+
```
|
|
40
|
+
git init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
3. Set up `.gitignore` to exclude build artifacts and caches:
|
|
44
|
+
```
|
|
45
|
+
# .gitignore content
|
|
46
|
+
.env
|
|
47
|
+
__pycache__/
|
|
48
|
+
*.pyc
|
|
49
|
+
*.pyo
|
|
50
|
+
*.so
|
|
51
|
+
build/
|
|
52
|
+
```
|
|
53
|
+
.
|
|
54
|
+
|
|
55
|
+
4. Build and install in editable mode (handles Cython compilation):
|
|
56
|
+
```
|
|
57
|
+
# Ensure pyenv or virtualenv for isolation
|
|
58
|
+
python3 -m venv venv
|
|
59
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
60
|
+
|
|
61
|
+
# Install Cython if needed
|
|
62
|
+
pip install cython
|
|
63
|
+
|
|
64
|
+
# Build extensions
|
|
65
|
+
chmod +x build.sh
|
|
66
|
+
./build.sh # Or python setup.py build_ext --inplace if using setup.py
|
|
67
|
+
|
|
68
|
+
# Editable install
|
|
69
|
+
pip install -e .
|
|
70
|
+
```
|
|
71
|
+
This compiles Cython files (e.g., `cli.pyx` if converted) into `.so` binaries in `build/lib/` and makes the package available as `VideoJoin` .
|
|
72
|
+
|
|
73
|
+
### Via pip (Packaged Release)
|
|
74
|
+
|
|
75
|
+
Once published to PyPI (future), install directly:
|
|
76
|
+
```
|
|
77
|
+
pip3 install VideoJoin
|
|
78
|
+
```
|
|
79
|
+
This pulls from PyPI, installs dependencies (none beyond stdlib), and sets up the entry point for `videojoin` command or `python -m VideoJoin` .
|
|
80
|
+
|
|
81
|
+
For requirements management, create `requirements.txt` with any dev tools:
|
|
82
|
+
```
|
|
83
|
+
cython
|
|
84
|
+
pytest # For tests
|
|
85
|
+
```
|
|
86
|
+
Then `pip3 install -r requirements.txt` .
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
### Command-Line Execution
|
|
91
|
+
|
|
92
|
+
Run the tool directly from the source directory:
|
|
93
|
+
```
|
|
94
|
+
python -m src.VideoJoin
|
|
95
|
+
```
|
|
96
|
+
Or after installation:
|
|
97
|
+
```
|
|
98
|
+
python -m VideoJoin
|
|
99
|
+
```
|
|
100
|
+
(If entry point is configured in `pyproject.toml`, use `videojoin` as a script.)
|
|
101
|
+
|
|
102
|
+
The tool will:
|
|
103
|
+
1. Scan the current folder for video files.
|
|
104
|
+
2. Prompt for selection of first and second video (prevents duplicates).
|
|
105
|
+
3. Ask for output filename (defaults to `{file1} + {file2}.mp4`).
|
|
106
|
+
4. Execute FFmpeg and report success/failure.
|
|
107
|
+
|
|
108
|
+
Example session:
|
|
109
|
+
```
|
|
110
|
+
Video Joiner – WITH ORIGINAL AUDIO (using ffmpeg)
|
|
111
|
+
|
|
112
|
+
Found video files:
|
|
113
|
+
1. clip1.mp4
|
|
114
|
+
2. clip2.mkv
|
|
115
|
+
|
|
116
|
+
Choose FIRST video → 1
|
|
117
|
+
|
|
118
|
+
Found video files:
|
|
119
|
+
1. clip2.mkv
|
|
120
|
+
|
|
121
|
+
Choose SECOND video → 1
|
|
122
|
+
|
|
123
|
+
Output filename [clip1 + clip2.mp4]: joined.mp4
|
|
124
|
+
|
|
125
|
+
Joining with perfect audio sync:
|
|
126
|
+
clip1.mp4
|
|
127
|
+
+ clip2.mkv
|
|
128
|
+
→ joined.mp4
|
|
129
|
+
|
|
130
|
+
Running ffmpeg (stream copy – no quality loss)…
|
|
131
|
+
SUCCESS! Perfectly joined with original sound → joined.mp4
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For batch or advanced use, extend via importing `from VideoJoin.cli import main` in scripts .
|
|
135
|
+
|
|
136
|
+
### Building for Distribution
|
|
137
|
+
|
|
138
|
+
- Use `python -m build` to create wheels/sdists (configured in `pyproject.toml`).
|
|
139
|
+
- Cython outputs like `VideoJoin.cpython-312-x86_64-linux-gnu.so` go to `build/lib/` (gitignore them for clean repos) .
|
|
140
|
+
|
|
141
|
+
## Project Structure
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
VideoJoin/
|
|
145
|
+
├── build.sh # POSIX build script for Cython
|
|
146
|
+
├── docs/ # Documentation
|
|
147
|
+
│ ├── CHANGELOG.md
|
|
148
|
+
│ ├── folder-structure.md
|
|
149
|
+
│ └── VideoClip-spec.md
|
|
150
|
+
├── pyproject.toml # Build config (setuptools/Cython)
|
|
151
|
+
├── README.md # This file
|
|
152
|
+
└── src/
|
|
153
|
+
└── VideoJoin/
|
|
154
|
+
├── cli.py # Core logic (Cython-compatible)
|
|
155
|
+
├── __init__.py # Package init and version
|
|
156
|
+
└── __main__.py # Entry point
|
|
157
|
+
```
|
|
158
|
+
Add `tests/` for unit tests (e.g., `test_cli.py`) and `requirements-dev.txt` for tools like pytest .
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
- **Folder Creation**: Use `mkdir -p src/VideoJoin docs tests` for extensions .
|
|
163
|
+
- **Logging/History**: The CLI uses print statements; extend with `inspect` for traceable calls if needed .
|
|
164
|
+
- **Testing**: Run `pytest tests/` after setup.
|
|
165
|
+
- **Versioning**: Update `__version__` in `__init__.py` and `CHANGELOG.md` per semantic rules .
|
|
166
|
+
- **License**: Add `LICENSE` (e.g., MIT) for open-source use .
|
|
167
|
+
|
|
168
|
+
## Troubleshooting
|
|
169
|
+
|
|
170
|
+
- **FFmpeg Not Found**: Install via package manager (e.g., `apt install ffmpeg` on Ubuntu) or download binaries.
|
|
171
|
+
- **Cython Build Errors**: Verify Python version with `which python3` and ensure C compiler; use `language_level=3` in directives .
|
|
172
|
+
- **Permission Issues**: On Unix, `chmod +x` scripts; use virtualenv to avoid global installs.
|
|
173
|
+
- **Cross-Platform**: Test paths with `pathlib`; avoid OS-specific assumptions .
|
|
174
|
+
|
|
175
|
+
For issues, check `CHANGELOG.md` or open a Git issue. Contributions welcome via pull requests after Git setup .
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT License (add `LICENSE` file with standard text) .
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "VideoJoin"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "A logging example application with sudo detection and log rotation"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Wilgat Wong", email = "wilgat.wong@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["logging", "sudo", "chronicle", "example"]
|
|
16
|
+
|
|
17
|
+
dependencies = [
|
|
18
|
+
"ChronicleLogger>=1.0.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
# Official project links (this is what shows on PyPI!)
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/Wilgat/VideoJoin"
|
|
24
|
+
Repository = "https://github.com/Wilgat/VideoJoin"
|
|
25
|
+
Issues = "https://github.com/Wilgat/VideoJoin/issues"
|
|
26
|
+
|
|
27
|
+
# This makes `video-join` command available after pip install
|
|
28
|
+
[project.scripts]
|
|
29
|
+
video-join = "VideoJoin.cli:main"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from __future__ import print_function, unicode_literals
|
|
3
|
+
# VideoJoin_with_Audio_FIXED.py – Actually keeps the sound! (2025 version)
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import subprocess
|
|
9
|
+
|
|
10
|
+
def get_mp4_files():
|
|
11
|
+
return sorted([f for f in Path('.').iterdir()
|
|
12
|
+
if f.is_file() and f.suffix.lower() in {'.mp4', '.mov', '.mkv', '.avi', '.m4v'}],
|
|
13
|
+
key=lambda x: x.name.lower())
|
|
14
|
+
|
|
15
|
+
def show_list(files):
|
|
16
|
+
print("\nFound video files:")
|
|
17
|
+
for i, f in enumerate(files, 1):
|
|
18
|
+
print(f" {i:2d}. {f.name}")
|
|
19
|
+
print()
|
|
20
|
+
|
|
21
|
+
def choose(files, prompt):
|
|
22
|
+
while True:
|
|
23
|
+
try:
|
|
24
|
+
idx = int(input(prompt)) - 1
|
|
25
|
+
if 0 <= idx < len(files):
|
|
26
|
+
return files[idx]
|
|
27
|
+
print(f" → Enter 1–{len(files)}")
|
|
28
|
+
except ValueError:
|
|
29
|
+
print(" → Please type a number")
|
|
30
|
+
|
|
31
|
+
def create_file_list(file1, file2, list_path="filelist.txt"):
|
|
32
|
+
with open(list_path, "w", encoding="utf-8") as f:
|
|
33
|
+
f.write(f"file '{file1}'\n")
|
|
34
|
+
f.write(f"file '{file2}'\n")
|
|
35
|
+
|
|
36
|
+
def main():
|
|
37
|
+
print("Video Joiner – WITH ORIGINAL AUDIO (using ffmpeg)\n")
|
|
38
|
+
|
|
39
|
+
files = get_mp4_files()
|
|
40
|
+
if len(files) < 2:
|
|
41
|
+
print("Need at least 2 video files in this folder!")
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
|
|
44
|
+
show_list(files)
|
|
45
|
+
vid1 = choose(files, "Choose FIRST video → ")
|
|
46
|
+
|
|
47
|
+
# Remove the chosen one so user doesn't pick the same twice by mistake
|
|
48
|
+
remaining = [f for f in files if f != vid1]
|
|
49
|
+
show_list(remaining)
|
|
50
|
+
vid2 = choose(remaining, "Choose SECOND video → ")
|
|
51
|
+
|
|
52
|
+
default_name = f"{vid1.stem} + {vid2.stem}.mp4"
|
|
53
|
+
out_name = input(f"\nOutput filename [{default_name}]: ").strip()
|
|
54
|
+
if not out_name:
|
|
55
|
+
out_name = default_name
|
|
56
|
+
if not out_name.lower().endswith(('.mp4', '.mkv', '.mov')):
|
|
57
|
+
out_name += '.mp4'
|
|
58
|
+
|
|
59
|
+
print(f"\nJoining with perfect audio sync:")
|
|
60
|
+
print(f" {vid1.name}")
|
|
61
|
+
print(f" + {vid2.name}")
|
|
62
|
+
print(f" → {out_name}\n")
|
|
63
|
+
|
|
64
|
+
# Method 1: Super fast & perfect (99.9% of cases)
|
|
65
|
+
cmd = [
|
|
66
|
+
'ffmpeg', '-y',
|
|
67
|
+
'-f', 'concat',
|
|
68
|
+
'-safe', '0',
|
|
69
|
+
'-i', 'filelist.txt',
|
|
70
|
+
'-c', 'copy', # ← no re-encoding = pixel-perfect + original audio
|
|
71
|
+
'-map', '0:v', '-map', '0:a?', # take video + audio if exists
|
|
72
|
+
out_name
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
create_file_list(vid1, vid2)
|
|
76
|
+
|
|
77
|
+
print("Running ffmpeg (stream copy – no quality loss)…")
|
|
78
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
79
|
+
|
|
80
|
+
if result.returncode == 0:
|
|
81
|
+
print(f"\nSUCCESS! Perfectly joined with original sound → {out_name}")
|
|
82
|
+
print(" Play it with any player – audio is there,")
|
|
83
|
+
else:
|
|
84
|
+
print("Fast method failed (different resolutions/codec?). Trying safe re-encode...")
|
|
85
|
+
# Method 2: Safe but slightly slower (re-encodes video only when needed)
|
|
86
|
+
cmd2 = [
|
|
87
|
+
'ffmpeg', '-y',
|
|
88
|
+
'-i', str(vid1),
|
|
89
|
+
'-i', str(vid2),
|
|
90
|
+
'-filter_complex', '[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]',
|
|
91
|
+
'-c:v', 'libx264', '-preset', 'fast', '-crf', '18',
|
|
92
|
+
'-c:a', 'aac', '-b:a', '192k',
|
|
93
|
+
'-map', '[v]', '-map', '[a]',
|
|
94
|
+
out_name
|
|
95
|
+
]
|
|
96
|
+
subprocess.run(cmd2)
|
|
97
|
+
print(f"\nDone (with very minor re-encode) → {out_name}")
|
|
98
|
+
|
|
99
|
+
# Clean up
|
|
100
|
+
if os.path.exists("filelist.txt"):
|
|
101
|
+
os.remove("filelist.txt")
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
# Simple check if ffmpeg is available
|
|
105
|
+
try:
|
|
106
|
+
subprocess.run(['ffmpeg', '-version'], capture_output=True, check=True)
|
|
107
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
108
|
+
print("ERROR: ffmpeg not found!")
|
|
109
|
+
print(" Please install ffmpeg and make sure it's in your PATH")
|
|
110
|
+
print(" → https://ffmpeg.org/download.html")
|
|
111
|
+
sys.exit(1)
|
|
112
|
+
|
|
113
|
+
main()
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: VideoJoin
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A logging example application with sudo detection and log rotation
|
|
5
|
+
Author-email: Wilgat Wong <wilgat.wong@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Wilgat/VideoJoin
|
|
8
|
+
Project-URL: Repository, https://github.com/Wilgat/VideoJoin
|
|
9
|
+
Project-URL: Issues, https://github.com/Wilgat/VideoJoin/issues
|
|
10
|
+
Keywords: logging,sudo,chronicle,example
|
|
11
|
+
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: ChronicleLogger>=1.0.0
|
|
14
|
+
|
|
15
|
+
# VideoJoin
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
|
|
19
|
+
VideoJoin is a lightweight command-line tool for concatenating two video files (MP4, MOV, MKV, AVI, M4V) while preserving original audio and video quality using FFmpeg. It supports fast stream copying for compatible files and falls back to re-encoding for mismatches, making it ideal for quick edits without quality loss. As a Cython-optimized project, it leverages compiled extensions for efficient file scanning and subprocess handling, suitable for developers and users in media workflows .
|
|
20
|
+
|
|
21
|
+
This project follows a modular structure with source code in `src/VideoJoin/`, documentation in `docs/`, and build automation via `pyproject.toml` and `build.sh` for cross-platform compatibility (Linux, macOS, Windows with adjustments) .
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- Interactive selection of video files from the current directory.
|
|
26
|
+
- Automatic sorting and listing of eligible videos by name (case-insensitive).
|
|
27
|
+
- Lossless joining via FFmpeg concat (no re-encoding when possible).
|
|
28
|
+
- Fallback to high-quality re-encoding (libx264 CRF 18, AAC 192k) for incompatible formats.
|
|
29
|
+
- Temporary file handling with cleanup.
|
|
30
|
+
- FFmpeg dependency check on startup.
|
|
31
|
+
- Cython compilation for performance boosts in I/O operations .
|
|
32
|
+
|
|
33
|
+
## Prerequisites
|
|
34
|
+
|
|
35
|
+
- Python 3.6+ (recommend 3.12 for Cython compatibility; use pyenv for isolation: `curl https://pyenv.run | bash`, then `pyenv install 3.12.0` and `pyenv shell 3.12.0`) .
|
|
36
|
+
- FFmpeg installed and in your PATH (download from https://ffmpeg.org/download.html).
|
|
37
|
+
- C compiler (e.g., gcc on Linux/macOS, Visual Studio on Windows) for Cython builds.
|
|
38
|
+
- Git for version control (recommended to initialize a repository and use `.gitignore` to exclude `__pycache__/`, `build/`, `*.so`, `.env`) .
|
|
39
|
+
|
|
40
|
+
No additional pip packages are required beyond the standard library, but for development, consider `cython` via `pip install cython` in an isolated environment .
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### From Source (Recommended for Development)
|
|
45
|
+
|
|
46
|
+
1. Clone or download the repository:
|
|
47
|
+
```
|
|
48
|
+
git clone <repo-url>
|
|
49
|
+
cd VideoJoin
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. Initialize Git if starting fresh (optional but recommended):
|
|
53
|
+
```
|
|
54
|
+
git init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
3. Set up `.gitignore` to exclude build artifacts and caches:
|
|
58
|
+
```
|
|
59
|
+
# .gitignore content
|
|
60
|
+
.env
|
|
61
|
+
__pycache__/
|
|
62
|
+
*.pyc
|
|
63
|
+
*.pyo
|
|
64
|
+
*.so
|
|
65
|
+
build/
|
|
66
|
+
```
|
|
67
|
+
.
|
|
68
|
+
|
|
69
|
+
4. Build and install in editable mode (handles Cython compilation):
|
|
70
|
+
```
|
|
71
|
+
# Ensure pyenv or virtualenv for isolation
|
|
72
|
+
python3 -m venv venv
|
|
73
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
74
|
+
|
|
75
|
+
# Install Cython if needed
|
|
76
|
+
pip install cython
|
|
77
|
+
|
|
78
|
+
# Build extensions
|
|
79
|
+
chmod +x build.sh
|
|
80
|
+
./build.sh # Or python setup.py build_ext --inplace if using setup.py
|
|
81
|
+
|
|
82
|
+
# Editable install
|
|
83
|
+
pip install -e .
|
|
84
|
+
```
|
|
85
|
+
This compiles Cython files (e.g., `cli.pyx` if converted) into `.so` binaries in `build/lib/` and makes the package available as `VideoJoin` .
|
|
86
|
+
|
|
87
|
+
### Via pip (Packaged Release)
|
|
88
|
+
|
|
89
|
+
Once published to PyPI (future), install directly:
|
|
90
|
+
```
|
|
91
|
+
pip3 install VideoJoin
|
|
92
|
+
```
|
|
93
|
+
This pulls from PyPI, installs dependencies (none beyond stdlib), and sets up the entry point for `videojoin` command or `python -m VideoJoin` .
|
|
94
|
+
|
|
95
|
+
For requirements management, create `requirements.txt` with any dev tools:
|
|
96
|
+
```
|
|
97
|
+
cython
|
|
98
|
+
pytest # For tests
|
|
99
|
+
```
|
|
100
|
+
Then `pip3 install -r requirements.txt` .
|
|
101
|
+
|
|
102
|
+
## Usage
|
|
103
|
+
|
|
104
|
+
### Command-Line Execution
|
|
105
|
+
|
|
106
|
+
Run the tool directly from the source directory:
|
|
107
|
+
```
|
|
108
|
+
python -m src.VideoJoin
|
|
109
|
+
```
|
|
110
|
+
Or after installation:
|
|
111
|
+
```
|
|
112
|
+
python -m VideoJoin
|
|
113
|
+
```
|
|
114
|
+
(If entry point is configured in `pyproject.toml`, use `videojoin` as a script.)
|
|
115
|
+
|
|
116
|
+
The tool will:
|
|
117
|
+
1. Scan the current folder for video files.
|
|
118
|
+
2. Prompt for selection of first and second video (prevents duplicates).
|
|
119
|
+
3. Ask for output filename (defaults to `{file1} + {file2}.mp4`).
|
|
120
|
+
4. Execute FFmpeg and report success/failure.
|
|
121
|
+
|
|
122
|
+
Example session:
|
|
123
|
+
```
|
|
124
|
+
Video Joiner – WITH ORIGINAL AUDIO (using ffmpeg)
|
|
125
|
+
|
|
126
|
+
Found video files:
|
|
127
|
+
1. clip1.mp4
|
|
128
|
+
2. clip2.mkv
|
|
129
|
+
|
|
130
|
+
Choose FIRST video → 1
|
|
131
|
+
|
|
132
|
+
Found video files:
|
|
133
|
+
1. clip2.mkv
|
|
134
|
+
|
|
135
|
+
Choose SECOND video → 1
|
|
136
|
+
|
|
137
|
+
Output filename [clip1 + clip2.mp4]: joined.mp4
|
|
138
|
+
|
|
139
|
+
Joining with perfect audio sync:
|
|
140
|
+
clip1.mp4
|
|
141
|
+
+ clip2.mkv
|
|
142
|
+
→ joined.mp4
|
|
143
|
+
|
|
144
|
+
Running ffmpeg (stream copy – no quality loss)…
|
|
145
|
+
SUCCESS! Perfectly joined with original sound → joined.mp4
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
For batch or advanced use, extend via importing `from VideoJoin.cli import main` in scripts .
|
|
149
|
+
|
|
150
|
+
### Building for Distribution
|
|
151
|
+
|
|
152
|
+
- Use `python -m build` to create wheels/sdists (configured in `pyproject.toml`).
|
|
153
|
+
- Cython outputs like `VideoJoin.cpython-312-x86_64-linux-gnu.so` go to `build/lib/` (gitignore them for clean repos) .
|
|
154
|
+
|
|
155
|
+
## Project Structure
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
VideoJoin/
|
|
159
|
+
├── build.sh # POSIX build script for Cython
|
|
160
|
+
├── docs/ # Documentation
|
|
161
|
+
│ ├── CHANGELOG.md
|
|
162
|
+
│ ├── folder-structure.md
|
|
163
|
+
│ └── VideoClip-spec.md
|
|
164
|
+
├── pyproject.toml # Build config (setuptools/Cython)
|
|
165
|
+
├── README.md # This file
|
|
166
|
+
└── src/
|
|
167
|
+
└── VideoJoin/
|
|
168
|
+
├── cli.py # Core logic (Cython-compatible)
|
|
169
|
+
├── __init__.py # Package init and version
|
|
170
|
+
└── __main__.py # Entry point
|
|
171
|
+
```
|
|
172
|
+
Add `tests/` for unit tests (e.g., `test_cli.py`) and `requirements-dev.txt` for tools like pytest .
|
|
173
|
+
|
|
174
|
+
## Development
|
|
175
|
+
|
|
176
|
+
- **Folder Creation**: Use `mkdir -p src/VideoJoin docs tests` for extensions .
|
|
177
|
+
- **Logging/History**: The CLI uses print statements; extend with `inspect` for traceable calls if needed .
|
|
178
|
+
- **Testing**: Run `pytest tests/` after setup.
|
|
179
|
+
- **Versioning**: Update `__version__` in `__init__.py` and `CHANGELOG.md` per semantic rules .
|
|
180
|
+
- **License**: Add `LICENSE` (e.g., MIT) for open-source use .
|
|
181
|
+
|
|
182
|
+
## Troubleshooting
|
|
183
|
+
|
|
184
|
+
- **FFmpeg Not Found**: Install via package manager (e.g., `apt install ffmpeg` on Ubuntu) or download binaries.
|
|
185
|
+
- **Cython Build Errors**: Verify Python version with `which python3` and ensure C compiler; use `language_level=3` in directives .
|
|
186
|
+
- **Permission Issues**: On Unix, `chmod +x` scripts; use virtualenv to avoid global installs.
|
|
187
|
+
- **Cross-Platform**: Test paths with `pathlib`; avoid OS-specific assumptions .
|
|
188
|
+
|
|
189
|
+
For issues, check `CHANGELOG.md` or open a Git issue. Contributions welcome via pull requests after Git setup .
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT License (add `LICENSE` file with standard text) .
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/VideoJoin/__init__.py
|
|
4
|
+
src/VideoJoin/__main__.py
|
|
5
|
+
src/VideoJoin/cli.py
|
|
6
|
+
src/VideoJoin.egg-info/PKG-INFO
|
|
7
|
+
src/VideoJoin.egg-info/SOURCES.txt
|
|
8
|
+
src/VideoJoin.egg-info/dependency_links.txt
|
|
9
|
+
src/VideoJoin.egg-info/entry_points.txt
|
|
10
|
+
src/VideoJoin.egg-info/requires.txt
|
|
11
|
+
src/VideoJoin.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ChronicleLogger>=1.0.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VideoJoin
|