Compare commits

...

19 Commits

Author SHA1 Message Date
MathieuG-P c264684ec6 bumb 1.2.0-alpha.3 2023-06-05 14:44:27 +02:00
MathieuG-P aa32f4e2f4 Merge pull request #235 from Zagrios/hotfix/tweak-model-images-for-better-viewing
[hotfix] tweak models ui to improve images visibility
2023-06-05 14:29:50 +02:00
MathieuG-P bfafe0e4b1 [hotfix] tweak models ui to improve images visibility 2023-06-05 14:28:10 +02:00
MathieuG-P a8c36a5e7c nothing 2023-06-04 17:46:12 +02:00
MathieuG-P de3284922a Merge pull request #233 from Zagrios/hotfix/make-supporter-service-use-request-service
[hotfix] Supporter service now use Request service
2023-06-04 17:44:11 +02:00
MathieuG-P d018ac5c9a [hotfix] Supporter service now use Request service 2023-06-04 17:43:53 +02:00
MathieuG-P e69983d6a7 Merge pull request #232 from Zagrios/hotfix/faster-inital-mod-loading
[hotfix] Faster inital loading of mods
2023-06-04 17:19:53 +02:00
MathieuG-P 2a8f4feea8 [hotfix] Faster inital loading of mods 2023-06-04 17:19:30 +02:00
MathieuG-P b08aa4c1d9 Add supporter 2023-06-04 12:52:35 +02:00
MathieuG-P c0e169cead Merge pull request #231 from Zagrios/hotfix/some-mods-not-marked-as-installed-but-installed
[hotfix] Not filter out "declined" mod when detecting installed mods
2023-06-04 00:57:34 +02:00
MathieuG-P 99f087a89d [hotfix] Not filter out "declined" mod when detecting installed mods + add logs 2023-06-04 00:52:49 +02:00
MathieuG-P e0fd024314 Merge pull request #229 from Zagrios/hotfix/some-mods-not-update-after-install
[hotfix] Fix some mods not update after install
2023-06-03 21:54:03 +02:00
MathieuG-P 599e04a96f [hotfix] Fix some mods not update after install 2023-06-03 21:53:35 +02:00
MathieuG-P 77b838187c Merge pull request #225 from Zagrios/hotfix/add-warning-for-steam-username-max-length
[hotfix] Add warning if the password exceed 64 characters
2023-05-29 21:00:38 +02:00
MathieuG-P 0ce2b9493a [hotfix] Add warning if the password exceed 64 characters 2023-05-29 20:59:27 +02:00
MathieuG-P 8124577728 Merge branch 'master' of https://github.com/Zagrios/bs-manager 2023-05-27 18:21:40 +02:00
MathieuG-P 2e5929c74c add supporter 2023-05-27 18:21:38 +02:00
Iluhadesu a4908ef850 Add v1.30.0 to bs_versions.json 2023-05-25 04:05:50 +00:00
MathieuG-P cf0fa2b787 bumb 1.2.0-alpha.2 2023-05-24 23:57:48 +02:00
15 changed files with 72 additions and 56 deletions
+8
View File
@@ -541,5 +541,13 @@
"ReleaseImg": "https://cdn.akamai.steamstatic.com/steamcommunity/public/images/clans/32055887/9c3d476c03e4a2ac72ca5df016b7c94d242b41cb.png",
"ReleaseDate": "1683644991",
"year": "2023"
},
{
"BSVersion": "1.30.0",
"BSManifest": "7304715857122259127",
"ReleaseURL": "https://steamcommunity.com/games/620980/announcements/detail/3725085394628677636",
"ReleaseImg": "https://cdn.akamai.steamstatic.com/steamcommunity/public/images/clans/32055887/cd56688ad716b544af14a61b2fbace9088478887.png",
"ReleaseDate": "1684965390",
"year": "2023"
}
]
+3 -1
View File
@@ -6,5 +6,7 @@
{"username": "Carbon", "type": "gold"},
{"username": "Naysy"},
{"username": "Falmil"},
{"username": "K1Lc4m"}
{"username": "K1Lc4m"},
{"username": "Adam"},
{"username": "Cabalia"}
]
+2 -1
View File
@@ -472,7 +472,8 @@
},
"password": {
"label": "Passwort",
"placeholder": "Gebe dein Passwort ein"
"placeholder": "Gebe dein Passwort ein",
"max-length-warning": "Das Passwort überschreitet 64 Zeichen! Wenn das Passwort ungültig ist, versuchen Sie nur die ersten 64 Zeichen einzugeben."
},
"stay": {
"label": "Verbunden bleiben"
+2 -1
View File
@@ -472,7 +472,8 @@
},
"password": {
"label": "Password",
"placeholder": "Enter your password"
"placeholder": "Enter your password",
"max-length-warning": "The password exceeds 64 characters! If the password is invalid, try to put its first 64 characters."
},
"stay": {
"label": "Stay connected"
+2 -1
View File
@@ -471,7 +471,8 @@
},
"password": {
"label": "Contraseña",
"placeholder": "Introduzca su contraseña"
"placeholder": "Introduzca su contraseña",
"max-length-warning": "¡La contraseña supera los 64 caracteres! Si la contraseña es inválida, intenta ingresar solo sus primeros 64 caracteres."
},
"stay": {
"label": "Manténgase conectado"
+2 -1
View File
@@ -471,7 +471,8 @@
},
"password": {
"label": "Mot de passe",
"placeholder": "Entre ton mot de passe"
"placeholder": "Entre ton mot de passe",
"max-length-warning": "Le mot de passe dépasse 64 caractères ! Si le mot de passe est invalide, tente d'entrer seulement ses 64 premiers caractères."
},
"stay": {
"label": "Rester connecté"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "bs-manager",
"version": "1.2.0-alpha.1",
"version": "1.2.0-alpha.3",
"description": "A foundation for scalable desktop apps",
"main": "./dist/main/main.js",
"author": {
@@ -90,6 +90,8 @@ export class BSInstallerService{
public async downloadBsVersion(downloadInfos: DownloadInfo): Promise<DownloadEvent>{
// TODO : Can be a lot improved by using ipcV2 and Observable
if(this.downloadProcess && this.downloadProcess.connected){ throw "AlreadyDownloading"; }
const {bsVersion} = downloadInfos;
if(!bsVersion){ return {type: "[Error]"}; }
+1 -1
View File
@@ -30,7 +30,7 @@ export class BSVersionLibService{
}
private getRemoteVersions(): Promise<BSVersion[]>{
return this.requestService.get<BSVersion[]>(this.REMOTE_BS_VERSIONS_URL);
return this.requestService.getJSON<BSVersion[]>(this.REMOTE_BS_VERSIONS_URL);
}
private async getLocalVersions(): Promise<BSVersion[]>{
@@ -38,7 +38,7 @@ export class BeatModsApiService {
private async getVersionAlias(): Promise<Map<string, BSVersion[]>>{
if(this.aliasesCache.size){ return this.aliasesCache; }
return this.requestService.get<Record<string, string[]>>(this.BEAT_MODS_ALIAS).then(rawAliases => {
return this.requestService.getJSON<Record<string, string[]>>(this.BEAT_MODS_ALIAS).then(rawAliases => {
Object.entries(rawAliases).forEach(([key, value]) => {
this.aliasesCache.set(key, value.map(s => ({BSVersion: s} as BSVersion)));
});
@@ -64,7 +64,7 @@ export class BeatModsApiService {
const alias = await this.getAliasOfVersion(version);
return this.requestService.get<Mod[]>(this.getVersionModsUrl(alias)).then(mods => {
return this.requestService.getJSON<Mod[]>(this.getVersionModsUrl(alias)).then(mods => {
mods = mods.map(mod => this.asignDependencies(mod, mods));
this.versionModsCache.set(version.BSVersion, mods);
return mods;
@@ -73,16 +73,10 @@ export class BeatModsApiService {
public async getAllMods(): Promise<Mod[]>{
if(!!this.allModsCache){ return this.allModsCache; }
return this.requestService.get<Mod[]>(this.getAllModsUrl()).then(mods => {
return this.requestService.getJSON<Mod[]>(this.getAllModsUrl()).then(mods => {
this.allModsCache = mods;
return this.allModsCache;
});
}
public loadAllMods(){ return this.getAllMods(); }
}
@@ -48,7 +48,7 @@ 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" || mod.status === "declined"){ return false; }
if(mod.name.toLowerCase() === "bsipa"){ return false; }
return mod.downloads.some(download => download.hashMd5.some(md5 => md5.hash === hash));
})
}
@@ -245,7 +245,7 @@ export class BsModsManagerService {
public async getInstalledMods(version: BSVersion): Promise<Mod[]>{
this.manifestMatches = [];
await this.beatModsApi.loadAllMods();
await this.beatModsApi.getAllMods();
const bsipa = await this.getBsipaInstalled(version);
return Promise.all([
this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING),
@@ -253,11 +253,16 @@ export class BsModsManagerService {
this.getModsInDir(version, ModsInstallFolder.PLUGINS),
this.getModsInDir(version, ModsInstallFolder.LIBS)
]).then(dirMods => {
const res = [];
if(!!bsipa){ res.push(bsipa); }
const installedMods = Array.from(new Map<string, Mod>(dirMods.flat().map(m => [m.name, m])).values());
res.push(...installedMods);
return res;
const modsDict = new Map<string, Mod>();
if(!!bsipa){ modsDict.set(bsipa.name, bsipa); }
for(const mod of dirMods.flat()){
if(modsDict.has(mod.name)){ continue; }
modsDict.set(mod.name, mod);
}
return Array.from(modsDict.values());
});
}
+17 -14
View File
@@ -1,8 +1,9 @@
import { RequestOptions, get } from "https";
import { get } from "https";
import { createWriteStream, unlink } from "fs";
import { Progression, unlinkPath } from "main/helpers/fs.helpers";
import { Observable, buffer, shareReplay, tap } from "rxjs";
import { Progression } from "main/helpers/fs.helpers";
import { Observable, shareReplay, tap } from "rxjs";
import log from "electron-log";
import fetch, { RequestInfo, RequestInit } from "node-fetch";
export class RequestService {
@@ -15,18 +16,20 @@ export class RequestService {
private constructor(){}
public get<T = any>(options: string|RequestOptions): Promise<T>{
public async getJSON<T = unknown>(url: RequestInfo, options?: RequestInit): Promise<T>{
try {
const response = await fetch(url, options);
return new Promise((resolve, reject) => {
let body = ''
get(options, (res) => {
res.on('data', chunk => body += chunk);
res.on('end', () => {
resolve(JSON.parse(body));
});
res.on('error', (err) => reject(err))
}).on("error", err => reject(err));
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status} ${response}`);
}
return await response.json();
}
catch (err) {
log.error(err);
throw err;
}
}
public downloadFile(url: string, dest: string): Observable<Progression<string>>{
+10 -16
View File
@@ -1,10 +1,10 @@
import { writeFileSync } from "fs";
import { readJSON } from "fs-extra";
import { get } from "https";
import isOnline from "is-online";
import path from "path";
import { Supporter } from "shared/models/supporters/supporter.interface";
import { UtilsService } from "./utils.service";
import { RequestService } from "./request.service";
import { allSettled } from "../../shared/helpers/promise.helpers";
export class SupportersService {
@@ -16,6 +16,8 @@ export class SupportersService {
private cache: Supporter[];
private readonly utilsService: UtilsService;
private readonly requestService: RequestService;
public static getInstance(): SupportersService{
if(!SupportersService.instance){ SupportersService.instance = new SupportersService(); }
@@ -24,6 +26,7 @@ export class SupportersService {
private constructor(){
this.utilsService = UtilsService.getInstance();
this.requestService = RequestService.getInstance();
}
private async updateLocalSupporters(supporters: Supporter[]): Promise<void>{
@@ -31,15 +34,8 @@ export class SupportersService {
writeFileSync(patreonsPath, JSON.stringify(supporters, null, "\t"), {encoding: 'utf-8', flag: 'w'});
}
private async getRemoteSupporters(): Promise<Supporter[]>{
return new Promise<Supporter[]>((resolve, reject) => {
let body = ''
get(this.PATREONS_URL, (res) => {
res.on('data', chunk => body += chunk);
res.on('end', () => resolve(JSON.parse(body)));
res.on('error', () => reject(null))
})
})
private getRemoteSupporters(): Promise<Supporter[]>{
return this.requestService.getJSON(this.PATREONS_URL);
}
private async getLocalSupporters(): Promise<Supporter[]>{
@@ -50,11 +46,9 @@ export class SupportersService {
private async loadSupporters(): Promise<Supporter[]>{
if(!!this.cache && this.cache.length){ return this.cache; }
const isOnlineRes = await isOnline({timeout: 1500});
const [localVersions, remoteVersions] = await Promise.all([
this.getLocalSupporters(), (isOnlineRes && this.getRemoteSupporters())
]);
const [localVersions, remoteVersions] = await allSettled([
this.getLocalSupporters(), this.getRemoteSupporters()
], {keepStructure: true});
const supporters = remoteVersions?.length ? remoteVersions : localVersions;
@@ -25,7 +25,7 @@ export const LoginModal: ModalComponent<{username: string, password: string, sta
}
return (
<form onSubmit={(e) => {e.preventDefault(); loggin();}}>
<form className="max-w-xs" onSubmit={(e) => {e.preventDefault(); loggin();}}>
<h1 className="text-3xl uppercase tracking-wide w-full text-center text-gray-800 dark:text-gray-200">{t("modals.steam-login.title")}</h1>
<BsmImage className="mx-auto h-20" image={BeatImpatient} />
@@ -33,9 +33,12 @@ export const LoginModal: ModalComponent<{username: string, password: string, sta
<label className="block font-bold cursor-pointer tracking-wide text-gray-800 dark:text-gray-200" htmlFor="username">{t("modals.steam-login.inputs.username.label")}</label>
<input className="w-full bg-light-main-color-1 dark:bg-main-color-1 px-1 py-[2px] rounded-md outline-none" onChange={e => setUsername(e.target.value)} value={username} type="text" name="username" id="username" placeholder={t("modals.steam-login.inputs.username.placeholder")}/>
</div>
<div className="mb-2">
<div className="mb-2 flex flex-col w-full">
<label className="block font-bold cursor-pointer tracking-wide text-gray-800 dark:text-gray-200" htmlFor="password">{t("modals.steam-login.inputs.password.label")}</label>
<input className="w-full bg-light-main-color-1 dark:bg-main-color-1 px-1 py-[2px] rounded-md outline-none" onChange={e => setPassword(e.target.value)} value={password} type="password" name="password" id="password" placeholder={t("modals.steam-login.inputs.password.placeholder")}/>
{password?.length > 64 && (
<span className="text-orange-700 dark:text-orange-400 text-xs whitespace-normal max-w-full w-full overflow-hidden">{t("modals.steam-login.inputs.password.max-length-warning")}</span>
)}
</div>
<span onClick={whyCredentials} className="underline my-4 block cursor-pointer">{t("modals.steam-login.why-credentials")}</span>
@@ -102,7 +102,8 @@ function modelItem<T = unknown>(props: Props<T>) {
<GlowEffect visible={props.selected || hovered}/>
<div className="absolute top-0 left-0 w-full h-full rounded-lg overflow-hidden blur-none bg-black shadow-sm shadow-black">
<div ref={ref} className="contents">
<BsmImage className={`absolute top-0 left-0 w-full h-full object-cover ${props.type === MSModelType.Avatar ? "object-top" : ""}`} image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<BsmImage className={`absolute top-0 left-0 w-full h-full object-cover brightness-50 scale-[200%] blur-md`} image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<BsmImage className={`absolute top-0 left-1/2 -translate-x-1/2 max-w-[20rem] w-full h-full object-cover`} image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<div className="absolute top-0 right-0 h-full w-0 flex flex-col items-end gap-1 pt-1.5 pr-1.5">
{!props.isDownloading ? (
actionButtons().map((button, index) => (