Compare commits

...

10 Commits

Author SHA1 Message Date
MathieuG-P f30cad74d7 chore: Add GitHub Actions workflow for releasing Linux 2024-07-14 17:15:31 +02:00
MathieuG-P ede82393da chore: update category in package.json 2024-07-14 17:11:19 +02:00
MathieuG-P 9ee468af03 add icons for linux 2024-07-14 16:41:07 +02:00
MathieuG-P ca722b2a18 fix displaying "no playlist found" when playlists is loading 2024-07-13 18:50:12 +02:00
MathieuG-P c219e9655d update deps 2024-07-13 18:45:50 +02:00
MathieuG-P a6c1ba9fee Merge pull request #508 from Zagrios/qol/mods-load-faster
[QOL] Mods load faster
2024-07-13 17:31:03 +02:00
MathieuG-P 6e9ea1bd9a Merge branch 'master' into qol/mods-load-faster 2024-07-13 17:21:48 +02:00
MathieuG-P 84f27d571b nothing 2024-07-13 17:21:32 +02:00
MathieuG-P 51549161cd [qol] change use hash cache to load installed mods faster 2024-07-13 17:17:43 +02:00
MathieuG-P 198002238e change recommended version to 1.37.0 2024-07-13 15:58:03 +02:00
17 changed files with 522 additions and 818 deletions
+32
View File
@@ -0,0 +1,32 @@
# This workflow will...
name: Realease Linux
on:
workflow_dispatch:
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 18.x
cache: "npm"
- run: npm ci
- run: npm run build && electron-builder --linux --x64 --publish always
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: release
path: release
+3 -3
View File
@@ -679,8 +679,7 @@
"ReleaseURL": "https://steamcommunity.com/games/620980/announcements/detail/3865840827122760836",
"ReleaseImg": "https://clan.akamai.steamstatic.com/images/32055887/ae11d195bbe41a0f244d7b4d055a0ab89f88e5bb.png",
"ReleaseDate": "1702309893",
"year": "2023",
"recommended": true
"year": "2023"
},
{
"BSVersion": "1.34.5",
@@ -734,7 +733,8 @@
"ReleaseURL": "https://store.steampowered.com/news/app/620980/view/4161968170153497460",
"ReleaseImg": "https://clan.akamai.steamstatic.com/images//32055887/f82d34c7582137a6748a28c5b02670ff4b235356.png",
"ReleaseDate": "1717513346",
"year": "2024"
"year": "2024",
"recommended": true
},
{
"BSVersion": "1.37.1",
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Before

Width:  |  Height:  |  Size: 442 KiB

After

Width:  |  Height:  |  Size: 442 KiB

+407 -770
View File
File diff suppressed because it is too large Load Diff
+14 -12
View File
@@ -36,7 +36,6 @@
},
"build": {
"extraResources": [
"./assets/favicon.ico",
"./assets/jsons/bs-versions.json",
"./assets/jsons/patreons.json",
"./assets/proto/song_details_cache_v1.proto"
@@ -56,8 +55,9 @@
"nsis",
"nsis-web"
],
"icon": "assets/favicon.ico",
"icon": "./build/icons/win/favicon.ico",
"extraResources": [
"./build/icons/win",
"./assets/scripts/*.exe"
]
},
@@ -65,8 +65,10 @@
"target": [
"AppImage"
],
"category": "Development",
"icon": "./build/icons/png",
"category": "Utility;Game;",
"extraResources": [
"./build/icons/png",
"./assets/scripts/DepotDownloader"
]
},
@@ -180,7 +182,7 @@
"css-minimizer-webpack-plugin": "^6.0.0",
"detect-port": "^1.5.1",
"electron": "^28.2.4",
"electron-builder": "^24.12.0",
"electron-builder": "^24.13.3",
"electron-devtools-installer": "^3.2.0",
"electronmon": "^2.0.2",
"esbuild": "^0.20.1",
@@ -243,20 +245,20 @@
"electron-debug": "^3.2.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.8",
"electron-updater": "^6.2.1",
"fast-deep-equal": "^3.1.3",
"framer-motion": "^11.2.6",
"fs-extra": "^11.2.0",
"got": "^14.2.0",
"got": "^14.4.1",
"history": "^5.3.0",
"is-elevated": "^4.0.0",
"jszip": "^3.10.1",
"md5-file": "^5.0.0",
"node-abi": "^3.56.0",
"node-abi": "^3.65.0",
"node-fetch": "^3.3.2",
"node-stream-zip": "^1.15.0",
"pako": "^2.1.0",
"protobufjs": "^7.3.0",
"protobufjs": "^7.3.2",
"qrcode.react": "^3.1.0",
"query-process": "^0.0.3",
"react": "^18.2.0",
@@ -264,17 +266,17 @@
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
"react-range": "^1.8.14",
"react-router-dom": "^6.22.1",
"react-virtualized-auto-sizer": "^1.0.23",
"react-router-dom": "^6.24.1",
"react-virtualized-auto-sizer": "^1.0.24",
"react-window": "^1.8.10",
"recursive-readdir": "^2.2.3",
"rfdc": "^1.3.1",
"rxjs": "^7.8.1",
"sanitize-filename": "^1.6.3",
"semver": "^7.6.0",
"semver": "^7.6.2",
"serialize-error": "^11.0.3",
"striptags": "^4.0.0-alpha.4",
"tailwind-merge": "^2.3.0",
"tailwind-merge": "^2.4.0",
"tailwind-scrollbar-hide": "^1.1.7",
"tailwindcss-scoped-groups": "^2.0.0",
"tippy.js": "^6.3.7",
@@ -14,6 +14,7 @@ export class BeatModsApiService {
private readonly aliasesCache = new Map<string, BSVersion[]>();
private readonly versionModsCache = new Map<string, Mod[]>();
private readonly modsHashCache = new Map<string, Mod>();
private allModsCache: Mod[];
@@ -66,6 +67,29 @@ export class BeatModsApiService {
return mod;
}
private updateModsHashCache(mods: Mod[]): void {
if(!Array.isArray(mods)){
return;
}
for (const mod of mods) {
for (const downloads of (mod.downloads ?? [])) {
for (const hashMd5 of (downloads.hashMd5 ?? [])) {
this.modsHashCache.set(hashMd5.hash, mod);
}
}
for (const dep of (mod.dependencies ?? [])) {
for (const downloads of (dep.downloads ?? [])) {
for (const hashMd5 of (downloads.hashMd5 ?? [])) {
this.modsHashCache.set(hashMd5.hash, dep);
}
}
}
}
}
public async getVersionMods(version: BSVersion): Promise<Mod[]> {
if (this.versionModsCache.has(version.BSVersion)) {
return this.versionModsCache.get(version.BSVersion);
@@ -76,6 +100,9 @@ export class BeatModsApiService {
return this.requestService.getJSON<Mod[]>(this.getVersionModsUrl(alias)).then(mods => {
mods = mods.map(mod => this.asignDependencies(mod, mods));
this.versionModsCache.set(version.BSVersion, mods);
this.updateModsHashCache(mods);
return mods;
});
}
@@ -89,4 +116,15 @@ export class BeatModsApiService {
return this.allModsCache;
});
}
public getModByHash(hash: string): Promise<Mod> {
if (this.modsHashCache.has(hash)) {
return Promise.resolve(this.modsHashCache.get(hash));
}
return this.requestService.getJSON<Mod[]>(`${this.BEAT_MODS_API_URL}mod?hash=${hash}`).then(mods => {
this.updateModsHashCache(mods);
return mods.at(0);
});
}
}
@@ -48,23 +48,14 @@ export class BsModsManagerService {
}
private async getModFromHash(hash: string): Promise<Mod> {
const allMods = await this.beatModsApi.getAllMods();
return allMods.find(mod => {
if (mod.name.toLowerCase() === "bsipa") {
return false;
}
return mod.downloads.some(download => download.hashMd5.some(md5 => md5.hash === hash));
});
}
private async getIpaFromHash(hash: string): Promise<Mod> {
const allMods = await this.beatModsApi.getAllMods();
return allMods.find(mod => {
if (mod.name.toLowerCase() !== "bsipa") {
return false;
}
return mod.downloads.some(download => download.hashMd5.some(md5 => md5.hash === hash));
});
const mod = await this.beatModsApi.getModByHash(hash);
if(mod?.name?.toLowerCase() === "bsipa"){
return undefined;
}
return mod;
}
private async getModsInDir(version: BSVersion, modsDir: ModsInstallFolder): Promise<Mod[]> {
@@ -84,7 +75,6 @@ export class BsModsManagerService {
return undefined;
}
const hash = await md5File(filePath);
const mod = await this.getModFromHash(hash);
if (!mod) {
@@ -107,7 +97,7 @@ export class BsModsManagerService {
});
const mods = await Promise.all(promises);
return mods.filter(Boolean);
return mods.filter(Boolean);
}
private async getBsipaInstalled(version: BSVersion): Promise<Mod> {
@@ -117,7 +107,7 @@ export class BsModsManagerService {
return undefined;
}
const injectorMd5 = await md5File(injectorPath);
return this.getIpaFromHash(injectorMd5);
return this.beatModsApi.getModByHash(injectorMd5);
}
private async downloadZip(zipUrl: string): Promise<JSZip> {
@@ -322,8 +312,10 @@ export class BsModsManagerService {
public async getInstalledMods(version: BSVersion): Promise<Mod[]> {
this.manifestMatches = [];
await this.beatModsApi.getAllMods();
const bsipa = await this.getBsipaInstalled(version);
return Promise.all([this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING), this.getModsInDir(version, ModsInstallFolder.LIBS_PENDING), this.getModsInDir(version, ModsInstallFolder.PLUGINS), this.getModsInDir(version, ModsInstallFolder.LIBS)]).then(dirMods => {
const modsDict = new Map<string, Mod>();
@@ -62,7 +62,7 @@ export const DownloadPlaylistModal: ModalComponent<void, {version: BSVersion, ow
}, [searchParams]);
const handleNewSearch = (value: Omit<PlaylistSearchParams, "page">) => {
setPlaylists(() => []);
setPlaylists(() => undefined);
setSearchParams(() => ({ ...value, page: 0}));
};
@@ -9,8 +9,8 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component";
import BeatWaitingImg from "../../../../../../assets/images/apngs/beat-waiting.png";
import BeatConflictImg from "../../../../../../assets/images/apngs/beat-conflict.png";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { skip, filter, map } from "rxjs/operators";
import { Observable, Subscription, combineLatest, lastValueFrom, noop } from "rxjs";
import { skip, filter } from "rxjs/operators";
import { Subscription, lastValueFrom, noop } from "rxjs";
import { useTranslation } from "renderer/hooks/use-translation.hook";
import { LinkOpenerService } from "renderer/services/link-opener.service";
import { useInView } from "framer-motion";
@@ -96,24 +96,27 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion;
});
modsManager.installMods(modsToInstall, version).then(() => {
lastValueFrom(loadMods());
loadMods();
});
};
const loadMods = (): Observable<void> => {
const loadMods = (): Promise<void> => {
if (os.isOffline) {
return new Observable<void>(subscriber => subscriber.complete());
return Promise.resolve();
}
return combineLatest([
modsManager.getAvailableMods(version),
modsManager.getInstalledMods(version)
]).pipe(map(([available, installed]) => {
const promise = async () => {
const available = await lastValueFrom(modsManager.getAvailableMods(version));
const installed = await lastValueFrom(modsManager.getInstalledMods(version));
return [available, installed];
}
return promise().then(([available, installed]) => {
const defaultMods = configService.get<string[]>("default_mods" as DefaultConfigKey);
setModsAvailable(() => modsToCategoryMap(available));
setModsSelected(() => available.filter(m => m.required || defaultMods.some(d => m.name.toLowerCase() === d.toLowerCase()) || installed.some(i => m.name === i.name)));
setModsInstalled(() => modsToCategoryMap(installed));
}));
});
};
useEffect(() => {
@@ -141,14 +144,14 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion;
return onDisclamerDecline?.();
}
subs.push(loadMods().subscribe());
loadMods();
subs.push(
modsManager.isUninstalling$.pipe(
skip(1),
filter(uninstalling => !uninstalling)
).subscribe(() => {
subs.push(loadMods().subscribe());
loadMods();
})
);
});