Mirror extractor logs to item logs

This commit is contained in:
Sucukdeluxe 2026-03-09 01:36:08 +01:00
parent 9449788e56
commit c898c6de65
2 changed files with 54 additions and 3 deletions

View File

@ -1159,6 +1159,26 @@ export function resolveArchiveItemsFromList(archiveName: string, items: Download
return [];
}
export function extractArchiveNameFromExtractorLogMessage(message: string): string | null {
const text = String(message || "").trim();
if (!text) {
return null;
}
const patterns = [
/archive=([^,\s|]+)/i,
/Entpacke Archiv:\s*([^\s]+)\s*->/i,
/Entpack-Fehler\s+([^\s]+)\s+\[/i
];
for (const pattern of patterns) {
const match = text.match(pattern);
if (match?.[1]) {
return match[1].trim();
}
}
return null;
}
function retryDelayWithJitter(attempt: number, baseMs: number): number {
const exponential = baseMs * Math.pow(1.5, Math.min(attempt - 1, 14));
const capped = Math.min(exponential, 120000);
@ -1368,6 +1388,25 @@ export class DownloadManager extends EventEmitter {
});
}
private logExtractionForItems(
pkg: PackageEntry,
items: DownloadItem[],
prefix: string,
level: "INFO" | "WARN" | "ERROR",
message: string
): void {
const fullMessage = `${prefix}: ${message}`;
this.logPackageForPackage(pkg, level, fullMessage);
const archiveName = extractArchiveNameFromExtractorLogMessage(message);
if (!archiveName) {
return;
}
for (const item of resolveArchiveItemsFromList(archiveName, items)) {
this.logPackageForItem(item, level, fullMessage, { archiveName });
}
}
private logPackageForItem(
item: DownloadItem,
level: "INFO" | "WARN" | "ERROR",
@ -8714,7 +8753,7 @@ export class DownloadManager extends EventEmitter {
hybridMode: true,
maxParallel: this.settings.maxParallelExtract || 2,
extractCpuPriority: "high",
onLog: (level, message) => this.logPackageForPackage(pkg, level, `Hybrid-Extractor: ${message}`),
onLog: (level, message) => this.logExtractionForItems(pkg, items, "Hybrid-Extractor", level, message),
onArchiveFailure: (failure) => {
const failedArchiveKey = readyArchiveKeyByName.get(String(failure.archiveName || "").toLowerCase());
if (failedArchiveKey) {
@ -9193,7 +9232,7 @@ export class DownloadManager extends EventEmitter {
// All downloads finished — use NORMAL OS priority so extraction runs at
// full speed (matching manual 7-Zip/WinRAR speed).
extractCpuPriority: "high",
onLog: (level, message) => this.logPackageForPackage(pkg, level, `Extractor: ${message}`),
onLog: (level, message) => this.logExtractionForItems(pkg, completedItems, "Extractor", level, message),
onArchiveFailure: (failure) => {
if (autoRecoveredArchives.has(failure.archiveName)) {
return;

View File

@ -5,7 +5,7 @@ import http from "node:http";
import { EventEmitter, once } from "node:events";
import AdmZip from "adm-zip";
import { afterEach, describe, expect, it } from "vitest";
import { DownloadManager, getAuthoritativeRealDebridTotal } from "../src/main/download-manager";
import { DownloadManager, extractArchiveNameFromExtractorLogMessage, getAuthoritativeRealDebridTotal } from "../src/main/download-manager";
import { defaultSettings } from "../src/main/constants";
import { parseDebridLinkApiKeys } from "../src/shared/debrid-link-keys";
import { getProviderUsageDayKey } from "../src/shared/provider-daily-limits";
@ -15,6 +15,18 @@ import { primeDebridLinkRuntimeCooldownForTests, resetDebridLinkRuntimeStateForT
const tempDirs: string[] = [];
const originalFetch = globalThis.fetch;
describe("extractArchiveNameFromExtractorLogMessage", () => {
it("detects archive names from extractor log variants", () => {
expect(extractArchiveNameFromExtractorLogMessage("Extract-Backend Start: archive=scn-dhanbs7-S02E008.rar, mode=legacy")).toBe("scn-dhanbs7-S02E008.rar");
expect(extractArchiveNameFromExtractorLogMessage("Entpacke Archiv: scn-dhanbs7-S02E008.rar -> C:\\target")).toBe("scn-dhanbs7-S02E008.rar");
expect(extractArchiveNameFromExtractorLogMessage("Entpack-Fehler scn-dhanbs7-S02E008.rar [missing_parts]: Error: boom")).toBe("scn-dhanbs7-S02E008.rar");
});
it("returns null when no archive name is present", () => {
expect(extractArchiveNameFromExtractorLogMessage("Post-Processing Entpacken Ende")).toBeNull();
});
});
async function waitFor(predicate: () => boolean, timeoutMs = 15000): Promise<void> {
const started = Date.now();
while (!predicate()) {