[feature-136] models management almost finished, still need to add translations

This commit is contained in:
MathieuG-P
2023-05-19 19:06:59 +02:00
parent 76bdde0fe8
commit bdc893d8a5
21 changed files with 308 additions and 128 deletions
@@ -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};
+52 -12
View File
@@ -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());
});
}