mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-136] models management almost finished, still need to add translations
This commit is contained in:
@@ -16,7 +16,7 @@ import log from 'electron-log';
|
||||
import { WindowManagerService } from "../window-manager.service";
|
||||
import { ipcMain } from "electron";
|
||||
import { IpcRequest } from 'shared/models/ipc';
|
||||
import { Observable } from "rxjs";
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { Archive } from "../../models/archive.class";
|
||||
import { deleteFolder, ensureFolderExist, getFoldersInFolder, pathExist } from "../../helpers/fs.helpers";
|
||||
import { readFile } from "fs/promises";
|
||||
@@ -116,7 +116,7 @@ export class LocalMapsManagerService {
|
||||
await ensureFolderExist(this.utils.getTempPath());
|
||||
const dest = path.join(tempPath, fileName);
|
||||
|
||||
const zipPath = await this.reqService.downloadFile(zipUrl, dest);
|
||||
const zipPath = (await lastValueFrom(this.reqService.downloadFile(zipUrl, dest))).data;
|
||||
const zip = new StreamZip.async({file : zipPath});
|
||||
|
||||
return {zip, zipPath};
|
||||
|
||||
@@ -14,7 +14,7 @@ import sanitize from "sanitize-filename";
|
||||
import { Progression, ensureFolderExist, unlinkPath } from "../../helpers/fs.helpers";
|
||||
import { MODEL_FILE_EXTENSIONS, MODEL_TYPES, MODEL_TYPE_FOLDERS } from "../../../shared/models/models/constants";
|
||||
import { InstallationLocationService } from "../installation-location.service";
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { Observable, Subscription, lastValueFrom, map } from "rxjs";
|
||||
import { readdir } from "fs/promises";
|
||||
import md5File from "md5-file";
|
||||
import { allSettled } from "../../../shared/helpers/promise.helpers";
|
||||
@@ -85,13 +85,42 @@ export class LocalModelsManagerService {
|
||||
|
||||
}
|
||||
|
||||
public async downloadModel(model: MSModel, version: BSVersion): Promise<string>{
|
||||
|
||||
const modelFolder = await this.getModelFolderPath(model.type, version);
|
||||
const modelDest = path.join(modelFolder, sanitize(path.basename(model.download)));
|
||||
public downloadModel(model: MSModel, version: BSVersion): Observable<Progression<BsmLocalModel>>{
|
||||
return new Observable<Progression<BsmLocalModel>>(subscriber => {
|
||||
|
||||
return this.request.downloadFile(model.download, modelDest);
|
||||
const subs: Subscription[] = [];
|
||||
|
||||
(async () => {
|
||||
|
||||
const modelFolder = await this.getModelFolderPath(model.type, version);
|
||||
const modelDest = path.join(modelFolder, sanitize(path.basename(model.download)));
|
||||
|
||||
let url = model.download.split("/");
|
||||
url[url.length - 1] = encodeURIComponent(url[url.length - 1]);
|
||||
|
||||
const download$ = this.request.downloadFile(url.join("/"), modelDest);
|
||||
|
||||
subs.push(download$.subscribe({ next: value => subscriber.next({...value, data: undefined}), error: e => subscriber.error(e) }));
|
||||
|
||||
const downloaded = await lastValueFrom(download$);
|
||||
|
||||
const res: BsmLocalModel = {
|
||||
path: downloaded.data,
|
||||
fileName: path.basename(downloaded.data),
|
||||
hash: await md5File(downloaded.data),
|
||||
type: model.type,
|
||||
model,
|
||||
version
|
||||
}
|
||||
|
||||
subscriber.next({...downloaded, data: res});
|
||||
|
||||
})().catch(err => subscriber.error(err)).then(() => subscriber.complete());
|
||||
|
||||
return () => {
|
||||
subs.forEach(sub => sub.unsubscribe());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async oneClickDownloadModel(model: MSModel): Promise<void>{
|
||||
@@ -104,13 +133,13 @@ export class LocalModelsManagerService {
|
||||
|
||||
const fisrtVersion = versions.shift();
|
||||
|
||||
const downloaded = await this.downloadModel(model, fisrtVersion);
|
||||
const downloaded = await lastValueFrom(this.downloadModel(model, fisrtVersion));
|
||||
|
||||
for(const version of versions){
|
||||
|
||||
const modelDest = path.join(await this.getModelFolderPath(model.type, version), path.basename(downloaded));
|
||||
const modelDest = path.join(await this.getModelFolderPath(model.type, version), path.basename(downloaded.data.path));
|
||||
|
||||
copyFileSync(downloaded, modelDest);
|
||||
copyFileSync(downloaded.data.path, modelDest);
|
||||
|
||||
}
|
||||
|
||||
@@ -133,7 +162,7 @@ export class LocalModelsManagerService {
|
||||
const progression: Progression<BsmLocalModel[]> = {
|
||||
total: 0,
|
||||
current: 0,
|
||||
extra: null
|
||||
data: null
|
||||
};
|
||||
|
||||
return new Observable<Progression<BsmLocalModel[]>>(subscriber => {
|
||||
@@ -149,7 +178,7 @@ export class LocalModelsManagerService {
|
||||
path: modelPath,
|
||||
fileName: path.basename(modelPath, MODEL_FILE_EXTENSIONS[type]),
|
||||
model: await this.modelSaber.getModelByHash(hash),
|
||||
type, hash
|
||||
type, hash, version
|
||||
}
|
||||
|
||||
progression.current++;
|
||||
@@ -159,7 +188,7 @@ export class LocalModelsManagerService {
|
||||
return localModel;
|
||||
}));
|
||||
|
||||
progression.extra = models;
|
||||
progression.data = models;
|
||||
subscriber.next(progression);
|
||||
|
||||
})().catch(e => subscriber.error(e)).finally(() => subscriber.complete());
|
||||
@@ -167,11 +196,9 @@ export class LocalModelsManagerService {
|
||||
|
||||
}
|
||||
|
||||
public exportModels(output: string, version?: BSVersion, models?: BsmLocalModel[]): Observable<ArchiveProgress>{
|
||||
// TOTO NOT ASYNC
|
||||
|
||||
public exportModels(output: string, version?: BSVersion, models?: BsmLocalModel[]): Observable<Progression>{
|
||||
|
||||
return new Observable<ArchiveProgress>(subscriber => {
|
||||
return new Observable<Progression>(subscriber => {
|
||||
|
||||
const archive = new Archive(output);
|
||||
|
||||
@@ -199,7 +226,7 @@ export class LocalModelsManagerService {
|
||||
const progression: Progression = {
|
||||
total: models.length,
|
||||
current: 0,
|
||||
extra: null
|
||||
data: null
|
||||
};
|
||||
|
||||
for(const model of models){
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import path from "path";
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { BehaviorSubject, Observable, lastValueFrom } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BSLocalVersionService } from "../bs-local-version.service";
|
||||
import { DeepLinkService } from "../deep-link.service";
|
||||
@@ -97,7 +97,7 @@ export class LocalPlaylistsManagerService {
|
||||
copyFileSync(bpListUrlOrPath, bpListDest);
|
||||
}
|
||||
else{
|
||||
await this.request.downloadFile(bpListUrlOrPath, bpListDest);
|
||||
await lastValueFrom(this.request.downloadFile(bpListUrlOrPath, bpListDest));
|
||||
}
|
||||
|
||||
return bpListDest;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { spawn } from "child_process";
|
||||
import { BS_EXECUTABLE } from "../../constants";
|
||||
import log from "electron-log";
|
||||
import { deleteFolder, ensureFolderExist, pathExist, unlinkPath } from "../../helpers/fs.helpers";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export class BsModsManagerService {
|
||||
|
||||
@@ -102,7 +103,7 @@ export class BsModsManagerService {
|
||||
await ensureFolderExist(this.utilsService.getTempPath());
|
||||
const dest = path.join(tempPath, fileName);
|
||||
|
||||
const zipPath = await this.requestService.downloadFile(zipUrl, dest);
|
||||
const zipPath = (await lastValueFrom(this.requestService.downloadFile(zipUrl, dest))).data;
|
||||
const zip = new StreamZip.async({file : zipPath});
|
||||
|
||||
return {zip, zipPath};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { RequestOptions, get } from "https";
|
||||
import { createWriteStream, unlink } from "fs";
|
||||
import { Progression, unlinkPath } from "main/helpers/fs.helpers";
|
||||
import { Observable, buffer, shareReplay, tap } from "rxjs";
|
||||
import log from "electron-log";
|
||||
|
||||
export class RequestService {
|
||||
|
||||
@@ -13,6 +16,7 @@ export class RequestService {
|
||||
private constructor(){}
|
||||
|
||||
public get<T = any>(options: string|RequestOptions): Promise<T>{
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let body = ''
|
||||
get(options, (res) => {
|
||||
@@ -25,21 +29,57 @@ export class RequestService {
|
||||
});
|
||||
}
|
||||
|
||||
public downloadFile(url: string, dest: string): Promise<string>{
|
||||
return new Promise((resolve, reject) => {
|
||||
public downloadFile(url: string, dest: string): Observable<Progression<string>>{
|
||||
|
||||
return new Observable<Progression<string>>(subscriber => {
|
||||
const progress: Progression<string> = { current: 0, total: 0 };
|
||||
|
||||
const file = createWriteStream(dest);
|
||||
get(url, res => {
|
||||
res.pipe(file);
|
||||
file.on("close", () => {
|
||||
file.close(() => resolve(dest))
|
||||
}).on("error", err => {
|
||||
unlink(dest, () => reject(err));
|
||||
});
|
||||
}).on("error", err => {
|
||||
unlink(dest, () => reject(err));
|
||||
|
||||
file.on("close", () => {
|
||||
progress["data"] = dest;
|
||||
subscriber.next(progress); subscriber.complete();
|
||||
});
|
||||
});
|
||||
file.on("error", err => unlink(dest, () => subscriber.error(err)));
|
||||
|
||||
const req = get(url, res => {
|
||||
|
||||
progress.total = parseInt(res.headers?.["content-length"] || "0", 10);
|
||||
|
||||
res.on("data", chunk => {
|
||||
progress.current += chunk.length;
|
||||
subscriber.next(progress);
|
||||
});
|
||||
|
||||
res.pipe(file);
|
||||
|
||||
});
|
||||
|
||||
req.on("error", err => { subscriber.error(err); });
|
||||
|
||||
}).pipe(tap({error: e => log.error(e)}), shareReplay(1));
|
||||
|
||||
}
|
||||
|
||||
public downloadBuffer(url: string): Observable<Buffer>{
|
||||
|
||||
return new Observable<Buffer>(subscriber => {
|
||||
const allChunks: Buffer[] = [];
|
||||
|
||||
const req = get(url, res => {
|
||||
res.on("data", chunk => {
|
||||
allChunks.push(chunk);
|
||||
});
|
||||
res.on('end', () => {
|
||||
subscriber.next(Buffer.concat(allChunks));
|
||||
subscriber.complete();
|
||||
});
|
||||
res.on('error', (err) => subscriber.error(err))
|
||||
});
|
||||
|
||||
req.on("error", err => { subscriber.error(err); });
|
||||
|
||||
}).pipe(tap({error: e => log.error(e)}), shareReplay(1));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Observable } from "rxjs";
|
||||
import { MSGetQuery, MSGetQueryFilterType, MSModel, MSModelPlatform } from "../../../../shared/models/models/model-saber.model";
|
||||
import { ModelSaberApiService } from "./model-saber-api.service";
|
||||
import log from "electron-log";
|
||||
import striptags from "striptags"
|
||||
|
||||
export class ModelSaberService {
|
||||
|
||||
@@ -71,6 +72,8 @@ export class ModelSaberService {
|
||||
|
||||
const model = Array.from(Object.values(res.data)).at(0);
|
||||
|
||||
model.name = striptags(model.name ?? "");
|
||||
|
||||
this.modelsHashCache.set(hash, model);
|
||||
|
||||
return model
|
||||
@@ -87,7 +90,11 @@ export class ModelSaberService {
|
||||
(async () => {
|
||||
const res = await this.modelSaberApi.searchModel(query);
|
||||
if(res.status !== 200){ observer.error(res.status); }
|
||||
observer.next(Object.values(res.data));
|
||||
observer.next(Object.values(res.data).map(model => {
|
||||
if(!model || !model.name){ return model; }
|
||||
(model as MSModel).name = striptags(model.name);
|
||||
return model;
|
||||
}));
|
||||
})().catch(e => observer.error(e)).then(() => observer.complete());
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user