Add unzip functionality for non-torrent downloads

Add functionality to automatically unzip downloaded .zip files from sources other than torrents.

* Add `unzipFile` helper function in `src/main/services/download/helpers.ts` to handle unzipping .zip files.
* Modify `src/main/services/download/download-manager.ts` to check if the downloaded file is a .zip file and unzip it after download completion.
* Update `src/main/services/python-rpc.ts` to support unzipping functionality by handling .zip files in the `spawn` method.
This commit is contained in:
Michal Margetín 2025-01-31 23:14:54 +01:00
parent 7c7f621d95
commit 07b1b059af
3 changed files with 29 additions and 2 deletions

View file

@ -15,7 +15,7 @@ import {
LibtorrentStatus, LibtorrentStatus,
PauseDownloadPayload, PauseDownloadPayload,
} from "./types"; } from "./types";
import { calculateETA, getDirSize } from "./helpers"; import { calculateETA, getDirSize, unzipFile } from "./helpers";
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
import { RealDebridClient } from "./real-debrid"; import { RealDebridClient } from "./real-debrid";
import path from "path"; import path from "path";
@ -139,6 +139,12 @@ export class DownloadManager {
); );
this.cancelDownload(gameId); this.cancelDownload(gameId);
if (game.uri?.endsWith(".zip")) {
const zipFilePath = path.join(game.downloadPath!, game.folderName!);
const outputDir = path.join(game.downloadPath!, game.folderName!);
await unzipFile(zipFilePath, outputDir);
}
} }
await downloadQueueRepository.delete({ game }); await downloadQueueRepository.delete({ game });

View file

@ -1,6 +1,7 @@
import path from "node:path"; import path from "node:path";
import fs from "node:fs"; import fs from "node:fs";
import { logger } from "../logger"; import { logger } from "../logger";
import unzipper from "unzipper";
export const calculateETA = ( export const calculateETA = (
totalLength: number, totalLength: number,
@ -38,3 +39,15 @@ export const getDirSize = async (dir: string): Promise<number> => {
return 0; return 0;
} }
}; };
export const unzipFile = async (zipFilePath: string, outputDir: string) => {
try {
await fs.createReadStream(zipFilePath)
.pipe(unzipper.Extract({ path: outputDir }))
.promise();
logger.info(`Unzipped ${zipFilePath} to ${outputDir}`);
} catch (error) {
logger.error(`Failed to unzip ${zipFilePath}`, error);
throw error;
}
};

View file

@ -8,6 +8,7 @@ import crypto from "node:crypto";
import { pythonRpcLogger } from "./logger"; import { pythonRpcLogger } from "./logger";
import { Readable } from "node:stream"; import { Readable } from "node:stream";
import { app, dialog } from "electron"; import { app, dialog } from "electron";
import { unzipFile } from "./download/helpers"; // Import the unzip helper function
interface GamePayload { interface GamePayload {
game_id: number; game_id: number;
@ -42,7 +43,7 @@ export class PythonRPC {
readable.on("data", pythonRpcLogger.log); readable.on("data", pythonRpcLogger.log);
} }
public static spawn( public static async spawn(
initialDownload?: GamePayload, initialDownload?: GamePayload,
initialSeeding?: GamePayload[] initialSeeding?: GamePayload[]
) { ) {
@ -96,6 +97,13 @@ export class PythonRPC {
this.pythonProcess = childProcess; this.pythonProcess = childProcess;
} }
// Handle unzipping if initialDownload is a .zip file
if (initialDownload && initialDownload.url.endsWith(".zip")) {
const zipFilePath = path.join(initialDownload.save_path, initialDownload.url.split('/').pop()!);
const outputDir = initialDownload.save_path;
await unzipFile(zipFilePath, outputDir);
}
} }
public static kill() { public static kill() {