mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
fix rerendering AND fix downloader map folder name
This commit is contained in:
Generated
+1
-4
@@ -12111,7 +12111,6 @@
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
|
||||
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"truncate-utf8-bytes": "^1.0.0"
|
||||
}
|
||||
@@ -13207,7 +13206,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
||||
"integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"utf8-byte-length": "^1.0.1"
|
||||
}
|
||||
@@ -13567,8 +13565,7 @@
|
||||
"utf8-byte-length": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
|
||||
"integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA=="
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
|
||||
@@ -248,6 +248,7 @@
|
||||
"react-visibility-sensor": "^5.1.1",
|
||||
"regedit": "^5.1.1",
|
||||
"rxjs": "^7.5.6",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"semver": "^7.3.8",
|
||||
"tailwind-scrollbar-hide": "^1.1.7",
|
||||
"tailwindcss-scoped-groups": "^2.0.0",
|
||||
|
||||
@@ -4,6 +4,7 @@ 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";
|
||||
|
||||
ipcMain.on('get-version-maps', (event, request: IpcRequest<BSVersion>) => {
|
||||
const utilsService = UtilsService.getInstance();
|
||||
@@ -60,11 +61,11 @@ ipcMain.on("delete-maps", async (event, request: IpcRequest<{version: BSVersion,
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("download-map", async (event, request: IpcRequest<{zipUrl: string, version: BSVersion}>) => {
|
||||
ipcMain.on("download-map", async (event, request: IpcRequest<{map: BsvMapDetail, version: BSVersion}>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
maps.downloadMap(request.args.zipUrl, request.args.version).then(() => {
|
||||
maps.downloadMap(request.args.map, request.args.version).then(() => {
|
||||
utils.ipcSend(request.responceChannel, {success: true});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from "path";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { RawMapInfoData } from "shared/models/maps";
|
||||
import { BsvMapDetail, RawMapInfoData } from "shared/models/maps";
|
||||
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { BSLocalVersionService } from "../bs-local-version.service";
|
||||
import { InstallationLocationService } from "../installation-location.service";
|
||||
@@ -10,6 +10,7 @@ import { lstatSync, symlinkSync, unlinkSync, readdirSync } from "fs";
|
||||
import { copySync } from "fs-extra";
|
||||
import StreamZip from "node-stream-zip";
|
||||
import { RequestService } from "../request.service";
|
||||
import sanitize from "sanitize-filename";
|
||||
|
||||
export class LocalMapsManagerService {
|
||||
|
||||
@@ -162,16 +163,19 @@ export class LocalMapsManagerService {
|
||||
|
||||
}
|
||||
|
||||
public async downloadMap(zipUrl: string, version?: BSVersion){
|
||||
public async downloadMap(map: BsvMapDetail, version?: BSVersion){
|
||||
|
||||
console.log(zipUrl, version);
|
||||
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 mapsFolder = await this.getMapsFolderPath(version);
|
||||
|
||||
const {zip, zipPath} = await this.downloadMapZip(zipUrl);
|
||||
const zipName = path.parse(zipPath).name;
|
||||
|
||||
const mapPath = path.join(mapsFolder, zipName);
|
||||
const mapFolderName = sanitize(`${map.id}-${map.name}`);
|
||||
|
||||
const mapPath = path.join(mapsFolder, mapFolderName);
|
||||
|
||||
if(!zip){ throw `Cannot download ${zipUrl}`; }
|
||||
|
||||
|
||||
+9
-6
@@ -1,6 +1,6 @@
|
||||
import { MapsManagerService } from "renderer/services/maps-manager.service"
|
||||
import { BSVersion } from "shared/bs-version.interface"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"
|
||||
import { Subscription } from "rxjs"
|
||||
import { MapItem, ParsedMapDiff } from "./map-item.component"
|
||||
@@ -46,9 +46,11 @@ export function LocalMapsListPanel({version, className, filter, search} : Props)
|
||||
subs.push(mapsManager.getMaps(version).subscribe(localMaps => setMaps(() => [...localMaps])));
|
||||
}
|
||||
|
||||
const handleDelete = (map: BsmLocalMap) => {
|
||||
const handleDelete = useCallback((hash: string) => {
|
||||
const map = maps.find(map => map.hash === hash);
|
||||
console.log(maps);
|
||||
mapsManager.deleteMaps([map], version).then(res => res && loadMaps())
|
||||
}
|
||||
}, [maps]);
|
||||
|
||||
const extractMapDiffs = (map: BsmLocalMap): Map<BsvMapCharacteristic, ParsedMapDiff[]> => {
|
||||
const res = new Map<BsvMapCharacteristic, ParsedMapDiff[]>();
|
||||
@@ -73,7 +75,7 @@ export function LocalMapsListPanel({version, className, filter, search} : Props)
|
||||
return res;
|
||||
}
|
||||
|
||||
const onMapSelected = (hash: string) => {
|
||||
const onMapSelected = useCallback((hash: string) => {
|
||||
const hashs = [...selectedMaps];
|
||||
if(hashs.some(selectedHash => selectedHash === hash)){
|
||||
const i = hashs.findIndex(selectedHash => selectedHash === hash);
|
||||
@@ -83,7 +85,7 @@ export function LocalMapsListPanel({version, className, filter, search} : Props)
|
||||
hashs.push(hash);
|
||||
}
|
||||
setSelectedMaps(() => hashs);
|
||||
}
|
||||
}, [selectedMaps]);
|
||||
|
||||
const isMapFitFilter = (map: BsmLocalMap): boolean => {
|
||||
|
||||
@@ -199,8 +201,9 @@ export function LocalMapsListPanel({version, className, filter, search} : Props)
|
||||
duration={map.bsaverInfo?.metadata?.duration}
|
||||
selected={selectedMaps.some(hash => hash === map.hash)}
|
||||
diffs={extractMapDiffs(map)} mapId={map.bsaverInfo?.id} qualified={null} ranked={map.bsaverInfo?.ranked} autorId={map.bsaverInfo?.uploader?.id} likes={map.bsaverInfo?.stats?.upvotes} createdAt={map.bsaverInfo?.createdAt}
|
||||
onDelete={() => handleDelete(map)}
|
||||
onDelete={handleDelete}
|
||||
onSelected={onMapSelected}
|
||||
callBackParam={map.hash}
|
||||
/>;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { BsmBasicSpinner } from "../shared/bsm-basic-spinner/bsm-basic-spinner.c
|
||||
|
||||
export type ParsedMapDiff = {type: BsvMapDifficultyType, name: string, stars: number}
|
||||
|
||||
export type MapItemProps = {
|
||||
export type MapItemProps<T = any> = {
|
||||
hash: string,
|
||||
title: string,
|
||||
autor: string,
|
||||
@@ -37,19 +37,18 @@ export type MapItemProps = {
|
||||
createdAt: string,
|
||||
selected?: boolean,
|
||||
downloading?: boolean,
|
||||
onDelete?: (hash: string) => void,
|
||||
onDownload?: (zipUrl: string) => void,
|
||||
onSelected?: (hash: string) => void,
|
||||
onCancelDownload?: (zipUrl: string) => void
|
||||
callBackParam: T
|
||||
onDelete?: (param: T) => void,
|
||||
onDownload?: (param: T) => void,
|
||||
onSelected?: (param: T) => void,
|
||||
onCancelDownload?: (param: T) => void
|
||||
}
|
||||
|
||||
export const MapItem = memo(({hash, title, autor, songAutor, coverUrl, songUrl, autorId, mapId, diffs, qualified, ranked, bpm, duration, likes, createdAt, selected, downloading, onDelete, onDownload, onSelected, onCancelDownload}: MapItemProps) => {
|
||||
export const MapItem = memo(({hash, title, autor, songAutor, coverUrl, songUrl, autorId, mapId, diffs, qualified, ranked, bpm, duration, likes, createdAt, selected, downloading, callBackParam, onDelete, onDownload, onSelected, onCancelDownload}: MapItemProps) => {
|
||||
|
||||
const linkOpener = LinkOpenerService.getInstance();
|
||||
const audioPlayer = AudioPlayerService.getInstance();
|
||||
|
||||
|
||||
|
||||
const color = useThemeColor("first-color");
|
||||
|
||||
const [hovered, setHovered] = useState(false);
|
||||
@@ -132,7 +131,7 @@ export const MapItem = memo(({hash, title, autor, songAutor, coverUrl, songUrl,
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.li className="relative h-[100px] min-w-[370px] shrink-0 grow basis-0 text-white group cursor-pointer" onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)} style={{zIndex: hovered && 5, transform: "translateZ(0) scale(1.0, 1.0)", backfaceVisibility: "hidden"}} onClick={e => {onSelected?.(hash)}}>
|
||||
<motion.li className="relative h-[100px] min-w-[370px] shrink-0 grow basis-0 text-white group cursor-pointer" onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)} style={{zIndex: hovered && 5, transform: "translateZ(0) scale(1.0, 1.0)", backfaceVisibility: "hidden"}} onClick={e => {onSelected?.(callBackParam)}}>
|
||||
{(hovered || selected) && onSelected && <motion.span className="glow-on-hover !transition-none" animate={{opacity: 1}} transition={{duration: .2, ease: "linear"}}/>}
|
||||
<AnimatePresence>
|
||||
{(diffsPanelHovered || bottomBarHovered) && (
|
||||
@@ -209,9 +208,9 @@ export const MapItem = memo(({hash, title, autor, songAutor, coverUrl, songUrl,
|
||||
<span className="absolute w-[10px] h-[10px] bottom-0 right-full bg-inherit" style={{clipPath: 'path("M11 11 L11 0 L10 0 A10 10 0 0 1 0 10 L 0 11 Z")'}}/>
|
||||
|
||||
<div className="flex flex-col justify-center items-center gap-1 w-full h-full overflow-hidden opacity-0 group-hover:opacity-100">
|
||||
{onDelete && !downloading && <BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={color} icon="trash" withBar={false} onClick={e => {e.stopPropagation(); onDelete(hash)}}/>}
|
||||
{onDownload && !downloading && <BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={color} icon="download" withBar={false} onClick={e => {e.stopPropagation(); onDownload(zipUrl)}}/>}
|
||||
{onCancelDownload && !downloading && <BsmButton className="w-6 h-6 p-1 rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={"red"} icon="cross" withBar={false} onClick={e => {e.stopPropagation(); onCancelDownload(zipUrl)}}/>}
|
||||
{onDelete && !downloading && <BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={color} icon="trash" withBar={false} onClick={e => {e.stopPropagation(); onDelete(callBackParam)}}/>}
|
||||
{onDownload && !downloading && <BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={color} icon="download" withBar={false} onClick={e => {e.stopPropagation(); onDownload(callBackParam)}}/>}
|
||||
{onCancelDownload && !downloading && <BsmButton className="w-6 h-6 p-1 rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={"red"} icon="cross" withBar={false} onClick={e => {e.stopPropagation(); onCancelDownload(callBackParam)}}/>}
|
||||
{downloading && <BsmBasicSpinner className="w-6 h-6 p-1 rounded-md !bg-inherit hover:!bg-main-color-2 flex items-center justify-center" spinnerClassName="brightness-150" style={{color}} thikness="3px"/>}
|
||||
{previewUrl && <BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={color} icon="eye" withBar={false} onClick={e => {e.stopPropagation(); openPreview()}}/>}
|
||||
{mapId && <BsmButton className="w-6 h-6 p-1 rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150" iconColor={color} icon="twitch" withBar={false} onClick={e => {e.stopPropagation(); copyBsr()}}/>}
|
||||
@@ -223,6 +222,11 @@ export const MapItem = memo(({hash, title, autor, songAutor, coverUrl, songUrl,
|
||||
}, areEqual)
|
||||
|
||||
function areEqual(prevProps: MapItemProps, nextProps: MapItemProps): boolean {
|
||||
Array.from(Object.entries(prevProps)).forEach(v => {
|
||||
if(!equal(prevProps[v[0]], nextProps[v[0]])){
|
||||
console.log(v[0]);
|
||||
}
|
||||
});
|
||||
return equal(prevProps, nextProps);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Fragment, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { FilterPanel } from "renderer/components/maps-mangement-components/filter-panel.component";
|
||||
import { MapItem, ParsedMapDiff } from "renderer/components/maps-mangement-components/map-item.component";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
@@ -92,7 +92,7 @@ export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
const inQueue = mapsInQueue.some(toDownload => equal(toDownload.version, data) && toDownload.map.id === map.id);
|
||||
|
||||
return (
|
||||
<MapItem
|
||||
<MapItem
|
||||
autor={map.metadata.levelAuthorName}
|
||||
autorId={map.uploader.id}
|
||||
bpm={map.metadata.bpm}
|
||||
@@ -109,20 +109,21 @@ export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
diffs={extractMapDiffs(map)}
|
||||
songUrl={map.versions.at(0).previewURL}
|
||||
key={map.id}
|
||||
onDownload={(!isMapOwned && !inQueue) && (() => {handleDownloadMap(map)})}
|
||||
onCancelDownload={(inQueue && !isDownloading) && (() => {handleCancelDownload(map)})}
|
||||
onDownload={(!isMapOwned && !inQueue) && (handleDownloadMap)}
|
||||
onCancelDownload={(inQueue && !isDownloading) && (handleCancelDownload)}
|
||||
downloading={isDownloading}
|
||||
callBackParam={map}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const handleDownloadMap = (map: BsvMapDetail) => {
|
||||
mapsDownloader.addMapToDownload({map, version: data});
|
||||
}
|
||||
const handleDownloadMap = useCallback((map: BsvMapDetail) => {
|
||||
mapsDownloader.addMapToDownload({map, version: data})
|
||||
}, []);
|
||||
|
||||
const handleCancelDownload = (map: BsvMapDetail) => {
|
||||
const handleCancelDownload = useCallback((map: BsvMapDetail) => {
|
||||
mapsDownloader.removeMapToDownload({map, version: data});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleSearch = () => {
|
||||
const searchParams: SearchParams = {
|
||||
|
||||
@@ -72,7 +72,7 @@ export class MapsDownloaderService {
|
||||
|
||||
private async downloadMap(map: BsvMapDetail, version: BSVersion): Promise<boolean>{
|
||||
if(this.os.isOffline){ return false }
|
||||
const res = await this.ipc.send("download-map", {args: {zipUrl: getMapZipUrlFromMapDetails(map), version}});
|
||||
const res = await this.ipc.send<void, {map: BsvMapDetail, version: BSVersion}>("download-map", {args: {map, version}});
|
||||
return res.success;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user