mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-18 00:33:59 +00:00
refactor: enhance download management by prioritizing interrupted downloads and improving error logging
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
DeckyPlugin,
|
||||
DownloadSourcesChecker,
|
||||
WSClient,
|
||||
logger,
|
||||
} from "@main/services";
|
||||
import { migrateDownloadSources } from "./helpers/migrate-download-sources";
|
||||
|
||||
@@ -73,18 +74,47 @@ export const loadState = async () => {
|
||||
return orderBy(games, "timestamp", "desc");
|
||||
});
|
||||
|
||||
downloads.forEach((download) => {
|
||||
let interruptedDownload = null;
|
||||
|
||||
for (const download of downloads) {
|
||||
const downloadKey = levelKeys.game(download.shop, download.objectId);
|
||||
|
||||
// Reset extracting state
|
||||
if (download.extracting) {
|
||||
downloadsSublevel.put(levelKeys.game(download.shop, download.objectId), {
|
||||
await downloadsSublevel.put(downloadKey, {
|
||||
...download,
|
||||
extracting: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const [nextItemOnQueue] = downloads.filter((game) => game.queued);
|
||||
// Find interrupted active download (download that was running when app closed)
|
||||
// Mark it as paused but remember it for auto-resume
|
||||
if (download.status === "active" && !interruptedDownload) {
|
||||
interruptedDownload = download;
|
||||
await downloadsSublevel.put(downloadKey, {
|
||||
...download,
|
||||
status: "paused",
|
||||
});
|
||||
} else if (download.status === "active") {
|
||||
// Mark other active downloads as paused
|
||||
await downloadsSublevel.put(downloadKey, {
|
||||
...download,
|
||||
status: "paused",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const downloadsToSeed = downloads.filter(
|
||||
// Re-fetch downloads after status updates
|
||||
const updatedDownloads = await downloadsSublevel
|
||||
.values()
|
||||
.all()
|
||||
.then((games) => orderBy(games, "timestamp", "desc"));
|
||||
|
||||
// Prioritize interrupted download, then queued downloads
|
||||
const downloadToResume =
|
||||
interruptedDownload ?? updatedDownloads.find((game) => game.queued);
|
||||
|
||||
const downloadsToSeed = updatedDownloads.filter(
|
||||
(game) =>
|
||||
game.shouldSeed &&
|
||||
game.downloader === Downloader.Torrent &&
|
||||
@@ -92,7 +122,22 @@ export const loadState = async () => {
|
||||
game.uri !== null
|
||||
);
|
||||
|
||||
await DownloadManager.startRPC(nextItemOnQueue, downloadsToSeed);
|
||||
// For torrents or if JS downloader is disabled, use Python RPC
|
||||
const isTorrent = downloadToResume?.downloader === Downloader.Torrent;
|
||||
const useJsDownloader =
|
||||
userPreferences?.useNativeHttpDownloader && !isTorrent;
|
||||
|
||||
if (useJsDownloader && downloadToResume) {
|
||||
// Start Python RPC for seeding only, then resume HTTP download with JS
|
||||
await DownloadManager.startRPC(undefined, downloadsToSeed);
|
||||
await DownloadManager.startDownload(downloadToResume).catch((err) => {
|
||||
// If resume fails, just log it - user can manually retry
|
||||
logger.error("Failed to auto-resume download:", err);
|
||||
});
|
||||
} else {
|
||||
// Use Python RPC for everything (torrent or fallback)
|
||||
await DownloadManager.startRPC(downloadToResume, downloadsToSeed);
|
||||
}
|
||||
|
||||
startMainLoop();
|
||||
|
||||
|
||||
@@ -147,6 +147,32 @@ export class JsHttpDownloader {
|
||||
signal: this.abortController?.signal,
|
||||
});
|
||||
|
||||
// Handle 416 Range Not Satisfiable - existing file is larger than server file
|
||||
// This happens when downloading same game from different source
|
||||
if (response.status === 416 && startByte > 0) {
|
||||
logger.log(
|
||||
"[JsHttpDownloader] Range not satisfiable, deleting existing file and restarting"
|
||||
);
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
this.bytesDownloaded = 0;
|
||||
this.resetSpeedTracking();
|
||||
|
||||
// Retry without Range header
|
||||
const headersWithoutRange = { ...requestHeaders };
|
||||
delete headersWithoutRange["Range"];
|
||||
|
||||
return this.executeDownload(
|
||||
url,
|
||||
headersWithoutRange,
|
||||
filePath,
|
||||
0,
|
||||
savePath,
|
||||
usedFallback
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok && response.status !== 206) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user