diff --git a/src/main/services/download/download-manager.ts b/src/main/services/download/download-manager.ts index b6a21ca3..3cd30a7b 100644 --- a/src/main/services/download/download-manager.ts +++ b/src/main/services/download/download-manager.ts @@ -29,24 +29,30 @@ import { BuzzheavierApi, FuckingFastApi } from "@main/services/hosters"; export class DownloadManager { private static downloadingGameId: string | null = null; - private static extractFilename( - url: string, - originalUrl?: string - ): string | undefined { - if (originalUrl?.includes("#")) { - const hashPart = originalUrl.split("#")[1]; - if (hashPart && !hashPart.startsWith("http")) return hashPart; + private static extractFilename(url: string, originalUrl?: string): string | undefined { + if (originalUrl?.includes('#')) { + const hashPart = originalUrl.split('#')[1]; + if (hashPart && !hashPart.startsWith('http') && hashPart.includes('.')) { + return hashPart; + } } - if (url.includes("#")) { - const hashPart = url.split("#")[1]; - if (hashPart && !hashPart.startsWith("http")) return hashPart; + if (url.includes('#')) { + const hashPart = url.split('#')[1]; + if (hashPart && !hashPart.startsWith('http') && hashPart.includes('.')) { + return hashPart; + } } try { const urlObj = new URL(url); - const filename = urlObj.pathname.split("/").pop(); - if (filename?.length) return filename; + const pathname = urlObj.pathname; + const pathParts = pathname.split('/'); + const filename = pathParts[pathParts.length - 1]; + + if (filename?.includes('.') && filename.length > 0) { + return decodeURIComponent(filename); + } } catch { // Invalid URL } @@ -55,22 +61,17 @@ export class DownloadManager { } private static sanitizeFilename(filename: string): string { - return filename.replace(/[<>:"/\\|?*]/g, "_"); + return filename.replaceAll(/[<>:"/\\|?*]/g, '_'); } - private static createDownloadPayload( - directUrl: string, - originalUrl: string, - downloadId: string, - savePath: string - ) { - const filename = this.extractFilename(directUrl, originalUrl); - const sanitizedFilename = filename - ? this.sanitizeFilename(filename) - : undefined; - + private static createDownloadPayload(directUrl: string, originalUrl: string, downloadId: string, savePath: string) { + const filename = this.extractFilename(originalUrl, directUrl) || this.extractFilename(directUrl); + const sanitizedFilename = filename ? this.sanitizeFilename(filename) : undefined; + if (sanitizedFilename) { logger.log(`[DownloadManager] Using filename: ${sanitizedFilename}`); + } else { + logger.log(`[DownloadManager] No filename extracted, aria2 will use default`); } return { @@ -108,9 +109,7 @@ export class DownloadManager { } private static async getDownloadStatus() { - const response = await PythonRPC.rpc.get( - "/status" - ); + const response = await PythonRPC.rpc.get("/status"); if (response.data === null || !this.downloadingGameId) return null; const downloadId = this.downloadingGameId; @@ -126,8 +125,7 @@ export class DownloadManager { status, } = response.data; - const isDownloadingMetadata = - status === LibtorrentStatus.DownloadingMetadata; + const isDownloadingMetadata = status === LibtorrentStatus.DownloadingMetadata; const isCheckingFiles = status === LibtorrentStatus.CheckingFiles; const download = await downloadsSublevel.get(downloadId); @@ -192,10 +190,7 @@ export class DownloadManager { if (progress === 1 && download) { publishDownloadCompleteNotification(game); - if ( - userPreferences?.seedAfterDownloadComplete && - download.downloader === Downloader.Torrent - ) { + if (userPreferences?.seedAfterDownloadComplete && download.downloader === Downloader.Torrent) { await downloadsSublevel.put(gameId, { ...download, status: "seeding", @@ -216,22 +211,13 @@ export class DownloadManager { } if (shouldExtract) { - const gameFilesManager = new GameFilesManager( - game.shop, - game.objectId - ); + const gameFilesManager = new GameFilesManager(game.shop, game.objectId); - if ( - FILE_EXTENSIONS_TO_EXTRACT.some((ext) => - download.folderName?.endsWith(ext) - ) - ) { + if (FILE_EXTENSIONS_TO_EXTRACT.some((ext) => download.folderName?.endsWith(ext))) { gameFilesManager.extractDownloadedFile(); } else { gameFilesManager - .extractFilesInDirectory( - path.join(download.downloadPath, download.folderName!) - ) + .extractFilesInDirectory(path.join(download.downloadPath, download.folderName)) .then(() => gameFilesManager.setExtractionComplete()); } } @@ -239,13 +225,11 @@ export class DownloadManager { const downloads = await downloadsSublevel .values() .all() - .then((games) => - sortBy( - games.filter((game) => game.status === "paused" && game.queued), - "timestamp", - "DESC" - ) - ); + .then((games) => sortBy( + games.filter((game) => game.status === "paused" && game.queued), + "timestamp", + "DESC" + )); const [nextItemOnQueue] = downloads; @@ -272,9 +256,7 @@ export class DownloadManager { if (!download) return; - const totalSize = await getDirSize( - path.join(download.downloadPath, status.folderName) - ); + const totalSize = await getDirSize(path.join(download.downloadPath, status.folderName)); if (totalSize < status.fileSize) { await this.cancelDownload(status.gameId); @@ -295,10 +277,7 @@ export class DownloadManager { static async pauseDownload(downloadKey = this.downloadingGameId) { await PythonRPC.rpc - .post("/action", { - action: "pause", - game_id: downloadKey, - } as PauseDownloadPayload) + .post("/action", { action: "pause", game_id: downloadKey } as PauseDownloadPayload) .catch(() => {}); if (downloadKey === this.downloadingGameId) { @@ -389,44 +368,24 @@ export class DownloadManager { }; } case Downloader.Buzzheavier: { - logger.log( - `[DownloadManager] Processing Buzzheavier download for URI: ${download.uri}` - ); + logger.log(`[DownloadManager] Processing Buzzheavier download for URI: ${download.uri}`); try { const directUrl = await BuzzheavierApi.getDirectLink(download.uri); logger.log(`[DownloadManager] Buzzheavier direct URL obtained`); - return this.createDownloadPayload( - directUrl, - download.uri, - downloadId, - download.downloadPath - ); + return this.createDownloadPayload(directUrl, download.uri, downloadId, download.downloadPath); } catch (error) { - logger.error( - `[DownloadManager] Error processing Buzzheavier download:`, - error - ); + logger.error(`[DownloadManager] Error processing Buzzheavier download:`, error); throw error; } } case Downloader.FuckingFast: { - logger.log( - `[DownloadManager] Processing FuckingFast download for URI: ${download.uri}` - ); + logger.log(`[DownloadManager] Processing FuckingFast download for URI: ${download.uri}`); try { const directUrl = await FuckingFastApi.getDirectLink(download.uri); logger.log(`[DownloadManager] FuckingFast direct URL obtained`); - return this.createDownloadPayload( - directUrl, - download.uri, - downloadId, - download.downloadPath - ); + return this.createDownloadPayload(directUrl, download.uri, downloadId, download.downloadPath); } catch (error) { - logger.error( - `[DownloadManager] Error processing FuckingFast download:`, - error - ); + logger.error(`[DownloadManager] Error processing FuckingFast download:`, error); throw error; } } @@ -471,9 +430,7 @@ export class DownloadManager { }; } case Downloader.Hydra: { - const downloadUrl = await HydraDebridClient.getDownloadUrl( - download.uri - ); + const downloadUrl = await HydraDebridClient.getDownloadUrl(download.uri); if (!downloadUrl) throw new Error(DownloadError.NotCachedOnHydra); return {