diff --git a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx index e48061df..fedbb615 100644 --- a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx +++ b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx @@ -24,7 +24,7 @@ export function LocalMapsListPanel({version, className} : Props) { const subs: Subscription[] = []; if(isVisible && !maps?.length){ - subs.push(mapsManager.getMaps(version).subscribe(localMaps => setMaps(() => localMaps))); + subs.push(mapsManager.getMaps(version).subscribe(localMaps => setMaps(() => [...localMaps]))); } return () => { subs.forEach(s => s.unsubscribe()); } @@ -53,7 +53,7 @@ export function LocalMapsListPanel({version, className} : Props) { autor={map.rawInfo._levelAuthorName} bpm={map.rawInfo._beatsPerMinute} duration={null} - diffs={extractMapDiffs(map)} mapId={null} qualified={null} ranked={null} autorLink={null} + diffs={extractMapDiffs(map)} mapId={map.bsaverInfo?.id} qualified={null} ranked={null} autorLink={null} />; } diff --git a/src/renderer/components/maps-mangement-components/map-item.component.tsx b/src/renderer/components/maps-mangement-components/map-item.component.tsx index 1f293db6..67977f7a 100644 --- a/src/renderer/components/maps-mangement-components/map-item.component.tsx +++ b/src/renderer/components/maps-mangement-components/map-item.component.tsx @@ -1,12 +1,9 @@ -import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface" import { BsmImage } from "../shared/bsm-image.component"; import { BsvMapCharacteristic, BsvMapDifficultyType } from "shared/models/maps/beat-saver.model" import { useThemeColor } from "renderer/hooks/use-theme-color.hook"; -import { LinkOpenerService } from "renderer/services/link-opener.service"; import { BsmLink } from "../shared/bsm-link.component"; import { BsmIcon } from "../svgs/bsm-icon.component"; import { BsmButton } from "../shared/bsm-button.component"; -import { MouseEventHandler } from "react"; export type MapItemProps = { hash: string, @@ -29,10 +26,10 @@ export function MapItem({hash, title, autor, coverUrl, songUrl, autorLink, mapId const color = useThemeColor("first-color"); - const zipUrl = `https://r2cdn.beatsaver.com/${hash}.zip` - const previewUrl = `https://skystudioapps.com/bs-viewer/?url=${zipUrl}` + const zipUrl = `https://r2cdn.beatsaver.com/${hash}.zip`; + const previewUrl = `https://skystudioapps.com/bs-viewer/?url=${zipUrl}`; + const mapUrl = mapId ? `https://beatsaver.com/maps/${mapId}` : null; - console.log(diffs) const renderAutor = () => { if(!autor){ null; } @@ -47,7 +44,7 @@ export function MapItem({hash, title, autor, coverUrl, songUrl, autorLink, mapId const colorPill = diffColors[diff] ?? ""; return ( -
  • +
  • {diff === "ExpertPlus" ? "Expert+" : diff}
  • @@ -76,7 +73,7 @@ export function MapItem({hash, title, autor, coverUrl, songUrl, autorLink, mapId
  • -

    {title}

    + {title} {renderAutor()}
      {Array.from(diffs.entries()).map(([charac, diffs]) => diffs.map(diff => renderDiff(charac, diff)))} diff --git a/src/renderer/components/shared/bsm-link.component.tsx b/src/renderer/components/shared/bsm-link.component.tsx index f91617ef..896fde52 100644 --- a/src/renderer/components/shared/bsm-link.component.tsx +++ b/src/renderer/components/shared/bsm-link.component.tsx @@ -1,6 +1,4 @@ import { LinkOpenerService } from "renderer/services/link-opener.service" -import { ModalService } from "renderer/services/modale.service"; -import { IframeModal } from "../modal/modal-types/iframe-modal.component"; type Props = { className?: string, @@ -15,6 +13,7 @@ export function BsmLink({className, href, children, style, internal}: Props) { const linkOpener = LinkOpenerService.getInstance(); const openLink = () => { + if(!href){ return; } linkOpener.open(href, internal); } diff --git a/src/renderer/models/api/api.model.ts b/src/renderer/models/api/api.model.ts new file mode 100644 index 00000000..ee82bba6 --- /dev/null +++ b/src/renderer/models/api/api.model.ts @@ -0,0 +1,4 @@ +export interface ApiResult{ + status: number, + data: T +} \ No newline at end of file diff --git a/src/renderer/services/beat-saver.service.ts b/src/renderer/services/beat-saver.service.ts deleted file mode 100644 index f3c7a217..00000000 --- a/src/renderer/services/beat-saver.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BsvMapDetail } from "shared/models/maps"; - -export class BeatSaverService { - - private static instance: BeatSaverService; - - public static getInstance(): BeatSaverService{ - if(!BeatSaverService.instance){ BeatSaverService.instance = new BeatSaverService(); } - return BeatSaverService.instance; - } - - private constructor(){} - - public getMapDetailsFromHashs(hashs: string[]): BsvMapDetail{ - return null; - } - -} \ No newline at end of file diff --git a/src/renderer/services/beat-saver/beat-saver-api.service.ts b/src/renderer/services/beat-saver/beat-saver-api.service.ts new file mode 100644 index 00000000..0eeb32be --- /dev/null +++ b/src/renderer/services/beat-saver/beat-saver-api.service.ts @@ -0,0 +1,31 @@ +import { ApiResult } from "renderer/models/api/api.model"; +import { BsvMapDetail } from "shared/models/maps"; + +export class BeatSaverApiService { + + private static instance: BeatSaverApiService; + + public static getInstance(): BeatSaverApiService{ + if(!BeatSaverApiService.instance){ BeatSaverApiService.instance = new BeatSaverApiService(); } + return BeatSaverApiService.instance; + } + + private readonly bsaverApiUrl = "https://beatsaver.com/api" + + private constructor(){} + + public async getMapsDetailsByHashs(hashs: T[]): Promise, BsvMapDetail>>>{ + + if(hashs.length > 50){ throw "too musch map hashs"; } + + const paramsHashs = hashs.join(","); + + const resp = await fetch(`${this.bsaverApiUrl}/maps/hash/${paramsHashs}`); + + const data = await resp.json() as Record, BsvMapDetail>; + + return {status: resp.status, data: data}; + + } + +} \ No newline at end of file diff --git a/src/renderer/services/beat-saver/beat-saver.service.ts b/src/renderer/services/beat-saver/beat-saver.service.ts new file mode 100644 index 00000000..482f8e5a --- /dev/null +++ b/src/renderer/services/beat-saver/beat-saver.service.ts @@ -0,0 +1,44 @@ +import { splitIntoChunk } from "renderer/helpers/array-tools"; +import { Observable } from "rxjs"; +import { BsvMapDetail } from "shared/models/maps"; +import { BeatSaverApiService } from "./beat-saver-api.service"; + +export class BeatSaverService { + + private static instance: BeatSaverService; + + public static getInstance(): BeatSaverService{ + if(!BeatSaverService.instance){ BeatSaverService.instance = new BeatSaverService(); } + return BeatSaverService.instance; + } + + private readonly bsaverApi: BeatSaverApiService; + + private constructor(){ + this.bsaverApi = BeatSaverApiService.getInstance(); + } + + public getMapDetailsFromHashs(hashs: string[]): Observable{ + const chunkHash = splitIntoChunk(hashs, 50); + + return new Observable(observer => { + (async () => { + + const mapDetails: BsvMapDetail[] = []; + + for(const hashs of chunkHash){ + const res = await this.bsaverApi.getMapsDetailsByHashs(hashs); + if(res.status === 200){ + mapDetails.push(...Object.values(res.data)); + observer.next(mapDetails); + } + + } + + observer.complete(); + })() + }) + + } + +} \ No newline at end of file diff --git a/src/renderer/services/maps-manager.service.ts b/src/renderer/services/maps-manager.service.ts index f263ef95..145c3866 100644 --- a/src/renderer/services/maps-manager.service.ts +++ b/src/renderer/services/maps-manager.service.ts @@ -1,6 +1,7 @@ import { Observable } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"; +import { BeatSaverService } from "./beat-saver/beat-saver.service"; import { IpcService } from "./ipc.service"; export class MapsManagerService { @@ -13,9 +14,11 @@ export class MapsManagerService { } private readonly ipcService: IpcService; + private readonly bsaver: BeatSaverService; private constructor(){ this.ipcService = IpcService.getInstance(); + this.bsaver = BeatSaverService.getInstance(); } public getMaps(version?: BSVersion): Observable{ @@ -24,6 +27,13 @@ export class MapsManagerService { this.ipcService.send("get-version-maps", {args: version}).then(res => { if(!res.success){ return obs.next(null);} obs.next(res.data); + + this.bsaver.getMapDetailsFromHashs(res.data.map(localMap => localMap.hash)).subscribe(mapsDetails => { + mapsDetails.forEach(details => { + res.data.find(localMap => localMap.hash === details.versions.find(details => details?.hash === localMap.hash)?.hash).bsaverInfo = details + }); + obs.next(res.data); + }) }); }); }