mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
Merge branch 'v1.5.0' into feature/playlists/107
This commit is contained in:
@@ -1,63 +1,21 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { SearchParams } from "shared/models/maps/beat-saver.model";
|
||||
import { BeatSaverService } from "../services/thrid-party/beat-saver/beat-saver.service";
|
||||
import log from "electron-log";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
|
||||
ipcMain.on("bsv-search-map", async (event, request: IpcRequest<SearchParams>) => {
|
||||
const utlis = UtilsService.getInstance();
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on("bsv-search-map", (args, reply) => {
|
||||
const bsvService = BeatSaverService.getInstance();
|
||||
|
||||
bsvService
|
||||
.searchMaps(request.args)
|
||||
.then(maps => {
|
||||
utlis.ipcSend(request.responceChannel, { success: true, data: maps });
|
||||
})
|
||||
.catch(e => {
|
||||
utlis.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
reply(from(bsvService.searchMaps(args)));
|
||||
});
|
||||
|
||||
ipcMain.on("bsv-get-map-details-from-hashs", async (event, request: IpcRequest<string[]>) => {
|
||||
const utlis = UtilsService.getInstance();
|
||||
ipc.on("bsv-get-map-details-from-hashs", (args, reply) => {
|
||||
const bsvService = BeatSaverService.getInstance();
|
||||
|
||||
bsvService
|
||||
.getMapDetailsFromHashs(request.args)
|
||||
.then(maps => {
|
||||
utlis.ipcSend(request.responceChannel, { success: true, data: maps });
|
||||
})
|
||||
.catch(e => {
|
||||
log.error(e);
|
||||
utlis.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
reply(from(bsvService.getMapDetailsFromHashs(args)));
|
||||
});
|
||||
|
||||
ipcMain.on("bsv-get-map-details-by-id", async (event, request: IpcRequest<string>) => {
|
||||
const utlis = UtilsService.getInstance();
|
||||
ipc.on("bsv-get-map-details-by-id", (args, reply) => {
|
||||
const bsvService = BeatSaverService.getInstance();
|
||||
|
||||
bsvService
|
||||
.getMapDetailsById(request.args)
|
||||
.then(maps => {
|
||||
utlis.ipcSend(request.responceChannel, { success: true, data: maps });
|
||||
})
|
||||
.catch(e => {
|
||||
utlis.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("bsv-get-playlist-details-by-id", async (event, request: IpcRequest<string>) => {
|
||||
const utlis = UtilsService.getInstance();
|
||||
const bsvService = BeatSaverService.getInstance();
|
||||
|
||||
bsvService
|
||||
.getPlaylistPage(request.args)
|
||||
.then(maps => {
|
||||
utlis.ipcSend(request.responceChannel, { success: true, data: maps });
|
||||
})
|
||||
.catch(e => {
|
||||
utlis.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
console.log("AAAAAAZEZE", args);
|
||||
reply(from(bsvService.getMapDetailsById(args)));
|
||||
});
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
|
||||
import { LaunchOption } from "shared/models/bs-launch";
|
||||
import { BSLauncherService } from "../services/bs-launcher/bs-launcher.service"
|
||||
import { IpcService } from '../services/ipc.service';
|
||||
import { from } from "rxjs";
|
||||
import { SteamLauncherService } from "../services/bs-launcher/steam-launcher.service";
|
||||
import { OculusLauncherService } from "../services/bs-launcher/oculus-launcher.service";
|
||||
import { SteamService } from "../services/steam.service";
|
||||
import log from "electron-log";
|
||||
import isElevated from "is-elevated";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on<LaunchOption>('bs-launch.launch', (req, reply) => {
|
||||
ipc.on('bs-launch.launch', (args, reply) => {
|
||||
const bsLauncher = BSLauncherService.getInstance();
|
||||
reply(bsLauncher.launch(req.args));
|
||||
reply(bsLauncher.launch(args));
|
||||
});
|
||||
|
||||
ipc.on<boolean>("bs-launch.need-start-as-admin", (_, reply) => {
|
||||
ipc.on("bs-launch.need-start-as-admin", (_, reply) => {
|
||||
const steam = SteamService.getInstance();
|
||||
reply(from(isElevated().then(elevated => {
|
||||
if(elevated){ return false; }
|
||||
@@ -27,12 +25,12 @@ ipc.on<boolean>("bs-launch.need-start-as-admin", (_, reply) => {
|
||||
})));
|
||||
});
|
||||
|
||||
ipc.on<LaunchOption>("create-launch-shortcut", (req, reply) => {
|
||||
ipc.on("create-launch-shortcut", (args, reply) => {
|
||||
const bsLauncher = BSLauncherService.getInstance();
|
||||
reply(from(bsLauncher.createLaunchShortcut(req.args)));
|
||||
reply(from(bsLauncher.createLaunchShortcut(args)));
|
||||
});
|
||||
|
||||
ipc.on<void>("bs-launch.restore-steamvr", (_, reply) => {
|
||||
ipc.on("bs-launch.restore-steamvr", (_, reply) => {
|
||||
const steamLauncher = SteamLauncherService.getInstance();
|
||||
reply(from(steamLauncher.restoreSteamVR()));
|
||||
});
|
||||
|
||||
@@ -1,119 +1,64 @@
|
||||
import { LocalMapsManagerService } from "../services/additional-content/maps/local-maps-manager.service";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
import log from "electron-log"
|
||||
import { from, of, throwError } from "rxjs";
|
||||
import { tryit } from "shared/helpers/error.helpers";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on("load-version-maps", async (request: IpcRequest<BSVersion>, reply) => {
|
||||
ipc.on("load-version-maps", (args, reply) => {
|
||||
const localMaps = LocalMapsManagerService.getInstance();
|
||||
reply(localMaps.getMaps(request.args));
|
||||
reply(localMaps.getMaps(args));
|
||||
});
|
||||
|
||||
ipc.on("verion-have-maps-linked", async (request: IpcRequest<BSVersion>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("delete-maps", (args, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
utils.ipcSend<boolean>(request.responceChannel, { success: true, data: await maps.versionIsLinked(request.args) });
|
||||
reply(maps.deleteMaps(args));
|
||||
});
|
||||
|
||||
ipc.on("link-version-maps", async (request: IpcRequest<{ version: BSVersion; keepMaps: boolean }>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("export-maps", async (args, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
maps.linkVersionMaps(request.args.version, request.args.keepMaps)
|
||||
.then(() => {
|
||||
utils.ipcSend<void>(request.responceChannel, { success: true });
|
||||
})
|
||||
.catch(err => {
|
||||
utils.ipcSend<void>(request.responceChannel, { success: true, error: err });
|
||||
});
|
||||
reply(await maps.exportMaps(args.version, args.maps, args.outPath));
|
||||
});
|
||||
|
||||
ipc.on("unlink-version-maps", async (request: IpcRequest<{ version: BSVersion; keepMaps: boolean }>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("download-map", async (args, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
maps.unlinkVersionMaps(request.args.version, request.args.keepMaps)
|
||||
.then(() => {
|
||||
utils.ipcSend<void>(request.responceChannel, { success: true });
|
||||
})
|
||||
.catch(err => {
|
||||
utils.ipcSend<void>(request.responceChannel, { success: true, error: err });
|
||||
});
|
||||
reply(from(maps.downloadMap(args.map, args.version)));
|
||||
});
|
||||
|
||||
ipc.on("delete-maps", async (request: IpcRequest<BsmLocalMap[]>, reply) => {
|
||||
ipc.on("one-click-install-map", (args, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
reply(maps.deleteMaps(request.args));
|
||||
reply(from(maps.oneClickDownloadMap(args)))
|
||||
});
|
||||
|
||||
ipc.on("export-maps", async (request: IpcRequest<{ version: BSVersion; maps: BsmLocalMap[]; outPath: string }>, reply) => {
|
||||
ipc.on("register-maps-deep-link", (_, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
reply(await maps.exportMaps(request.args.version, request.args.maps, request.args.outPath));
|
||||
});
|
||||
const { error, result } = tryit(() => maps.enableDeepLinks());
|
||||
|
||||
ipc.on("download-map", async (request: IpcRequest<{ map: BsvMapDetail; version: BSVersion }>, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
reply(from(maps.downloadMap(request.args.map, request.args.version)));
|
||||
});
|
||||
|
||||
ipc.on("one-click-install-map", async (request: IpcRequest<BsvMapDetail>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
maps.oneClickDownloadMap(request.args)
|
||||
.then(() => {
|
||||
utils.ipcSend(request.responceChannel, { success: true });
|
||||
})
|
||||
.catch(err => {
|
||||
log.error(err);
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: err });
|
||||
});
|
||||
});
|
||||
|
||||
ipc.on("register-maps-deep-link", async (request: IpcRequest<void>) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.enableDeepLinks();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
if(error) {
|
||||
return reply(throwError(() => error));
|
||||
}
|
||||
|
||||
reply(of(result));
|
||||
});
|
||||
|
||||
ipc.on("unregister-maps-deep-link", async (request: IpcRequest<void>) => {
|
||||
ipc.on("unregister-maps-deep-link", (_, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
const { error, result } = tryit(() => maps.disableDeepLinks());
|
||||
|
||||
try {
|
||||
const res = maps.disableDeepLinks();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
if(error) {
|
||||
return reply(throwError(() => error));
|
||||
}
|
||||
|
||||
reply(of(result));
|
||||
});
|
||||
|
||||
ipc.on("is-map-deep-links-enabled", async (request: IpcRequest<void>) => {
|
||||
ipc.on("is-map-deep-links-enabled", (_, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
const { error, result } = tryit(() => maps.isDeepLinksEnabled());
|
||||
|
||||
try {
|
||||
const res = maps.isDeepLinksEnabled();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
if(error) {
|
||||
return reply(throwError(() => error));
|
||||
}
|
||||
});
|
||||
|
||||
ipc.on("get-version-maps-path", async (req: IpcRequest<BSVersion>, reply) => {
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
reply(from(maps.getMapsFolderPath(req.args)));
|
||||
reply(of(result));
|
||||
});
|
||||
|
||||
@@ -1,82 +1,45 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { MSModel, MSModelType } from "shared/models/models/model-saber.model";
|
||||
import { LocalModelsManagerService } from "../services/additional-content/local-models-manager.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface";
|
||||
import { ModelDownload } from "renderer/services/models-management/models-downloader.service";
|
||||
import { from, of } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipcMain.on("one-click-install-model", async (event, request: IpcRequest<MSModel>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("one-click-install-model", (args, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
|
||||
models
|
||||
.oneClickDownloadModel(request.args)
|
||||
.then(() => {
|
||||
utils.ipcSend(request.responceChannel, { success: true });
|
||||
})
|
||||
.catch(e => {
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
reply(from(models.oneClickDownloadModel(args)));
|
||||
});
|
||||
|
||||
ipcMain.on("register-models-deep-link", async (event, request: IpcRequest<void>) => {
|
||||
ipc.on("register-models-deep-link", (_, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
reply(of(models.enableDeepLinks()));
|
||||
});
|
||||
|
||||
ipc.on("unregister-models-deep-link", (_, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
reply(of(models.disableDeepLinks()));
|
||||
});
|
||||
|
||||
ipc.on("is-models-deep-links-enabled", (_, reply) => {
|
||||
const maps = LocalModelsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.enableDeepLinks();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
}
|
||||
reply(of(maps.isDeepLinksEnabled()));
|
||||
});
|
||||
|
||||
ipcMain.on("unregister-models-deep-link", async (event, request: IpcRequest<void>) => {
|
||||
const maps = LocalModelsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.disableDeepLinks();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on("is-models-deep-links-enabled", async (event, request: IpcRequest<void>) => {
|
||||
const maps = LocalModelsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.isDeepLinksEnabled();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
}
|
||||
});
|
||||
|
||||
ipc.on<ModelDownload>("download-model", async (req, reply) => {
|
||||
ipc.on("download-model", (args, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
reply(models.downloadModel(req.args.model, req.args.version));
|
||||
reply(models.downloadModel(args.model, args.version));
|
||||
});
|
||||
|
||||
ipc.on<{ version: BSVersion; type: MSModelType }>("get-version-models", async (req, reply) => {
|
||||
ipc.on("get-version-models", (args, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
const res = await models.getModels(req.args.type, req.args.version);
|
||||
reply(res);
|
||||
reply(from(models.getModels(args.type, args.version)));
|
||||
});
|
||||
|
||||
ipc.on<{ version: BSVersion; models: BsmLocalModel[]; outPath: string }>("export-models", async (req, reply) => {
|
||||
ipc.on("export-models", (args, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
reply(models.exportModels(req.args.outPath, req.args.version, req.args.models));
|
||||
reply(models.exportModels(args.outPath, args.version, args.models));
|
||||
});
|
||||
|
||||
ipc.on<BsmLocalModel[]>("delete-models", async (req, reply) => {
|
||||
ipc.on("delete-models", (args, reply) => {
|
||||
const models = LocalModelsManagerService.getInstance();
|
||||
reply(models.deleteModels(req.args));
|
||||
reply(models.deleteModels(args));
|
||||
});
|
||||
|
||||
@@ -1,67 +1,30 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { BsModsManagerService } from "../services/mods/bs-mods-manager.service";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { Mod } from "shared/models/mods/mod.interface";
|
||||
import { InstallModsResult } from "shared/models/mods";
|
||||
import log from "electron-log";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on<BSVersion>("get-available-mods", (req, reply) => {
|
||||
ipc.on("get-available-mods", (args, reply) => {
|
||||
const modsManager = BsModsManagerService.getInstance();
|
||||
reply(from(modsManager.getAvailableMods(req.args)));
|
||||
reply(from(modsManager.getAvailableMods(args)));
|
||||
});
|
||||
|
||||
ipc.on<BSVersion>("get-installed-mods", (req, reply) => {
|
||||
ipc.on("get-installed-mods", (args, reply) => {
|
||||
const modsManager = BsModsManagerService.getInstance();
|
||||
reply(from(modsManager.getInstalledMods(req.args)));
|
||||
reply(from(modsManager.getInstalledMods(args)));
|
||||
});
|
||||
|
||||
ipcMain.on("install-mods", (event, request: IpcRequest<{ mods: Mod[]; version: BSVersion }>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("install-mods", (args, reply) => {
|
||||
const modsManager = BsModsManagerService.getInstance();
|
||||
|
||||
modsManager
|
||||
.installMods(request.args.mods, request.args.version)
|
||||
.then(nbInstalled => {
|
||||
utils.ipcSend<InstallModsResult>(request.responceChannel, { success: true, data: nbInstalled });
|
||||
})
|
||||
.catch(err => {
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: err });
|
||||
log.error("ipc", "install-mods", err, request);
|
||||
});
|
||||
reply(from(modsManager.installMods(args.mods, args.version)));
|
||||
});
|
||||
|
||||
ipcMain.on("uninstall-mods", (event, request: IpcRequest<{ mods: Mod[]; version: BSVersion }>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("uninstall-mods", (args, reply) => {
|
||||
const modsManager = BsModsManagerService.getInstance();
|
||||
|
||||
modsManager
|
||||
.uninstallMods(request.args.mods, request.args.version)
|
||||
.then(nbInstalled => {
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: nbInstalled });
|
||||
})
|
||||
.catch(err => {
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: err });
|
||||
log.error("ipc", "uninstall-mods", err, request);
|
||||
});
|
||||
reply(from(modsManager.uninstallMods(args.mods, args.version)));
|
||||
});
|
||||
|
||||
ipcMain.on("uninstall-all-mods", (event, request: IpcRequest<BSVersion>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("uninstall-all-mods", (args, reply) => {
|
||||
const modsManager = BsModsManagerService.getInstance();
|
||||
|
||||
modsManager
|
||||
.uninstallAllMods(request.args)
|
||||
.then(nbInstalled => {
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: nbInstalled });
|
||||
})
|
||||
.catch(err => {
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: err });
|
||||
log.error("ipc", "uninstall-all-mods", err, request);
|
||||
});
|
||||
reply(from(modsManager.uninstallAllMods(args)));
|
||||
});
|
||||
|
||||
@@ -1,63 +1,46 @@
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { LocalPlaylistsManagerService } from "../services/additional-content/local-playlists-manager.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { of, throwError } from "rxjs";
|
||||
import { BPList } from "shared/models/playlists/playlist.interface";
|
||||
import { of } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on<string>("one-click-install-playlist", (req, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
reply(playlists.oneClickInstallPlaylist(req.args));
|
||||
ipc.on("one-click-install-playlist", (args, reply) => {
|
||||
const mapsManager = LocalPlaylistsManagerService.getInstance();
|
||||
reply(mapsManager.oneClickInstallPlaylist(args));
|
||||
});
|
||||
|
||||
ipc.on<{playlist: BPList, version: BSVersion}>("install-playlist", (req, reply) => {
|
||||
ipc.on("register-playlists-deep-link", (args, reply) => {
|
||||
const maps = LocalPlaylistsManagerService.getInstance();
|
||||
reply(of(maps.enableDeepLinks()));
|
||||
});
|
||||
|
||||
ipc.on("unregister-playlists-deep-link", (args, reply) => {
|
||||
const maps = LocalPlaylistsManagerService.getInstance();
|
||||
reply(of(maps.disableDeepLinks()));
|
||||
});
|
||||
|
||||
ipc.on("is-playlists-deep-links-enabled", (args, reply) => {
|
||||
const maps = LocalPlaylistsManagerService.getInstance();
|
||||
reply(of(maps.isDeepLinksEnabled()));
|
||||
});
|
||||
|
||||
ipc.on("install-playlist", (args, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
|
||||
if(req.args.playlist?.customData?.syncURL){
|
||||
return reply(playlists.downloadPlaylist(req.args.playlist.customData.syncURL, req.args.version));
|
||||
if(args.playlist?.customData?.syncURL){
|
||||
return reply(playlists.downloadPlaylist(args.playlist.customData.syncURL, args.version));
|
||||
}
|
||||
|
||||
reply(playlists.downloadPlaylistSongs(req.args.playlist.songs, req.args.version));
|
||||
reply(playlists.downloadPlaylistSongs(args.playlist.songs, args.version));
|
||||
|
||||
});
|
||||
|
||||
ipc.on("register-playlists-deep-link", (_, reply) => {
|
||||
ipc.on("get-version-playlists-details", (args, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
|
||||
try {
|
||||
reply(of(playlists.enableDeepLinks()));
|
||||
} catch (e) {
|
||||
reply(throwError(() => e));
|
||||
}
|
||||
reply(playlists.getVersionPlaylistsDetails(args));
|
||||
});
|
||||
|
||||
ipc.on("unregister-playlists-deep-link", (_, reply) => {
|
||||
ipc.on("delete-playlist", (args, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
|
||||
try {
|
||||
reply(of(playlists.disableDeepLinks()));
|
||||
} catch (e) {
|
||||
reply(throwError(() => e));
|
||||
}
|
||||
});
|
||||
|
||||
ipc.on("is-playlists-deep-links-enabled", (_, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
|
||||
try {
|
||||
reply(of(playlists.isDeepLinksEnabled()));
|
||||
} catch (e) {
|
||||
reply(throwError(() => e));
|
||||
}
|
||||
});
|
||||
|
||||
ipc.on<BSVersion>("get-version-playlists-details", (req, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
reply(playlists.getVersionPlaylistsDetails(req.args));
|
||||
});
|
||||
|
||||
ipc.on<{path: string, deleteMaps?: boolean}>("delete-playlist", (req, reply) => {
|
||||
const playlists = LocalPlaylistsManagerService.getInstance();
|
||||
reply(playlists.deletePlaylist(req.args));
|
||||
reply(playlists.deletePlaylist(args));
|
||||
});
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BSLocalVersionService } from "../services/bs-local-version.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on<BSVersion>("bs.uninstall", (req, reply) => {
|
||||
ipc.on("bs.uninstall", (args, reply) => {
|
||||
const bsLocalVersionService = BSLocalVersionService.getInstance();
|
||||
|
||||
reply(from(bsLocalVersionService.deleteVersion(req.args)));
|
||||
reply(from(bsLocalVersionService.deleteVersion(args)));
|
||||
});
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { BsOculusDownloaderService } from "../../services/bs-version-download/bs-oculus-downloader.service";
|
||||
import { BsSteamDownloaderService, DownloadInfo, DownloadSteamInfo } from "../../services/bs-version-download/bs-steam-downloader.service";
|
||||
import { BsSteamDownloaderService } from "../../services/bs-version-download/bs-steam-downloader.service";
|
||||
import { InstallationLocationService } from "../../services/installation-location.service";
|
||||
import { IpcService } from "../../services/ipc.service";
|
||||
import { from, of } from "rxjs";
|
||||
import { BSLocalVersionService, ImportVersionOptions } from "../../services/bs-local-version.service";
|
||||
import { BSLocalVersionService } from "../../services/bs-local-version.service";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on<ImportVersionOptions>("import-version", (req, reply) => {
|
||||
ipc.on("import-version", (args, reply) => {
|
||||
const versionManager = BSLocalVersionService.getInstance();
|
||||
reply(versionManager.importVersion(req.args));
|
||||
reply(versionManager.importVersion(args));
|
||||
});
|
||||
|
||||
// #region Steam
|
||||
// #region Steam
|
||||
|
||||
ipc.on("is-dotnet-6-installed", (_, reply) => {
|
||||
const installer = BsSteamDownloaderService.getInstance();
|
||||
@@ -24,24 +24,24 @@ ipc.on("bs-download.installation-folder", (_, reply) => {
|
||||
reply(from(installLocation.installationDirectory()));
|
||||
});
|
||||
|
||||
ipc.on<string>("bs-download.set-installation-folder", (req, reply) => {
|
||||
ipc.on("bs-download.set-installation-folder", (args, reply) => {
|
||||
const installerService = InstallationLocationService.getInstance();
|
||||
reply(from(installerService.setInstallationDirectory(req.args)));
|
||||
reply(from(installerService.setInstallationDirectory(args)));
|
||||
});
|
||||
|
||||
ipc.on<DownloadSteamInfo>("auto-download-bs-version", (req, reply) => {
|
||||
ipc.on("auto-download-bs-version", (args, reply) => {
|
||||
const bsInstaller = BsSteamDownloaderService.getInstance();
|
||||
reply(bsInstaller.autoDownloadBsVersion(req.args));
|
||||
reply(bsInstaller.autoDownloadBsVersion(args));
|
||||
});
|
||||
|
||||
ipc.on<DownloadSteamInfo>("download-bs-version", (req, reply) => {
|
||||
ipc.on("download-bs-version", (args, reply) => {
|
||||
const bsInstaller = BsSteamDownloaderService.getInstance();
|
||||
reply(bsInstaller.downloadBsVersion(req.args))
|
||||
reply(bsInstaller.downloadBsVersion(args))
|
||||
});
|
||||
|
||||
ipc.on<DownloadSteamInfo>("download-bs-version-qr", (req, reply) => {
|
||||
ipc.on("download-bs-version-qr", (args, reply) => {
|
||||
const bsInstaller = BsSteamDownloaderService.getInstance();
|
||||
reply(bsInstaller.downloadBsVersionWithQRCode(req.args))
|
||||
reply(bsInstaller.downloadBsVersionWithQRCode(args))
|
||||
});
|
||||
|
||||
ipc.on("stop-download-bs-version", (_, reply) => {
|
||||
@@ -49,23 +49,18 @@ ipc.on("stop-download-bs-version", (_, reply) => {
|
||||
reply(of(bsInstaller.stopDownload()));
|
||||
});
|
||||
|
||||
ipc.on<string>("send-input-bs-download", (req, reply) => {
|
||||
ipc.on("send-input-bs-download", (args, reply) => {
|
||||
const bsInstaller = BsSteamDownloaderService.getInstance();
|
||||
reply(of(bsInstaller.sendInput(req.args)));
|
||||
reply(of(bsInstaller.sendInput(args)));
|
||||
});
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Oculus
|
||||
|
||||
ipc.on<DownloadInfo>("bs-oculus-download", async (req, reply) => {
|
||||
ipc.on("bs-oculus-download", async (args, reply) => {
|
||||
const oculusDownloader = BsOculusDownloaderService.getInstance();
|
||||
reply(oculusDownloader.downloadVersion(req.args));
|
||||
});
|
||||
|
||||
ipc.on<DownloadInfo>("bs-oculus-auto-download", async (req, reply) => {
|
||||
const oculusDownloader = BsOculusDownloaderService.getInstance();
|
||||
reply(oculusDownloader.autoDownloadVersion(req.args));
|
||||
reply(oculusDownloader.downloadVersion(args));
|
||||
});
|
||||
|
||||
ipc.on("bs-oculus-stop-download", async (_, reply) => {
|
||||
@@ -73,14 +68,4 @@ ipc.on("bs-oculus-stop-download", async (_, reply) => {
|
||||
reply(of(oculusDownloader.stopDownload()));
|
||||
});
|
||||
|
||||
ipc.on("bs-oculus-has-auth-token", async (_, reply) => {
|
||||
const oculusDownloader = BsOculusDownloaderService.getInstance();
|
||||
reply(from(oculusDownloader.getAuthToken().then(token => !!token)));
|
||||
});
|
||||
|
||||
ipc.on("bs-oculus-clear-auth-token", async (_, reply) => {
|
||||
const oculusDownloader = BsOculusDownloaderService.getInstance();
|
||||
reply(from(oculusDownloader.clearAuthToken()));
|
||||
});
|
||||
|
||||
// #endregion
|
||||
// #endregion
|
||||
|
||||
@@ -1,173 +1,69 @@
|
||||
import { ipcMain, shell } from "electron";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { shell } from "electron";
|
||||
import { BSVersionLibService } from "../services/bs-version-lib.service";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { BSLocalVersionService } from "../services/bs-local-version.service";
|
||||
import { BsmException } from "shared/models/bsm-exception.model";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
import path from "path";
|
||||
import { pathExist } from "../helpers/fs.helpers";
|
||||
import { FolderLinkerService, LinkOptions } from "../services/folder-linker.service";
|
||||
import { LocalMapsManagerService } from "../services/additional-content/maps/local-maps-manager.service";
|
||||
import { readJSON, writeJSON } from "fs-extra";
|
||||
import log from "electron-log";
|
||||
import { VersionLinkerAction } from "renderer/services/version-folder-linker.service";
|
||||
import { pathExists } from "fs-extra";
|
||||
import { VersionFolderLinkerService } from "../services/version-folder-linker.service";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipcMain.on("bs-version.get-version-dict", (_event, req: IpcRequest<void>) => {
|
||||
BSVersionLibService.getInstance()
|
||||
.getAvailableVersions()
|
||||
.then(versions => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: true, data: versions });
|
||||
})
|
||||
.catch(() => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: false });
|
||||
});
|
||||
ipc.on("bs-version.get-version-dict", (_, reply) => {
|
||||
const versionsLib = BSVersionLibService.getInstance();
|
||||
reply(from(versionsLib.getAvailableVersions()));
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.installed-versions", async (_event, req: IpcRequest<void>) => {
|
||||
BSLocalVersionService.getInstance()
|
||||
.getInstalledVersions()
|
||||
.then(versions => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: true, data: versions });
|
||||
})
|
||||
.catch(() => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: false });
|
||||
});
|
||||
ipc.on("bs-version.installed-versions", (_, reply) => {
|
||||
const versions = BSLocalVersionService.getInstance();
|
||||
reply(from(versions.getInstalledVersions()));
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.open-folder", async (_event, req: IpcRequest<BSVersion>) => {
|
||||
const localVersionService = BSLocalVersionService.getInstance();
|
||||
const versionFolder = await localVersionService.getVersionPath(req.args);
|
||||
if (!(await pathExist(versionFolder))) return;
|
||||
shell.openPath(versionFolder);
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.edit", async (__event, req: IpcRequest<{ version: BSVersion; name: string; color: string }>) => {
|
||||
BSLocalVersionService.getInstance()
|
||||
.editVersion(req.args.version, req.args.name, req.args.color)
|
||||
.then(res => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: !!res, data: res });
|
||||
})
|
||||
.catch((error: BsmException) => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: false, error });
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.clone", async (_event, req: IpcRequest<{ version: BSVersion; name: string; color: string }>) => {
|
||||
BSLocalVersionService.getInstance()
|
||||
.cloneVersion(req.args.version, req.args.name, req.args.color)
|
||||
.then(res => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: !!res, data: res });
|
||||
})
|
||||
.catch((error: BsmException) => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, { success: false, error });
|
||||
});
|
||||
});
|
||||
|
||||
ipc.on("get-version-full-path", async (req: IpcRequest<BSVersion>, reply) => {
|
||||
const localVersions = BSLocalVersionService.getInstance();
|
||||
reply(from(localVersions.getVersionPath(req.args)));
|
||||
});
|
||||
|
||||
ipc.on("relative-version-path-to-full", async (req: IpcRequest<{ version: BSVersion; relative: string }>, reply) => {
|
||||
path.isAbsolute(req.args.relative) && reply(from(Promise.resolve(req.args.relative)));
|
||||
|
||||
const localVersions = BSLocalVersionService.getInstance();
|
||||
const promise = localVersions
|
||||
.getVersionPath(req.args.version)
|
||||
.catch(() => null)
|
||||
.then(versionPath => {
|
||||
return path.join(versionPath, req.args.relative);
|
||||
});
|
||||
ipc.on("bs-version.open-folder", (args, reply) => {
|
||||
const versions = BSLocalVersionService.getInstance();
|
||||
const promise = versions.getVersionPath(args).then(versionFolder => {
|
||||
if(!versionFolder || !pathExists(versionFolder)) return;
|
||||
shell.openPath(versionFolder);
|
||||
})
|
||||
reply(from(promise));
|
||||
});
|
||||
|
||||
ipc.on("full-version-path-to-relative", async (req: IpcRequest<{ version: BSVersion; fullPath: string }>, reply) => {
|
||||
ipc.on("bs-version.edit", (args, reply) => {
|
||||
const versions = BSLocalVersionService.getInstance();
|
||||
reply(from(versions.editVersion(args.version, args.name, args.color)));
|
||||
});
|
||||
|
||||
ipc.on("bs-version.clone", (args, reply) => {
|
||||
const versions = BSLocalVersionService.getInstance();
|
||||
reply(from(versions.cloneVersion(args.version, args.name, args.color)));
|
||||
});
|
||||
|
||||
ipc.on("get-version-full-path", (args, reply) => {
|
||||
const localVersions = BSLocalVersionService.getInstance();
|
||||
const promise = localVersions
|
||||
.getVersionPath(req.args.version)
|
||||
.catch(() => null)
|
||||
.then(versionPath => {
|
||||
return path.relative(versionPath, req.args.fullPath);
|
||||
});
|
||||
reply(from(promise));
|
||||
reply(from(localVersions.getVersionPath(args)));
|
||||
});
|
||||
|
||||
ipc.on("get-linked-folders", async (req: IpcRequest<{ version: BSVersion; options?: { relative?: boolean } }>, reply) => {
|
||||
ipc.on("full-version-path-to-relative", (args, reply) => {
|
||||
const localVersions = BSLocalVersionService.getInstance();
|
||||
reply(from(localVersions.getVersionPath(args.version).then(versionPath => path.relative(versionPath, args.fullPath))));
|
||||
});
|
||||
|
||||
ipc.on("get-linked-folders", (args, reply) => {
|
||||
const versionLinker = VersionFolderLinkerService.getInstance();
|
||||
reply(from(versionLinker.getLinkedFolders(req.args.version, req.args.options)));
|
||||
reply(from(versionLinker.getLinkedFolders(args.version, args.options)));
|
||||
});
|
||||
|
||||
ipc.on("link-folder", async (req: IpcRequest<{ folder: string; options?: LinkOptions }>, reply) => {
|
||||
req.args.options ??= {};
|
||||
|
||||
const linker = FolderLinkerService.getInstance();
|
||||
|
||||
const relativeMapsFolder = path.join(LocalMapsManagerService.LEVELS_ROOT_FOLDER, LocalMapsManagerService.CUSTOM_LEVELS_FOLDER);
|
||||
|
||||
if (req.args.folder.includes(relativeMapsFolder)) {
|
||||
return reply(from(linker.linkFolder(req.args.folder, { keepContents: req.args.options?.keepContents, intermediateFolder: LocalMapsManagerService.SHARED_MAPS_FOLDER })));
|
||||
}
|
||||
|
||||
if (req.args.folder.includes("UserData")) {
|
||||
req.args.options = { ...req.args.options, backup: true };
|
||||
}
|
||||
|
||||
const res = from(linker.linkFolder(req.args.folder, req.args.options));
|
||||
|
||||
const jsonIPAPath = path.join(req.args.folder, "Beat Saber IPA.json");
|
||||
|
||||
if (!(await pathExist(jsonIPAPath))) {
|
||||
return reply(res);
|
||||
}
|
||||
|
||||
await res.toPromise();
|
||||
|
||||
try {
|
||||
const ipaData = (await readJSON(jsonIPAPath)) ?? ({} as any);
|
||||
ipaData.YeetMods = false;
|
||||
await writeJSON(jsonIPAPath, ipaData, { spaces: 4 });
|
||||
} catch (e) {
|
||||
log.error("Disable YeetMods", e);
|
||||
}
|
||||
|
||||
reply(res);
|
||||
});
|
||||
|
||||
ipc.on("link-version-folder-action", async (req: IpcRequest<VersionLinkerAction>, reply) => {
|
||||
ipc.on("link-version-folder-action", (args, reply) => {
|
||||
const versionLinker = VersionFolderLinkerService.getInstance();
|
||||
reply(from(versionLinker.doAction(req.args)));
|
||||
reply(from(versionLinker.doAction(args)));
|
||||
});
|
||||
|
||||
ipc.on("is-version-folder-linked", async (req: IpcRequest<{ version: BSVersion; relativeFolder: string }>, reply) => {
|
||||
ipc.on("is-version-folder-linked", (args, reply) => {
|
||||
const versionLinker = VersionFolderLinkerService.getInstance();
|
||||
reply(from(versionLinker.isFolderLinked(req.args.version, req.args.relativeFolder)));
|
||||
reply(from(versionLinker.isFolderLinked(args.version, args.relativeFolder)));
|
||||
});
|
||||
|
||||
ipc.on("unlink-folder", async (req: IpcRequest<{ folder: string; options?: LinkOptions }>, reply) => {
|
||||
req.args.options ??= {};
|
||||
|
||||
const linker = FolderLinkerService.getInstance();
|
||||
|
||||
const relativeMapsFolder = path.join(LocalMapsManagerService.LEVELS_ROOT_FOLDER, LocalMapsManagerService.CUSTOM_LEVELS_FOLDER);
|
||||
|
||||
if (req.args.folder.includes(relativeMapsFolder)) {
|
||||
return reply(from(linker.unlinkFolder(req.args.folder, { ...req.args.options, intermediateFolder: LocalMapsManagerService.SHARED_MAPS_FOLDER })));
|
||||
}
|
||||
|
||||
if (req.args.folder.includes("UserData")) {
|
||||
req.args.options = { ...req.args.options, backup: true };
|
||||
}
|
||||
|
||||
reply(from(linker.unlinkFolder(req.args.folder, req.args.options)));
|
||||
});
|
||||
|
||||
ipc.on("relink-all-versions-folders", async (req: IpcRequest<void>, reply) => {
|
||||
ipc.on("relink-all-versions-folders", (_, reply) => {
|
||||
const versionLinker = VersionFolderLinkerService.getInstance();
|
||||
reply(from(versionLinker.relinkAllVersionsFolders()));
|
||||
});
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { AutoUpdaterService } from "../services/auto-updater.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
import { from, of } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipcMain.on("download-update", async (event, request: IpcRequest<void>) => {
|
||||
ipc.on("download-update", (_, reply) => {
|
||||
const updaterService = AutoUpdaterService.getInstance();
|
||||
const utilsService = UtilsService.getInstance();
|
||||
|
||||
updaterService
|
||||
.downloadUpdate()
|
||||
.then(res => utilsService.ipcSend(request.responceChannel, { success: res }))
|
||||
.catch(() => utilsService.ipcSend(request.responceChannel, { success: false }));
|
||||
reply(from(updaterService.downloadUpdate()));
|
||||
});
|
||||
|
||||
ipc.on("check-update", (_, reply) => {
|
||||
@@ -22,7 +14,7 @@ ipc.on("check-update", (_, reply) => {
|
||||
reply(from(updaterService.isUpdateAvailable()));
|
||||
});
|
||||
|
||||
ipcMain.on("install-update", async (event, request: IpcRequest<void>) => {
|
||||
ipc.on("install-update", (_, reply) => {
|
||||
const updaterService = AutoUpdaterService.getInstance();
|
||||
updaterService.quitAndInstall();
|
||||
reply(of(updaterService.quitAndInstall()));
|
||||
});
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { ModelSaberService } from "../services/thrid-party/model-saber/model-saber.service";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { MSGetQuery } from "shared/models/models/model-saber.model";
|
||||
import { from } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipcMain.on("ms-get-model-by-id", async (event, request: IpcRequest<string | number>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("ms-get-model-by-id", (args, reply) => {
|
||||
const ms = ModelSaberService.getInstance();
|
||||
|
||||
ms.getModelById(request.args)
|
||||
.then(model => {
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: model });
|
||||
})
|
||||
.catch(e => {
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
reply(from(ms.getModelById(args)));
|
||||
});
|
||||
|
||||
ipc.on<MSGetQuery>("search-models", async (req, reply) => {
|
||||
ipc.on("search-models", async (args, reply) => {
|
||||
const ms = ModelSaberService.getInstance();
|
||||
reply(ms.searchModels(req.args));
|
||||
reply(ms.searchModels(args));
|
||||
});
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { ipcMain, shell, dialog, app, BrowserWindow } from "electron";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
|
||||
import { shell, dialog, app, BrowserWindow } from "electron";
|
||||
import { NotificationService } from "../services/notification.service";
|
||||
import { SteamService } from "../services/steam.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from, of } from "rxjs";
|
||||
|
||||
@@ -11,53 +7,37 @@ import { from, of } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipcMain.on("new-window", (event, request: IpcRequest<string>) => {
|
||||
shell.openExternal(request.args);
|
||||
ipc.on("new-window", (args, reply) => {
|
||||
reply(from(shell.openExternal(args)));
|
||||
});
|
||||
|
||||
ipc.on<string>("choose-folder", (req, reply) => {
|
||||
reply(from(dialog.showOpenDialog({ properties: ["openDirectory"], defaultPath: req.args ?? "" })));
|
||||
ipc.on("choose-folder", (args, reply) => {
|
||||
reply(from(dialog.showOpenDialog({ properties: ["openDirectory"], defaultPath: args ?? "" })));
|
||||
});
|
||||
|
||||
ipc.on<string>("view-path-in-explorer", (req, reply) => {
|
||||
reply(of(shell.showItemInFolder(req.args)));
|
||||
ipc.on("window.progression",(args, reply, sender) => {
|
||||
BrowserWindow.fromWebContents(sender)?.setProgressBar(args / 100);
|
||||
reply(of(undefined));
|
||||
});
|
||||
|
||||
ipcMain.on("window.progression", async (event, request: IpcRequest<number>) => {
|
||||
BrowserWindow.fromWebContents(event.sender)?.setProgressBar(request.args / 100);
|
||||
});
|
||||
|
||||
ipcMain.on("save-file", async (event, request: IpcRequest<{ filename?: string; filters?: Electron.FileFilter[] }>) => {
|
||||
dialog.showSaveDialog({ properties: ["showOverwriteConfirmation"], defaultPath: request.args.filename, filters: request.args.filters }).then(res => {
|
||||
const utils = UtilsService.getInstance();
|
||||
ipc.on("save-file", (args, reply) => {
|
||||
reply(from(dialog.showSaveDialog({ properties: ["showOverwriteConfirmation"], defaultPath: args.filename, filters: args.filters }).then(res => {
|
||||
if (res.canceled || !res.filePath) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
throw new Error("No file path selected");
|
||||
}
|
||||
UtilsService.getInstance().ipcSend(request.responceChannel, { success: true, data: res.filePath });
|
||||
});
|
||||
return res.filePath;
|
||||
})));
|
||||
});
|
||||
|
||||
ipc.on("current-version", (_, reply) => {
|
||||
reply(of(app.getVersion()));
|
||||
});
|
||||
|
||||
ipcMain.on("open-logs", async (event, request: IpcRequest<void>) => {
|
||||
shell.openPath(app.getPath("logs"));
|
||||
ipc.on("open-logs", (_, reply) => {
|
||||
reply(from(shell.openPath(app.getPath("logs"))));
|
||||
});
|
||||
|
||||
ipcMain.on("notify-system", async (event, request: IpcRequest<SystemNotificationOptions>) => {
|
||||
NotificationService.getInstance().notify(request.args);
|
||||
});
|
||||
|
||||
ipcMain.on("open-steam", async (event, request: IpcRequest<void>) => {
|
||||
const steam = SteamService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
steam
|
||||
.openSteam()
|
||||
.then(res => {
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
})
|
||||
.catch(e => {
|
||||
utils.ipcSend(request.responceChannel, { success: false, error: e });
|
||||
});
|
||||
ipc.on("notify-system", (args, reply) => {
|
||||
const systemNotification = NotificationService.getInstance();
|
||||
reply(of(systemNotification.notify(args)));
|
||||
});
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { SupportersService } from "../services/supporters.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
|
||||
ipcMain.on("get-supporters", (event, request: IpcRequest<void>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
ipc.on("get-supporters", (_, reply) => {
|
||||
const supportersService = SupportersService.getInstance();
|
||||
|
||||
supportersService
|
||||
.getSupporters()
|
||||
.then(supporters => {
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: supporters });
|
||||
})
|
||||
.catch(() => {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
});
|
||||
reply(from(supportersService.getSupporters()));
|
||||
});
|
||||
|
||||
@@ -1,40 +1,39 @@
|
||||
import { WindowManagerService } from "../services/window-manager.service";
|
||||
import { AppWindow } from "shared/models/window-manager/app-window.model";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { from } from "rxjs";
|
||||
import { BrowserWindow, ipcMain } from "electron";
|
||||
import { from, of } from "rxjs";
|
||||
import { BrowserWindow } from "electron";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
// Native windows control, do not pass through IPC service
|
||||
ipcMain.on("close-window", async (event) => {
|
||||
BrowserWindow.fromWebContents(event.sender)?.close();
|
||||
ipc.on("close-window", (_, reply, sender) => {
|
||||
reply(of(BrowserWindow.fromWebContents(sender)?.close()));
|
||||
});
|
||||
|
||||
ipcMain.on("maximise-window", async (event) => {
|
||||
BrowserWindow.fromWebContents(event.sender)?.maximize();
|
||||
ipc.on("maximise-window", (_, reply, sender) => {
|
||||
reply(of(BrowserWindow.fromWebContents(sender)?.maximize()));
|
||||
});
|
||||
|
||||
ipcMain.on("minimise-window", async (event) => {
|
||||
BrowserWindow.fromWebContents(event.sender)?.minimize();
|
||||
ipc.on("minimise-window", (_, reply, sender) => {
|
||||
reply(of(BrowserWindow.fromWebContents(sender)?.minimize()));
|
||||
});
|
||||
|
||||
ipcMain.on("unmaximise-window", async (event) => {
|
||||
BrowserWindow.fromWebContents(event.sender)?.unmaximize();
|
||||
ipc.on("unmaximise-window", (_, reply, sender) => {
|
||||
reply(of(BrowserWindow.fromWebContents(sender)?.unmaximize()));
|
||||
});
|
||||
|
||||
|
||||
ipc.on<AppWindow>("open-window-then-close-all", (req, reply) => {
|
||||
ipc.on("open-window-then-close-all", (args, reply) => {
|
||||
const windowManager = WindowManagerService.getInstance();
|
||||
|
||||
const res = windowManager.openWindow(req.args).then(() => {
|
||||
windowManager.closeAllWindows(req.args);
|
||||
const res = windowManager.openWindow(args).then(() => {
|
||||
windowManager.closeAllWindows(args);
|
||||
});
|
||||
|
||||
reply(from(res));
|
||||
});
|
||||
|
||||
ipc.on<AppWindow>("open-window-or-focus", (req, reply) => {
|
||||
ipc.on("open-window-or-focus", (args, reply) => {
|
||||
const windowManager = WindowManagerService.getInstance();
|
||||
reply(from(windowManager.openWindowOrFocus(req.args)));
|
||||
reply(from(windowManager.openWindowOrFocus(args)));
|
||||
});
|
||||
|
||||
+1
-8
@@ -26,12 +26,5 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
join: (...args: string[]): string => {
|
||||
return args.join(sep);
|
||||
}
|
||||
},
|
||||
window: {
|
||||
close: () => { ipcRenderer.send("close-window"); },
|
||||
minimise: () => { ipcRenderer.send("minimise-window"); },
|
||||
maximise: () => { ipcRenderer.send("maximise-window"); },
|
||||
unmaximise: () => { ipcRenderer.send("unmaximise-window"); },
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,14 +11,13 @@ import sanitize from "sanitize-filename";
|
||||
import { Progression, ensureFolderExist, unlinkPath } from "../../helpers/fs.helpers";
|
||||
import { MODEL_FILE_EXTENSIONS, MODEL_TYPES, MODEL_TYPE_FOLDERS } from "../../../shared/models/models/constants";
|
||||
import { InstallationLocationService } from "../installation-location.service";
|
||||
import { Observable, Subscription, lastValueFrom, of } from "rxjs";
|
||||
import { Observable, Subscription, lastValueFrom } from "rxjs";
|
||||
import { readdir } from "fs/promises";
|
||||
import md5File from "md5-file";
|
||||
import { allSettled } from "../../../shared/helpers/promise.helpers";
|
||||
import { ModelSaberService } from "../thrid-party/model-saber/model-saber.service";
|
||||
import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface";
|
||||
import { Archive } from "../../models/archive.class";
|
||||
import { IpcService } from "../ipc.service";
|
||||
|
||||
export class LocalModelsManagerService {
|
||||
private static instance: LocalModelsManagerService;
|
||||
@@ -40,7 +39,6 @@ export class LocalModelsManagerService {
|
||||
private readonly installPaths: InstallationLocationService;
|
||||
private readonly request: RequestService;
|
||||
private readonly modelSaber: ModelSaberService;
|
||||
private readonly ipc: IpcService;
|
||||
|
||||
private constructor() {
|
||||
this.deepLink = DeepLinkService.getInstance();
|
||||
@@ -49,26 +47,14 @@ export class LocalModelsManagerService {
|
||||
this.request = RequestService.getInstance();
|
||||
this.installPaths = InstallationLocationService.getInstance();
|
||||
this.modelSaber = ModelSaberService.getInstance();
|
||||
this.ipc = IpcService.getInstance();
|
||||
|
||||
this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.ModelSaber, link => {
|
||||
log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.ModelSaber, link);
|
||||
const url = new URL(link);
|
||||
|
||||
const type = url.host;
|
||||
const url = new URL(link);
|
||||
const id = url.pathname.replace("/", "").split("/").at(0);
|
||||
|
||||
this.openOneClickDownloadModelWindow(id, type);
|
||||
});
|
||||
}
|
||||
|
||||
private openOneClickDownloadModelWindow(id: string, type: string) {
|
||||
this.windows.openWindow("oneclick-download-model.html").then(window => {
|
||||
|
||||
this.ipc.once("one-click-model-info", (_, reply) => {
|
||||
reply(of({ id, type }));
|
||||
}, window.webContents.ipc);
|
||||
|
||||
this.windows.openWindow(`oneclick-download-model.html?modelId=${id}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ export class LocalPlaylistsManagerService {
|
||||
log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link);
|
||||
const url = new URL(link);
|
||||
const bplistUrl = url.host === "playlist" ? url.pathname.replace("/", "") : "";
|
||||
this.openOneClickDownloadPlaylistWindow(bplistUrl);
|
||||
this.windows.openWindow(`oneclick-download-playlist.html?playlistUrl=${bplistUrl}`);
|
||||
});
|
||||
|
||||
this.fileAssociation.registerFileAssociation(".bplist", filePath => {
|
||||
|
||||
@@ -14,18 +14,18 @@ import sanitize from "sanitize-filename";
|
||||
import { DeepLinkService } from "../../deep-link.service";
|
||||
import log from "electron-log";
|
||||
import { WindowManagerService } from "../../window-manager.service";
|
||||
import { Observable, lastValueFrom, of } from "rxjs";
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { Archive } from "../../../models/archive.class";
|
||||
import { deleteFolder, ensureFolderExist, getFilesInFolder, getFoldersInFolder, pathExist } from "../../../helpers/fs.helpers";
|
||||
import { Progression, deleteFolder, ensureFolderExist, getFilesInFolder, getFoldersInFolder, pathExist } from "../../../helpers/fs.helpers";
|
||||
import { readFile } from "fs/promises";
|
||||
import { FolderLinkerService } from "../../folder-linker.service";
|
||||
import { allSettled } from "../../../../shared/helpers/promise.helpers";
|
||||
import { splitIntoChunk } from "../../../../shared/helpers/array.helpers";
|
||||
import { IpcService } from "../../ipc.service";
|
||||
import { SongDetailsCacheService } from "./song-details-cache.service";
|
||||
import { sToMs } from "shared/helpers/time.helpers";
|
||||
import { SongCacheService } from "./song-cache.service";
|
||||
import { IpcService } from "../../ipc.service";
|
||||
import { pathToFileURL } from "url";
|
||||
import { sToMs } from "../../../../shared/helpers/time.helpers";
|
||||
|
||||
export class LocalMapsManagerService {
|
||||
private static instance: LocalMapsManagerService;
|
||||
@@ -53,10 +53,10 @@ export class LocalMapsManagerService {
|
||||
private readonly reqService: RequestService;
|
||||
private readonly deepLink: DeepLinkService;
|
||||
private readonly windows: WindowManagerService;
|
||||
private readonly ipc: IpcService;
|
||||
private readonly linker: FolderLinkerService;
|
||||
private readonly songDetailsCache: SongDetailsCacheService;
|
||||
private readonly songCache: SongCacheService;
|
||||
private readonly ipc: IpcService;
|
||||
|
||||
private constructor() {
|
||||
this.localVersion = BSLocalVersionService.getInstance();
|
||||
@@ -66,18 +66,22 @@ export class LocalMapsManagerService {
|
||||
this.deepLink = DeepLinkService.getInstance();
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
this.linker = FolderLinkerService.getInstance();
|
||||
this.ipc = IpcService.getInstance();
|
||||
this.songDetailsCache = SongDetailsCacheService.getInstance();
|
||||
this.songCache = SongCacheService.getInstance();
|
||||
this.ipc = IpcService.getInstance();
|
||||
|
||||
const handleOneClick = (mapId: string, isHash = false) => {
|
||||
this.windows.openWindow(`oneclick-download-map.html?mapId=${mapId}&isHash=${isHash}`);
|
||||
}
|
||||
|
||||
this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.BeatSaver, link => {
|
||||
log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link);
|
||||
this.openOneClickDownloadMapWindow(new URL(link).host);
|
||||
handleOneClick(new URL(link).host);
|
||||
});
|
||||
|
||||
this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.ScoreSaber, link => {
|
||||
log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.ScoreSaber, link);
|
||||
this.openOneClickDownloadMapWindow(new URL(link).host, true);
|
||||
handleOneClick(new URL(link).host, true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -157,14 +161,6 @@ export class LocalMapsManagerService {
|
||||
return { zip, zipPath };
|
||||
}
|
||||
|
||||
private openOneClickDownloadMapWindow(mapId: string, isHash = false): void {
|
||||
this.windows.openWindow("oneclick-download-map.html").then(window => {
|
||||
this.ipc.once("one-click-map-info", async (_, reply) => {
|
||||
reply(of({ id: mapId, isHash }));
|
||||
}, window.webContents.ipc);
|
||||
});
|
||||
}
|
||||
|
||||
public getMaps(version?: BSVersion): Observable<BsmLocalMapsProgress> {
|
||||
const progression: BsmLocalMapsProgress = {
|
||||
total: 0,
|
||||
@@ -307,7 +303,7 @@ export class LocalMapsManagerService {
|
||||
return localMap;
|
||||
}
|
||||
|
||||
public async exportMaps(version: BSVersion, maps: BsmLocalMap[], outPath: string) {
|
||||
public async exportMaps(version: BSVersion, maps: BsmLocalMap[], outPath: string): Promise<Observable<Progression>> {
|
||||
const archive = new Archive(outPath);
|
||||
|
||||
if (!maps || maps.length === 0) {
|
||||
|
||||
@@ -128,7 +128,7 @@ export class BSLauncherService {
|
||||
}
|
||||
|
||||
private createShortcutPngBuffer(color: Color): Promise<Buffer>{
|
||||
|
||||
|
||||
const svgBuffer = Buffer.from(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406.4 406.4" height="406.4" width="406.4">
|
||||
<rect rx="69.453" height="406.4" width="406.4" fill="${color.hex()}"/>
|
||||
@@ -141,8 +141,8 @@ export class BSLauncherService {
|
||||
|
||||
/**
|
||||
* Create .png file for the shortcut with the given color
|
||||
* @param {Color} color
|
||||
* @returns {Promise<string>} Path of the icon
|
||||
* @param {Color} color
|
||||
* @returns {Promise<string>} Path of the icon
|
||||
*/
|
||||
private async createShortcutPng(color: Color): Promise<string>{
|
||||
const pngBuffer = this.createShortcutPngBuffer(color);
|
||||
@@ -211,25 +211,25 @@ export class BSLauncherService {
|
||||
const bsPath: string = await (async () => {
|
||||
const bsPath = await this.localVersionService.getInstalledVersionPath(launchOption.version);
|
||||
return bsPath ?? this.localVersionService.getVersionPath(launchOption.version);
|
||||
})().catch(e => {
|
||||
log.error(e);
|
||||
})().catch(e => {
|
||||
log.error(e);
|
||||
return null;
|
||||
});
|
||||
|
||||
launchOption.version = (await this.localVersionService.getVersionOfBSFolder(bsPath, {
|
||||
steam: launchOption.version.steam,
|
||||
oculus: launchOption.version.oculus,
|
||||
oculus: launchOption.version.oculus,
|
||||
})) ?? launchOption.version;
|
||||
|
||||
launchOption.version = {...(await this.remoteVersion.getVersionDetails(launchOption.version.BSVersion)), ...launchOption.version};
|
||||
|
||||
this.ipc.once("shortcut-launch-options", (_data, reply) => {
|
||||
|
||||
this.ipc.once("shortcut-launch-options", (_, reply) => {
|
||||
reply(of(launchOption));
|
||||
});
|
||||
|
||||
this.windows.openWindow("shortcut-launch.html");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
type ShortcutParams = {
|
||||
@@ -246,9 +246,9 @@ type ShortcutParams = {
|
||||
|
||||
/**
|
||||
* Create .desktop file for url shortcut (only for linux)
|
||||
* @param {string} shortcutPath
|
||||
* @param options
|
||||
* @returns
|
||||
* @param {string} shortcutPath
|
||||
* @param options
|
||||
* @returns
|
||||
*/
|
||||
function createDesktopUrlShortcut(shortcutPath: string, options?: {
|
||||
url: string
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { BSVersion } from "../../../shared/bs-version.interface";
|
||||
import { WindowManagerService } from "../window-manager.service";
|
||||
import { minToMs, msToS } from "../../../shared/helpers/time.helpers";
|
||||
import log from "electron-log";
|
||||
import { CustomError } from "../../../shared/models/exceptions/custom-error.class";
|
||||
import { OculusDownloader } from "../../models/oculus-downloader.class";
|
||||
import { Cookie, session } from "electron";
|
||||
import { Progression, ensurePathNotAlreadyExist } from "../../helpers/fs.helpers";
|
||||
import { BSLocalVersionService } from "../bs-local-version.service";
|
||||
import { Observable, finalize, from, map, of, switchMap } from "rxjs";
|
||||
import { Observable, finalize, map, of, switchMap } from "rxjs";
|
||||
import path from "path";
|
||||
import { DownloadInfo } from "./bs-steam-downloader.service";
|
||||
import { BsStore } from "../../../shared/models/bs-store.enum";
|
||||
@@ -26,90 +22,19 @@ export class BsOculusDownloaderService {
|
||||
}
|
||||
|
||||
private readonly oculusDownloader: OculusDownloader;
|
||||
|
||||
private readonly windows: WindowManagerService;
|
||||
private readonly versions: BSLocalVersionService;
|
||||
|
||||
private constructor() {
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
this.versions = BSLocalVersionService.getInstance();
|
||||
|
||||
this.oculusDownloader = new OculusDownloader();
|
||||
}
|
||||
|
||||
private isUserTokenValid(token: string): boolean{
|
||||
return isOculusTokenValid(token, log.info);
|
||||
}
|
||||
|
||||
private isCookieValid(cookie: Cookie): boolean {
|
||||
|
||||
if(!cookie){
|
||||
return false;
|
||||
}
|
||||
|
||||
return cookie.expirationDate > msToS(Date.now());
|
||||
}
|
||||
|
||||
public async getAuthToken(): Promise<string | undefined> {
|
||||
const cookie = await session.defaultSession.cookies.get({ name: "oc_www_at" }).then(a => a?.at(0));
|
||||
|
||||
if(this.isCookieValid(cookie) && this.isUserTokenValid(cookie.value)){
|
||||
return cookie.value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async getUserTokenFromMetaAuth(keepToken: boolean): Promise<string>{
|
||||
|
||||
const redirectUrl = "https://developer.oculus.com/manage/";
|
||||
const loginUrl = `https://auth.oculus.com/login/?redirect_uri=${encodeURIComponent(redirectUrl)}`;
|
||||
const window = await this.windows.openWindow(loginUrl, { frame: true, width: 650, height: 800 });
|
||||
|
||||
let timout: NodeJS.Timeout;
|
||||
|
||||
const promise = new Promise<string>((resolve, reject) => {
|
||||
timout = setTimeout(() => {
|
||||
reject(new CustomError("Trying to get Oculus user token timed out", "META_LOGIN_TIMED_OUT"));
|
||||
window.close();
|
||||
}, minToMs(5));
|
||||
|
||||
window.webContents.on("did-navigate", async (_, url) => {
|
||||
if(!url.startsWith(redirectUrl)){ return; }
|
||||
|
||||
const token = (await window.webContents.session.cookies.get({ name: "oc_www_at" })).at(0)?.value;
|
||||
|
||||
if(!this.isUserTokenValid(token)){
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(token);
|
||||
});
|
||||
|
||||
window.on("closed", () => {
|
||||
reject(new CustomError("Oculus login window closed by user", "META_LOGIN_WINDOW_CLOSED_BY_USER"));
|
||||
});
|
||||
}).finally(() => {
|
||||
|
||||
clearTimeout(timout);
|
||||
|
||||
if(!keepToken){
|
||||
this.clearAuthToken();
|
||||
}
|
||||
|
||||
if(!window.isDestroyed() && window.isClosable()){
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
private async createDownloadVersion(version: BSVersion): Promise<{version: BSVersion, dest: string}>{
|
||||
const dest = await ensurePathNotAlreadyExist(await this.versions.getVersionPath(version));
|
||||
return {
|
||||
version: {
|
||||
...version,
|
||||
...version,
|
||||
...(path.basename(dest) !== version.BSVersion && { name: path.basename(dest) }),
|
||||
metadata: { store: BsStore.OCULUS, id: "" }
|
||||
},
|
||||
@@ -125,9 +50,7 @@ export class BsOculusDownloaderService {
|
||||
|
||||
let downloadVersion: BSVersion
|
||||
|
||||
const tokenObs$ = downloadInfo.token ? of(downloadInfo.token) : from(this.getUserTokenFromMetaAuth(downloadInfo.stay));
|
||||
|
||||
return tokenObs$.pipe(
|
||||
return of(downloadInfo.token).pipe(
|
||||
switchMap(token => {
|
||||
isOculusTokenValid(token, log.info); // Log token validity
|
||||
if(!downloadInfo.isVerification){
|
||||
@@ -138,7 +61,7 @@ export class BsOculusDownloaderService {
|
||||
switchMap(({token, version, dest}) => {
|
||||
downloadVersion = version;
|
||||
return this.oculusDownloader.downloadApp({ accessToken: token, binaryId: version.OculusBinaryId, destination: dest }).pipe(map(
|
||||
progress => ({...progress, data: version})
|
||||
progress => ({...progress, data: version})
|
||||
));
|
||||
}),
|
||||
finalize(() => downloadVersion && this.versions.initVersionMetadata(downloadVersion, { store: BsStore.OCULUS })),
|
||||
@@ -146,43 +69,9 @@ export class BsOculusDownloaderService {
|
||||
);
|
||||
}
|
||||
|
||||
public autoDownloadVersion(downloadInfo: DownloadInfo): Observable<Progression<BSVersion>>{
|
||||
|
||||
let downloadVersion: BSVersion
|
||||
|
||||
const tokenObs$ = downloadInfo.token ? of(downloadInfo.token) : from(this.getAuthToken());
|
||||
|
||||
return tokenObs$.pipe(
|
||||
map(token => {
|
||||
if(!token){
|
||||
throw new CustomError("No Meta auth token was found in cookies for auto download", "NO_META_AUTH_TOKEN");
|
||||
}
|
||||
return token;
|
||||
}),
|
||||
switchMap(token => {
|
||||
if(!downloadInfo.isVerification){
|
||||
return this.createDownloadVersion(downloadInfo.bsVersion).then(({version, dest}) => ({token, version, dest}));
|
||||
}
|
||||
return this.versions.getVersionPath(downloadInfo.bsVersion).then(path => ({token, version: downloadInfo.bsVersion, dest: path}));
|
||||
}),
|
||||
switchMap(({token, version, dest}) => {
|
||||
downloadVersion = version;
|
||||
return this.oculusDownloader.downloadApp({ accessToken: token, binaryId: version.OculusBinaryId, destination: dest }).pipe(
|
||||
map(progress => ({...progress, data: version})),
|
||||
);
|
||||
}),
|
||||
finalize(() => downloadVersion && this.versions.initVersionMetadata(downloadVersion, { store: BsStore.OCULUS })),
|
||||
finalize(() => this.oculusDownloader.stopDownload()),
|
||||
);
|
||||
}
|
||||
|
||||
public clearAuthToken(): Promise<void>{
|
||||
return session.defaultSession.clearStorageData({ storages: ["cookies"], origin: ".oculus.com" })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface OculusDownloadInfo {
|
||||
version: BSVersion;
|
||||
stay?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { BrowserWindow, IpcMainEvent, ipcMain } from "electron";
|
||||
import { BrowserWindow, IpcMainEvent, WebContents, ipcMain } from "electron";
|
||||
import { Observable } from "rxjs";
|
||||
import { IpcCompleteChannel, IpcErrorChannel, IpcTearDownChannel } from "shared/models/ipc/ipc-response.interface";
|
||||
import { IpcReplier } from "shared/models/ipc/ipc-request.interface";
|
||||
import { serializeError } from 'serialize-error';
|
||||
import log from "electron-log";
|
||||
import { IpcChannels, IpcRequestType, IpcResponseType } from "shared/models/ipc/ipc-routes";
|
||||
|
||||
export class IpcService {
|
||||
private static instance: IpcService;
|
||||
@@ -30,11 +31,11 @@ export class IpcService {
|
||||
return `${channel}_teardown`;
|
||||
}
|
||||
|
||||
private buildProxyListener<T>(listener: IpcListener<T>) {
|
||||
return (event: IpcMainEvent, req: IpcRequest<T>) => {
|
||||
private buildProxyListener<C extends IpcChannels>(listener: IpcListenerFromChannel<C>) {
|
||||
return (event: IpcMainEvent, req: IpcRequest<IpcRequestType<C>>) => {
|
||||
const window = BrowserWindow.fromWebContents(event.sender);
|
||||
const replier = (data: Observable<unknown>) => this.connectStream(req.responceChannel, window, data);
|
||||
listener(req, replier);
|
||||
listener(req.args, replier, event.sender);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,24 +55,26 @@ export class IpcService {
|
||||
complete: () => this.send(this.getCompleteChannel(channel), window)
|
||||
})
|
||||
|
||||
const unsubscribeOnDestroy = () => sub.unsubscribe();
|
||||
const unsubscribe = () => sub.unsubscribe();
|
||||
|
||||
window.webContents.once("destroyed", unsubscribeOnDestroy);
|
||||
window.webContents.ipc.once(this.getTearDownChannel(channel), () => sub.unsubscribe());
|
||||
window.webContents.once("destroyed", unsubscribe);
|
||||
window.webContents.ipc.once(this.getTearDownChannel(channel), unsubscribe);
|
||||
|
||||
sub.add(() => {
|
||||
window.webContents.removeListener("destroyed", unsubscribeOnDestroy);
|
||||
window.webContents.ipc.removeAllListeners(this.getTearDownChannel(channel));
|
||||
window.webContents.removeListener("destroyed", unsubscribe);
|
||||
});
|
||||
}
|
||||
|
||||
public on<T>(channel: string, listener: IpcListener<T>, ipc = ipcMain): void {
|
||||
ipc.on(channel, this.buildProxyListener(listener));
|
||||
public on<C extends IpcChannels>(channel: C, listener: IpcListenerFromChannel<C>, ipc = ipcMain): void {
|
||||
ipc.on(channel as string, this.buildProxyListener(listener));
|
||||
}
|
||||
|
||||
public once<T>(channel: string, listener: IpcListener<T>, ipc = ipcMain): void {
|
||||
ipc.once(channel, this.buildProxyListener(listener));
|
||||
public once<C extends IpcChannels>(channel: C, listener: IpcListenerFromChannel<C>, ipc = ipcMain): void {
|
||||
ipc.once(channel as string, this.buildProxyListener(listener));
|
||||
}
|
||||
}
|
||||
|
||||
type IpcListener<T = unknown> = (req: IpcRequest<T>, replier: IpcReplier) => void | Promise<void>;
|
||||
|
||||
type IpcListener<TRequest = unknown, TResponse = unknown> = (req: TRequest, replier: IpcReplier<TResponse>, webContents: WebContents) => void | Promise<void>;
|
||||
type IpcListenerFromChannel<C extends IpcChannels> = IpcListener<IpcRequestType<C>, IpcResponseType<C>>;
|
||||
|
||||
@@ -155,8 +155,13 @@ export class BsModsManagerService {
|
||||
}
|
||||
|
||||
return new Promise<boolean>(resolve => {
|
||||
log.info("START IPA PROCESS", `start /wait /min "" "${ipaPath}" ${args.join(" ")}`);
|
||||
const processIPA = spawn(`start /wait /min "" "${ipaPath}" ${args.join(" ")}`, { cwd: versionPath, detached: true, shell: true });
|
||||
const cmd = process.platform === 'linux'
|
||||
? `screen -dmS "BSIPA" dotnet ${ipaPath} ${args.join(" ")}` // Must run through screen, otherwise BSIPA tries to move console cursor and crashes.
|
||||
: `start /wait /min "" "${ipaPath}" ${args.join(" ")}`;
|
||||
|
||||
log.info("START IPA PROCESS", cmd);
|
||||
const processIPA = spawn(cmd, { cwd: versionPath, detached: true, shell: true });
|
||||
|
||||
processIPA.once("exit", code => {
|
||||
if (code === 0) {
|
||||
log.info("Ipa process exist with code 0");
|
||||
@@ -230,7 +235,7 @@ export class BsModsManagerService {
|
||||
log.error("Error while extracting mod zip", e);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
log.info("Mod zip extraction end", mod.name, "to", destDir, "success:", extracted);
|
||||
|
||||
const res = isBSIPA
|
||||
@@ -241,7 +246,9 @@ export class BsModsManagerService {
|
||||
}))
|
||||
: extracted;
|
||||
|
||||
res && this.nbInstalledMods++;
|
||||
if(res){
|
||||
this.nbInstalledMods++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Agent, get } from "https";
|
||||
import { Agent, RequestOptions, get } from "https";
|
||||
import { createWriteStream, unlink } from "fs";
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { Observable, shareReplay, tap } from "rxjs";
|
||||
import log from "electron-log";
|
||||
import fetch, { RequestInfo, RequestInit } from "node-fetch";
|
||||
import got, { GotOptions } from "got";
|
||||
import got, { Options } from "got";
|
||||
import { IncomingMessage } from "http";
|
||||
import { app } from "electron";
|
||||
import os from "os";
|
||||
|
||||
export class RequestService {
|
||||
private static instance: RequestService;
|
||||
@@ -17,16 +19,33 @@ export class RequestService {
|
||||
return RequestService.instance;
|
||||
}
|
||||
|
||||
private constructor() {}
|
||||
private readonly defaultRequestInit: RequestInit;
|
||||
|
||||
private get ipv4Agent(){
|
||||
return new Agent({ family: 4 });
|
||||
private constructor() {
|
||||
|
||||
this.defaultRequestInit = {
|
||||
headers: {
|
||||
"User-Agent": `BSManager/${app.getVersion()} (${os.type()} ${os.release()})`
|
||||
},
|
||||
agent: new Agent({ family: 4 }),
|
||||
};
|
||||
}
|
||||
|
||||
private getInitWithOptions(options?: RequestInit): RequestInit {
|
||||
return { ...this.defaultRequestInit, ...(options || {}) };
|
||||
}
|
||||
|
||||
private requestOptionsFromDefaultInit(): RequestOptions {
|
||||
return {
|
||||
headers: this.defaultRequestInit.headers as Record<string, string>,
|
||||
agent: this.defaultRequestInit.agent as Agent,
|
||||
};
|
||||
}
|
||||
|
||||
public async getJSON<T = unknown>(url: RequestInfo, options?: RequestInit): Promise<T> {
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {...options, agent: this.ipv4Agent});
|
||||
const response = await fetch(url, this.getInitWithOptions(options));
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status} ${url}`);
|
||||
@@ -52,7 +71,7 @@ export class RequestService {
|
||||
});
|
||||
file.on("error", err => unlink(dest, () => subscriber.error(err)));
|
||||
|
||||
const req = get(url, { agent: this.ipv4Agent }, res => {
|
||||
const req = get(url, this.requestOptionsFromDefaultInit(), res => {
|
||||
progress.total = parseInt(res.headers?.["content-length"] || "0", 10);
|
||||
|
||||
res.on("data", chunk => {
|
||||
@@ -69,9 +88,9 @@ export class RequestService {
|
||||
}).pipe(tap({ error: e => log.error(e, url, dest) }), shareReplay(1));
|
||||
}
|
||||
|
||||
public downloadBuffer(url: string, options?: GotOptions<string>): Observable<Progression<Buffer, IncomingMessage>> {
|
||||
return new Observable<Progression<Buffer>>(subscriber => {
|
||||
const progress: Progression<Buffer> = {
|
||||
public downloadBuffer(url: string, options?: Options & { isStream?: true }): Observable<Progression<Buffer, IncomingMessage>> {
|
||||
return new Observable<Progression<Buffer, IncomingMessage>>(subscriber => {
|
||||
const progress: Progression<Buffer, IncomingMessage> = {
|
||||
current: 0,
|
||||
total: 0,
|
||||
data: null,
|
||||
@@ -113,6 +132,6 @@ export class RequestService {
|
||||
req.destroy();
|
||||
}
|
||||
|
||||
}).pipe(tap({ error: e => log.error(e) }), shareReplay(1));
|
||||
}).pipe(tap({ error: log.error }), shareReplay(1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ export const EditVersionModal: ModalComponent<{ name: string; color: string }, {
|
||||
setColor(configService.get("second-color" as DefaultConfigKey));
|
||||
};
|
||||
|
||||
const resetName = () => {
|
||||
setName(version.BSVersion);
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
className="static"
|
||||
@@ -44,7 +48,12 @@ export const EditVersionModal: ModalComponent<{ name: string; color: string }, {
|
||||
<label className="block font-bold cursor-pointer tracking-wide text-gray-800 dark:text-gray-200" htmlFor="name">
|
||||
{t("modals.clone-version.inputs.name.label")}
|
||||
</label>
|
||||
<input className="w-full bg-light-main-color-1 dark:bg-main-color-1 px-1 py-[2px] rounded-md outline-none" onChange={e => setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("modals.clone-version.inputs.name.placeholder")} />
|
||||
<div className="relative">
|
||||
<input className="w-full bg-light-main-color-1 dark:bg-main-color-1 px-1 py-[2px] rounded-md outline-none" onChange={e => setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("modals.clone-version.inputs.name.placeholder")} />
|
||||
<div className="absolute right-2 top-0 h-full flex items-center">
|
||||
<BsmButton onClick={resetName} className="px-2 font-bold italic text-sm rounded-md" text="pages.settings.appearance.reset" withBar={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="block font-bold tracking-wide text-gray-800 dark:text-gray-200">{t("modals.clone-version.inputs.color.label")}</span>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { ModalComponent } from "renderer/services/modale.service";
|
||||
import { FolderLinkState, VersionFolderLinkerService, VersionLinkerActionType } from "renderer/services/version-folder-linker.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
|
||||
export const ShareFoldersModal: ModalComponent<void, BSVersion> = ({ options: {data} }) => {
|
||||
@@ -45,14 +46,14 @@ export const ShareFoldersModal: ModalComponent<void, BSVersion> = ({ options: {d
|
||||
}, [folders]);
|
||||
|
||||
const addFolder = async () => {
|
||||
const versionPath = await versionManager.getVersionPath(data).toPromise();
|
||||
const folder = await ipc.sendV2<{ canceled: boolean; filePaths: string[] }, string>("choose-folder", { args: versionPath }).toPromise();
|
||||
const versionPath = await lastValueFrom(versionManager.getVersionPath(data));
|
||||
const folder = await lastValueFrom(ipc.sendV2("choose-folder", versionPath));
|
||||
|
||||
if (!folder || folder.canceled || !folder.filePaths?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const relativeFolder = await ipc.sendV2<string>("full-version-path-to-relative", { args: { version: data, fullPath: folder.filePaths[0] } }).toPromise();
|
||||
const relativeFolder = await lastValueFrom(ipc.sendV2("full-version-path-to-relative", { version: data, fullPath: folder.filePaths[0] }));
|
||||
|
||||
if (folders.includes(relativeFolder)) {
|
||||
return;
|
||||
|
||||
@@ -10,11 +10,13 @@ import { BsmIconType } from "../svgs/bsm-icon.component";
|
||||
import "./title-bar.component.css";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function TitleBar({ template = "index.html" }: { template: AppWindow }) {
|
||||
|
||||
|
||||
const ipcService = useService(IpcService);
|
||||
const audio = useService(AudioPlayerService);
|
||||
const windowControls = useWindowControls();
|
||||
|
||||
const volume = useObservable(() => audio.volume$, audio.volume);
|
||||
const color = useThemeColor("first-color");
|
||||
@@ -22,7 +24,7 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin
|
||||
const [previewVersion, setPreviewVersion] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
lastValueFrom(ipcService.sendV2<string>("current-version")).then(version => {
|
||||
lastValueFrom(ipcService.sendV2("current-version")).then(version => {
|
||||
if (version.toLocaleLowerCase().includes("alpha")) {
|
||||
return setPreviewVersion("ALPHA");
|
||||
}
|
||||
@@ -35,19 +37,19 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin
|
||||
const [maximized, setMaximized] = useState(false);
|
||||
|
||||
const closeWindow = () => {
|
||||
return window.electron.window.close();
|
||||
return windowControls.close();
|
||||
};
|
||||
|
||||
const maximizeWindow = () => {
|
||||
window.electron.window.maximise();
|
||||
windowControls.maximise();
|
||||
};
|
||||
|
||||
const minimizeWindow = () => {
|
||||
window.electron.window.minimise();
|
||||
windowControls.minimise();
|
||||
};
|
||||
|
||||
const resetWindow = () => {
|
||||
window.electron.window.unmaximise();
|
||||
windowControls.unmaximise();
|
||||
};
|
||||
|
||||
const toogleMaximize = () => {
|
||||
@@ -117,7 +119,7 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<header id="titlebar" className="min-h-[22px] bg-transparent w-screen h-[22px] flex content-center items-center justify-start z-10">
|
||||
<div id="drag-region" className="grow h-full">
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useConstant } from "./use-constant.hook";
|
||||
|
||||
export function useWindowArgs<Key extends string>(...keys: Key[]): Record<Key, string|undefined> {
|
||||
|
||||
const getArgs = (...keys: Key[]) => {
|
||||
const url = new URLSearchParams(window.location.search);
|
||||
const result = {} as Record<Key, string>;
|
||||
keys.forEach(key => {
|
||||
result[key] = url.get(key) || undefined;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return useConstant(() => getArgs(...keys));
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { useService } from "./use-service.hook";
|
||||
import { useConstant } from "./use-constant.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export function useWindowControls() {
|
||||
const ipc = useService(IpcService);
|
||||
|
||||
const { close, maximise, minimise, unmaximise } = useConstant(() => ({
|
||||
close: () => lastValueFrom(ipc.sendV2("close-window")),
|
||||
maximise: () => lastValueFrom(ipc.sendV2("maximise-window")),
|
||||
minimise: () => lastValueFrom(ipc.sendV2("minimise-window")),
|
||||
unmaximise: () => lastValueFrom(ipc.sendV2("unmaximise-window"))
|
||||
}));
|
||||
|
||||
return { close, maximise, minimise, unmaximise };
|
||||
}
|
||||
@@ -35,7 +35,6 @@ import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BsmException } from "shared/models/bsm-exception.model";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { OculusDownloaderService } from "renderer/services/bs-version-download/oculus-downloader.service";
|
||||
import { BsStore } from "shared/models/bs-store.enum";
|
||||
import { SteamIcon } from "renderer/components/svgs/icons/steam-icon.component";
|
||||
import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component";
|
||||
@@ -52,7 +51,6 @@ export function SettingsPage() {
|
||||
const modalService = useService(ModalService);
|
||||
const bsDownloader = useService(BsDownloaderService);
|
||||
const steamDownloader = useService(SteamDownloaderService);
|
||||
const oculusDownloader = useService(OculusDownloaderService);
|
||||
const progressBarService = useService(ProgressBarService);
|
||||
const notificationService = useService(NotificationService);
|
||||
const i18nService = useService(I18nService);
|
||||
@@ -91,7 +89,7 @@ export function SettingsPage() {
|
||||
const [playlistsDeepLinkEnabled, setPlaylistsDeepLinkEnabled] = useState(false);
|
||||
const [modelsDeepLinkEnabled, setModelsDeepLinkEnabled] = useState(false);
|
||||
const [hasDownloaderSession, setHasDownloaderSession] = useState(false);
|
||||
const appVersion = useObservable(() => ipcService.sendV2<string>("current-version"));
|
||||
const appVersion = useObservable(() => ipcService.sendV2("current-version"));
|
||||
|
||||
const [isChangelogAvailable, setIsChangelogAvailable] = useState(true);
|
||||
const [changlogsLoading, setChanglogsLoading] = useState(false);
|
||||
@@ -116,16 +114,11 @@ export function SettingsPage() {
|
||||
};
|
||||
|
||||
const loadDownloadersSession = () => {
|
||||
if(steamDownloader.sessionExist()){ return setHasDownloaderSession(true); }
|
||||
|
||||
oculusDownloader.hasAuthToken().then(hasToken => {
|
||||
setHasDownloaderSession(hasToken);
|
||||
});
|
||||
setHasDownloaderSession(steamDownloader.sessionExist());
|
||||
}
|
||||
|
||||
const clearDownloadersSession = () => {
|
||||
steamDownloader.deleteSteamSession();
|
||||
oculusDownloader.clearAuthToken();
|
||||
loadDownloadersSession();
|
||||
}
|
||||
|
||||
@@ -171,7 +164,7 @@ export function SettingsPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileChooserRes = await ipcService.sendV2<{ canceled: boolean; filePaths: string[] }>("choose-folder").toPromise();
|
||||
const fileChooserRes = await lastValueFrom(ipcService.sendV2("choose-folder"));
|
||||
|
||||
if (!fileChooserRes.canceled && fileChooserRes.filePaths?.length) {
|
||||
progressBarService.showFake(0.008);
|
||||
@@ -217,7 +210,7 @@ export function SettingsPage() {
|
||||
const openDiscord = () => linkOpener.open("https://discord.gg/uSqbHVpKdV");
|
||||
const openTwitter = () => linkOpener.open("https://twitter.com/BSManager_");
|
||||
|
||||
const openLogs = () => ipcService.sendLazy("open-logs");
|
||||
const openLogs = () => lastValueFrom(ipcService.sendV2("open-logs"));
|
||||
|
||||
const showDeepLinkError = (isDeactivation: boolean) => {
|
||||
const desc = isDeactivation ? "notifications.settings.additional-content.deep-link.deactivation.error.description" : "notifications.settings.additional-content.deep-link.activation.error.description";
|
||||
@@ -231,8 +224,10 @@ export function SettingsPage() {
|
||||
};
|
||||
|
||||
const switchDeepLink = async (manager: MapsManagerService | PlaylistsManagerService | ModelsManagerService, enable: boolean, showNotification: boolean, setter: Dispatch<SetStateAction<boolean>>) => {
|
||||
const res = await (enable ? manager.enableDeepLink() : manager.disableDeepLink());
|
||||
showNotification && (res ? showDeepLinkSuccess(!enable) : showDeepLinkError(!enable));
|
||||
const res = await (enable ? manager.enableDeepLink() : manager.disableDeepLink()).then(() => true).catch(() => false);
|
||||
if(showNotification){
|
||||
res ? showDeepLinkSuccess(enable) : showDeepLinkError(enable);
|
||||
}
|
||||
const isEnable = await manager.isDeepLinksEnabled();
|
||||
setter(() => isEnable);
|
||||
return res;
|
||||
|
||||
@@ -42,7 +42,7 @@ export function VersionViewer() {
|
||||
}
|
||||
navigate(`/bs-version/${version.BSVersion}`, { state: version });
|
||||
};
|
||||
const openFolder = () => ipcService.sendLazy("bs-version.open-folder", { args: state });
|
||||
const openFolder = () => lastValueFrom(ipcService.sendV2("bs-version.open-folder", state));
|
||||
const verifyFiles = () => bsDownloader.verifyBsVersion(state);
|
||||
|
||||
const uninstall = async () => {
|
||||
|
||||
Vendored
-6
@@ -11,12 +11,6 @@ declare global {
|
||||
sep: "/"|"\\";
|
||||
join: (...args: string[]) => string;
|
||||
};
|
||||
window: {
|
||||
close: () => void;
|
||||
minimise: () => void;
|
||||
maximise: () => void;
|
||||
unmaximise: () => void;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,20 +47,17 @@ export class AutoUpdaterService {
|
||||
}
|
||||
|
||||
public isUpdateAvailable(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipcService.sendV2<boolean>("check-update")).catch(() => false);
|
||||
return lastValueFrom(this.ipcService.sendV2("check-update")).catch(() => false);
|
||||
}
|
||||
|
||||
public downloadUpdate(): Promise<boolean> {
|
||||
const promise = this.ipcService.send<boolean>("download-update").then(res => {
|
||||
return res.success;
|
||||
});
|
||||
|
||||
const promise = lastValueFrom(this.ipcService.sendV2("download-update")).then(() => true).catch(() => false);
|
||||
this.progressService.show(this.downloadProgress$, true);
|
||||
return promise;
|
||||
}
|
||||
|
||||
public quitAndInstall() {
|
||||
this.ipcService.sendLazy("install-update");
|
||||
lastValueFrom(this.ipcService.sendV2("install-update"));
|
||||
}
|
||||
|
||||
public getLastAppVersion(): string {
|
||||
@@ -103,7 +100,7 @@ export class AutoUpdaterService {
|
||||
}
|
||||
|
||||
public getAppVersion() : Observable<string> {
|
||||
return this.ipcService.sendV2<string>("current-version");
|
||||
return this.ipcService.sendV2("current-version");
|
||||
}
|
||||
|
||||
public async showChangelog(version:string): Promise<void>{
|
||||
|
||||
@@ -73,7 +73,7 @@ export class BSLauncherService {
|
||||
}
|
||||
|
||||
private async doMustStartAsAdmin(): Promise<boolean> {
|
||||
const needAdmin = await lastValueFrom(this.ipcService.sendV2<boolean, void>("bs-launch.need-start-as-admin"));
|
||||
const needAdmin = await lastValueFrom(this.ipcService.sendV2("bs-launch.need-start-as-admin"));
|
||||
if(!needAdmin){ return false; }
|
||||
if(this.config.get("dont-remind-admin")){ return true; }
|
||||
const modalRes = await this.modals.openModal(NeedLaunchAdminModal);
|
||||
@@ -83,7 +83,7 @@ export class BSLauncherService {
|
||||
}
|
||||
|
||||
public doLaunch(launchOptions: LaunchOption): Observable<BSLaunchEventData>{
|
||||
return this.ipcService.sendV2<BSLaunchEventData, LaunchOption>("bs-launch.launch", {args: launchOptions});
|
||||
return this.ipcService.sendV2("bs-launch.launch", launchOptions);
|
||||
}
|
||||
|
||||
public launch(launchOptions: LaunchOption): Observable<BSLaunchEventData> {
|
||||
@@ -114,13 +114,13 @@ export class BSLauncherService {
|
||||
|
||||
}
|
||||
|
||||
public createLaunchShortcut(launchOptions: LaunchOption): Observable<void>{
|
||||
public createLaunchShortcut(launchOptions: LaunchOption): Observable<boolean>{
|
||||
const options: LaunchOption = {...launchOptions, version: {...launchOptions.version, color: launchOptions.version.color || this.theme.getBsmColors()[1]}};
|
||||
return this.ipcService.sendV2<void, LaunchOption>("create-launch-shortcut", {args: options});
|
||||
return this.ipcService.sendV2("create-launch-shortcut", options);
|
||||
}
|
||||
|
||||
public restoreSteamVR(): Promise<void>{
|
||||
return lastValueFrom(this.ipcService.sendV2<void, void>("bs-launch.restore-steamvr"));
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-launch.restore-steamvr"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { UninstallAllModsModal } from "renderer/components/modal/modal-types/uninstall-all-mods-modal.component";
|
||||
import { UninstallModModal } from "renderer/components/modal/modal-types/uninstall-mod-modal.component";
|
||||
import { Observable, BehaviorSubject } from "rxjs";
|
||||
import { Observable, BehaviorSubject, lastValueFrom } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { InstallModsResult, UninstallModsResult, Mod, ModInstallProgression } from "shared/models/mods";
|
||||
import { Mod, ModInstallProgression } from "shared/models/mods";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ModalExitCode, ModalService } from "./modale.service";
|
||||
@@ -42,11 +42,11 @@ export class BsModsManagerService {
|
||||
}
|
||||
|
||||
public getAvailableMods(version: BSVersion): Observable<Mod[]> {
|
||||
return this.ipcService.sendV2<Mod[], BSVersion>("get-available-mods", { args: version });
|
||||
return this.ipcService.sendV2("get-available-mods", version);
|
||||
}
|
||||
|
||||
public getInstalledMods(version: BSVersion): Observable<Mod[]> {
|
||||
return this.ipcService.sendV2<Mod[], BSVersion>("get-installed-mods", { args: version });
|
||||
return this.ipcService.sendV2("get-installed-mods", version);
|
||||
}
|
||||
|
||||
public installMods(mods: Mod[], version: BSVersion): Promise<void> {
|
||||
@@ -71,19 +71,20 @@ export class BsModsManagerService {
|
||||
this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" });
|
||||
|
||||
this.isInstalling$.next(true);
|
||||
return this.ipcService.send<InstallModsResult, { mods: Mod[]; version: BSVersion }>("install-mods", { args: { mods, version } }).then(res => {
|
||||
if (res.success && res.data) {
|
||||
const isFullyInstalled = res.data.nbInstalledMods === res.data.nbModsToInstall;
|
||||
const title = `notifications.mods.install-mods.titles.${isFullyInstalled ? "success" : "warning"}`;
|
||||
const desc = `notifications.mods.install-mods.msg.${isFullyInstalled ? "success" : "warning"}`;
|
||||
|
||||
this.notifications.notify({ type: isFullyInstalled ? NotificationType.SUCCESS : NotificationType.WARNING, title, desc, duration: this.NOTIFICATION_DURATION });
|
||||
} else {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION });
|
||||
}
|
||||
return lastValueFrom(this.ipcService.sendV2("install-mods", { mods, version })).then(res => {
|
||||
const isFullyInstalled = res.nbInstalledMods === res.nbModsToInstall;
|
||||
|
||||
const title = `notifications.mods.install-mods.titles.${isFullyInstalled ? "success" : "warning"}`;
|
||||
const desc = `notifications.mods.install-mods.msg.${isFullyInstalled ? "success" : "warning"}`;
|
||||
|
||||
this.notifications.notify({ type: isFullyInstalled ? NotificationType.SUCCESS : NotificationType.WARNING, title, desc, duration: this.NOTIFICATION_DURATION });
|
||||
}).catch(e => {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION });
|
||||
}).finally(() => {
|
||||
this.isInstalling$.next(false);
|
||||
this.progressBar.hide();
|
||||
});
|
||||
})
|
||||
}
|
||||
public async uninstallMod(mod: Mod, version: BSVersion): Promise<void> {
|
||||
if (!this.progressBar.require()) {
|
||||
@@ -100,16 +101,15 @@ export class BsModsManagerService {
|
||||
this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" });
|
||||
|
||||
this.isUninstalling$.next(true);
|
||||
return this.ipcService.send("uninstall-mods", { args: { mods: [mod], version } }).then(res => {
|
||||
if (res.success) {
|
||||
this.notifications.notifySuccess({ title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION });
|
||||
} else {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION });
|
||||
}
|
||||
|
||||
return lastValueFrom(this.ipcService.sendV2("uninstall-mods", { mods: [mod], version })).then(() => {
|
||||
this.notifications.notifySuccess({ title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION });
|
||||
}).catch(e => {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION });
|
||||
}).finally(() => {
|
||||
this.isUninstalling$.next(false);
|
||||
this.progressBar.hide();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
public async uninstallAllMods(version: BSVersion) {
|
||||
@@ -127,15 +127,13 @@ export class BsModsManagerService {
|
||||
this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" });
|
||||
|
||||
this.isUninstalling$.next(true);
|
||||
return this.ipcService.send<UninstallModsResult>("uninstall-all-mods", { args: version }).then(res => {
|
||||
if (res.success) {
|
||||
this.notifications.notifySuccess({ title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION });
|
||||
} else {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION });
|
||||
}
|
||||
|
||||
return lastValueFrom(this.ipcService.sendV2("uninstall-all-mods", version)).then(() => {
|
||||
this.notifications.notifySuccess({ title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION });
|
||||
}).catch(e => {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION });
|
||||
}).finally(() => {
|
||||
this.isUninstalling$.next(false);
|
||||
this.progressBar.hide();
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme
|
||||
private startDownloadBsVersion(downloadInfo: DownloadInfo): Observable<Progression<BSVersion>>{
|
||||
const ignoreCode = [MetaAuthErrorCodes.META_LOGIN_WINDOW_CLOSED_BY_USER, OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED];
|
||||
return this.handleDownload(
|
||||
this.ipc.sendV2<Progression<BSVersion>>("bs-oculus-download", { args: downloadInfo }),
|
||||
this.ipc.sendV2("bs-oculus-download", downloadInfo ),
|
||||
ignoreCode
|
||||
);
|
||||
}
|
||||
@@ -115,15 +115,7 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme
|
||||
}
|
||||
|
||||
public stopDownload(): Promise<void>{
|
||||
return lastValueFrom(this.ipc.sendV2<void>("bs-oculus-stop-download"));
|
||||
return lastValueFrom(this.ipc.sendV2("bs-oculus-stop-download"));
|
||||
}
|
||||
|
||||
public hasAuthToken(): Promise<boolean>{
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("bs-oculus-has-auth-token"));
|
||||
}
|
||||
|
||||
public clearAuthToken(): Promise<void>{
|
||||
return lastValueFrom(this.ipc.sendV2<void>("bs-oculus-clear-auth-token"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
public isDotNet6Installed(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipcService.sendV2<boolean>("is-dotnet-6-installed"));
|
||||
return lastValueFrom(this.ipcService.sendV2("is-dotnet-6-installed"));
|
||||
}
|
||||
|
||||
private setSteamSession(username: string): void { localStorage.setItem(this.STEAM_SESSION_USERNAME_KEY, username); }
|
||||
@@ -67,11 +67,11 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
public async getInstallationFolder(): Promise<string> {
|
||||
return lastValueFrom(this.ipcService.sendV2<string>("bs-download.installation-folder"));
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-download.installation-folder"));
|
||||
}
|
||||
|
||||
public setInstallationFolder(path: string): Observable<string> {
|
||||
return this.ipcService.sendV2<string>("bs-download.set-installation-folder", { args: path });
|
||||
return this.ipcService.sendV2("bs-download.set-installation-folder", path);
|
||||
}
|
||||
|
||||
// ### Downloading
|
||||
@@ -177,7 +177,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
tap({
|
||||
error: (e) => {
|
||||
this.deleteSteamSession();
|
||||
!silent && this.hanndleErrorEvent(e)
|
||||
if(!silent){ this.hanndleErrorEvent(e) }
|
||||
}
|
||||
}),
|
||||
share({connector: () => new ReplaySubject(1)})
|
||||
@@ -193,20 +193,20 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
|
||||
const infos: DownloadSteamInfo = {...downloadInfo, username: this.getSteamUsername()}
|
||||
return this.wrapDownload(
|
||||
this.ipcService.sendV2<DepotDownloaderEvent>("auto-download-bs-version", { args: infos }),
|
||||
this.ipcService.sendV2("auto-download-bs-version", infos),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private startDownload(downloadInfo: DownloadSteamInfo){
|
||||
return this.wrapDownload(
|
||||
this.ipcService.sendV2<DepotDownloaderEvent>("download-bs-version", { args: downloadInfo })
|
||||
this.ipcService.sendV2("download-bs-version", downloadInfo )
|
||||
);
|
||||
}
|
||||
|
||||
private startQrCodeDownload(downloadInfo: DownloadSteamInfo){
|
||||
return this.wrapDownload(
|
||||
this.ipcService.sendV2<DepotDownloaderEvent>("download-bs-version-qr", { args: downloadInfo })
|
||||
this.ipcService.sendV2("download-bs-version-qr", downloadInfo)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
private sendInput(input: string){
|
||||
return lastValueFrom(this.ipcService.sendV2<void>("send-input-bs-download", { args: input }));
|
||||
return lastValueFrom(this.ipcService.sendV2("send-input-bs-download", input));
|
||||
}
|
||||
|
||||
public downloadBsVersion(version: BSVersion): Promise<BSVersion> {
|
||||
@@ -272,6 +272,6 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
public stopDownload(): Promise<void>{
|
||||
return lastValueFrom(this.ipcService.sendV2<void>("stop-download-bs-version"));
|
||||
return lastValueFrom(this.ipcService.sendV2("stop-download-bs-version"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { EditVersionModal } from "renderer/components/modal/modal-types/edit-ver
|
||||
import { popElement } from "shared/helpers/array.helpers";
|
||||
import { ImportVersionModal } from "renderer/components/modal/modal-types/import-version-modal.component";
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { ImportVersionOptions } from "main/services/bs-local-version.service";
|
||||
|
||||
export class BSVersionManagerService {
|
||||
private static instance: BSVersionManagerService;
|
||||
@@ -48,16 +47,16 @@ export class BSVersionManagerService {
|
||||
}
|
||||
|
||||
public askAvailableVersions(): Promise<BSVersion[]> {
|
||||
return this.ipcService.send<BSVersion[]>("bs-version.get-version-dict").then(res => {
|
||||
this.availableVersions$.next(res.data);
|
||||
return res.data;
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.get-version-dict")).then(res => {
|
||||
this.availableVersions$.next(res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
public askInstalledVersions(): Promise<BSVersion[]> {
|
||||
return this.ipcService.send<BSVersion[]>("bs-version.installed-versions").then(res => {
|
||||
this.setInstalledVersions(res.data);
|
||||
return res.data;
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.installed-versions")).then(res => {
|
||||
this.setInstalledVersions(res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,17 +72,17 @@ export class BSVersionManagerService {
|
||||
if (modalRes.data.name?.length < 2) {
|
||||
return null;
|
||||
}
|
||||
return this.ipcService.send<BSVersion>("bs-version.edit", { args: { version, name: modalRes.data.name, color: modalRes.data.color } }).then(res => {
|
||||
if (!res.success) {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${res.error.title}`,
|
||||
...(res.error.message && { desc: `notifications.custom-version.errors.msg.${res.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.edit", { version, name: modalRes.data.name, color: modalRes.data.color })).then(res => {
|
||||
this.askInstalledVersions();
|
||||
return res.data;
|
||||
});
|
||||
return res;
|
||||
}).catch(e => {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${e.error.title}`,
|
||||
...(e.error.message && { desc: `notifications.custom-version.errors.msg.${e.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
})
|
||||
}
|
||||
|
||||
public async cloneVersion(version: BSVersion): Promise<BSVersion> {
|
||||
@@ -97,19 +96,21 @@ export class BSVersionManagerService {
|
||||
if (modalRes.data.name?.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.progressBar.showFake(0.01);
|
||||
return this.ipcService.send<BSVersion>("bs-version.clone", { args: { version, name: modalRes.data.name, color: modalRes.data.color } }).then(res => {
|
||||
this.progressBar.hide(true);
|
||||
if (!res.success) {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${res.error.title}`,
|
||||
...(res.error.message && { desc: `notifications.custom-version.errors.msg.${res.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.clone", { version, name: modalRes.data.name, color: modalRes.data.color })).then(res => {
|
||||
this.notification.notifySuccess({ title: "notifications.custom-version.success.titles.CloningFinished" });
|
||||
this.askInstalledVersions();
|
||||
return res.data;
|
||||
return res;
|
||||
}).catch(e => {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${e.error.title}`,
|
||||
...(e.error.message && { desc: `notifications.custom-version.errors.msg.${e.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
}).finally(() => {
|
||||
this.progressBar.hide(true)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,12 +132,12 @@ export class BSVersionManagerService {
|
||||
|
||||
const store = resModal.data;
|
||||
|
||||
const folderRes = await lastValueFrom(this.ipcService.sendV2<{ canceled: boolean; filePaths: string[] }>("choose-folder"));
|
||||
const folderRes = await lastValueFrom(this.ipcService.sendV2("choose-folder"));
|
||||
if(!folderRes || folderRes.canceled || !folderRes.filePaths?.length){
|
||||
return;
|
||||
}
|
||||
|
||||
const import$ = this.ipcService.sendV2<Progression<BSVersion>, ImportVersionOptions>("import-version", { args: {fromPath: folderRes.filePaths.at(0), store} });
|
||||
const import$ = this.ipcService.sendV2("import-version", {fromPath: folderRes.filePaths.at(0), store});
|
||||
|
||||
subs.push(import$.subscribe(obs));
|
||||
|
||||
@@ -167,7 +168,7 @@ export class BSVersionManagerService {
|
||||
}
|
||||
|
||||
public getVersionPath(version: BSVersion): Observable<string> {
|
||||
return this.ipcService.sendV2("get-version-full-path", { args: version });
|
||||
return this.ipcService.sendV2("get-version-full-path", version);
|
||||
}
|
||||
|
||||
public static sortVersions(versions: BSVersion[]): BSVersion[] {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Observable, ReplaySubject, identity } from "rxjs";
|
||||
import { IpcRequest, IpcResponse } from "shared/models/ipc";
|
||||
import { deserializeError } from 'serialize-error';
|
||||
import { IpcCompleteChannel, IpcErrorChannel, IpcTearDownChannel } from "shared/models/ipc/ipc-response.interface";
|
||||
import { IpcChannels, IpcRequestType, IpcResponseType } from "shared/models/ipc/ipc-routes";
|
||||
|
||||
export class IpcService {
|
||||
private static instance: IpcService;
|
||||
@@ -63,25 +64,23 @@ export class IpcService {
|
||||
|
||||
// TODO : Convert all IPCs calls to V2
|
||||
|
||||
public sendV2<T, U = unknown>(channel: string, request?: IpcRequest<U>, defaultValue?: T): Observable<T> {
|
||||
if (!request) {
|
||||
request = { args: null, responceChannel: null };
|
||||
}
|
||||
public sendV2<C extends IpcChannels>(channel: C, data?: IpcRequestType<C>, defaultValue?: IpcResponseType<C>): Observable<IpcResponseType<C>> {
|
||||
|
||||
if (!request.responceChannel) {
|
||||
request.responceChannel = `${channel}_responce_${crypto.randomUUID()}`;
|
||||
}
|
||||
const request: IpcRequest<IpcRequestType<C>> = {
|
||||
args: data,
|
||||
responceChannel: `${channel}_responce_${crypto.randomUUID()}`
|
||||
};
|
||||
|
||||
const completeChannel: IpcCompleteChannel = `${request.responceChannel}_complete`;
|
||||
const errorChannel: IpcErrorChannel = `${request.responceChannel}_error`;
|
||||
const teardownChannel: IpcTearDownChannel = `${request.responceChannel}_teardown`;
|
||||
|
||||
const obs = new Observable<T>(observer => {
|
||||
window.electron.ipcRenderer.on(request.responceChannel, (res: T) => observer.next(res));
|
||||
const obs = new Observable<IpcResponseType<C>>(observer => {
|
||||
window.electron.ipcRenderer.on(request.responceChannel, (res: IpcResponseType<C>) => observer.next(res));
|
||||
window.electron.ipcRenderer.on(errorChannel, (err) => observer.error(deserializeError(err)));
|
||||
window.electron.ipcRenderer.on(completeChannel, () => observer.complete());
|
||||
|
||||
window.electron.ipcRenderer.sendMessage(channel, request);
|
||||
window.electron.ipcRenderer.sendMessage(channel as string, request);
|
||||
|
||||
return () => {
|
||||
window.electron.ipcRenderer.removeAllListeners(request.responceChannel);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Observable, Subject } from "rxjs";
|
||||
import { Observable, Subject, lastValueFrom } from "rxjs";
|
||||
import { IpcService } from "./ipc.service";
|
||||
|
||||
export class LinkOpenerService {
|
||||
@@ -23,7 +23,7 @@ export class LinkOpenerService {
|
||||
if (internal) {
|
||||
return this._iframeLink$.next(url);
|
||||
}
|
||||
this.ipcService.sendLazy("new-window", { args: url });
|
||||
lastValueFrom(this.ipcService.sendV2("new-window", url));
|
||||
}
|
||||
|
||||
public closeIframe() {
|
||||
|
||||
@@ -75,7 +75,7 @@ export class MapsDownloaderService {
|
||||
if (this.os.isOffline) {
|
||||
return null;
|
||||
}
|
||||
return this.ipc.sendV2<BsmLocalMap, { map: BsvMapDetail; version: BSVersion }>("download-map", { args: { map, version } });
|
||||
return this.ipc.sendV2("download-map", { map, version });
|
||||
}
|
||||
|
||||
public async openDownloadMapModal(version?: BSVersion, ownedMaps: BsmLocalMap[] = []): Promise<ModalResponse<void>> {
|
||||
@@ -132,12 +132,9 @@ export class MapsDownloaderService {
|
||||
this.downloadedListerners.splice(funcIndex, 1);
|
||||
}
|
||||
|
||||
public async oneClickInstallMap(map: BsvMapDetail): Promise<boolean> {
|
||||
public async oneClickInstallMap(map: BsvMapDetail): Promise<void> {
|
||||
this.progressBar.showFake(0.04);
|
||||
|
||||
const res = await this.ipc.send<void, BsvMapDetail>("one-click-install-map", { args: map });
|
||||
|
||||
return res.success;
|
||||
return lastValueFrom(this.ipc.sendV2("one-click-install-map", map));
|
||||
}
|
||||
|
||||
public get isDownloading(): boolean {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { LinkMapsModal } from "renderer/components/modal/modal-types/link-maps-modal.component";
|
||||
import { UnlinkMapsModal } from "renderer/components/modal/modal-types/unlink-maps-modal.component";
|
||||
import { Subject, Observable, of } from "rxjs";
|
||||
import { Subject, Observable, of, lastValueFrom } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BsmLocalMapsProgress, BsmLocalMap, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { BsmLocalMapsProgress, BsmLocalMap } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ModalExitCode, ModalService } from "./modale.service";
|
||||
import { DeleteMapsModal } from "renderer/components/modal/modal-types/delete-maps-modal.component";
|
||||
import { ProgressBarService } from "./progress-bar.service";
|
||||
import { OpenSaveDialogOption } from "shared/models/ipc";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { ArchiveProgress } from "shared/models/archive.interface";
|
||||
import { map, last, catchError } from "rxjs/operators";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { FolderLinkState, VersionFolderLinkerService } from "./version-folder-linker.service";
|
||||
@@ -48,7 +46,7 @@ export class MapsManagerService {
|
||||
}
|
||||
|
||||
public getMaps(version?: BSVersion): Observable<BsmLocalMapsProgress> {
|
||||
return this.ipcService.sendV2<BsmLocalMapsProgress>("load-version-maps", { args: version }, { loaded: 0, total: 0, maps: [] });
|
||||
return this.ipcService.sendV2("load-version-maps", version, { loaded: 0, total: 0, maps: [] });
|
||||
}
|
||||
|
||||
public async versionHaveMapsLinked(version: BSVersion): Promise<boolean> {
|
||||
@@ -97,7 +95,7 @@ export class MapsManagerService {
|
||||
|
||||
const showProgressBar = this.progressBar.require();
|
||||
|
||||
const progress$ = this.ipcService.sendV2<DeleteMapsProgress>("delete-maps", { args: maps }).pipe(map(progress => (progress.deleted / progress.total) * 100));
|
||||
const progress$ = this.ipcService.sendV2("delete-maps", maps ).pipe(map(progress => (progress.deleted / progress.total) * 100));
|
||||
|
||||
if (showProgressBar) {
|
||||
this.progressBar.show(progress$, true);
|
||||
@@ -120,20 +118,15 @@ export class MapsManagerService {
|
||||
return;
|
||||
}
|
||||
|
||||
const resFile = await this.ipcService.send<string, OpenSaveDialogOption>("save-file", {
|
||||
args: {
|
||||
filename: version ? `${version.BSVersion}Maps` : "Maps",
|
||||
filters: [{ name: "zip", extensions: ["zip"] }],
|
||||
},
|
||||
});
|
||||
const resFile = await lastValueFrom(this.ipcService.sendV2("save-file", { filename: version ? `${version.BSVersion}Maps` : "Maps", filters: [{ name: "zip", extensions: ["zip"] }]})).catch(() => null as string);
|
||||
|
||||
if (!resFile.success) {
|
||||
if (!resFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exportProgress$: Observable<ProgressionInterface> = this.ipcService.sendV2<ArchiveProgress, { version: BSVersion; maps: BsmLocalMap[]; outPath: string }>("export-maps", { args: { version, maps, outPath: resFile.data } }).pipe(
|
||||
const exportProgress$: Observable<ProgressionInterface> = this.ipcService.sendV2("export-maps", { version, maps, outPath: resFile }).pipe(
|
||||
map(p => {
|
||||
return { progression: (p.prossesedFiles / p.totalFiles) * 100, label: `${p.prossesedFiles} / ${p.totalFiles}` } as ProgressionInterface;
|
||||
return { progression: (p.current / p.total) * 100, label: `${p.current} / ${p.total}` } as ProgressionInterface;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -153,18 +146,15 @@ export class MapsManagerService {
|
||||
}
|
||||
|
||||
public async isDeepLinksEnabled(): Promise<boolean> {
|
||||
const res = await this.ipcService.send<boolean>("is-map-deep-links-enabled");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipcService.sendV2("is-map-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipcService.send<boolean>("register-maps-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipcService.sendV2("register-maps-deep-link"));
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipcService.send<boolean>("unregister-maps-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipcService.sendV2("unregister-maps-deep-link"));
|
||||
}
|
||||
|
||||
public get versionLinked$(): Observable<BSVersion> {
|
||||
|
||||
@@ -6,7 +6,6 @@ import { ModalResponse, ModalService } from "../modale.service";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { DownloadModelsModal } from "renderer/components/modal/modal-types/models/download-models-modal.component";
|
||||
import { ProgressBarService } from "../progress-bar.service";
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import equal from "fast-deep-equal";
|
||||
|
||||
@@ -42,7 +41,7 @@ export class ModelsDownloaderService {
|
||||
}
|
||||
|
||||
private async downloadModel(download: ModelDownload) {
|
||||
const download$ = this.ipc.sendV2<Progression<BsmLocalModel>>("download-model", { args: download });
|
||||
const download$ = this.ipc.sendV2("download-model", download);
|
||||
|
||||
if (!this.progress.isVisible) {
|
||||
const progress$: Observable<ProgressionInterface> = download$.pipe(
|
||||
@@ -124,13 +123,13 @@ export class ModelsDownloaderService {
|
||||
public async oneClickInstallModel(model: MSModel): Promise<boolean> {
|
||||
this.progress.showFake(0.04);
|
||||
|
||||
const res = await this.ipc.send("one-click-install-model", { args: model });
|
||||
const res = await lastValueFrom(this.ipc.sendV2("one-click-install-model", model)).then(() => true).catch(() => false);
|
||||
|
||||
this.progress.complete();
|
||||
await timer(500).toPromise();
|
||||
await lastValueFrom(timer(500));
|
||||
this.progress.hide(true);
|
||||
|
||||
return res.success;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import { UnlinkModelsModal } from "renderer/components/modal/modal-types/models/
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface";
|
||||
import { ProgressBarService } from "../progress-bar.service";
|
||||
import { OpenSaveDialogOption } from "shared/models/os/dialog.model";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { NotificationService } from "../notification.service";
|
||||
import { ConfigurationService } from "../configuration.service";
|
||||
@@ -101,7 +100,7 @@ export class ModelsManagerService {
|
||||
}
|
||||
|
||||
public $getModels(type: MSModelType, version?: BSVersion): Observable<Progression<BsmLocalModel[]>> {
|
||||
return this.ipc.sendV2<Progression<BsmLocalModel[]>>("get-version-models", { args: { version, type } });
|
||||
return this.ipc.sendV2("get-version-models", { version, type });
|
||||
}
|
||||
|
||||
public async exportModels(models: BsmLocalModel[], version?: BSVersion) {
|
||||
@@ -109,18 +108,16 @@ export class ModelsManagerService {
|
||||
return;
|
||||
}
|
||||
|
||||
const resFile = await this.ipc.send<string, OpenSaveDialogOption>("save-file", {
|
||||
args: {
|
||||
filename: version ? `${version.name ?? version.BSVersion} Models` : "Models",
|
||||
filters: [{ name: "zip", extensions: ["zip"] }],
|
||||
},
|
||||
});
|
||||
const resFile = await lastValueFrom(this.ipc.sendV2("save-file", {
|
||||
filename: version ? `${version.name ?? version.BSVersion} Models` : "Models",
|
||||
filters: [{ name: "zip", extensions: ["zip"] }]
|
||||
})).catch(() => null as string);
|
||||
|
||||
if (!resFile.success) {
|
||||
if (!resFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exportProgress$: Observable<ProgressionInterface> = this.ipc.sendV2<Progression, { version: BSVersion; models: BsmLocalModel[]; outPath: string }>("export-models", { args: { version, models, outPath: resFile.data } }).pipe(
|
||||
const exportProgress$ = this.ipc.sendV2("export-models", { version, models, outPath: resFile }).pipe(
|
||||
map(p => {
|
||||
return { progression: (p.current / p.total) * 100, label: `${p.current} / ${p.total}` } as ProgressionInterface;
|
||||
})
|
||||
@@ -171,7 +168,7 @@ export class ModelsManagerService {
|
||||
|
||||
const showProgressBar = this.progressBar.require();
|
||||
|
||||
const obs$ = this.ipc.sendV2<Progression<BsmLocalModel[]>>("delete-models", { args: models });
|
||||
const obs$ = this.ipc.sendV2("delete-models", models);
|
||||
|
||||
const progress$ = obs$.pipe(map(progress => (progress.current / progress.total) * 100));
|
||||
|
||||
@@ -189,16 +186,14 @@ export class ModelsManagerService {
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean> {
|
||||
return this.ipc.send<boolean>("is-models-deep-links-enabled").then(res => (res.success ? res.data : false));
|
||||
return lastValueFrom(this.ipc.sendV2("is-models-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipc.send<boolean>("register-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipc.sendV2("register-models-deep-link"));
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipc.send<boolean>("unregister-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipc.sendV2("unregister-models-deep-link"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { NotificationResult, NotificationType, Notification } from "../../shared/models/notification/notification.model";
|
||||
@@ -58,8 +58,8 @@ export class NotificationService {
|
||||
return this.notify(notification);
|
||||
}
|
||||
|
||||
public notifySystem(options: SystemNotificationOptions) {
|
||||
this.ipc.sendLazy<SystemNotificationOptions>("notify-system", { args: options });
|
||||
public notifySystem(options: SystemNotificationOptions): Observable<void> {
|
||||
return this.ipc.sendV2("notify-system", options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export class PlaylistDownloaderService {
|
||||
return new Observable<Progression<DownloadPlaylistProgressionData>>(subscriber => {
|
||||
(async () => {
|
||||
const playlist = await lastValueFrom(this.playlistQueue$.pipe(map(queue => queue.at(0)), filter(p => equal(bpList, p)), take(1)));
|
||||
const download$ = this.ipc.sendV2<Progression<DownloadPlaylistProgressionData>, unknown>("install-playlist", { args: { version, playlist } });
|
||||
const download$ = this.ipc.sendV2("install-playlist", { version, playlist });
|
||||
|
||||
await lastValueFrom(download$.pipe(tap(subscriber)));
|
||||
})()
|
||||
@@ -50,7 +50,7 @@ export class PlaylistDownloaderService {
|
||||
|
||||
public oneClickInstallPlaylist(bpListUrl: string): Observable<Progression<DownloadPlaylistProgressionData>> {
|
||||
|
||||
const download$ = this.ipc.sendV2<Progression<DownloadPlaylistProgressionData>, string>("one-click-install-playlist", { args: bpListUrl });
|
||||
const download$ = this.ipc.sendV2("one-click-install-playlist", bpListUrl);
|
||||
const progress$ = download$.pipe(map(data => (data.current / data.total) * 100));
|
||||
|
||||
this.progress.show(progress$, true);
|
||||
|
||||
@@ -31,11 +31,11 @@ export class PlaylistsManagerService {
|
||||
}
|
||||
|
||||
public getVersionPlaylistsDetails(version: BSVersion): Observable<Progression<LocalBPListsDetails[]>> {
|
||||
return this.ipc.sendV2("get-version-playlists-details", { args: version });
|
||||
return this.ipc.sendV2("get-version-playlists-details", version);
|
||||
}
|
||||
|
||||
public deletePlaylist(opt: {path: string, deleteMaps?: boolean}): Observable<Progression> {
|
||||
return this.ipc.sendV2<Progression, {path: string, deleteMaps?: boolean}>("delete-playlist", { args: opt });
|
||||
return this.ipc.sendV2("delete-playlist", opt);
|
||||
}
|
||||
|
||||
public async linkVersion(version: BSVersion): Promise<boolean> {
|
||||
@@ -67,15 +67,15 @@ export class PlaylistsManagerService {
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("is-playlists-deep-links-enabled"));
|
||||
return lastValueFrom(this.ipc.sendV2("is-playlists-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public enableDeepLink(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("register-playlists-deep-link"));
|
||||
return lastValueFrom(this.ipc.sendV2("register-playlists-deep-link"));
|
||||
}
|
||||
|
||||
public disableDeepLink(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("unregister-playlists-deep-link"));
|
||||
return lastValueFrom(this.ipc.sendV2("unregister-playlists-deep-link"));
|
||||
}
|
||||
|
||||
public $playlistsFolderLinkState(version: BSVersion): Observable<FolderLinkState> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { distinctUntilChanged, map } from "rxjs/operators";
|
||||
import { BehaviorSubject, Observable, Subscription, timer, of } from "rxjs";
|
||||
import { BehaviorSubject, Observable, Subscription, timer, of, lastValueFrom } from "rxjs";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { CSSProperties } from "react";
|
||||
@@ -36,7 +36,7 @@ export class ProgressBarService {
|
||||
}
|
||||
|
||||
private setSystemProgression(progression: number) {
|
||||
this.ipcService.sendLazy("window.progression", { args: progression });
|
||||
lastValueFrom(this.ipcService.sendV2("window.progression", progression));
|
||||
}
|
||||
|
||||
public subscribreTo(obs: Observable<ProgressionInterface | number>) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Supporter } from "shared/models/supporters";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export class SupportersService {
|
||||
private static instance: SupportersService;
|
||||
@@ -18,11 +19,6 @@ export class SupportersService {
|
||||
}
|
||||
|
||||
public getSupporters(): Promise<Supporter[]> {
|
||||
return this.ipcService.send<Supporter[]>("get-supporters").then(res => {
|
||||
if (!res.success) {
|
||||
return null;
|
||||
}
|
||||
return res.data;
|
||||
});
|
||||
return lastValueFrom(this.ipcService.sendV2("get-supporters"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import { BsvPlaylist, SearchParams } from "shared/models/maps/beat-saver.model";
|
||||
import { SearchParams } from "shared/models/maps/beat-saver.model";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export class BeatSaverService {
|
||||
private static instance: BeatSaverService;
|
||||
@@ -18,22 +19,14 @@ export class BeatSaverService {
|
||||
}
|
||||
|
||||
public async getMapDetailsFromHashs(hashs: string[]): Promise<BsvMapDetail[]> {
|
||||
const res = await this.ipc.send<BsvMapDetail[], string[]>("bsv-get-map-details-from-hashs", { args: hashs });
|
||||
return res.data ?? [];
|
||||
return lastValueFrom(this.ipc.sendV2("bsv-get-map-details-from-hashs", hashs));
|
||||
}
|
||||
|
||||
public async getMapDetailsById(id: string): Promise<BsvMapDetail> {
|
||||
const res = await this.ipc.send<BsvMapDetail, string>("bsv-get-map-details-by-id", { args: id });
|
||||
return res.data ?? null;
|
||||
return lastValueFrom(this.ipc.sendV2("bsv-get-map-details-by-id", id));
|
||||
}
|
||||
|
||||
public async searchMaps(search: SearchParams): Promise<BsvMapDetail[]> {
|
||||
const res = await this.ipc.send<BsvMapDetail[], SearchParams>("bsv-search-map", { args: search });
|
||||
return res.data ?? [];
|
||||
}
|
||||
|
||||
public async getPlaylistDetailsById(id: string): Promise<BsvPlaylist> {
|
||||
const res = await this.ipc.send<BsvPlaylist>("bsv-get-playlist-details-by-id", { args: id });
|
||||
return res.data ?? null;
|
||||
return lastValueFrom(this.ipc.sendV2("bsv-search-map", search));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MSGetQuery, MSGetQueryFilter, MSGetQueryFilterType, MSModel } from "shared/models/models/model-saber.model";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { Observable } from "rxjs";
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { MS_QUERY_FILTER_TYPES } from "shared/models/models/constants";
|
||||
|
||||
export class ModelSaberService {
|
||||
@@ -19,16 +19,12 @@ export class ModelSaberService {
|
||||
this.ipc = IpcService.getInstance();
|
||||
}
|
||||
|
||||
public async getModelById(id: number | string): Promise<MSModel> {
|
||||
const res = await this.ipc.send<MSModel>("ms-get-model-by-id", { args: id });
|
||||
if (!res.success) {
|
||||
return null;
|
||||
}
|
||||
return res.data;
|
||||
public getModelById(id: number | string): Promise<MSModel> {
|
||||
return lastValueFrom(this.ipc.sendV2("ms-get-model-by-id", id));
|
||||
}
|
||||
|
||||
public searchModels(query: MSGetQuery): Observable<MSModel[]> {
|
||||
return this.ipc.sendV2("search-models", { args: query });
|
||||
return this.ipc.sendV2("search-models", query);
|
||||
}
|
||||
|
||||
public parseFilter(stringFilters: string): MSGetQueryFilter[] {
|
||||
|
||||
@@ -59,7 +59,7 @@ export class VersionFolderLinkerService {
|
||||
}
|
||||
|
||||
private doAction(action: VersionLinkerAction): Observable<boolean> {
|
||||
return this.ipcService.sendV2<boolean, VersionLinkerAction>("link-version-folder-action", { args: action });
|
||||
return this.ipcService.sendV2("link-version-folder-action", action);
|
||||
}
|
||||
|
||||
private get currentAction$(): Observable<VersionLinkerAction> {
|
||||
@@ -126,7 +126,7 @@ export class VersionFolderLinkerService {
|
||||
}
|
||||
|
||||
public isVersionFolderLinked(version: BSVersion, relativeFolder: string): Observable<boolean> {
|
||||
return this.ipcService.sendV2("is-version-folder-linked", { args: { version, relativeFolder } });
|
||||
return this.ipcService.sendV2("is-version-folder-linked", { version, relativeFolder });
|
||||
}
|
||||
|
||||
public $folderLinkedState(version: BSVersion, relativeFolder: string): Observable<FolderLinkState> {
|
||||
@@ -159,7 +159,7 @@ export class VersionFolderLinkerService {
|
||||
}
|
||||
|
||||
public getLinkedFolders(version: BSVersion, options?: { relative?: boolean }): Observable<string[]> {
|
||||
return this.ipcService.sendV2("get-linked-folders", { args: { version, options } });
|
||||
return this.ipcService.sendV2("get-linked-folders", { version, options });
|
||||
}
|
||||
|
||||
public relinkAllVersionsFolders(): Observable<void> {
|
||||
|
||||
@@ -19,11 +19,11 @@ export class WindowManagerService {
|
||||
}
|
||||
|
||||
public openThenCloseAll(window: AppWindow): Promise<void> {
|
||||
return lastValueFrom(this.ipcService.sendV2<void>("open-window-then-close-all", { args: window }));
|
||||
return lastValueFrom(this.ipcService.sendV2("open-window-then-close-all", window));
|
||||
}
|
||||
|
||||
public openWindowOrFocus(window: AppWindow): Promise<void> {
|
||||
return lastValueFrom(this.ipcService.sendV2<void, AppWindow>("open-window-or-focus", { args: window }));
|
||||
return lastValueFrom(this.ipcService.sendV2("open-window-or-focus", window));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,25 +3,27 @@ import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-ba
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import TitleBar from "renderer/components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { MapsDownloaderService } from "renderer/services/maps-downloader.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { ProgressBarService } from "renderer/services/progress-bar.service";
|
||||
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import defaultImage from "../../../../assets/images/default-version-img.jpg";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { useWindowArgs } from "renderer/hooks/use-window-args.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function OneClickDownloadMap() {
|
||||
|
||||
const ipc = useService(IpcService);
|
||||
|
||||
const bsv = useService(BeatSaverService);
|
||||
const mapsDownloader = useService(MapsDownloaderService);
|
||||
const progressBar = useService(ProgressBarService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const { mapId, isHash } = useWindowArgs("mapId", "isHash");
|
||||
const [mapInfo, setMapInfo] = useState<BsvMapDetail>(null);
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const cover = mapInfo ? mapInfo.versions.at(0).coverURL : null;
|
||||
@@ -31,14 +33,16 @@ export default function OneClickDownloadMap() {
|
||||
|
||||
progressBar.open();
|
||||
|
||||
const promise = (async () => {
|
||||
const ipcRes = await lastValueFrom(ipc.sendV2<{ id: string; isHash: boolean }>("one-click-map-info"));
|
||||
console.log("AAAA", mapId, isHash);
|
||||
|
||||
const mapDetails = ipcRes.isHash ? (await bsv.getMapDetailsFromHashs([ipcRes.id])).at(0) : await bsv.getMapDetailsById(ipcRes.id);
|
||||
const promise = (async () => {
|
||||
|
||||
const mapDetails = isHash === "true" ? (await bsv.getMapDetailsFromHashs([mapId])).at(0) : await bsv.getMapDetailsById(mapId);
|
||||
console.log(mapDetails);
|
||||
|
||||
setMapInfo(() => mapDetails);
|
||||
|
||||
const res = await mapsDownloader.oneClickInstallMap(mapDetails);
|
||||
|
||||
const res = await mapsDownloader.oneClickInstallMap(mapDetails).then(() => true).catch(() => false);
|
||||
|
||||
progressBar.complete();
|
||||
|
||||
@@ -57,9 +61,9 @@ export default function OneClickDownloadMap() {
|
||||
});
|
||||
|
||||
promise.finally(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-ba
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import TitleBar from "renderer/components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { ProgressBarService } from "renderer/services/progress-bar.service";
|
||||
import { ModelSaberService } from "renderer/services/thrird-partys/model-saber.service";
|
||||
@@ -11,16 +10,18 @@ import { MSModel } from "shared/models/models/model-saber.model";
|
||||
import defaultImage from "../../../../assets/images/default-version-img.jpg";
|
||||
import { ModelsDownloaderService } from "renderer/services/models-management/models-downloader.service";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { useWindowArgs } from "renderer/hooks/use-window-args.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function OneClickDownloadModel() {
|
||||
|
||||
const ipc = useService(IpcService);
|
||||
const modelSaber = useService(ModelSaberService);
|
||||
const progress = useService(ProgressBarService);
|
||||
const modelDownloader = useService(ModelsDownloaderService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const { modelId } = useWindowArgs("modelId");
|
||||
const [model, setModel] = useState<MSModel>(null);
|
||||
const t = useTranslation();
|
||||
|
||||
@@ -30,9 +31,8 @@ export default function OneClickDownloadModel() {
|
||||
useEffect(() => {
|
||||
|
||||
const promise = (async () => {
|
||||
const infos = await lastValueFrom(ipc.sendV2<{ id: string; type: string }>("one-click-model-info"));
|
||||
|
||||
const model = await modelSaber.getModelById(infos.id);
|
||||
const model = await modelSaber.getModelById(modelId);
|
||||
|
||||
if (!model) {
|
||||
throw new Error("Failed to get model from ModelSaber");
|
||||
@@ -58,7 +58,7 @@ export default function OneClickDownloadModel() {
|
||||
});
|
||||
|
||||
promise.finally(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
@@ -13,16 +13,19 @@ import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { useConstant } from "renderer/hooks/use-constant.hook";
|
||||
import { BPList } from "shared/models/playlists/playlist.interface";
|
||||
import { useOnUpdate } from "renderer/hooks/use-on-update.hook";
|
||||
import { useWindowArgs } from "renderer/hooks/use-window-args.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function OneClickDownloadPlaylist() {
|
||||
|
||||
|
||||
|
||||
const t = useTranslation();
|
||||
const playlistDownloader = useService(PlaylistDownloaderService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const mapsContainer = useRef<HTMLDivElement>(null);
|
||||
const playlistUrl = useConstant(() => new URLSearchParams(window.location.search).get("playlistUrl"));
|
||||
const { playlistUrl } = useWindowArgs("playlistUrl");
|
||||
const download$ = useConstant(() => playlistDownloader.oneClickInstallPlaylist(playlistUrl));
|
||||
const playlistInfos = useObservable<BPList>(() => download$.pipe(filter(progress => !!progress.data?.playlistInfos), map(progress => progress.data.playlistInfos), take(1)));
|
||||
const downloadedMaps = useObservable(() => download$.pipe(filter(progress => !!progress.data?.downloadedMaps), map(progress => progress.data.downloadedMaps)));
|
||||
@@ -34,7 +37,7 @@ export default function OneClickDownloadPlaylist() {
|
||||
}).catch(() => {
|
||||
notification.notifySystem({ title: t("notifications.types.error"), body: t("notifications.playlists.one-click-install.error") });
|
||||
}).finally(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
}, []);
|
||||
@@ -61,7 +64,7 @@ export default function OneClickDownloadPlaylist() {
|
||||
<BsmImage className="mt-2 aspect-square w-1/2 object-cover rounded-md shadow-black shadow-lg" placeholder={defaultImage} image={playlistImage()} errorImage={defaultImage} />
|
||||
<h1 className="mt-4 overflow-hidden font-bold italic text-xl text-gray-200 tracking-wide w-full text-center whitespace-nowrap text-ellipsis px-2">{playlistInfos?.playlistTitle}</h1>
|
||||
<div className="w-full py-3 flex items-center justify-center max-w-full overflow-x-scroll overflow-y-hidden scrollbar scrollbar-thin scrollbar-track-transparent scrollbar-thumb-neutral-900" ref={mapsContainer}>
|
||||
<div className="flex justify-start items-start gap-2.5">{downloadedMaps?.map(map => map?.coverUrl &&
|
||||
<div className="flex justify-start items-start gap-2.5">{downloadedMaps?.map(map => map?.coverUrl &&
|
||||
<motion.img layout="position" key={map.hash} className="block aspect-square w-14 object-cover rounded-md shadow-black shadow-md" src={map?.coverUrl} initial={{ scale: 0 }} animate={{ scale: 1 }} whileHover={{ rotate: 5 }} />
|
||||
)}</div>
|
||||
</div>
|
||||
|
||||
@@ -13,20 +13,22 @@ import { BsNoteFill } from "renderer/components/svgs/icons/bs-note-fill.componen
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { motion } from "framer-motion"
|
||||
import { BSLaunchError, BSLaunchEventType, LaunchOption } from "shared/models/bs-launch";
|
||||
import { BSLaunchError, BSLaunchEventType } from "shared/models/bs-launch";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function ShortcutLaunch() {
|
||||
|
||||
|
||||
const windows = useService(WindowManagerService);
|
||||
const ipc = useService(IpcService);
|
||||
const bsLauncher = useService(BSLauncherService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const t = useTranslation();
|
||||
const color = useThemeColor("second-color");
|
||||
const launchOptions = useObservable(() => ipc.sendV2<LaunchOption>("shortcut-launch-options").pipe(take(1)), null)
|
||||
const launchOptions = useObservable(() => ipc.sendV2("shortcut-launch-options").pipe(take(1)), null)
|
||||
const [rotation, setRotation] = useState(0);
|
||||
const [status, setStatus] = useState<BSLaunchEventType>();
|
||||
|
||||
@@ -57,7 +59,7 @@ export default function ShortcutLaunch() {
|
||||
});
|
||||
|
||||
sub.add(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
return () => sub.unsubscribe();
|
||||
|
||||
@@ -5,4 +5,4 @@ export interface IpcRequest<T> {
|
||||
responceChannel?: string;
|
||||
}
|
||||
|
||||
export type IpcReplier = <T>(data: Observable<T>) => void;
|
||||
export type IpcReplier<T> = (data: Observable<T>) => void;
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { Observable } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BSLaunchEventData, LaunchOption } from "shared/models/bs-launch";
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import { BsmLocalMap, BsmLocalMapsProgress, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { SearchParams } from "../maps/beat-saver.model";
|
||||
import { ImportVersionOptions } from "main/services/bs-local-version.service";
|
||||
import { DownloadInfo, DownloadSteamInfo } from "main/services/bs-version-download/bs-steam-downloader.service";
|
||||
import { DepotDownloaderEvent } from "../bs-version-download/depot-downloader.model";
|
||||
import { MSGetQuery, MSModel, MSModelType } from "../models/model-saber.model";
|
||||
import { ModelDownload } from "renderer/services/models-management/models-downloader.service";
|
||||
import { BsmLocalModel } from "../models/bsm-local-model.interface";
|
||||
import { InstallModsResult, Mod, UninstallModsResult } from "../mods";
|
||||
import { BPList, DownloadPlaylistProgressionData } from "../playlists/playlist.interface";
|
||||
import { VersionLinkerAction } from "renderer/services/version-folder-linker.service";
|
||||
import { FileFilter, OpenDialogReturnValue } from "electron";
|
||||
import { SystemNotificationOptions } from "../notification/system-notification.model";
|
||||
import { Supporter } from "../supporters";
|
||||
import { AppWindow } from "../window-manager/app-window.model";
|
||||
import { LocalBPListsDetails } from "../playlists/local-playlist.models";
|
||||
|
||||
export type IpcReplier<T> = (data: Observable<T>) => void;
|
||||
|
||||
export interface IpcChannelMapping extends Record<string, { request: unknown, response: unknown }> {
|
||||
|
||||
/* ** bs-download-ipcs ** */
|
||||
"import-version": { request: ImportVersionOptions, response: Progression<BSVersion>};
|
||||
"is-dotnet-6-installed": { request: void, response: boolean};
|
||||
"bs-download.installation-folder": { request: void, response: string};
|
||||
"bs-download.set-installation-folder": { request: string, response: string};
|
||||
"auto-download-bs-version": { request: DownloadSteamInfo, response: DepotDownloaderEvent};
|
||||
"download-bs-version": { request: DownloadSteamInfo, response: DepotDownloaderEvent};
|
||||
"download-bs-version-qr": { request: DownloadSteamInfo, response: DepotDownloaderEvent};
|
||||
"stop-download-bs-version": { request: void, response: void};
|
||||
"send-input-bs-download": { request: string, response: boolean};
|
||||
"bs-oculus-download": { request: DownloadInfo, response: Progression<BSVersion>};
|
||||
"bs-oculus-stop-download": { request: void, response: void};
|
||||
|
||||
/* ** beat-saver-ipcs ** */
|
||||
"bsv-search-map": {request: SearchParams, response: BsvMapDetail[]};
|
||||
"bsv-get-map-details-from-hashs": {request: string[], response: BsvMapDetail[]};
|
||||
"bsv-get-map-details-by-id": {request: string, response: BsvMapDetail};
|
||||
|
||||
/* ** bs-launcher-ipcs ** */
|
||||
"create-launch-shortcut": { request: LaunchOption, response: boolean };
|
||||
"bs-launch.need-start-as-admin": { request: void, response: boolean };
|
||||
"bs-launch.launch": { request: LaunchOption, response: BSLaunchEventData };
|
||||
"bs-launch.restore-steamvr": { request: void, response: void };
|
||||
|
||||
/* ** bs-maps-ipcs ** */
|
||||
"load-version-maps": { request: BSVersion, response: BsmLocalMapsProgress};
|
||||
"delete-maps": { request: BsmLocalMap[], response: DeleteMapsProgress };
|
||||
"export-maps": { request: { version: BSVersion; maps: BsmLocalMap[]; outPath: string }, response: Progression };
|
||||
"download-map": { request: { map: BsvMapDetail; version: BSVersion }, response: BsmLocalMap };
|
||||
"one-click-install-map": { request: BsvMapDetail, response: void };
|
||||
"register-maps-deep-link": { request: void, response: boolean };
|
||||
"unregister-maps-deep-link": { request: void, response: boolean };
|
||||
"is-map-deep-links-enabled": { request: void, response: boolean };
|
||||
|
||||
/* ** bs-model-ipcs ** */
|
||||
"one-click-install-model": { request: MSModel, response: void };
|
||||
"register-models-deep-link": { request: void, response: boolean };
|
||||
"unregister-models-deep-link": { request: void, response: boolean };
|
||||
"is-models-deep-links-enabled": { request: void, response: boolean };
|
||||
"download-model": { request: ModelDownload, response: Progression<BsmLocalModel> };
|
||||
"get-version-models": { request: { version: BSVersion; type: MSModelType }, response: Progression<BsmLocalModel[]> };
|
||||
"export-models": { request: { version: BSVersion; models: BsmLocalModel[]; outPath: string }, response: Progression };
|
||||
"delete-models": { request: BsmLocalModel[], response: Progression<BsmLocalModel[]> };
|
||||
|
||||
/* ** bs-mods-ipcs ** */
|
||||
"get-available-mods": { request: BSVersion, response: Mod[] };
|
||||
"get-installed-mods": { request: BSVersion, response: Mod[] };
|
||||
"install-mods": { request: { mods: Mod[]; version: BSVersion }, response: InstallModsResult };
|
||||
"uninstall-mods": { request: { mods: Mod[]; version: BSVersion }, response: UninstallModsResult };
|
||||
"uninstall-all-mods": { request: BSVersion, response: UninstallModsResult };
|
||||
|
||||
/* ** bs-playlist-ipcs ** */
|
||||
"one-click-install-playlist": { request: string, response: Progression<DownloadPlaylistProgressionData> };
|
||||
"register-playlists-deep-link": { request: void, response: boolean };
|
||||
"unregister-playlists-deep-link": { request: void, response: boolean };
|
||||
"is-playlists-deep-links-enabled": { request: void, response: boolean };
|
||||
"install-playlist": {request: {playlist: BPList, version: BSVersion}, response: Progression<DownloadPlaylistProgressionData>};
|
||||
"get-version-playlists-details": {request: BSVersion, response: Progression<LocalBPListsDetails[]>};
|
||||
"delete-playlist": {request: {path: string, deleteMaps?: boolean}, response: Progression};
|
||||
|
||||
/* ** bs-uninstall-ipcs ** */
|
||||
"bs.uninstall": { request: BSVersion, response: boolean };
|
||||
|
||||
/* ** bs-version-ipcs ** */
|
||||
"bs-version.get-version-dict": { request: void, response: BSVersion[] };
|
||||
"bs-version.installed-versions": { request: void, response: BSVersion[] };
|
||||
"bs-version.open-folder": { request: BSVersion, response: void };
|
||||
"bs-version.edit": { request: { version: BSVersion; name: string; color: string }, response: BSVersion };
|
||||
"bs-version.clone": { request: { version: BSVersion; name: string; color: string }, response: BSVersion };
|
||||
"get-version-full-path": { request: BSVersion, response: string };
|
||||
"full-version-path-to-relative": { request: { version: BSVersion; fullPath: string }, response: string };
|
||||
"get-linked-folders": { request: { version: BSVersion; options?: { relative?: boolean } }, response: string[] };
|
||||
"link-version-folder-action": { request: VersionLinkerAction, response: boolean };
|
||||
"is-version-folder-linked": { request: { version: BSVersion; relativeFolder: string }, response: boolean };
|
||||
"relink-all-versions-folders": { request: void, response: void };
|
||||
|
||||
/* ** launcher-ipcs ** */
|
||||
"download-update": { request: void, response: boolean };
|
||||
"check-update": { request: void, response: boolean };
|
||||
"install-update": { request: void, response: void };
|
||||
|
||||
/* ** model-saber.ipcs ** */
|
||||
"ms-get-model-by-id": { request: string | number, response: MSModel };
|
||||
"search-models": { request: MSGetQuery, response: MSModel[] };
|
||||
|
||||
/* ** os-controls-ipcs ** */
|
||||
"new-window": { request: string, response: void };
|
||||
"choose-folder": { request: string, response: OpenDialogReturnValue };
|
||||
"window.progression": { request: number, response: void };
|
||||
"save-file": { request: { filename?: string; filters?: FileFilter[] }, response: string };
|
||||
"current-version": { request: void, response: string };
|
||||
"open-logs": { request: void, response: string };
|
||||
"notify-system": { request: SystemNotificationOptions, response: void };
|
||||
|
||||
/* ** supporters-ipcs ** */
|
||||
"get-supporters": { request: void, response: Supporter[] };
|
||||
|
||||
/* **window-manager-ipcs ** */
|
||||
"close-window": { request: void, response: void };
|
||||
"maximise-window": { request: void, response: void };
|
||||
"minimise-window": { request: void, response: void };
|
||||
"unmaximise-window": { request: void, response: void };
|
||||
"open-window-then-close-all": { request: AppWindow, response: void };
|
||||
"open-window-or-focus": { request: AppWindow, response: void };
|
||||
|
||||
/* ** OTHERS (if your IPC channel is not in a "-ipcs" file, put it here) ** */
|
||||
"shortcut-launch-options": { request: void, response: LaunchOption };
|
||||
}
|
||||
|
||||
export type IpcRequestType<Channel extends keyof IpcChannelMapping> = IpcChannelMapping[Channel]['request'];
|
||||
export type IpcResponseType<Channel extends keyof IpcChannelMapping> = IpcChannelMapping[Channel]['response'];
|
||||
export type IpcChannels = keyof IpcChannelMapping;
|
||||
Reference in New Issue
Block a user