mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
oneclick install map from bsv now work
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import { render } from '@testing-library/react';
|
||||
import App from '../renderer/App';
|
||||
import App from '../renderer/windows/App';
|
||||
|
||||
describe('App', () => {
|
||||
it('should render', () => {
|
||||
|
||||
@@ -15,7 +15,7 @@ ipcMain.on("bsv-search-map", async (event, request: IpcRequest<SearchParams>) =>
|
||||
})
|
||||
});
|
||||
|
||||
ipcMain.on("bsv-bet-map-details-from-hashs", async (event, request: IpcRequest<string[]>) => {
|
||||
ipcMain.on("bsv-get-map-details-from-hashs", async (event, request: IpcRequest<string[]>) => {
|
||||
const utlis = UtilsService.getInstance();
|
||||
const bsvService = BeatSaverService.getInstance();
|
||||
|
||||
@@ -24,4 +24,15 @@ ipcMain.on("bsv-bet-map-details-from-hashs", async (event, request: IpcRequest<s
|
||||
}).catch(e => {
|
||||
utlis.ipcSend(request.responceChannel, {success: false, error: e});
|
||||
})
|
||||
});
|
||||
|
||||
ipcMain.on("bsv-get-map-details-by-id", async (event, request: IpcRequest<string>) => {
|
||||
const utlis = UtilsService.getInstance();
|
||||
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});
|
||||
})
|
||||
});
|
||||
@@ -84,6 +84,18 @@ ipcMain.on("download-map", async (event, request: IpcRequest<{map: BsvMapDetail,
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("one-click-install-map", async (event, request: IpcRequest<BsvMapDetail>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
maps.oneClickDownloadMap(request.args).then(() => {
|
||||
utils.ipcSend(request.responceChannel, {success: true});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
utils.ipcSend(request.responceChannel, {success: false, error: err});
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("register-maps-deep-link", async (event, request: IpcRequest<void>) => {
|
||||
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
+33
-7
@@ -15,6 +15,9 @@ import './ipcs';
|
||||
import { UtilsService } from './services/utils.service';
|
||||
import { WindowManagerService } from './services/window-manager.service';
|
||||
import { DeepLinkService } from './services/deep-link.service';
|
||||
import { AppWindow } from 'shared/models/window-manager/app-window.model';
|
||||
import { LocalMapsManagerService } from './services/maps/local-maps-manager.service';
|
||||
import { argv } from 'process';
|
||||
|
||||
export const PRELOAD_PATH = app.isPackaged ? path.join(__dirname, 'preload.js') : path.join(__dirname, '../../.erb/dll/preload.js')
|
||||
|
||||
@@ -48,11 +51,17 @@ const installExtensions = async () => {
|
||||
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.log);
|
||||
};
|
||||
|
||||
const createWindow = async () => {
|
||||
const createWindow = async (window: AppWindow = "launcher.html") => {
|
||||
if(isDebug){ await installExtensions(); }
|
||||
WindowManagerService.getInstance().openWindow("launcher.html");
|
||||
WindowManagerService.getInstance().openWindow(window);
|
||||
};
|
||||
|
||||
const initServicesMustBeInitialized = () => {
|
||||
LocalMapsManagerService.getInstance();
|
||||
// Playlist
|
||||
// Model
|
||||
}
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
// Respect the OSX convention of having the application in memory even
|
||||
// after all windows have been closed
|
||||
@@ -68,9 +77,30 @@ if(!gotTheLock){
|
||||
}
|
||||
else{
|
||||
|
||||
app.on('second-instance', (e, argv) => {
|
||||
|
||||
const deepLink = argv.find(arg => DeepLinkService.getInstance().isDeepLink(arg));
|
||||
|
||||
if(!deepLink){ return; }
|
||||
|
||||
DeepLinkService.getInstance().dispatchLinkOpened(deepLink);
|
||||
|
||||
});
|
||||
|
||||
app.whenReady().then(() => {
|
||||
|
||||
//process.argv.push("beatsaver://2d133");
|
||||
|
||||
initServicesMustBeInitialized();
|
||||
|
||||
createWindow();
|
||||
const deepLink = process.argv.find(arg => DeepLinkService.getInstance().isDeepLink(arg));
|
||||
|
||||
if(!deepLink){
|
||||
createWindow();
|
||||
}
|
||||
else{
|
||||
DeepLinkService.getInstance().dispatchLinkOpened(deepLink);
|
||||
}
|
||||
|
||||
protocol.registerFileProtocol('file', (request, callback) => {
|
||||
const pathname = decodeURI(request.url.replace('file:///', ''));
|
||||
@@ -78,8 +108,4 @@ else{
|
||||
});
|
||||
|
||||
}).catch(log.error);
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
DeepLinkService.getInstance().dispatchLinkOpened(url);
|
||||
});
|
||||
}
|
||||
@@ -16,6 +16,8 @@ export class DeepLinkService {
|
||||
|
||||
private readonly listeners = new Map<string, Listerner[]>()
|
||||
|
||||
private constructor(){}
|
||||
|
||||
public registerDeepLink(protocol: string): boolean{
|
||||
|
||||
if(process.defaultApp && process.argv.length >= 2){
|
||||
@@ -79,6 +81,19 @@ export class DeepLinkService {
|
||||
|
||||
}
|
||||
|
||||
public isDeepLink(link: string): boolean{
|
||||
|
||||
try{
|
||||
const url = new URL(link);
|
||||
const protocol = url.protocol.replace(":", "");
|
||||
return Array.from(this.listeners.keys()).some(key => key === protocol);
|
||||
}
|
||||
catch(e){
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type Listerner = (link: string) => void;
|
||||
@@ -14,6 +14,9 @@ import sanitize from "sanitize-filename";
|
||||
import archiver from "archiver";
|
||||
import { DeepLinkService } from "../deep-link.service";
|
||||
import log from 'electron-log';
|
||||
import { WindowManagerService } from "../window-manager.service";
|
||||
import { ipcMain } from "electron";
|
||||
import { IpcRequest } from 'shared/models/ipc';
|
||||
|
||||
export class LocalMapsManagerService {
|
||||
|
||||
@@ -37,6 +40,7 @@ export class LocalMapsManagerService {
|
||||
private readonly utils: UtilsService;
|
||||
private readonly reqService: RequestService;
|
||||
private readonly deepLink: DeepLinkService;
|
||||
private readonly windows: WindowManagerService;
|
||||
|
||||
private constructor(){
|
||||
this.localVersion = BSLocalVersionService.getInstance();
|
||||
@@ -44,13 +48,16 @@ export class LocalMapsManagerService {
|
||||
this.utils = UtilsService.getInstance();
|
||||
this.reqService = RequestService.getInstance();
|
||||
this.deepLink = DeepLinkService.getInstance();
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
|
||||
this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.BeatSaver, (link) => {
|
||||
log.info("RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link);
|
||||
log.info("MAP RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link);
|
||||
this.openOneClickDownloadMapWindow(new URL(link).host);
|
||||
});
|
||||
|
||||
this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.ScoreSaber, (link) => {
|
||||
log.info("RECEIVED FROM", this.DEEP_LINKS.ScoreSaber, link);
|
||||
log.info("MAP RECEIVED FROM", this.DEEP_LINKS.ScoreSaber, link);
|
||||
this.openOneClickDownloadMapWindow(new URL(link).host, true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -130,6 +137,18 @@ export class LocalMapsManagerService {
|
||||
|
||||
}
|
||||
|
||||
private openOneClickDownloadMapWindow(mapId: string, isHash = false): void{
|
||||
|
||||
this.windows.openWindow("oneclick-download-map.html");
|
||||
|
||||
console.log("oui");
|
||||
|
||||
ipcMain.once("one-click-map-info", async (event, req: IpcRequest<void>) => {
|
||||
this.utils.ipcSend(req.responceChannel, {success: true, data: {id: mapId, isHash}});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public async getMaps(version?: BSVersion): Promise<BsmLocalMap[]>{
|
||||
const levelsFolder = await this.getMapsFolderPath(version);
|
||||
|
||||
@@ -185,6 +204,8 @@ export class LocalMapsManagerService {
|
||||
}
|
||||
|
||||
public async deleteMaps(maps: BsmLocalMap[], verion?: BSVersion){
|
||||
|
||||
console.log(verion);
|
||||
|
||||
const mapsFolders = await this.getAbsoluteFolderOfMaps(maps, verion);
|
||||
const mapsHashsToDelete = maps.map(map => map.hash);
|
||||
@@ -198,11 +219,11 @@ export class LocalMapsManagerService {
|
||||
|
||||
}
|
||||
|
||||
public async downloadMap(map: BsvMapDetail, version?: BSVersion){
|
||||
public async downloadMap(map: BsvMapDetail, version?: BSVersion): Promise<string>{
|
||||
|
||||
if(!map.versions.at(0).hash){ throw "Cannot download map, no hash found"; }
|
||||
|
||||
const zipUrl = `https://r2cdn.beatsaver.com/${map.versions.at(0).hash}.zip`
|
||||
const zipUrl = map.versions.at(0).downloadURL;
|
||||
|
||||
const mapsFolder = await this.getMapsFolderPath(version);
|
||||
|
||||
@@ -220,6 +241,8 @@ export class LocalMapsManagerService {
|
||||
await zip.close();
|
||||
|
||||
unlinkSync(zipPath);
|
||||
|
||||
return mapPath;
|
||||
}
|
||||
|
||||
public async exportMaps(version: BSVersion, maps: BsmLocalMap[], outPath: string){
|
||||
@@ -250,6 +273,32 @@ export class LocalMapsManagerService {
|
||||
|
||||
}
|
||||
|
||||
public async oneClickDownloadMap(map: BsvMapDetail): Promise<void>{
|
||||
|
||||
console.log("AALLLOO");
|
||||
|
||||
const downloadedMap = await this.downloadMap(map);
|
||||
|
||||
console.log(downloadedMap);
|
||||
|
||||
const versions = await this.localVersion.getInstalledVersions();
|
||||
|
||||
for(const version of versions){
|
||||
|
||||
if(await this.versionIsLinked(version)){ continue; }
|
||||
|
||||
const versionMapsPath = await this.getMapsFolderPath(version);
|
||||
|
||||
this.utils.createFolderIfNotExist(versionMapsPath);
|
||||
|
||||
console.log(downloadedMap, path.join(versionMapsPath, path.basename(downloadedMap)));
|
||||
|
||||
copySync(downloadedMap, path.join(versionMapsPath, path.basename(downloadedMap)), {overwrite: true});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enableDeepLinks(): boolean{
|
||||
return Array.from(Object.values(this.DEEP_LINKS)).every(link => this.deepLink.registerDeepLink(link));
|
||||
}
|
||||
|
||||
@@ -89,6 +89,16 @@ export class BeatSaverApiService {
|
||||
|
||||
}
|
||||
|
||||
public async getMapDetailsById(id: string): Promise<ApiResult<BsvMapDetail>>{
|
||||
|
||||
const res = await fetch(`${this.bsaverApiUrl}/maps/id/${id}`);
|
||||
|
||||
const data = await res.json() as BsvMapDetail;
|
||||
|
||||
return {status: res.status, data};
|
||||
|
||||
}
|
||||
|
||||
public async searchMaps(search: SearchParams): Promise<ApiResult<SearchResponse>>{
|
||||
|
||||
console.log(search);
|
||||
|
||||
@@ -47,6 +47,13 @@ export class BeatSaverService {
|
||||
return mapDetails;
|
||||
}
|
||||
|
||||
public async getMapDetailsById(id: string): Promise<BsvMapDetail>{
|
||||
|
||||
const res = await this.bsaverApi.getMapDetailsById(id);
|
||||
return res.data;
|
||||
|
||||
}
|
||||
|
||||
public searchMaps(search: SearchParams): Promise<BsvMapDetail[]>{
|
||||
|
||||
return this.bsaverApi.searchMaps(search).then(res => {
|
||||
|
||||
@@ -12,7 +12,8 @@ export class WindowManagerService{
|
||||
|
||||
private readonly appWindowsOptions: Record<AppWindow, BrowserWindowConstructorOptions> = {
|
||||
"launcher.html": {width: 380, height: 500, minWidth: 380, minHeight: 500, resizable: false},
|
||||
"index.html": {width: 1080, height: 720, minWidth: 900, minHeight: 500}
|
||||
"index.html": {width: 1080, height: 720, minWidth: 900, minHeight: 500},
|
||||
"oneclick-download-map.html": {width: 350, height: 400, minWidth: 350, minHeight: 400, resizable: false}
|
||||
}
|
||||
|
||||
private readonly baseWindowOption: BrowserWindowConstructorOptions = {
|
||||
@@ -32,15 +33,18 @@ export class WindowManagerService{
|
||||
|
||||
private constructor(){}
|
||||
|
||||
public openWindow(windowType: AppWindow): Promise<BrowserWindow>{
|
||||
const window = new BrowserWindow({...this.appWindowsOptions[windowType], ...this.baseWindowOption});
|
||||
public openWindow(windowType: AppWindow, options?: BrowserWindowConstructorOptions): Promise<BrowserWindow>{
|
||||
const window = new BrowserWindow({...this.appWindowsOptions[windowType], ...this.baseWindowOption, ...options});
|
||||
|
||||
console.log({...this.appWindowsOptions[windowType], ...this.baseWindowOption, ...options});
|
||||
|
||||
const promise = window.loadURL(resolveHtmlPath(windowType));
|
||||
window.removeMenu();
|
||||
window.setMenu(null);
|
||||
|
||||
window.once("ready-to-show", () => {
|
||||
if (!window) { throw new Error('"window" is not defined'); }
|
||||
return window.show();
|
||||
window.show();
|
||||
});
|
||||
|
||||
window.once("closed", () => {
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
|
||||
const handleDelete = useCallback((map: BsmLocalMap) => {
|
||||
mapsManager.deleteMaps([map], version).then(res => res && loadMaps())
|
||||
}, []);
|
||||
}, [version]);
|
||||
|
||||
const extractMapDiffs = (map: BsmLocalMap): Map<BsvMapCharacteristic, ParsedMapDiff[]> => {
|
||||
const res = new Map<BsvMapCharacteristic, ParsedMapDiff[]>();
|
||||
|
||||
@@ -14,20 +14,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#window-controls {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 46px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#window-controls .button {
|
||||
grid-row: 1 / span 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#close-button:hover {
|
||||
background: #E81123 !important;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
||||
import { IpcService } from 'renderer/services/ipc.service';
|
||||
import './title-bar.component.css'
|
||||
|
||||
export default function TitleBar({template = "main"} : {template?: "update"|"main"}) {
|
||||
export default function TitleBar({template = "main"} : {template?: "update"|"main"|"oneclick"}) {
|
||||
|
||||
const ipcService = IpcService.getInstance();
|
||||
|
||||
@@ -30,24 +30,51 @@ export default function TitleBar({template = "main"} : {template?: "update"|"mai
|
||||
setMaximized(!maximized);
|
||||
}
|
||||
|
||||
return (
|
||||
<header id="titlebar" className="min-h-[22px] bg-light-main-color-1 shrink-0 dark:bg-main-color-1 w-screen h-[22px] flex content-center items-center justify-start z-10">
|
||||
<div id="drag-region" className='grow basis-0 h-full'>
|
||||
{template !== "update" && (<div id="window-title" className='pl-1'>
|
||||
<span className='text-gray-800 dark:text-gray-100 font-bold text-xs italic'>BSManager</span>
|
||||
</div>)}
|
||||
</div>
|
||||
{template !== "update" && (<div id="window-controls">
|
||||
<div onClick={minimizeWindow} className="button button text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-[#4F545C] cursor-pointer" id="min-button" >
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect fill="currentColor" width="10" height="1" x="1" y="6"> </rect></svg>
|
||||
</div>
|
||||
<div onClick={toogleMaximize} className="button text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-[#4F545C] cursor-pointer" id="max-button">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="currentColor"> </rect></svg>
|
||||
</div>
|
||||
<div onClick={closeWindow} className="button text-gray-800 dark:text-gray-200 cursor-pointer" id="close-button" draggable="false">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><polygon fill="currentColor" fillRule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"> </polygon></svg>
|
||||
</div>
|
||||
</div>)}
|
||||
</header>
|
||||
)
|
||||
if(template === "main"){
|
||||
|
||||
return (
|
||||
<header id="titlebar" className="min-h-[22px] bg-light-main-color-1 shrink-0 dark:bg-main-color-1 w-screen h-[22px] flex content-center items-center justify-start z-10">
|
||||
<div id="drag-region" className='grow basis-0 h-full'>
|
||||
<div id="window-title" className='pl-1'>
|
||||
<span className='text-gray-800 dark:text-gray-100 font-bold text-xs italic'>BSManager</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="window-controls" className="h-full flex shrink-0">
|
||||
<div onClick={minimizeWindow} className="text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-[#4F545C] cursor-pointer w-11 h-full shrink-0 flex justify-center items-center" id="min-button" >
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect fill="currentColor" width="10" height="1" x="1" y="6"> </rect></svg>
|
||||
</div>
|
||||
<div onClick={toogleMaximize} className="text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-[#4F545C] cursor-pointer w-11 h-full shrink-0 flex justify-center items-center" id="max-button">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="currentColor"> </rect></svg>
|
||||
</div>
|
||||
<div onClick={closeWindow} className="text-gray-800 dark:text-gray-200 cursor-pointer w-11 h-full shrink-0 flex justify-center items-center" id="close-button" draggable="false">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><polygon fill="currentColor" fillRule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"> </polygon></svg>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
||||
}
|
||||
if(template === "update"){
|
||||
return (
|
||||
<header id="titlebar" className="min-h-[22px] bg-transparent w-screen h-[22px] z-10">
|
||||
<div id="drag-region" className='grow basis-0 h-full'></div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
if(template === "oneclick"){
|
||||
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'>
|
||||
<div id="window-title" className='pl-1'>
|
||||
<span className='text-gray-100 font-bold text-xs italic'>BSManager</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="window-controls" className="h-full flex shrink-0">
|
||||
<div onClick={closeWindow} className="text-gray-200 cursor-pointer w-7 h-full shrink-0 flex justify-center items-center rounded-bl-md" id="close-button" draggable="false">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><polygon fill="currentColor" fillRule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"> </polygon></svg>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
font-family: acumin-pro, sans-serif;
|
||||
}
|
||||
|
||||
html, body{
|
||||
margin: 0; padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html.dark{
|
||||
background-color: #202225;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
//@ts-ignore
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { HashRouter } from 'react-router-dom';
|
||||
import App from './App';
|
||||
import Launcher from './Launcher';
|
||||
import App from './windows/App';
|
||||
import Launcher from './windows/Launcher';
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import './index.css'
|
||||
import OneClickDownloadMap from './windows/OneClick/OneClickDownloadMap';
|
||||
|
||||
const launcherContainer = document.getElementById('launcher');
|
||||
const oneclickDownloadMapContainer = document.getElementById('oneclick-download-map');
|
||||
|
||||
if(!!launcherContainer){
|
||||
createRoot(launcherContainer).render(<Launcher/>)
|
||||
}
|
||||
else if(!!oneclickDownloadMapContainer){
|
||||
createRoot(oneclickDownloadMapContainer).render(<OneClickDownloadMap/>)
|
||||
}
|
||||
else{
|
||||
const root = document.getElementById('root');
|
||||
createRoot(root).render(
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://use.typekit.net/okr8ven.css">
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="script-src 'self' 'unsafe-inline'"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="oneclick-download-map"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -122,6 +122,16 @@ export class MapsDownloaderService {
|
||||
this.downloadedListerners.splice(funcIndex, 1);
|
||||
}
|
||||
|
||||
public async oneClickInstallMap(map: BsvMapDetail): Promise<boolean>{
|
||||
|
||||
this.progressBar.showFake(0.008);
|
||||
|
||||
const res = await this.ipc.send<void, BsvMapDetail>("one-click-install-map", {args: map});
|
||||
|
||||
return res.success;
|
||||
|
||||
}
|
||||
|
||||
public get isDownloading(): boolean{
|
||||
return !!this.currentDownload$.value;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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 { finalize } from "rxjs/operators";
|
||||
import { Subject, Observable } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface";
|
||||
|
||||
@@ -4,6 +4,8 @@ import { IpcService } from "./ipc.service";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { CSSProperties } from "react";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { from } from "rxjs";
|
||||
import { of } from "rxjs";
|
||||
|
||||
export class ProgressBarService{
|
||||
|
||||
@@ -73,6 +75,10 @@ export class ProgressBarService{
|
||||
this._progression$.next({progression: 100});
|
||||
}
|
||||
|
||||
public open(): void{
|
||||
this.show(of(0), true, this._style$.value);
|
||||
}
|
||||
|
||||
public hide(unsubscribe: boolean = true){
|
||||
if(unsubscribe){ this.unsubscribe(); }
|
||||
this._visible$.next(false);
|
||||
|
||||
@@ -17,10 +17,16 @@ export class BeatSaverService {
|
||||
}
|
||||
|
||||
public async getMapDetailsFromHashs(hashs: string[]): Promise<BsvMapDetail[]>{
|
||||
const res = await this.ipc.send<BsvMapDetail[], string[]>("bsv-bet-map-details-from-hashs", {args: hashs});
|
||||
const res = await this.ipc.send<BsvMapDetail[], string[]>("bsv-get-map-details-from-hashs", {args: hashs});
|
||||
return res.data ?? [];
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public async searchMaps(search: SearchParams): Promise<BsvMapDetail[]>{
|
||||
const res = await this.ipc.send<BsvMapDetail[], SearchParams>("bsv-search-map", {args: search});
|
||||
return res.data ?? []
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { NavBar } from "./components/nav-bar/nav-bar.component";
|
||||
import TitleBar from "./components/title-bar/title-bar.component";
|
||||
import { NavBar } from "../components/nav-bar/nav-bar.component";
|
||||
import TitleBar from "../components/title-bar/title-bar.component";
|
||||
import { Routes, Route, useLocation } from "react-router-dom";
|
||||
import { AvailableVersionsList } from "./pages/available-versions-list.components";
|
||||
import { VersionViewer } from "./pages/version-viewer.component";
|
||||
import { Modal } from "./components/modal/modal.component";
|
||||
import { SettingsPage } from "./pages/settings-page.component";
|
||||
import { BsmProgressBar } from "./components/progress-bar/bsm-progress-bar.component";
|
||||
import { AvailableVersionsList } from "../pages/available-versions-list.components";
|
||||
import { VersionViewer } from "../pages/version-viewer.component";
|
||||
import { Modal } from "../components/modal/modal.component";
|
||||
import { SettingsPage } from "../pages/settings-page.component";
|
||||
import { BsmProgressBar } from "../components/progress-bar/bsm-progress-bar.component";
|
||||
import { useEffect } from "react";
|
||||
import { ThemeService } from "./services/theme.service";
|
||||
import { NotificationOverlay } from "./components/notification/notification-overlay.component";
|
||||
import { PageStateService } from "./services/page-state.service";
|
||||
import { MapsPage } from "./pages/maps-page.component";
|
||||
import { ThemeService } from "../services/theme.service";
|
||||
import { NotificationOverlay } from "../components/notification/notification-overlay.component";
|
||||
import { PageStateService } from "../services/page-state.service";
|
||||
import { MapsPage } from "../pages/maps-page.component";
|
||||
import "tailwindcss/tailwind.css";
|
||||
import { BsmIframeView } from "./components/shared/bsm-map-preview.component";
|
||||
import { BsmIframeView } from "../components/shared/bsm-map-preview.component";
|
||||
import 'tippy.js/dist/tippy.css';
|
||||
|
||||
export default function App() {
|
||||
@@ -1,12 +1,12 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { BsManagerIcon } from "./components/nav-bar/bsmanager-icon.component";
|
||||
import { BsmProgressBar } from "./components/progress-bar/bsm-progress-bar.component";
|
||||
import TitleBar from "./components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "./hooks/use-translation.hook";
|
||||
import { AutoUpdaterService } from "./services/auto-updater.service";
|
||||
import { ThemeService } from "./services/theme.service";
|
||||
import { WindowManagerService } from "./services/window-manager.service";
|
||||
import { BsManagerIcon } from "../components/nav-bar/bsmanager-icon.component";
|
||||
import { BsmProgressBar } from "../components/progress-bar/bsm-progress-bar.component";
|
||||
import TitleBar from "../components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "../hooks/use-translation.hook";
|
||||
import { AutoUpdaterService } from "../services/auto-updater.service";
|
||||
import { ThemeService } from "../services/theme.service";
|
||||
import { WindowManagerService } from "../services/window-manager.service";
|
||||
|
||||
export default function Launcher() {
|
||||
|
||||
@@ -22,6 +22,7 @@ export default function Launcher() {
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const sub = themeService.theme$.subscribe(() => {
|
||||
if(themeService.isDark || (themeService.isOS && window.matchMedia('(prefers-color-scheme: dark)').matches)){ document.documentElement.classList.add('dark'); }
|
||||
else { document.documentElement.classList.remove('dark'); }
|
||||
@@ -0,0 +1,75 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-bar.component";
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import TitleBar from "renderer/components/title-bar/title-bar.component";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { MapsDownloaderService } from "renderer/services/maps-downloader.service";
|
||||
import { ProgressBarService } from "renderer/services/progress-bar.service";
|
||||
import { ThemeService } from "renderer/services/theme.service";
|
||||
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import defaultImage from '../../../../assets/images/default-version-img.jpg'
|
||||
|
||||
export default function OneClickDownloadMap() {
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
const bsv = BeatSaverService.getInstance();
|
||||
const mapsDownloader = MapsDownloaderService.getInstance();
|
||||
const themeService = ThemeService.getInstance();
|
||||
const progressBar = ProgressBarService.getInstance();
|
||||
|
||||
const [mapInfo, setMapInfo] = useState<BsvMapDetail>(null);
|
||||
|
||||
const cover = mapInfo ? mapInfo.versions.at(0).coverURL : null;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const sub = themeService.theme$.subscribe(() => {
|
||||
if(themeService.isDark || (themeService.isOS && window.matchMedia('(prefers-color-scheme: dark)').matches)){ document.documentElement.classList.add('dark'); }
|
||||
else { document.documentElement.classList.remove('dark'); }
|
||||
});
|
||||
|
||||
progressBar.open();
|
||||
|
||||
ipc.send<{id: string, isHash: boolean}>("one-click-map-info").then(res => {
|
||||
|
||||
console.log(res);
|
||||
|
||||
if(res.data.isHash){
|
||||
return bsv.getMapDetailsFromHashs([res.data.id]).then(res => setMapInfo(() => res.at(0)));
|
||||
}
|
||||
|
||||
bsv.getMapDetailsById(res.data.id).then(async map => {
|
||||
|
||||
setMapInfo(() => map);
|
||||
|
||||
mapsDownloader.oneClickInstallMap(map).finally(() => ipc.sendLazy('window.close'));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
console.log(mapInfo);
|
||||
|
||||
return (
|
||||
<div className="relative w-screen h-screen overflow-hidden">
|
||||
<div className="w-full h-full absolute top-0 left-0">
|
||||
<BsmImage className="absolute top-0 left-0 w-full h-full object-cover bg-center" placeholder={defaultImage} image={cover}/>
|
||||
</div>
|
||||
<div className="w-full h-full absolute top-0 left-0 backdrop-blur-md backdrop-brightness-50 flex flex-col justify-start items-center gap-10">
|
||||
<TitleBar template="oneclick"/>
|
||||
<BsmImage className="aspect-square w-1/2 object-cover rounded-md bg-center shadow-black shadow-lg" placeholder={defaultImage} image={cover}/>
|
||||
<h1 className="font-bold italic text-xl text-gray-200 tracking-wide">{mapInfo?.name ?? "Chargement de la map..."}</h1>
|
||||
</div>
|
||||
<BsmProgressBar/>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
@@ -1 +1,5 @@
|
||||
export type AppWindow = "index.html" | "launcher.html";
|
||||
export type AppWindow = (
|
||||
"index.html" |
|
||||
"launcher.html" |
|
||||
"oneclick-download-map.html"
|
||||
);
|
||||
Reference in New Issue
Block a user