Store policy 10.2.2 forbids dynamic code inclusion, and this was the only third-party binary the app ever downloaded and ran. It had already failed in production: the pin aged out of BtbN's 14-day retention and the download 404'd on the creator's first real recording attempt (2026-09-01). Bundling kills that failure class permanently and deletes the startup network dependency. - scripts/fetch-ffmpeg.sh populates a gitignored ./ffmpeg from a pinned month-end BtbN LGPL-shared artifact, SHA-256 verified before extraction, idempotent, FFMPEG_ZIP= override. 135 MB of DLLs in git would tax every commit on this 9p tree; the URL + hash are the audit trail LGPL §6 wants. - ytLive.csproj copies ffmpeg\** to output and publish (Always), and a GuardBundledFfmpeg target fails the BUILD if the folder is missing, so a fresh clone finds out before a take rather than during one. - FfmpegLocator loses the downloader, the zip extraction and the %APPDATA%\ytLlive\tools cache. Order is now bundle -> PATH, deliberately inverted: a PATH ffmpeg may be a different major version or a GPL build, and the bundle is what was pinned, license-vetted and tested. A missing bundle throws loudly; the old "found something on disk" path could satisfy a missing bundle with a stale copy, and silent drift is the worst failure mode for a dependency certification inspects. - ffplay.exe (18 MB) is not shipped; nothing calls it. - THIRD-PARTY-NOTICES.txt: "downloads" -> "bundled" throughout, and the stale build tag autobuild-2026-08-09-13-03 — the tag that 404'd — corrected to autobuild-2026-08-31-13-27 with the exact artifact name and archive hash. OpenH264 made precise: compiled INTO avcodec-63.dll, no separate binary. Checked whether other third-party binaries needed bundling: no. e_sqlite3.dll and WebView2Loader.dll already ship via NuGet into runtimes\win-x64\native\, OpenH264 is inside avcodec-63.dll, the rest are managed. Two gaps remain that bundling cannot fix, recorded in the map: the WebView2 Evergreen runtime is a machine prerequisite (TASK 48 item 2), and Velopack's updater downloads and executes, so its teardown is a compliance action. Tests: 16 locator facts, suite 379/379, 0 warnings. The integration test runs the bundled ffmpeg -version, which is the only assertion that proves the sibling libav*.dll resolved — presence checks pass with the DLLs missing and a shared build then fails to start. TheLocatorCarriesNoNetworkCapability keeps 10.2.2 from rotting back. Analysis: TASKS/research-store-certification.md §4.
99 lines
3.7 KiB
Bash
99 lines
3.7 KiB
Bash
#!/usr/bin/env bash
|
|
# fetch-ffmpeg.sh — populate ./ffmpeg/ with the pinned BtbN LGPL-shared FFmpeg build.
|
|
#
|
|
# WHY THIS EXISTS: the app used to download ffmpeg from GitHub on first run and execute
|
|
# it. That is Windows Store policy 10.2.2 (dynamic code inclusion) and it already cost a
|
|
# real failure — the pin aged out of BtbN's 14-day retention and the download 404'd on
|
|
# the creator's first recording attempt (2026-09-01). FFmpeg is now BUNDLED, so nothing is
|
|
# fetched at runtime. This script is the BUILD-TIME half of that: a fresh clone has no
|
|
# ffmpeg/ folder, so it must be filled once before the first build.
|
|
#
|
|
# The binaries are NOT committed to git (135 MB of incompressible DLLs would tax every
|
|
# commit on this 9p-bridged working tree). The URL + SHA-256 below are the audit trail
|
|
# that the LGPL written-offer obligation actually needs, and they are reviewable in a diff.
|
|
#
|
|
# Usage: ./scripts/fetch-ffmpeg.sh
|
|
# FFMPEG_ZIP=/path/to/already-downloaded.zip ./scripts/fetch-ffmpeg.sh
|
|
#
|
|
# Idempotent: re-running with ffmpeg/ already populated verifies and exits. Delete
|
|
# ffmpeg/ to force a refetch.
|
|
|
|
set -euo pipefail
|
|
|
|
# Pinned BtbN lgpl-shared win64 build. A MONTH-END autobuild tag on purpose: BtbN keeps
|
|
# ~14 dailies, but month-end builds for ~2 years. Do not "refresh" this to a daily — that
|
|
# is the mistake that caused the 404.
|
|
URL="https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-08-31-13-27/ffmpeg-N-126342-gf88b741dbf-win64-lgpl-shared.zip"
|
|
SHA256="46ea6521ed3877689d2ff0bd03640ac2637104415f6237d42625d13408767146"
|
|
|
|
# The files we ship. ffplay.exe (18 MB) is deliberately excluded — nothing in the app
|
|
# calls it, and shipping an unused player would widen the package and the license surface
|
|
# for nothing.
|
|
WANT_EXE="ffmpeg.exe ffprobe.exe"
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
DEST="$ROOT/ffmpeg"
|
|
|
|
if [ -f "$DEST/ffmpeg.exe" ]; then
|
|
echo "✓ ffmpeg/ already populated — nothing to do."
|
|
echo " (delete $DEST to force a refetch)"
|
|
exit 0
|
|
fi
|
|
|
|
command -v python3 >/dev/null 2>&1 || {
|
|
echo "❌ python3 is required to extract the zip (unzip is not installed in this WSL)."
|
|
echo " Set FFMPEG_ZIP to a pre-downloaded archive, or install python3."
|
|
exit 1
|
|
}
|
|
|
|
ZIP="${FFMPEG_ZIP:-}"
|
|
if [ -z "$ZIP" ]; then
|
|
ZIP="$(mktemp -t ffmpeg-pin-XXXXXX.zip)"
|
|
trap 'rm -f "$ZIP"' EXIT
|
|
echo "══ Downloading the pinned FFmpeg build (~65 MB, one time) ══"
|
|
curl -fsSL --retry 3 -o "$ZIP" "$URL"
|
|
fi
|
|
|
|
echo "══ Verifying SHA-256 ══"
|
|
GOT="$(sha256sum "$ZIP" | cut -d' ' -f1)"
|
|
if [ "$GOT" != "$SHA256" ]; then
|
|
echo "❌ SHA-256 mismatch — refusing to extract."
|
|
echo " expected $SHA256"
|
|
echo " actual $GOT"
|
|
exit 1
|
|
fi
|
|
echo "✓ $GOT"
|
|
|
|
echo "══ Extracting into ffmpeg/ ══"
|
|
python3 - "$ZIP" "$DEST" "$WANT_EXE" <<'PY'
|
|
import os, sys, zipfile
|
|
|
|
archive_path, dest, want = sys.argv[1], sys.argv[2], set(sys.argv[3].split())
|
|
wanted_exe = {n for n in want}
|
|
|
|
os.makedirs(dest, exist_ok=True)
|
|
found = []
|
|
with zipfile.ZipFile(archive_path) as z:
|
|
for name in z.namelist():
|
|
if '/bin/' not in name or name.endswith('/'):
|
|
continue
|
|
base = os.path.basename(name)
|
|
if not (base.endswith('.dll') or base in wanted_exe):
|
|
continue
|
|
with z.open(name) as src, open(os.path.join(dest, base), 'wb') as out:
|
|
out.write(src.read())
|
|
found.append(base)
|
|
|
|
missing = wanted_exe - set(found)
|
|
if missing:
|
|
sys.exit(f"❌ archive is missing required binaries: {sorted(missing)}")
|
|
|
|
print(f"✓ extracted {len(found)} files")
|
|
for base in sorted(found):
|
|
print(f" {base}")
|
|
PY
|
|
|
|
echo ""
|
|
echo "✓ Bundled FFmpeg ready. The build copies ffmpeg/ → bin/<config>/<tfm>/ffmpeg/."
|
|
echo " Nothing is downloaded at runtime any more (Store policy 10.2.2 satisfied)."
|