[feat-75] support drag and drop for map zip files

This commit is contained in:
silentrald
2024-09-06 00:01:41 +08:00
parent d5b7dff7a9
commit 0f3de55e9e
16 changed files with 326 additions and 6 deletions
@@ -7,7 +7,7 @@ import { InstallationLocationService } from "../../installation-location.service
import { UtilsService } from "../../utils.service";
import crypto, { BinaryLike } from "crypto";
import { lstatSync } from "fs";
import { copy, createReadStream, ensureDir, pathExists, pathExistsSync, realpath, unlink } from "fs-extra";
import { copy, createReadStream, ensureDir, pathExists, pathExistsSync, realpath, unlink, writeFile } from "fs-extra";
import StreamZip from "node-stream-zip";
import { RequestService } from "../../request.service";
import sanitize from "sanitize-filename";
@@ -29,6 +29,8 @@ import { FieldRequired } from "shared/helpers/type.helpers";
import { MapInfo } from "shared/models/maps/info/map-info.model";
import { parseMapInfoDat } from "shared/parsers/maps/map-info.parser";
import { tryit } from "shared/helpers/error.helpers";
import { processZip } from "main/helpers/zip.helpers";
import JSZip from "jszip";
import { CustomError } from "shared/models/exceptions/custom-error.class";
export class LocalMapsManagerService {
@@ -326,6 +328,55 @@ export class LocalMapsManagerService {
return null;
}
public async importMap(zipPath: string, version?: BSVersion): Promise<BsmLocalMap> {
try {
if (!pathExistsSync(zipPath)) {
throw new CustomError(`Zip file "${zipPath}" does not exist`, "not-found-zip");
}
const mapFolderName = path.basename(zipPath, ".zip");
const mapsFolder = await this.getMapsFolderPath(version);
const mapPath = path.join(mapsFolder, mapFolderName);
log.info(`Importing map "${zipPath}" to "${mapPath}"`);
const zip = await JSZip.loadAsync(await readFile(zipPath));
const infoFile = zip.file("Info.dat");
if (!infoFile) { // Simple check for importing maps
throw new CustomError(`Invalid zip file "${zipPath}"`, "invalid-zip");
}
await ensureFolderExist(mapPath);
await processZip(zip, async (relativePath, file) => {
const filepath = path.join(mapPath, relativePath);
if (file.dir) {
await ensureFolderExist(filepath);
return 0;
}
log.info(`Extracting "${filepath}"`);
const content = await file.async("nodebuffer");
await writeFile(filepath, content);
return content.length;
});
const localMap = await this.loadMapInfoFromPath(mapPath);
localMap.songDetails = this.songDetailsCache.getSongDetails(localMap.hash);
this.ipc.send<{map: BsmLocalMap, version?: BSVersion}>(
"map-downloaded",
this.windows.getWindows("index.html").at(0),
{ map: localMap, version }
);
return localMap;
} catch (error: any) {
throw error instanceof CustomError
? error
: CustomError.fromError(error);
}
}
public async downloadMap(map: BsvMapDetail, version?: BSVersion): Promise<BsmLocalMap> {
if (!map.versions.at(0).hash) {