Fix disk-backpressure stalls and improve episode-token parsing
This commit is contained in:
@@ -62,6 +62,22 @@ describe("extractEpisodeToken", () => {
|
||||
it("extracts from episode token at end of string", () => {
|
||||
expect(extractEpisodeToken("show.s02e03")).toBe("S02E03");
|
||||
});
|
||||
|
||||
it("extracts double episode token s01e01e02", () => {
|
||||
expect(extractEpisodeToken("tvr-mammon-s01e01e02-720p")).toBe("S01E01E02");
|
||||
});
|
||||
|
||||
it("extracts double episode with dot separators", () => {
|
||||
expect(extractEpisodeToken("Show.S01E03E04.720p")).toBe("S01E03E04");
|
||||
});
|
||||
|
||||
it("extracts double episode at end of string", () => {
|
||||
expect(extractEpisodeToken("show.s02e05e06")).toBe("S02E05E06");
|
||||
});
|
||||
|
||||
it("extracts double episode with single-digit numbers", () => {
|
||||
expect(extractEpisodeToken("show-s1e1e2-720p")).toBe("S01E01E02");
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyEpisodeTokenToFolderName", () => {
|
||||
@@ -96,6 +112,21 @@ describe("applyEpisodeTokenToFolderName", () => {
|
||||
it("is case-insensitive for -4SF/-4SJ suffix", () => {
|
||||
expect(applyEpisodeTokenToFolderName("Show.720p-4SF", "S01E01")).toBe("Show.720p.S01E01-4SF");
|
||||
});
|
||||
|
||||
it("applies double episode token to season-only folder", () => {
|
||||
expect(applyEpisodeTokenToFolderName("Mammon.S01.German.1080P.Bluray.x264-SMAHD", "S01E01E02"))
|
||||
.toBe("Mammon.S01E01E02.German.1080P.Bluray.x264-SMAHD");
|
||||
});
|
||||
|
||||
it("replaces existing double episode in folder with new token", () => {
|
||||
expect(applyEpisodeTokenToFolderName("Show.S01E01E02.720p-4sf", "S01E03E04"))
|
||||
.toBe("Show.S01E03E04.720p-4sf");
|
||||
});
|
||||
|
||||
it("replaces existing single episode in folder with double episode token", () => {
|
||||
expect(applyEpisodeTokenToFolderName("Show.S01E01.720p-4sf", "S01E01E02"))
|
||||
.toBe("Show.S01E01E02.720p-4sf");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sourceHasRpToken", () => {
|
||||
@@ -556,4 +587,37 @@ describe("buildAutoRenameBaseNameFromFolders", () => {
|
||||
);
|
||||
expect(result).toBe("Cheat.der.Betrug.S01E01.GERMAN.720p.WEB.h264-tmsf");
|
||||
});
|
||||
|
||||
it("renames double episode file into season folder (Mammon style)", () => {
|
||||
const result = buildAutoRenameBaseNameFromFoldersWithOptions(
|
||||
[
|
||||
"Mammon.S01.German.1080P.Bluray.x264-SMAHD"
|
||||
],
|
||||
"tvr-mammon-s01e01e02-720p",
|
||||
{ forceEpisodeForSeasonFolder: true }
|
||||
);
|
||||
expect(result).toBe("Mammon.S01E01E02.German.1080P.Bluray.x264-SMAHD");
|
||||
});
|
||||
|
||||
it("renames second double episode file correctly", () => {
|
||||
const result = buildAutoRenameBaseNameFromFoldersWithOptions(
|
||||
[
|
||||
"Mammon.S01.German.1080P.Bluray.x264-SMAHD"
|
||||
],
|
||||
"tvr-mammon-s01e03e04-720p",
|
||||
{ forceEpisodeForSeasonFolder: true }
|
||||
);
|
||||
expect(result).toBe("Mammon.S01E03E04.German.1080P.Bluray.x264-SMAHD");
|
||||
});
|
||||
|
||||
it("renames third double episode file correctly", () => {
|
||||
const result = buildAutoRenameBaseNameFromFoldersWithOptions(
|
||||
[
|
||||
"Mammon.S01.German.1080P.Bluray.x264-SMAHD"
|
||||
],
|
||||
"tvr-mammon-s01e05e06-720p",
|
||||
{ forceEpisodeForSeasonFolder: true }
|
||||
);
|
||||
expect(result).toBe("Mammon.S01E05E06.German.1080P.Bluray.x264-SMAHD");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -880,7 +880,14 @@ describe("download manager", () => {
|
||||
);
|
||||
|
||||
manager.addPackages([{ name: "drain-stall", links: ["https://dummy/drain-stall"] }]);
|
||||
const queuedSnapshot = manager.getSnapshot();
|
||||
const packageId = queuedSnapshot.session.packageOrder[0] || "";
|
||||
const itemId = queuedSnapshot.session.packages[packageId]?.itemIds[0] || "";
|
||||
manager.start();
|
||||
await waitFor(() => {
|
||||
const status = manager.getSnapshot().session.items[itemId]?.fullStatus || "";
|
||||
return status.includes("Warte auf Festplatte");
|
||||
}, 12000);
|
||||
await waitFor(() => !manager.getSnapshot().session.running, 40000);
|
||||
|
||||
const item = Object.values(manager.getSnapshot().session.items)[0];
|
||||
@@ -4329,6 +4336,63 @@ describe("download manager", () => {
|
||||
expect(internal.speedBytesLastWindow).toBe(0);
|
||||
});
|
||||
|
||||
it("does not trigger global stall abort while write-buffer is disk-blocked", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
const previousGlobalWatchdog = process.env.RD_GLOBAL_STALL_TIMEOUT_MS;
|
||||
process.env.RD_GLOBAL_STALL_TIMEOUT_MS = "2500";
|
||||
|
||||
try {
|
||||
const manager = new DownloadManager(
|
||||
{
|
||||
...defaultSettings(),
|
||||
token: "rd-token",
|
||||
outputDir: path.join(root, "downloads"),
|
||||
extractDir: path.join(root, "extract")
|
||||
},
|
||||
emptySession(),
|
||||
createStoragePaths(path.join(root, "state"))
|
||||
);
|
||||
|
||||
manager.addPackages([{ name: "disk-block-guard", links: ["https://dummy/disk-block-guard"] }]);
|
||||
const snapshot = manager.getSnapshot();
|
||||
const packageId = snapshot.session.packageOrder[0] || "";
|
||||
const itemId = snapshot.session.packages[packageId]?.itemIds[0] || "";
|
||||
|
||||
const internal = manager as unknown as any;
|
||||
internal.session.running = true;
|
||||
internal.session.paused = false;
|
||||
internal.session.reconnectUntil = 0;
|
||||
internal.session.totalDownloadedBytes = 0;
|
||||
internal.session.items[itemId].status = "downloading";
|
||||
internal.lastGlobalProgressBytes = 0;
|
||||
internal.lastGlobalProgressAt = Date.now() - 10000;
|
||||
|
||||
const abortController = new AbortController();
|
||||
internal.activeTasks.set(itemId, {
|
||||
itemId,
|
||||
packageId,
|
||||
abortController,
|
||||
abortReason: "none",
|
||||
resumable: true,
|
||||
nonResumableCounted: false,
|
||||
blockedOnDiskWrite: true,
|
||||
blockedOnDiskSince: Date.now() - 5000
|
||||
});
|
||||
|
||||
internal.runGlobalStallWatchdog(Date.now());
|
||||
|
||||
expect(abortController.signal.aborted).toBe(false);
|
||||
expect(internal.lastGlobalProgressAt).toBeGreaterThan(Date.now() - 2000);
|
||||
} finally {
|
||||
if (previousGlobalWatchdog === undefined) {
|
||||
delete process.env.RD_GLOBAL_STALL_TIMEOUT_MS;
|
||||
} else {
|
||||
process.env.RD_GLOBAL_STALL_TIMEOUT_MS = previousGlobalWatchdog;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("cleans run tracking when start conflict is skipped", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
Reference in New Issue
Block a user