mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
add possibility to change installations folder
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import path from 'path';
|
||||
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
|
||||
import { UtilsService } from '../services/utils.service';
|
||||
import { BSVersion } from '../services/bs-version-manager.service';
|
||||
import { BSInstallerService, DownloadEventType } from '../services/bs-installer.service';
|
||||
import { IpcRequest } from '../../shared/models/ipc-models.model';
|
||||
import { InstallationLocationService } from '../services/installation-location.service';
|
||||
import { UtilsService } from '../services/utils.service';
|
||||
|
||||
|
||||
export interface InitDownloadInfoInterface {
|
||||
@@ -29,6 +29,22 @@ ipcMain.on('bs-download.start', async (event, args: DownloadInfo) => {
|
||||
|
||||
ipcMain.on(`bs-download.${DownloadEventType.GUARD_CODE}`, async (event, args) => {
|
||||
BSInstallerService.getInstance().sendInputProcess(args);
|
||||
});
|
||||
|
||||
ipcMain.on('bs-download.installation-folder', async (event, request: IpcRequest<void>) => {
|
||||
const installationFolder = InstallationLocationService.getInstance().installationDirectory;
|
||||
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: installationFolder});
|
||||
});
|
||||
|
||||
ipcMain.on('bs-download.set-installation-folder', (event, request: IpcRequest<string>) => {
|
||||
const installerService = InstallationLocationService.getInstance();
|
||||
installerService.setInstallationDirectory(request.args).then(res => {
|
||||
console.log("déplacement terminer");
|
||||
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: res});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: false, error: err});
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ ipcMain.on('bs-launch.launch', async (event, args: LauchOption) => { //Create a
|
||||
cwd = await steamService.getGameFolder(BS_APP_ID, "Beat Saber");
|
||||
}
|
||||
else{
|
||||
cwd = path.join(installerService.getBSInstallationFolder(), args.version.BSVersion);
|
||||
cwd = path.join(installerService.installationFolder, args.version.BSVersion);
|
||||
}
|
||||
const exePath = path.join(cwd, BS_EXECUTABLE);
|
||||
if(!UtilsService.getInstance().pathExist(exePath)){ UtilsService.getInstance().ipcSend("bs-launch.launch", 2); return; }
|
||||
|
||||
@@ -25,7 +25,7 @@ ipcMain.on("bs-version.open-folder", async (event, args: BSVersion) => {
|
||||
console.log(versionFolder)
|
||||
}
|
||||
else{
|
||||
versionFolder = path.join(bsInstallerService.getBSInstallationFolder(), args.BSVersion);
|
||||
versionFolder = path.join(bsInstallerService.installationFolder, args.BSVersion);
|
||||
}
|
||||
if(UtilsService.getInstance().folderExist(versionFolder)){
|
||||
exec(`start "" "${versionFolder}"`);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import './bs-download-ipcs';
|
||||
import './window-controls-ipcs';
|
||||
import './os-controls-ipcs';
|
||||
import './bs-launcher-ipcs';
|
||||
import './bs-version-ipcs';
|
||||
import './bs-uninstall-ipcs';
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ipcMain, shell, dialog } from 'electron';
|
||||
import { UtilsService } from '../services/utils.service';
|
||||
import { IpcRequest } from '../../shared/models/ipc-models.model';
|
||||
import { getMainWindow } from '../main';
|
||||
|
||||
ipcMain.on('window.close', async () => {
|
||||
getMainWindow()?.close();
|
||||
});
|
||||
|
||||
ipcMain.on('window.maximize', async () => {
|
||||
getMainWindow()?.maximize();
|
||||
});
|
||||
|
||||
ipcMain.on('window.minimize', async () => {
|
||||
getMainWindow()?.minimize();
|
||||
});
|
||||
|
||||
ipcMain.on('window.reset', async () => {
|
||||
getMainWindow()?.restore();
|
||||
});
|
||||
|
||||
ipcMain.on('new-window', async (event, url: string) => {
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
ipcMain.on('choose-folder', async (event, request: IpcRequest<void>) => {
|
||||
dialog.showOpenDialog({properties: ['openDirectory']}).then(res => {
|
||||
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: res});
|
||||
})
|
||||
})
|
||||
@@ -1,18 +0,0 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import { getMainWindow } from '../main';
|
||||
|
||||
ipcMain.on('window.close', async () => {
|
||||
getMainWindow()?.close();
|
||||
});
|
||||
|
||||
ipcMain.on('window.maximize', async () => {
|
||||
getMainWindow()?.maximize();
|
||||
});
|
||||
|
||||
ipcMain.on('window.minimize', async () => {
|
||||
getMainWindow()?.minimize();
|
||||
});
|
||||
|
||||
ipcMain.on('window.reset', async () => {
|
||||
getMainWindow()?.restore();
|
||||
});
|
||||
@@ -5,26 +5,30 @@ import { SteamService } from "./steam.service";
|
||||
import { UtilsService } from "./utils.service";
|
||||
import { ChildProcessWithoutNullStreams, spawn } from "child_process";
|
||||
import log from "electron-log";
|
||||
import { InstallationLocationService } from "./installation-location.service";
|
||||
|
||||
export class BSInstallerService{
|
||||
|
||||
private static readonly INSTALLATION_FOLDER = path.join("BSManager", "BSInstances");
|
||||
private static readonly INSTALLATION_FOLDER = "BSInstances";
|
||||
|
||||
private static instance: BSInstallerService;
|
||||
|
||||
private readonly utils: UtilsService;
|
||||
private readonly steamService: SteamService;
|
||||
private readonly bsVersionService: BSVersionManagerService;
|
||||
private readonly installLocationService: InstallationLocationService;
|
||||
|
||||
private downloadProcess: ChildProcessWithoutNullStreams;
|
||||
|
||||
private installationFolder: string;
|
||||
|
||||
private constructor(){
|
||||
this.bsVersionService = BSVersionManagerService.getInstance();
|
||||
this.utils = UtilsService.getInstance();
|
||||
this.steamService = SteamService.getInstance();
|
||||
this.installationFolder = path.join(this.utils.getUserDocumentsFolder(), BSInstallerService.INSTALLATION_FOLDER);
|
||||
this.installLocationService = InstallationLocationService.getInstance();
|
||||
}
|
||||
|
||||
public get installationFolder(): string{
|
||||
return path.join(this.installLocationService.installationDirectory, BSInstallerService.INSTALLATION_FOLDER);
|
||||
}
|
||||
|
||||
public static getInstance(){
|
||||
@@ -36,9 +40,6 @@ export class BSInstallerService{
|
||||
return path.join(this.utils.getAssetsPath(), 'depot-downloader', 'DepotDownloader.exe');
|
||||
}
|
||||
|
||||
public getBSInstallationFolder(): string{ return this.installationFolder; }
|
||||
public setBSInstallationFolder(path: string){ this.installationFolder = path; }
|
||||
|
||||
public async getInstalledBsVersion(): Promise<BSVersion[]>{
|
||||
const versions: BSVersion[] = [];
|
||||
const steamBsFolder = await this.steamService.getGameFolder(BS_APP_ID, "Beat Saber")
|
||||
@@ -50,9 +51,9 @@ export class BSInstallerService{
|
||||
}
|
||||
}
|
||||
|
||||
if(!this.utils.folderExist(this.getBSInstallationFolder())){ return versions }
|
||||
if(!this.utils.folderExist(this.installationFolder)){ return versions }
|
||||
|
||||
const folderInInstallation = this.utils.listDirsInDir(this.getBSInstallationFolder());
|
||||
const folderInInstallation = this.utils.listDirsInDir(this.installationFolder);
|
||||
|
||||
folderInInstallation.forEach(f => {
|
||||
const version = this.bsVersionService.getVersionDetailFromVersionNumber(f);
|
||||
@@ -72,7 +73,7 @@ export class BSInstallerService{
|
||||
const bsVersion = this.bsVersionService.getVersionDetailFromVersionNumber(downloadInfos.bsVersion.BSVersion);
|
||||
if(!bsVersion){ this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`); return; }
|
||||
|
||||
this.utils.createFolderIfNotExist(this.getBSInstallationFolder());
|
||||
this.utils.createFolderIfNotExist(this.installationFolder);
|
||||
this.downloadProcess = spawn(
|
||||
this.getDepotDownloaderExePath(),
|
||||
[
|
||||
@@ -83,7 +84,7 @@ export class BSInstallerService{
|
||||
`-dir ${bsVersion.BSVersion}`,
|
||||
(downloadInfos.stay || !downloadInfos.password) && "-remember-password"
|
||||
],
|
||||
{shell: true, cwd: this.getBSInstallationFolder()}
|
||||
{shell: true, cwd: this.installationFolder}
|
||||
)
|
||||
|
||||
this.downloadProcess.stdout.on('data', async (data) => {
|
||||
|
||||
@@ -22,7 +22,7 @@ export class BSUninstallerService {
|
||||
|
||||
public async uninstall(version :BSVersion){
|
||||
if(version.steam){ throw "Cannot uninstall steam version"; }
|
||||
const versionFolder = path.join(this.bsInstallerService.getBSInstallationFolder(), version.BSVersion);
|
||||
const versionFolder = path.join(this.bsInstallerService.installationFolder, version.BSVersion);
|
||||
if(!this.utilsService.folderExist(versionFolder)){ throw "Version folder not exist"; }
|
||||
|
||||
return await this.utilsService.deleteFolder(versionFolder);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import ElectronStore from "electron-store";
|
||||
|
||||
export class ConfigurationService {
|
||||
|
||||
private static instance: ConfigurationService;
|
||||
|
||||
private readonly _store: ElectronStore;
|
||||
|
||||
public static getInstance(): ConfigurationService{
|
||||
if(!ConfigurationService.instance){ ConfigurationService.instance = new ConfigurationService(); }
|
||||
return ConfigurationService.instance;
|
||||
}
|
||||
|
||||
private constructor(){
|
||||
this._store = new ElectronStore();
|
||||
}
|
||||
|
||||
public get store(): ElectronStore{ return this._store; }
|
||||
|
||||
public set(key: string, value: any): void{
|
||||
this.store.set(key, value);
|
||||
}
|
||||
|
||||
public get(key: string): any{
|
||||
return this.store.get(key);
|
||||
}
|
||||
|
||||
public delete(key: string): void{
|
||||
this.store.delete(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import path from "path";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { UtilsService } from "./utils.service";
|
||||
import fs from 'fs-extra';
|
||||
import log from "electron-log";
|
||||
|
||||
export class InstallationLocationService {
|
||||
|
||||
private static instance: InstallationLocationService;
|
||||
|
||||
private readonly INSTALLATION_FOLDER = "BSManager";
|
||||
private readonly STORE_INSTALLATION_PATH_KEY = "installation-folder";
|
||||
|
||||
|
||||
private readonly configService: ConfigurationService;
|
||||
private readonly utilsService: UtilsService;
|
||||
|
||||
|
||||
private _installationDirectory: string;
|
||||
|
||||
public static getInstance(): InstallationLocationService{
|
||||
if(!InstallationLocationService.instance){ InstallationLocationService.instance = new InstallationLocationService(); }
|
||||
return InstallationLocationService.instance;
|
||||
}
|
||||
|
||||
private constructor(){
|
||||
this.configService = ConfigurationService.getInstance();
|
||||
this.utilsService = UtilsService.getInstance();
|
||||
this.initInstallationLocation();
|
||||
}
|
||||
|
||||
private initInstallationLocation(): void{
|
||||
this._installationDirectory = (this.configService.get(this.STORE_INSTALLATION_PATH_KEY) || this.utilsService.getUserDocumentsFolder()) as string;
|
||||
}
|
||||
|
||||
public get installationDirectory(): string{
|
||||
return path.join(this._installationDirectory, this.INSTALLATION_FOLDER);
|
||||
}
|
||||
|
||||
public setInstallationDirectory(newDir: string): Promise<string>{
|
||||
const oldDir = this.installationDirectory;
|
||||
const newDest = path.join(newDir, this.INSTALLATION_FOLDER);
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
fs.move(oldDir, newDest, { overwrite: true }).then(() => {
|
||||
this._installationDirectory = newDir;
|
||||
this.configService.store.set(this.STORE_INSTALLATION_PATH_KEY, newDir);
|
||||
resolve(this.installationDirectory);
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
log.error(err);
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import { ModalExitCode, ModalResponse } from "renderer/services/modale.service";
|
||||
import BeatConflict from "../../../../../assets/beat-conflict.png"
|
||||
|
||||
export function InstallationFolderModal({resolver}: {resolver: (x: ModalResponse) => void}) {
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className="absolute bg-gradient-to-r from-blue-500 to-red-500 top-0 w-full left-0 h-1"></span>
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">installation folder</h1>
|
||||
<BsmImage className="mx-auto h-24" image={BeatConflict}/>
|
||||
<p className="max-w-sm">Changing the default installation folder for Beat Saber instances will cause all installed data to be moved to the new folder.</p>
|
||||
<div className="grid grid-flow-col grid-cols-2 gap-4 mt-4">
|
||||
<BsmButton className="rounded-md text-center bg-gray-500 hover:brightness-110 transition-all" onClick={() => resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="Cancel"/>
|
||||
<BsmButton className="rounded-md text-center bg-blue-500 hover:brightness-110 transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED})} withBar={false} text="Choose Folder"/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { IpcResponse } from 'shared/models/ipc-models.model';
|
||||
import { DownloadInfo } from '../../main/ipcs/bs-download-ipcs';
|
||||
import { BSVersion } from '../../main/services/bs-version-manager.service'
|
||||
import { BSVersionManagerService } from './bs-version-manager.service';
|
||||
import { IpcService } from './ipc.service';
|
||||
import { ModalExitCode, ModalService, ModalType } from './modale.service';
|
||||
|
||||
export class BsDownloaderService{
|
||||
@@ -9,6 +11,7 @@ export class BsDownloaderService{
|
||||
private static instance: BsDownloaderService;
|
||||
|
||||
private readonly modalService: ModalService = ModalService.getInsance();
|
||||
private readonly ipcService: IpcService;
|
||||
private readonly bsVersionManager: BSVersionManagerService = BSVersionManagerService.getInstance();
|
||||
|
||||
public readonly currentBsVersionDownload$: BehaviorSubject<BSVersion> = new BehaviorSubject(null);
|
||||
@@ -16,6 +19,7 @@ export class BsDownloaderService{
|
||||
|
||||
public readonly selectedBsVersion$: BehaviorSubject<BSVersion> = new BehaviorSubject(null);
|
||||
|
||||
|
||||
public static getInstance(): BsDownloaderService{
|
||||
if(!BsDownloaderService.instance){ BsDownloaderService.instance = new BsDownloaderService(); }
|
||||
return BsDownloaderService.instance;
|
||||
@@ -23,6 +27,7 @@ export class BsDownloaderService{
|
||||
|
||||
private constructor(){
|
||||
this.asignListerners();
|
||||
this.ipcService = IpcService.getInstance();
|
||||
}
|
||||
|
||||
private asignListerners(): void{
|
||||
@@ -81,4 +86,13 @@ export class BsDownloaderService{
|
||||
return !!this.currentBsVersionDownload$.value || !!this.downloadProgress$.value;
|
||||
}
|
||||
|
||||
public async getInstallationFolder(): Promise<string>{
|
||||
const res = await this.ipcService.send<string>("bs-download.installation-folder");
|
||||
return res.success ? res.data : "";
|
||||
}
|
||||
|
||||
public setInstallationFolder(path: string): Promise<IpcResponse<string>>{
|
||||
return this.ipcService.send<string>("bs-download.set-installation-folder", {args: path});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ export enum ModalType {
|
||||
STEAM_LOGIN = "STEAM_LOGIN",
|
||||
GUARD_CODE = "GUARD_CODE",
|
||||
UNINSTALL = "UNINSTALL",
|
||||
INSTALLATION_FOLDER = "INSTALLATION_FOLDER",
|
||||
}
|
||||
|
||||
export enum ModalExitCode {
|
||||
|
||||
Reference in New Issue
Block a user