feat(queue): announce tool preparation before every download starts
Windows CI / verify (push) Failing after 3m56s

On a fresh installation the first download repairs the managed
Streamlink and FFmpeg copies, which downloads and extracts roughly two
hundred megabytes before the actual VOD transfer begins. The queue item
previously sat on a generic starting status for that entire window - the
old preparing hint only appeared when the streamlink command had not
been verified yet, and a prior System Check verifies the command without
making the managed repair any cheaper, so users saw no explanation for
delays of a minute or more. All three download paths - VOD, live
recording and merge groups - now report a dedicated localized
"Preparing download tools" status before the tool gates run, and the
misleading conditional hint was removed.
This commit is contained in:
Sucukdeluxe
2026-08-14 18:28:21 +02:00
parent 5c1ddf26ca
commit d2a4ba2154
3 changed files with 46 additions and 18 deletions
+14
View File
@@ -85,6 +85,20 @@ describe('main runtime safety production paths', () => {
expect(closeHandler.indexOf('finish({ success: true, filename })')).toBeGreaterThan(closeHandler.indexOf('partialDownloadRegistry.commit'));
});
it('announces tool preparation before every download tool gate', () => {
const source = mainSource();
const vod = source.slice(source.indexOf('async function downloadVOD'), source.indexOf('async function processDownloadMergeGroup'));
const live = source.slice(source.indexOf('async function downloadLiveStream'), source.indexOf('async function downloadVOD'));
const mergeGroup = source.slice(source.indexOf('async function processDownloadMergeGroup'), source.indexOf('// ---- PHASE 2: MERGING ----'));
for (const [label, fragment] of [['vod', vod], ['live', live], ['merge', mergeGroup]] as const) {
const announce = fragment.indexOf("tBackend('statusPreparingTools')");
const gate = fragment.indexOf('await ensureStreamlinkInstalled()');
expect(announce, `${label} announces tool preparation`).toBeGreaterThan(-1);
expect(gate, `${label} gates on streamlink`).toBeGreaterThan(announce);
}
expect(source).not.toContain("tBackend('statusCheckingTools')");
});
it('reports the auto-install failure guidance on every download tool gate', () => {
const source = mainSource();
const mergeGroup = source.slice(source.indexOf('async function processDownloadMergeGroup'), source.indexOf('// ---- PHASE 2: MERGING ----'));
+22 -8
View File
@@ -129,7 +129,7 @@ import {
refreshBundledToolPaths, ensureStreamlinkInstalled, ensureFfmpegInstalled,
getManagedToolStatuses, repairManagedTools, resetManagedTools,
canExecute, canExecuteCommand,
cacheVerifiedStreamlinkCommand, isVerifiedStreamlinkCommand,
cacheVerifiedStreamlinkCommand,
cacheVerifiedFfmpegCommands, isVerifiedFfmpegCommands,
invalidateVerifiedToolCaches, setManagedToolExecutionObserver
} from './tools';
@@ -5885,6 +5885,16 @@ async function downloadLiveStream(
item: QueueItem,
onProgress: (progress: DownloadProgress) => void
): Promise<DownloadResult> {
onProgress({
id: item.id,
progress: -1,
speed: '',
eta: '',
status: tBackend('statusPreparingTools'),
currentPart: 0,
totalParts: 0
});
const streamlinkReady = await ensureStreamlinkInstalled();
if (!streamlinkReady) {
return { success: false, error: tBackend('streamlinkAutoInstallFailed') };
@@ -6203,21 +6213,15 @@ async function downloadVOD(
};
}
const streamlinkCmd = getStreamlinkCommand();
const streamlinkVersionArgs = [...streamlinkCmd.prefixArgs, '--version'];
const streamlinkAlreadyVerified = isVerifiedStreamlinkCommand(streamlinkCmd.command, streamlinkVersionArgs);
if (!streamlinkAlreadyVerified) {
onProgress({
id: item.id,
progress: -1,
speed: '',
eta: '',
status: tBackend('statusCheckingTools'),
status: tBackend('statusPreparingTools'),
currentPart: 0,
totalParts: 0
});
}
const streamlinkReady = await ensureStreamlinkInstalled();
if (!streamlinkReady) {
@@ -6469,6 +6473,16 @@ async function processDownloadMergeGroup(
// ---- PHASE 1: DOWNLOADING ----
if (mg.mergePhase === 'downloading') {
onProgress({
id: item.id,
progress: -1,
speed: '',
eta: '',
status: tBackend('statusPreparingTools'),
currentPart: 0,
totalParts: 0
});
const streamlinkReady = await ensureStreamlinkInstalled();
if (!streamlinkReady) {
return { success: false, error: tBackend('streamlinkAutoInstallFailed') };
+2 -2
View File
@@ -32,7 +32,7 @@ export const BACKEND_MESSAGES = {
diskSpaceShortGeneric: 'Zu wenig Speicherplatz.',
attemptFailed: 'Versuch {attempt}/{max} fehlgeschlagen ({errorClass}): {error}',
retryingIn: 'Neuer Versuch in {seconds}s ({errorClass})...',
statusCheckingTools: 'Prüfe Download-Tools...',
statusPreparingTools: 'Download-Tools werden vorbereitet …',
statusDownloadStarted: 'Download wird gestartet …',
statusBytesDownloaded: '{bytes} heruntergeladen',
statusFetchingChatReplay: 'Chat-Replay wird heruntergeladen...',
@@ -73,7 +73,7 @@ export const BACKEND_MESSAGES = {
diskSpaceShortGeneric: 'Not enough disk space.',
attemptFailed: 'Attempt {attempt}/{max} failed ({errorClass}): {error}',
retryingIn: 'Retrying in {seconds}s ({errorClass})...',
statusCheckingTools: 'Checking download tools...',
statusPreparingTools: 'Preparing download tools',
statusDownloadStarted: 'Starting download …',
statusBytesDownloaded: '{bytes} downloaded',
statusFetchingChatReplay: 'Fetching chat replay...',