Version 1 OneShot

This commit is contained in:
2026-10-09 18:58:50 +00:00
parent 514c13d184
commit bf0d661eed
27 changed files with 3039 additions and 0 deletions

108
README.md
View File

@@ -0,0 +1,108 @@
# FFmpeg Wrapper
A desktop GUI for common ffmpeg jobs: remuxing MKV files to Jellyfin-friendly MP4s, choosing which
audio tracks to keep, stripping audio, re-encoding, and scaling. Works on single files or whole batches.
It's a single executable for Windows and Linux, built with Python, Qt (PySide6) and PyInstaller.
![icon](assets/icon.png)
## Features
- **Single file or batch.** Use *Add Files*, *Add Folder* (recursive), or drag and drop. Files are
probed in the background and shown with duration, video info, and audio and subtitle counts.
- **Target container.** MP4, MKV, MOV, M4V, WebM, AVI or MPEG-TS. The encoder lists only show codecs
the chosen container can hold.
- **Audio track picker.** Every audio track in the selected file is listed with its language, codec,
channels and title. Tick the tracks you want and drag them into order. The first ticked track
becomes the default. **Apply to All Files** copies your choice to the rest of the queue,
matching tracks by language, codec and layout, so a season of episodes takes one click.
- **Strip audio.** Set Audio mode to *Strip audio*.
- **Keep streams unaltered.** *Copy* mode remuxes video and/or audio without re-encoding. *Auto*
copies whatever the container supports and re-encodes only what it can't hold (for example
DTS/TrueHD to AAC for MP4).
- **Up/downscale video.** Pick 360p up to 8K, or a custom WxH, with aspect ratio kept and Lanczos
scaling. Portrait and rotated phone videos are handled. You can also change the frame rate.
Encoders: H.264, HEVC, AV1, VP9, MPEG-4, plus NVENC, QuickSync and AMF if your ffmpeg has them.
There are CRF quality and speed preset controls.
- **Up/downmix audio.** Change channels (mono, stereo, 5.1, 7.1), sample rate, bitrate, and codec
(AAC, AC-3, E-AC-3, Opus, MP3, Vorbis, FLAC, ALAC, PCM).
- **Output folder.** Save next to the source or in a chosen folder. You can add a filename suffix
and choose what happens when the output file already exists (keep both, overwrite, or skip).
The source file is never overwritten.
- **Subtitles** are kept where possible. MP4 and MOV turn text subs into `mov_text`, and image subs
(PGS) are dropped with a note in the log. MKV keeps everything, including font attachments.
- MP4/MOV outputs get `+faststart`, and HEVC is tagged `hvc1` for Apple and TV compatibility.
- The window shows per-file and overall progress, has a **Stop** button, and keeps a full log.
**Show Command** prints the exact ffmpeg command so you can copy it.
- ffmpeg writes to `name.part.ext` and the file is renamed only on success, so a failed or
cancelled job never leaves a half-written file.
## Getting ffmpeg
The app looks for `ffmpeg` and `ffprobe` in this order:
1. The folder set in **Settings > Set FFmpeg Location...**
2. Next to the executable (or in `ffmpeg/`, `ffmpeg/bin/` or `bin/` beside it)
3. Your `PATH`
The release archives (`FFmpegWrapper-<version>-windows-x64.zip` / `-linux-x64.tar.gz`) already
include ffmpeg and ffprobe next to the executable. If you use the bare executable, install ffmpeg
(`sudo apt install ffmpeg`, `winget install ffmpeg`, ...) or point the app at it.
## Running from source
```bash
python -m venv .venv
.venv/bin/pip install -r requirements-dev.txt # Windows: .venv\Scripts\pip ...
python scripts/fetch_ffmpeg.py # optional: downloads ffmpeg into ./ffmpeg/bin
python run.py
```
Tests: `python -m pytest`. The integration tests run real conversions when ffmpeg is found, either
on `PATH` or through `FFWRAP_FFMPEG_DIR=ffmpeg/bin`.
## Building the executables
PyInstaller does not cross-compile. Build the Windows `.exe` on Windows and the Linux binary on Linux.
```bash
pip install -r requirements-dev.txt
python build.py # -> dist/FFmpegWrapper or dist/FFmpegWrapper.exe
python build.py --ffmpeg-dir ffmpeg/bin # also bundles ffmpeg + ffprobe into a .zip / .tar.gz
python scripts/smoke_test.py dist/FFmpegWrapper # optional: headless start-up check
```
`--onedir` builds a folder instead of a single file. It starts faster because nothing has to be
unpacked on launch.
**CI:** [.github/workflows/build.yml](.github/workflows/build.yml) builds, tests and smoke-tests both
platforms on every `v*` tag (or a manual run) and attaches the archives to the release. Gitea and
Forgejo Actions can run it too, but they need a Windows runner registered.
### Notes
- **Linux:** the binary needs glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+, Fedora 36+,
Mint 21+). It bundles the Qt XCB libraries, but uses the system's OpenGL/EGL driver libraries.
To get a menu entry, copy `assets/icon.png` and write a `.desktop` file that points at the binary.
- **PySide6 is pinned below 6.12.** PySide6 6.12.0 mis-counts references to Python's `None`
(in `QComboBox.clear()`/`currentData()`), which crashes the app on Python 3.11. Python 3.12+ is
not affected, but keep the pin until a fixed PySide6 ships.
- **Licensing:** the bundled ffmpeg builds come from
[BtbN/FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds) and are GPL. Keep that in mind if you
redistribute the archives.
- Settings (last options, window size, ffmpeg location) are saved per user through Qt's QSettings:
the registry on Windows, `~/.config/ffwrap/FFmpegWrapper.conf` on Linux.
## Project layout
```
ffwrap/
formats.py container/encoder tables and compatibility rules (no Qt)
probe.py ffprobe -> MediaInfo/Stream dataclasses
command.py Options -> ffmpeg arguments, output naming, audio-track matching (no Qt)
tools.py locating ffmpeg/ffprobe, encoder detection
gui/ main window, queue model, QProcess batch runner
build.py PyInstaller build + packaging
scripts/ fetch_ffmpeg.py, smoke_test.py, make_icon.py
tests/ unit tests + real-ffmpeg integration tests
```