mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-107] Can now open .bplist file with BSManager
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 401 KiB |
+1
-1
@@ -100,7 +100,7 @@
|
||||
"owner": "Zagrios"
|
||||
},
|
||||
"fileAssociations": [
|
||||
{ "ext": "bplist", "description": "Beat Saber Playlist", "icon": "./assets/favicon.ico", "role": "Viewer" }
|
||||
{ "ext": "bplist", "description": "Beat Saber Playlist (BSManager)", "icon": "./assets/bsm_file.ico", "role": "Viewer" }
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
|
||||
+27
-13
@@ -21,6 +21,7 @@ import { BSLauncherService } from "./services/bs-launcher/bs-launcher.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { LivShortcut } from "./services/liv/liv-shortcut.service";
|
||||
import { SteamLauncherService } from "./services/bs-launcher/steam-launcher.service";
|
||||
import { FileAssociationService } from "./services/file-association.service";
|
||||
|
||||
const isDebug = process.env.NODE_ENV === "development" || process.env.DEBUG_PROD === "true";
|
||||
|
||||
@@ -69,19 +70,29 @@ const initServicesMustBeInitialized = () => {
|
||||
BSLauncherService.getInstance();
|
||||
}
|
||||
|
||||
const findDeepLinkInArgs = (args: string[]): string => {
|
||||
return args.find(arg => DeepLinkService.getInstance().isDeepLink(arg));
|
||||
}
|
||||
|
||||
const findAssociatedFileInArgs = (args: string[]): string => {
|
||||
return args.find(arg => FileAssociationService.getInstance().isFileAssociated(arg));
|
||||
}
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit();
|
||||
} else {
|
||||
app.on("second-instance", (_, argv) => {
|
||||
const deepLink = argv.find(arg => DeepLinkService.getInstance().isDeepLink(arg));
|
||||
const deepLink = findDeepLinkInArgs(argv);
|
||||
const associatedFile = findAssociatedFileInArgs(argv);
|
||||
|
||||
if (!deepLink) {
|
||||
return;
|
||||
if (deepLink) {
|
||||
DeepLinkService.getInstance().dispatchLinkOpened(deepLink);
|
||||
} else if (associatedFile) {
|
||||
FileAssociationService.getInstance().handleFileAssociation(associatedFile);
|
||||
}
|
||||
|
||||
DeepLinkService.getInstance().dispatchLinkOpened(deepLink);
|
||||
});
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
@@ -90,25 +101,28 @@ if (!gotTheLock) {
|
||||
})
|
||||
|
||||
app.whenReady().then(() => {
|
||||
|
||||
|
||||
app.setAppUserModelId(APP_NAME);
|
||||
|
||||
initServicesMustBeInitialized();
|
||||
|
||||
const deepLink = process.argv.find(arg => DeepLinkService.getInstance().isDeepLink(arg));
|
||||
|
||||
if (!deepLink) {
|
||||
createWindow();
|
||||
} else {
|
||||
const deepLink = findDeepLinkInArgs(process.argv);
|
||||
const associatedFile = findAssociatedFileInArgs(process.argv);
|
||||
|
||||
if (deepLink) {
|
||||
DeepLinkService.getInstance().dispatchLinkOpened(deepLink);
|
||||
} else if (associatedFile) {
|
||||
FileAssociationService.getInstance().handleFileAssociation(associatedFile);
|
||||
} else {
|
||||
createWindow();
|
||||
}
|
||||
|
||||
|
||||
SteamLauncherService.getInstance().restoreSteamVR();
|
||||
|
||||
|
||||
// Log renderer errors
|
||||
ipcMain.on("log-error", (_, args: IpcRequest<unknown>) => {
|
||||
log.error(args?.args);
|
||||
});
|
||||
|
||||
|
||||
}).catch(log.error);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { readFileSync } from "fs";
|
||||
import { BeatSaverService } from "../thrid-party/beat-saver/beat-saver.service";
|
||||
import { copy, copyFile, pathExists, realpath } from "fs-extra";
|
||||
import { Progression, ensureFolderExist, pathExist } from "../../helpers/fs.helpers";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { FileAssociationService } from "../file-association.service";
|
||||
|
||||
export class LocalPlaylistsManagerService {
|
||||
private static instance: LocalPlaylistsManagerService;
|
||||
@@ -33,18 +33,18 @@ export class LocalPlaylistsManagerService {
|
||||
private readonly maps: LocalMapsManagerService;
|
||||
private readonly request: RequestService;
|
||||
private readonly deepLink: DeepLinkService;
|
||||
private readonly fileAssociation: FileAssociationService;
|
||||
private readonly windows: WindowManagerService;
|
||||
private readonly bsaver: BeatSaverService;
|
||||
private readonly ipc: IpcService;
|
||||
|
||||
private constructor() {
|
||||
this.maps = LocalMapsManagerService.getInstance();
|
||||
this.versions = BSLocalVersionService.getInstance();
|
||||
this.request = RequestService.getInstance();
|
||||
this.deepLink = DeepLinkService.getInstance();
|
||||
this.fileAssociation = FileAssociationService.getInstance();
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
this.bsaver = BeatSaverService.getInstance();
|
||||
this.ipc = IpcService.getInstance();
|
||||
|
||||
this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.BeatSaver, link => {
|
||||
log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link);
|
||||
@@ -52,11 +52,16 @@ export class LocalPlaylistsManagerService {
|
||||
const bplistUrl = url.host === "playlist" ? url.pathname.replace("/", "") : "";
|
||||
this.openOneClickDownloadPlaylistWindow(bplistUrl);
|
||||
});
|
||||
|
||||
this.fileAssociation.registerFileAssociation(".bplist", filePath => {
|
||||
log.info("FILE ASSOCIATION RECEIVED", filePath);
|
||||
this.openOneClickDownloadPlaylistWindow(filePath);
|
||||
});
|
||||
}
|
||||
|
||||
private async getPlaylistsFolder(version?: BSVersion) {
|
||||
if (!version) {
|
||||
throw "Playlists are not available to be linked yet";
|
||||
throw new Error("Playlists are not available to be linked yet");
|
||||
}
|
||||
|
||||
const versionFolder = await this.versions.getVersionPath(version);
|
||||
@@ -79,14 +84,14 @@ export class LocalPlaylistsManagerService {
|
||||
}
|
||||
return lastValueFrom(this.request.downloadFile(bslistSource, destFile)).then(res => res.data);
|
||||
}
|
||||
|
||||
|
||||
private async readPlaylistFile(path: string): Promise<BPList> {
|
||||
if (!(await pathExist(path))) {
|
||||
throw `bplist file not exist at ${path}`;
|
||||
|
||||
private async readPlaylistFile(filePath: string): Promise<BPList> {
|
||||
if (!(await pathExist(filePath))) {
|
||||
throw new Error(`bplist file not exist at ${filePath}`);
|
||||
}
|
||||
|
||||
const rawContent = readFileSync(path).toString();
|
||||
const rawContent = readFileSync(filePath).toString();
|
||||
|
||||
return JSON.parse(rawContent);
|
||||
}
|
||||
@@ -102,8 +107,8 @@ export class LocalPlaylistsManagerService {
|
||||
|
||||
const bpListFilePath = await this.installBPListFile(bpListUrl, version);
|
||||
const bpList = await this.readPlaylistFile(bpListFilePath);
|
||||
|
||||
const progress: Progression<DownloadPlaylistProgressionData> = {
|
||||
|
||||
const progress: Progression<DownloadPlaylistProgressionData> = {
|
||||
total: bpList.songs.length,
|
||||
current: 0,
|
||||
data: {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { pathExistsSync } from "fs-extra";
|
||||
import path from "path";
|
||||
import log from "electron-log";
|
||||
|
||||
export class FileAssociationService {
|
||||
private static instance: FileAssociationService;
|
||||
|
||||
public static getInstance(): FileAssociationService {
|
||||
if (!FileAssociationService.instance) {
|
||||
FileAssociationService.instance = new FileAssociationService();
|
||||
}
|
||||
return FileAssociationService.instance;
|
||||
}
|
||||
|
||||
private readonly listeners = new Map<ExtKey, Listerner[]>();
|
||||
|
||||
private constructor() {}
|
||||
|
||||
private getAbsolutePath(filePath: string) {
|
||||
return path.isAbsolute(filePath) ? filePath : path.join(process.cwd(), filePath);
|
||||
}
|
||||
|
||||
public registerFileAssociation(ext: ExtKey, fn: Listerner) {
|
||||
if (!this.listeners.has(ext)) {
|
||||
this.listeners.set(ext, [] as Listerner[]);
|
||||
}
|
||||
|
||||
this.listeners.get(ext).push(fn);
|
||||
}
|
||||
|
||||
public isFileAssociated(filePath: string): boolean {
|
||||
const fileExt = path.extname(filePath) as ExtKey;
|
||||
return this.listeners.has(fileExt);
|
||||
}
|
||||
|
||||
public handleFileAssociation(filePath: string) {
|
||||
const absolutePath = this.getAbsolutePath(filePath);
|
||||
|
||||
if(!pathExistsSync(absolutePath)) {
|
||||
log.error(`[FileAssociationService] File not found: ${absolutePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const fileExt = path.extname(absolutePath) as ExtKey;
|
||||
const listeners = this.listeners.get(fileExt);
|
||||
|
||||
if (!listeners) {
|
||||
log.error(`[FileAssociationService] No listeners for file: ${absolutePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
listeners.forEach(listener => listener(this.getAbsolutePath(filePath)));
|
||||
}
|
||||
}
|
||||
type ExtKey = `.${string}`;
|
||||
type Listerner = (filePath: string) => void;
|
||||
Reference in New Issue
Block a user