mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
chore(release): refresh cross-platform FFmpeg payloads
This commit is contained in:
+8
-7
@@ -11,7 +11,7 @@ Targets:
|
|||||||
|
|
||||||
## Distribution policy
|
## Distribution policy
|
||||||
|
|
||||||
Firelink does not use an Apple Developer account. macOS releases are unsigned and not notarized. Users must explicitly approve the downloaded app through Finder or macOS Privacy & Security. Release copy must never describe these builds as signed, notarized, or Gatekeeper-approved.
|
Firelink does not use an Apple Developer account. macOS releases are ad-hoc signed but not notarized or Gatekeeper-approved. Users may still need to explicitly approve the downloaded app through Finder or macOS Privacy & Security. Release copy must not describe these builds as Developer ID signed, notarized, or Gatekeeper-approved.
|
||||||
|
|
||||||
Windows releases are currently unsigned. SmartScreen may warn until code signing is added.
|
Windows releases are currently unsigned. SmartScreen may warn until code signing is added.
|
||||||
|
|
||||||
@@ -58,10 +58,12 @@ node scripts/verify-binaries.js --search-root "$APP" --target aarch64-apple-darw
|
|||||||
node scripts/smoke-packaged-app.js --executable "$APP/Contents/MacOS/firelink"
|
node scripts/smoke-packaged-app.js --executable "$APP/Contents/MacOS/firelink"
|
||||||
```
|
```
|
||||||
|
|
||||||
GitHub release publication is intentionally manual. Tag pushes build and upload
|
GitHub release publication follows `.github/workflows/release.yml`. A `v*` tag
|
||||||
artifacts, but the `publish` job only runs from a `workflow_dispatch` on a `v*`
|
push builds, verifies, and publishes the GitHub release after the platform jobs
|
||||||
tag when both release-certification inputs are checked after Windows, Linux,
|
pass. A `workflow_dispatch` on a `v*` tag also publishes when its
|
||||||
and macOS clean-machine QA.
|
`publish_release` input is enabled. The current workflow has no separate
|
||||||
|
release-certification inputs; clean-machine QA remains a release-owner gate
|
||||||
|
before pushing the tag.
|
||||||
|
|
||||||
## Automated release builds
|
## Automated release builds
|
||||||
|
|
||||||
@@ -74,7 +76,6 @@ git push origin v<version>
|
|||||||
|
|
||||||
GitHub Actions builds all targets on native runners, verifies engines inside
|
GitHub Actions builds all targets on native runners, verifies engines inside
|
||||||
final package contents, performs packaged launch smoke where supported, and
|
final package contents, performs packaged launch smoke where supported, and
|
||||||
uploads artifacts. Publish the GitHub Release with a manual `workflow_dispatch`
|
publishes the GitHub Release after the build matrix passes.
|
||||||
run on the same tag after clean-machine QA is complete.
|
|
||||||
|
|
||||||
No target may silently skip missing engines, failed extraction, checksum mismatch, or missing package output.
|
No target may silently skip missing engines, failed extraction, checksum mismatch, or missing package output.
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
"version": "8.1.2-22-g94138f6973",
|
"version": "8.1.2-22-g94138f6973",
|
||||||
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-07-06-14-19/ffmpeg-n8.1.2-22-g94138f6973-win64-gpl-8.1.zip",
|
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-07-14-13-19/ffmpeg-n8.1.2-22-g94138f6973-win64-gpl-8.1.zip",
|
||||||
"sha256": "a758e2836a8f33c5f21fc44270cb00392acc6d0085dd0ba14fe14ae75935813d"
|
"sha256": "fb627ebbf9b16a3142fa48b8acd27cd9196d57aee1f719e1233416e95da7e877"
|
||||||
},
|
},
|
||||||
"aria2c": {
|
"aria2c": {
|
||||||
"version": "1.37.0",
|
"version": "1.37.0",
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
"version": "8.1.2-22-g94138f6973",
|
"version": "8.1.2-22-g94138f6973",
|
||||||
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-07-06-14-19/ffmpeg-n8.1.2-22-g94138f6973-linux64-gpl-8.1.tar.xz",
|
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-07-14-13-19/ffmpeg-n8.1.2-22-g94138f6973-linux64-gpl-8.1.tar.xz",
|
||||||
"sha256": "df99ffb3803ee56dc68954f43f950ea9f33685a3595a5da8a3e73ef4bef37e3c"
|
"sha256": "96cf2585a4b2874044320cbc5d4078af57e266f0c86cca9888507c5faab3aee8"
|
||||||
},
|
},
|
||||||
"aria2c": {
|
"aria2c": {
|
||||||
"version": "1.37.0",
|
"version": "1.37.0",
|
||||||
|
|||||||
+3
-2
@@ -16,10 +16,11 @@
|
|||||||
"sha256": "111b2f5ed760f1e1a2ec06117c4e8094fcde336ba16122dda1c5e7209bf1862d"
|
"sha256": "111b2f5ed760f1e1a2ec06117c4e8094fcde336ba16122dda1c5e7209bf1862d"
|
||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
"version": "N-125450-gfad2e0bc50",
|
"version": "N-125610-g312c830916",
|
||||||
"source": "https://ffmpeg.org/",
|
"source": "https://ffmpeg.org/",
|
||||||
"build": "GPLv3 build identified by binary as https://www.martin-riedl.de",
|
"build": "GPLv3 build identified by binary as https://www.martin-riedl.de",
|
||||||
"sha256": "be2c39e5c9ef923f60da6cb62f5a209ed98b4da8a732d9f06de4355d5ea99e58"
|
"url": "https://ffmpeg.martin-riedl.de/download/macos/arm64/1784052810_N-125610-g312c830916/ffmpeg.zip",
|
||||||
|
"sha256": "f65b4ba782b25e9f4374765d421793c6613f692d8e50b2888079657793619034"
|
||||||
},
|
},
|
||||||
"deno": {
|
"deno": {
|
||||||
"version": "2.9.2",
|
"version": "2.9.2",
|
||||||
|
|||||||
+46
-19
@@ -83,22 +83,38 @@ async function latestMartinRiedlMacArm64Release() {
|
|||||||
async function latestMartinRiedlMacArm64Snapshot() {
|
async function latestMartinRiedlMacArm64Snapshot() {
|
||||||
const html = await fetchText('https://ffmpeg.martin-riedl.de/');
|
const html = await fetchText('https://ffmpeg.martin-riedl.de/');
|
||||||
const snapshotSection = html.split('Download Snapshot Build')[1]?.split('Download Release Build')[0] || '';
|
const snapshotSection = html.split('Download Snapshot Build')[1]?.split('Download Release Build')[0] || '';
|
||||||
|
const card = snapshotSection.match(/<h3>macOS \(Apple Silicon\/arm64\)<\/h3>[\s\S]*?<\/div>/)?.[0] || '';
|
||||||
const match =
|
const match =
|
||||||
snapshotSection.match(/macOS \(Apple Silicon\/arm64\)[\s\S]*?<b>Release:\s*<\/b>\s*([A-Za-z0-9.-]+)/) ||
|
card.match(/<b>Release:\s*<\/b>\s*([A-Za-z0-9.-]+)/) ||
|
||||||
snapshotSection.match(/macOS \(Apple Silicon\/arm64\)[\s\S]*?Release:\s*([A-Za-z0-9.-]+)/);
|
card.match(/Release:\s*([A-Za-z0-9.-]+)/);
|
||||||
return match?.[1];
|
const url = card.match(/href="([^"]+\/ffmpeg\.zip)"/)?.[1];
|
||||||
|
return match?.[1]
|
||||||
|
? { version: match[1], url: url ? new URL(url, 'https://ffmpeg.martin-riedl.de').href : undefined }
|
||||||
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function latestBtbnFfmpegN81Build() {
|
async function latestBtbnFfmpegN81Build() {
|
||||||
const releases = await fetchJson('https://api.github.com/repos/BtbN/FFmpeg-Builds/releases?per_page=10');
|
const releases = await fetchJson('https://api.github.com/repos/BtbN/FFmpeg-Builds/releases?per_page=10');
|
||||||
for (const release of releases) {
|
for (const release of releases) {
|
||||||
if (release.tag_name === 'latest') continue;
|
if (release.tag_name === 'latest') continue;
|
||||||
const versions = (release.assets || [])
|
const assets = (release.assets || [])
|
||||||
.map(asset => asset.name.match(/^ffmpeg-n(8\.1\.\d+-\d+-g[0-9a-f]+)-(?:win64-gpl-8\.1\.zip|linux64-gpl-8\.1\.tar\.xz)$/)?.[1])
|
.map(asset => {
|
||||||
|
const match = asset.name.match(/^ffmpeg-n(8\.1\.\d+-\d+-g[0-9a-f]+)-(win64|linux64)-gpl-8\.1\.(?:zip|tar\.xz)$/);
|
||||||
|
if (!match) return undefined;
|
||||||
|
return {
|
||||||
|
target: match[2] === 'win64' ? 'windows' : 'linux',
|
||||||
|
version: match[1],
|
||||||
|
url: asset.browser_download_url,
|
||||||
|
};
|
||||||
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const unique = [...new Set(versions)];
|
const unique = [...new Set(assets.map(asset => asset.version))];
|
||||||
if (unique.length === 1 && versions.length >= 2) {
|
const byTarget = Object.fromEntries(assets.map(asset => [asset.target, asset]));
|
||||||
return unique[0];
|
if (unique.length === 1 && byTarget.windows && byTarget.linux) {
|
||||||
|
return {
|
||||||
|
version: unique[0],
|
||||||
|
urls: { windows: byTarget.windows.url, linux: byTarget.linux.url },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -131,22 +147,26 @@ function packagedEngineVersions(engineLock) {
|
|||||||
const rows = [];
|
const rows = [];
|
||||||
for (const [target, targetLock] of Object.entries(engineLock.targets || {})) {
|
for (const [target, targetLock] of Object.entries(engineLock.targets || {})) {
|
||||||
for (const [engine, meta] of Object.entries(targetLock.engines || {})) {
|
for (const [engine, meta] of Object.entries(targetLock.engines || {})) {
|
||||||
rows.push({ target, engine, version: meta.version });
|
rows.push({ target, engine, version: meta.version, url: meta.url });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkRows(rows, latestByEngine, latestByTargetEngine = {}) {
|
function checkRows(rows, latestByEngine, latestByTargetEngine = {}, latestUrlsByTargetEngine = {}) {
|
||||||
let outdated = 0;
|
let outdated = 0;
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
const latest = latestByTargetEngine[`${row.target}:${row.engine}`] || latestByEngine[row.engine];
|
const latest = latestByTargetEngine[`${row.target}:${row.engine}`] || latestByEngine[row.engine];
|
||||||
if (!latest) continue;
|
if (!latest) continue;
|
||||||
const current = normalizeVersion(row.version);
|
const current = normalizeVersion(row.version);
|
||||||
const wanted = normalizeVersion(latest);
|
const wanted = normalizeVersion(latest);
|
||||||
const status = compareVersions(current, wanted) < 0 ? 'outdated' : 'current';
|
const latestUrl = latestUrlsByTargetEngine[`${row.target}:${row.engine}`];
|
||||||
if (status === 'outdated') outdated += 1;
|
const versionOutdated = compareVersions(current, wanted) < 0;
|
||||||
|
const sourceOutdated = Boolean(latestUrl && row.url && row.url !== latestUrl);
|
||||||
|
const status = versionOutdated ? 'outdated' : sourceOutdated ? 'source-outdated' : 'current';
|
||||||
|
if (status !== 'current') outdated += 1;
|
||||||
console.log(` ${row.target} ${row.engine}: ${current} -> ${wanted} ${status}`);
|
console.log(` ${row.target} ${row.engine}: ${current} -> ${wanted} ${status}`);
|
||||||
|
if (sourceOutdated) console.log(` source: ${row.url} -> ${latestUrl}`);
|
||||||
}
|
}
|
||||||
return outdated;
|
return outdated;
|
||||||
}
|
}
|
||||||
@@ -184,9 +204,14 @@ async function main() {
|
|||||||
ffmpeg,
|
ffmpeg,
|
||||||
};
|
};
|
||||||
const latestByTargetEngine = {
|
const latestByTargetEngine = {
|
||||||
'x86_64-pc-windows-msvc:ffmpeg': btbnFfmpegN81Build || ffmpeg,
|
'x86_64-pc-windows-msvc:ffmpeg': btbnFfmpegN81Build?.version || ffmpeg,
|
||||||
'x86_64-unknown-linux-gnu:ffmpeg': btbnFfmpegN81Build || ffmpeg,
|
'x86_64-unknown-linux-gnu:ffmpeg': btbnFfmpegN81Build?.version || ffmpeg,
|
||||||
'aarch64-apple-darwin:ffmpeg': martinRiedlMacArm64Snapshot || martinRiedlMacArm64Ffmpeg,
|
'aarch64-apple-darwin:ffmpeg': martinRiedlMacArm64Snapshot?.version || martinRiedlMacArm64Ffmpeg,
|
||||||
|
};
|
||||||
|
const latestUrlsByTargetEngine = {
|
||||||
|
'x86_64-pc-windows-msvc:ffmpeg': btbnFfmpegN81Build?.urls.windows,
|
||||||
|
'x86_64-unknown-linux-gnu:ffmpeg': btbnFfmpegN81Build?.urls.linux,
|
||||||
|
'aarch64-apple-darwin:ffmpeg': martinRiedlMacArm64Snapshot?.url,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('\nlatest engines:');
|
console.log('\nlatest engines:');
|
||||||
@@ -194,21 +219,23 @@ async function main() {
|
|||||||
console.log(` ${engine}: ${normalizeVersion(version)}`);
|
console.log(` ${engine}: ${normalizeVersion(version)}`);
|
||||||
}
|
}
|
||||||
console.log('\nlatest engine provider builds:');
|
console.log('\nlatest engine provider builds:');
|
||||||
console.log(` BtbN FFmpeg n8.1 Windows/Linux: ${normalizeVersion(btbnFfmpegN81Build || ffmpeg)}`);
|
console.log(` BtbN FFmpeg n8.1 Windows/Linux: ${normalizeVersion(btbnFfmpegN81Build?.version || ffmpeg)}`);
|
||||||
console.log(` Martin Riedl FFmpeg macOS arm64 snapshot: ${normalizeVersion(martinRiedlMacArm64Snapshot || martinRiedlMacArm64Ffmpeg)}`);
|
console.log(` Martin Riedl FFmpeg macOS arm64 snapshot: ${normalizeVersion(martinRiedlMacArm64Snapshot?.version || martinRiedlMacArm64Ffmpeg)}`);
|
||||||
|
|
||||||
console.log('\nengine source lock:');
|
console.log('\nengine source lock:');
|
||||||
outdatedCount += checkRows(
|
outdatedCount += checkRows(
|
||||||
sourceEngineVersions(parseJsonFile('engine-sources.lock.json')),
|
sourceEngineVersions(parseJsonFile('engine-sources.lock.json')),
|
||||||
latestByEngine,
|
latestByEngine,
|
||||||
latestByTargetEngine
|
latestByTargetEngine,
|
||||||
|
latestUrlsByTargetEngine
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('\npackaged engine lock:');
|
console.log('\npackaged engine lock:');
|
||||||
outdatedCount += checkRows(
|
outdatedCount += checkRows(
|
||||||
packagedEngineVersions(parseJsonFile('engines.lock.json')),
|
packagedEngineVersions(parseJsonFile('engines.lock.json')),
|
||||||
latestByEngine,
|
latestByEngine,
|
||||||
latestByTargetEngine
|
latestByTargetEngine,
|
||||||
|
latestUrlsByTargetEngine
|
||||||
);
|
);
|
||||||
|
|
||||||
if (outdatedCount > 0) {
|
if (outdatedCount > 0) {
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user