Skip to content

Commit a337a44

Browse files
cdgriffithluzpazJacobDev1anne-o-pixelmikeSGman
authored
Version 6.0.0 (#713)
Major Updates --------- Co-authored-by: luzpaz <luzpaz@users.noreply.github.com> Co-authored-by: JacobDev1 <65915437+JacobDev1@users.noreply.github.com> Co-authored-by: anne-o-pixel <81879599+anne-o-pixel@users.noreply.github.com> Co-authored-by: Dude <398394+mikeSGman@users.noreply.github.com>
1 parent 250db2f commit a337a44

131 files changed

Lines changed: 13765 additions & 4041 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ jobs:
99
build-nix:
1010
strategy:
1111
matrix:
12-
os: [ ubuntu-22.04, ubuntu-24.04, macos-13, macos-14 ]
12+
os: [ ubuntu-22.04, ubuntu-24.04, macos-14 ]
1313
runs-on: ${{ matrix.os }}
1414

1515
steps:
1616
- uses: actions/checkout@v4
1717

1818
- uses: actions/setup-python@v5
1919
with:
20-
python-version: "3.12"
20+
python-version: "3.13"
2121

2222
- name: Install the latest version of uv and activate the environment
2323
uses: astral-sh/setup-uv@v6
@@ -84,7 +84,7 @@ jobs:
8484
- uses: actions/checkout@v4
8585
- uses: actions/setup-python@v5
8686
with:
87-
python-version: "3.12"
87+
python-version: "3.13"
8888

8989
- name: Install the latest version of uv and activate the environment
9090
uses: astral-sh/setup-uv@v6

.github/workflows/pythonpublish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Set up Python
1919
uses: actions/setup-python@v5
2020
with:
21-
python-version: '3.12'
21+
python-version: '3.13'
2222

2323
- name: Install Dependencies
2424
run: |

.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212

1313
- uses: actions/setup-python@v5
1414
with:
15-
python-version: "3.12"
15+
python-version: "3.13"
1616

1717
- name: Install the latest version of uv and activate the environment
1818
uses: astral-sh/setup-uv@v6
@@ -30,7 +30,7 @@ jobs:
3030

3131
- uses: actions/setup-python@v5
3232
with:
33-
python-version: "3.12"
33+
python-version: "3.13"
3434

3535
- name: Install the latest version of uv and activate the environment
3636
uses: astral-sh/setup-uv@v6

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,5 @@ test.html
124124
iso-639-3.*
125125
build-dir/
126126
benchmarking/
127+
128+
./.claude/settings.local.json

CHANGES

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,71 @@
11
# Changelog
22

3+
## Version 6.0.0
4+
5+
* Adding #709 PGS to SRT OCR subtitle extraction feature (thanks to mikeSGman)
6+
* Adding #712 audio profile title options: No Title, Generate Title, and Custom Title (thanks to gaalos)
7+
* Adding gifski GIF encoder support with automatic PATH detection and manual path configuration
8+
* Adding external subtitle file support - import .srt, .ass, .ssa, .vtt, and .sup files into the subtitle track list
9+
* Adding AVC (x264) encoder options: AQ Mode, Psy-RD, Level, and custom x264 params
10+
* Adding "Detected External Programs" section to Settings showing status of NVEncC, QSVEncC, VCEEncC, HDR10+ Parser, and PGS OCR tools
11+
* Adding resizable columns to Concatenation Builder window with minimum widths based on header text
12+
* Adding Keyframe checkbox to Settings menu as "Use keyframes for preview images" option (default enabled)
13+
* Adding video info bar below file area showing bit depth, color space, chroma subsampling, HDR10, and HDR10+ at a glance
14+
* Adding HDR10+ passthrough awareness for AOM AV1 encoder with FFmpeg 8.0+ version detection and UI indicators
15+
* Adding HDR10+ tool auto-download on Windows startup and Help menu
16+
* Adding AOM AV1 encoder options: Tune (psnr/ssim), Denoise, AQ Mode, allintra usage mode, and custom aom-params pass-through
17+
* Adding rav1e encoder options: Tune (Psychovisual/Psnr), Photon Noise (film grain synthesis), Scene Detection toggle, HDR10 metadata passthrough, and custom rav1e-params pass-through
18+
* Adding Dolby Vision copy support for NVEncC, QSVEncC, and VCEEncC HEVC/AV1 encoders
19+
* Adding preview time slider to overlay at bottom of preview image
20+
* Adding time display next to preview slider in H:MM:SS format
21+
* Adding async queue saving to prevent GUI blocking during queue operations
22+
* Adding atomic file writes for queue to prevent corruption from interrupted saves
23+
* Adding file-based locking for queue operations to prevent race conditions between instances
24+
* Adding graceful shutdown handling for worker process and background threads
25+
* Adding Start/End Time tab to right-side options panel between Size and Crop tabs with compact 3-column layout
26+
* Adding save dialog for subtitle extraction allowing users to choose output location, defaulting to the output directory
27+
* Adding VVC encoder options: Perceptual QPA toggle, Intra Period, Threads, IFP (inter-frame parallelism), 8-bit pixel format support, and HDR10 metadata passthrough (mastering display, content light level, color signaling, chroma location)
28+
* Adding VP9 encoder options: Auto Alt-Ref Frames, Lag in Frames, Tune Content, AQ Mode, and Sharpness
29+
* Fixing #337 #700 #597 refactoring all FFmpeg command building from string concatenation to List[str] to fix shlex.split() failures with quotes, special characters in titles, and Windows path handling issues (thanks to Xoanon88 and Buzz0016)
30+
* Fixing #481 MP4 subtitle copy mode using wrong codec - now uses mov_text instead of copy for MP4 containers (thanks to wmonte75)
31+
* Fixing #687 dialogs staying on top of all windows and unable to minimize by removing WindowStaysOnTopHint flag (thanks to Krawk)
32+
* Fixing #688 typo in changelog (thanks to luzpaz)
33+
* Fixing #695 Qt6 decimal input fields enforcing locale-specific decimal separators (comma vs dot) by forcing C locale (thanks to isben)
34+
* Fixing #696 RAW command display boxes too small on macOS by using actual document size for height calculation (thanks to isben)
35+
* Fixing #707 Rigaya encoder binary detection with case-insensitive search (thanks to anne-o-pixel)
36+
* Fixing #708 process priority niceness values inverted on Linux and removed Realtime option on non-Windows (thanks to JacobDev1)
37+
* Fixing encoding incorrectly reported as successful when FFmpeg fails immediately (e.g. VAAPI on Windows) due to race condition between worker and output reader thread
38+
* Fixing copy encoder failing when OpenCL is enabled by not adding hardware device flags when filters are disabled
39+
* Fixing zscale "no path between colorspaces" error during HDR tonemapping by explicitly specifying input transfer characteristic
40+
* Fixing thumbnail generation failing on non-full-range YUV sources (e.g. HDR AV1) with FFmpeg 8.0+ by adding -strict unofficial to mjpeg encoder
41+
* Fixing FFmpeg download failing when destination directories (e.g. presets) already exist from a previous install
42+
* Fixing HDR10+ detection to use ffprobe for non-HEVC codecs (AV1, VP9, etc.) and as fallback when hdr10plus_tool is unavailable
43+
* Fixing Windows taskbar showing generic icon instead of FastFlix icon by setting AppUserModelID and deferring blocking version check until after event loop starts
44+
* Fixing Settings browse buttons column being too wide by setting fixed width and column stretch
45+
* Fixing PGS OCR requiring manual checkbox enable - now auto-detects availability from tesseract and pgsrip
46+
* Fixing PGS OCR subtitle extraction using pgsrip.Sup to process already-extracted .sup file instead of re-extracting from MKV (fixes wrong file path and mkvextract failures)
47+
* Fixing extract dropdown arrow being oversized by scaling the menu-indicator to match up/down button proportions
48+
* Fixing QFont::setPointSize warnings in PyInstaller executables by using pt instead of px for stylesheet font sizes
49+
* Fixing video track selector showing unnecessarily when source video has only one video track
50+
* Fixing rav1e and AOM AV1 custom params list being corrupted to "[]" string on profile load/reload, breaking HDR10+ metadata passthrough
51+
* Fixing visual border between filename area and video track selector
52+
* Fixing test suite hanging due to missing QApplication in PySide6 widget tests
53+
* Fixing window resizing beyond screen boundaries when switching profiles on macOS
54+
* Fixing potential GUI freeze when log queue fills up during encoding
55+
* Fixing file handle leaks in command runner when process startup fails
56+
* Fixing crash when dragging non-video content over the main window
57+
* Fixing rotation setting not being applied correctly when loading profiles
58+
* Fixing flip settings not restoring correctly when returning video from queue
59+
* Fixing GIF encoder not applying resolution scaling
60+
* Fixing audio profile loading - validator returned wrong enum type (MatchType instead of MatchItem)
61+
* Fixing "monoo" typo in downmix mapping that caused mono downmix to fail
62+
* Fixing undefined variable crash when creating duplicate audio tracks via profile filters
63+
* Fixing IndexError when applying profile audio filters to videos with non-sequential track indices
64+
* Fixing TypeError crash with Rigaya encoders when audio quality not explicitly set
65+
* Fixing AttributeError crash when audio track metadata is incomplete
66+
* Fixing queue file generation mismatch errors due to redundant save calls on startup and when adding to queue
67+
68+
369
## Version 5.12.4
470

571
* Fixing #675 "Default Source Folder" not used when adding Complete Folders (thanks to Krawk)
@@ -10,7 +76,7 @@
1076

1177
## Version 5.12.3
1278

13-
* Fixing #673 changing subtitle langauge in the UI did not take effect in the command (thanks to danielly2020)
79+
* Fixing #673 changing subtitle language in the UI did not take effect in the command (thanks to danielly2020)
1480
* Fixing #673 extract subtitle command was looking for subtitle index, not absolute index (thanks to danielly2020)
1581

1682
## Version 5.12.2

CLAUDE.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
FastFlix is a Python GUI application for video encoding/transcoding using PySide6 (Qt6). It wraps FFmpeg and supports 25+ encoder backends including x264, x265, AV1 variants, VP9, VVC, and hardware encoders (NVIDIA NVEncC, Intel QSVEncC, AMD VCEEncC).
8+
9+
**Requirements:** Python 3.13+, FFmpeg 4.3+ (5.0+ recommended)
10+
11+
## Build & Development Commands
12+
13+
```bash
14+
# Install dependencies
15+
uv sync --frozen
16+
17+
# Lint and format
18+
uv run ruff check # Check for violations
19+
uv run ruff check --fix # Auto-fix issues
20+
uv run ruff format # Format code
21+
22+
# Run tests
23+
uv run pytest tests -v
24+
PYTEST_QT_API=pyside6 uv run pytest tests -v # Linux with Qt
25+
26+
# Run specific test file
27+
uv run pytest tests/encoders/test_hevc_x265_command_builder.py -v
28+
29+
# Run the application
30+
python -m fastflix
31+
32+
# Build executables
33+
uv run pyinstaller FastFlix_Windows_OneFile.spec
34+
uv run pyinstaller FastFlix_Nix_OneFile.spec
35+
```
36+
37+
## Code Style
38+
39+
- Line length: 120 characters
40+
- Double quotes for strings
41+
- Ruff for linting and formatting (Black-compatible)
42+
- Type hints via Pydantic models
43+
44+
## Architecture
45+
46+
### Multi-Process Design
47+
- **Main process** (`entry.py`): Sets up queues and spawns worker subprocess
48+
- **GUI process** (`application.py`): Qt application (prevents UI blocking)
49+
- **Worker process** (`conversion_worker.py`): Processes conversion queue
50+
- Queue communication between processes for status/logging
51+
52+
### Encoder Plugin System
53+
Each encoder lives in `fastflix/encoders/{encoder_name}/` with:
54+
- `__init__.py`: Encoder metadata/registration
55+
- `command_builder.py`: Implements `build(fastflix) -> List[Command]`
56+
- Settings model in `models/encode.py` (Pydantic)
57+
- UI panel in `widgets/panels/{encoder_name}/`
58+
59+
### Key Modules
60+
| Module | Purpose |
61+
|--------|---------|
62+
| `flix.py` | Core FFmpeg/FFprobe interaction |
63+
| `widgets/main.py` | Main GUI window |
64+
| `models/config.py` | Configuration management |
65+
| `models/encode.py` | Encoder settings models |
66+
| `encoders/common/helpers.py` | Shared command building utilities |
67+
68+
### Data Flow
69+
1. User loads video → `parse()` via FFprobe
70+
2. Encoding options set → Pydantic model validation
71+
3. Video queued → Added to `conversion_list`
72+
4. Worker processes → Encoder's `build()` generates FFmpeg commands
73+
5. `command_runner.py` executes → Progress streamed to GUI
74+
75+
## Adding a New Encoder
76+
77+
1. Create directory: `fastflix/encoders/{encoder_name}/`
78+
2. Add settings class to `models/encode.py`
79+
3. Implement `command_builder.py` with `build(fastflix) -> List[Command]`
80+
4. Create UI panel in `widgets/panels/{encoder_name}/`
81+
5. Add tests in `tests/encoders/test_{encoder_name}_command_builder.py`
82+
83+
## Configuration
84+
85+
- Config file: `~/.config/FastFlix/fastflix.yaml`
86+
- Portable mode: Place `fastflix.yaml` in app directory
87+
- Environment overrides: `FF_FFMPEG`, `FF_FFPROBE`, `FF_HDR10PLUS`, `FF_CONFIG`
88+
89+
## FFmpeg Command Research
90+
91+
**IMPORTANT:** Always research FFmpeg commands online before implementing or modifying encoder command builders. FFmpeg options and filter syntax can change between versions.
92+
93+
Resources to consult:
94+
- Official FFmpeg documentation: https://ffmpeg.org/ffmpeg.html
95+
- FFmpeg filters documentation: https://ffmpeg.org/ffmpeg-filters.html
96+
- FFmpeg wiki: https://trac.ffmpeg.org/wiki
97+
98+
Key considerations:
99+
- Filter order matters (e.g., scale before palettegen for GIFs)
100+
- Use appropriate scale flags (lanczos/bicubic over bilinear)
101+
- Verify filter_complex syntax for multi-input/output chains
102+
- Check encoder-specific options in official docs
103+
104+
## Changelog
105+
106+
**IMPORTANT:** Always update the `CHANGES` file when making significant additions or bug fixes during a session. Add entries under the current version section at the top of the file using the format:
107+
- `* Adding {feature description}` for new features
108+
- `* Fixing {bug description}` for bug fixes
109+
110+
## Branching
111+
112+
- `master`: Release branch
113+
- `develop`: Development branch (PRs merge here)

FastFlix_Nix_OneFile.spec

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- mode: python ; coding: utf-8 -*-
2-
from PyInstaller.utils.hooks import collect_submodules
2+
from PyInstaller.utils.hooks import collect_submodules, copy_metadata, collect_data_files
33
import toml
44
import os
55
import platform
@@ -26,9 +26,12 @@ all_imports.remove("python-box")
2626
all_imports.append("box")
2727
all_imports.append("iso639")
2828

29+
# Add pgsrip for OCR support
30+
all_imports.extend(["pgsrip", "pytesseract", "cv2", "numpy", "pysrt", "babelfish", "babelfish.converters", "babelfish.converters.alpha2", "babelfish.converters.alpha3b", "babelfish.converters.alpha3t", "babelfish.converters.name", "babelfish.converters.opensubtitles", "cleanit"])
31+
2932
a = Analysis(['fastflix/__main__.py'],
3033
binaries=[],
31-
datas=[('CHANGES', 'fastflix/.'), ('docs/build-licenses.txt', 'docs')] + all_fastflix_files,
34+
datas=[('CHANGES', 'fastflix/.'), ('docs/build-licenses.txt', 'docs')] + all_fastflix_files + copy_metadata('pgsrip') + copy_metadata('pytesseract') + copy_metadata('babelfish') + copy_metadata('cleanit') + copy_metadata('trakit') + collect_data_files('babelfish') + collect_data_files('cleanit'),
3235
hiddenimports=all_imports,
3336
hookspath=[],
3437
runtime_hooks=[],

FastFlix_Windows_Installer.spec

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- mode: python ; coding: utf-8 -*-
2-
from PyInstaller.utils.hooks import collect_submodules
2+
from PyInstaller.utils.hooks import collect_submodules, copy_metadata, collect_data_files
33
import toml
44

55
block_cipher = None
@@ -24,9 +24,12 @@ all_imports.remove("python-box")
2424
all_imports.append("box")
2525
all_imports.append("iso639")
2626

27+
# Add pgsrip for OCR support
28+
all_imports.extend(["pgsrip", "pytesseract", "cv2", "numpy", "pysrt", "babelfish", "babelfish.converters", "babelfish.converters.alpha2", "babelfish.converters.alpha3b", "babelfish.converters.alpha3t", "babelfish.converters.name", "babelfish.converters.opensubtitles", "cleanit"])
29+
2730
a = Analysis(['fastflix\\__main__.py'],
2831
binaries=[],
29-
datas=[('CHANGES', 'fastflix\\.'), ('docs\\build-licenses.txt', 'docs')] + all_fastflix_files,
32+
datas=[('CHANGES', 'fastflix\\.'), ('docs\\build-licenses.txt', 'docs')] + all_fastflix_files + copy_metadata('pgsrip') + copy_metadata('pytesseract') + copy_metadata('babelfish') + copy_metadata('cleanit') + copy_metadata('trakit') + collect_data_files('babelfish') + collect_data_files('cleanit'),
3033
hiddenimports=all_imports,
3134
hookspath=[],
3235
runtime_hooks=[],

FastFlix_Windows_OneFile.spec

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
import toml
44

5-
from PyInstaller.utils.hooks import collect_submodules
5+
from PyInstaller.utils.hooks import collect_submodules, copy_metadata, collect_data_files
66

77
block_cipher = None
88

@@ -27,13 +27,16 @@ all_imports.remove("python-box")
2727
all_imports.append("box")
2828
all_imports.append("iso639")
2929

30+
# Add pgsrip for OCR support
31+
all_imports.extend(["pgsrip", "pytesseract", "cv2", "numpy", "pysrt", "babelfish", "babelfish.converters", "babelfish.converters.alpha2", "babelfish.converters.alpha3b", "babelfish.converters.alpha3t", "babelfish.converters.name", "babelfish.converters.opensubtitles", "cleanit"])
32+
3033
portable_file = "fastflix\\portable.py"
3134
with open(portable_file, "w") as portable:
3235
portable.write(" ")
3336

3437
a = Analysis(['fastflix\\__main__.py'],
3538
binaries=[],
36-
datas=[('CHANGES', 'fastflix\\.'), ('docs\\build-licenses.txt', 'docs')] + all_fastflix_files,
39+
datas=[('CHANGES', 'fastflix\\.'), ('docs\\build-licenses.txt', 'docs')] + all_fastflix_files + copy_metadata('pgsrip') + copy_metadata('pytesseract') + copy_metadata('babelfish') + copy_metadata('cleanit') + copy_metadata('trakit') + collect_data_files('babelfish') + collect_data_files('cleanit'),
3740
hiddenimports=all_imports,
3841
hookspath=[],
3942
runtime_hooks=[],

0 commit comments

Comments
 (0)