New Features
- Client fallback to local ffmpeg on dial failure (#16, #18) — when the remote server is unreachable, the client can transparently run the host's local
ffmpeg/ffprobeso transcoding (Jellyfin etc.) keeps
working. Opt-in viafallbackToLocalin client config orFFMPEG_OVER_IP_CLIENT_FALLBACK_TO_LOCAL=true.- Triggers only on dial failure; mid-session errors stay fatal.
- Local binary resolved via
$PATH, with self-exclusion (viaos.Executable+EvalSymlinks) to prevent recursion when the client is installed asffmpegonPATH. - Optional
fallbackRewritesreuses server rewrite logic (now shared viainternal/rewrite). FFMPEG_OVER_IP_*env vars stripped from the child so the auth secret can't leak via/proc/<pid>/environ.- All diagnostics go through the configured
logsink — never to the stdout/stderr that callers parse. - Cross-platform exit-code mapping (128+sig on Unix; raw
ExitCodeon Windows). - Optional client
debugflag logs original/rewritten args.
Improvements
- Argv-aware rewrites (#21) — the rewrite engine now matches whole argv elements (with multi-token support) instead of running
strings.ReplaceAllper element.findandreplaceare split on whitespace; a rewrite matches whenfind's tokens equal a consecutive run of whole argv elements, and the run is replaced byreplace's tokens.- Enables GPU-vendor translation like
["-hwaccel qsv", "-hwaccel cuda -hwaccel_output_format cuda"]. - Empty/whitespace-only
replaceremoves the matched run. - Rewrites apply in declared order; same rewrite fires for every matching run.
- Breaking change: configs that relied on substring rewriting inside args (e.g.
["nvenc", "qsv"]to rewriteh264_nvenc→h264_qsv) must be updated to whole-element form (["h264_nvenc", "h264_qsv"]). docs/configuration.mdand the JSONC templates updated with new examples (2→2 swap, 2→4 expansion, 1→0 / 2→0 deletion); client template now also documentsfallbackToLocalandfallbackRewrites.
Bug Fixes
-
Allow 32-bit PowerShell on 64-bit Windows in install scripts (#15) — switched the arch check from
[RuntimeInformation]::OSArchitecture(which returnsX86under WoW64 due to a .NET Framework quirk) to
[Environment]::Is64BitOperatingSystem, so the default Windows PowerShell shortcut works on 64-bit Windows. Reported in #9. -
Handle flat and wrapped zip layouts in install scripts — older release zips nest binaries in a top-level wrapper directory; newer manually-uploaded zips are flat. Scripts now detect the wrapper at extract
time and fall back to the extract root when absent, so both layouts install correctly.
Testing / CI
-
Auto-attach build zips to GitHub Releases on
v*tags — release workflow now packages per-platform build outputs into the historical<platform>-ffmpeg-over-ip-<role>.zipnaming, generates an aggregated
SHA256SUMS, and publishes viasoftprops/action-gh-release. Permissions staycontents: readby default; only the publish job re-grantscontents: write. -
Existing tests pass on Windows (#20) — fixed several pre-existing tests in
internal/process,internal/config,internal/filehandler, andcmd/serverthat depended on Unix-only details (SIGUSR1,
/bin/echo, POSIX file mode bits, POSIX errno names,HOMEenv var, deleting an open file). None had run in CI before; the suite is now genuinely cross-platform and runs onwindows-latest.internal/process:TestSignalSIGUSR1moved to a!windows-tagged file;TestMainexits early on Windows.cmd/server:TestHandleConnectionSuccessbuilds a tinyechostub viago buildinstead of relying on/bin/echo.internal/config: tests mirrorHOME→USERPROFILEandTMPDIR→TMP/TEMPon Windows;TestLoadConfigUnreadableFileskips on Windows (chmod 0o000 doesn't deny read on NTFS);TestExpandLogVars
substitutes the canonicalos.TempDir()form on Windows.internal/filehandler:TestFstatcompares mode againstos.Statrather than a hardcoded0o644; non-existent-file tests uset.TempDir()to avoidERROR_BAD_UNITcolliding with POSIXENOTDIR.
-
Small production changes justified by Windows test fixes:
config.SetupLoggingnow returns a cleanup func that closes the log file.cmd/client/main.goandcmd/server/main.godefer it, closing the file cleanly on shutdown instead of leaking. Required because
Windows can't delete a file with an open handle.filehandler.mapErrnofalls back toerrors.Is(err, fs.ErrNotExist / fs.ErrExist / fs.ErrPermission / fs.ErrInvalid)after the POSIXsyscall.Errnoswitch misses, catching Windows error codes like
ERROR_FILE_NOT_FOUNDandERROR_ALREADY_EXISTSthat don't share numeric values with POSIX errnos. Unix behavior preserved (POSIX match runs first).
-
Added
windows-latestCI job for OS-specific paths; expanded the Go test job to includecmd/; added an integration script covering the fallback path end-to-end (rewrite + env scrub + exit propagation,
ffproberouting, fallback-off regression, no-binary-on-PATH, self-skip,debug=true).
Full Changelog: v5.1.0...v5.2.0