get maps details from bsaver api

This commit is contained in:
MathieuG-P
2022-11-09 00:46:01 +01:00
parent 84450419c1
commit 0a5c158657
8 changed files with 97 additions and 30 deletions
@@ -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}
/>;
}
@@ -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 (
<li className="h-5 flex justify-center items-center gap-1 rounded-full px-2 active:brightness-75" style={{backgroundColor: colorPill}}>
<li key={`${charac}-${diff}`} className="h-5 flex justify-center items-center gap-1 rounded-full px-2 active:brightness-75" style={{backgroundColor: colorPill}}>
<BsmIcon className="h-4 w-4" icon="bsMapDifficulty"/>
<span className="text-xs mb-[1.5px]">{diff === "ExpertPlus" ? "Expert+" : diff}</span>
</li>
@@ -76,7 +73,7 @@ export function MapItem({hash, title, autor, coverUrl, songUrl, autorLink, mapId
<li className="bg-main-color-1 rounded-md flex flex-row h-[120px] min-w-[400px] shrink overflow-hidden grow text-white basis-0">
<BsmImage className="" image={coverUrl}/>
<div className="h-full flex flex-col grow px-3 min-w-0 shrink">
<h1 className={`font-bold overflow-hidden text-ellipsis whitespace-nowrap ${mapId && "cursor-pointer hover:underline"}`} style={{textDecorationColor: color}}>{title}</h1>
<BsmLink href={mapUrl} className={`font-bold overflow-hidden text-ellipsis whitespace-nowrap ${mapId && "cursor-pointer hover:underline"}`} style={{textDecorationColor: color}}>{title}</BsmLink>
{renderAutor()}
<ol className="flex pb-1 gap-2 overflow-x-scroll scrollbar scrollbar-thin" style={{scrollbarGutter: "stable", }} onMouseMove={scrollDiffs} onMouseLeave={resetScrollDiffs}>
{Array.from(diffs.entries()).map(([charac, diffs]) => diffs.map(diff => renderDiff(charac, diff)))}
@@ -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);
}
+4
View File
@@ -0,0 +1,4 @@
export interface ApiResult<T = unknown>{
status: number,
data: T
}
@@ -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;
}
}
@@ -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<T extends string>(hashs: T[]): Promise<ApiResult<Record<Lowercase<T>, 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<Lowercase<T>, BsvMapDetail>;
return {status: resp.status, data: data};
}
}
@@ -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<BsvMapDetail[]>{
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<BsvMapDetail>(res.data));
observer.next(mapDetails);
}
}
observer.complete();
})()
})
}
}
@@ -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<BsmLocalMap[]>{
@@ -24,6 +27,13 @@ export class MapsManagerService {
this.ipcService.send<BsmLocalMap[], BSVersion>("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);
})
});
});
}