mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-274] Improve Oculus downloading + add Modal to choose from where to download Beat Saber
This commit is contained in:
Generated
+5
-3
@@ -11,7 +11,6 @@
|
||||
"@electron/fuses": "^1.6.2",
|
||||
"@node-steam/vdf": "^2.2.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@types/pako": "^2.0.1",
|
||||
"archiver": "^6.0.1",
|
||||
"color": "^4.2.3",
|
||||
"dateformat": "^5.0.3",
|
||||
@@ -65,6 +64,7 @@
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
"@types/pako": "^2.0.1",
|
||||
"@types/react": "^18.0.33",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-outside-click-handler": "^1.3.1",
|
||||
@@ -2749,7 +2749,8 @@
|
||||
"node_modules/@types/pako": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.1.tgz",
|
||||
"integrity": "sha512-fXhui1fHdLrUR0KEyQsBzqdi3Z+MitnRcpI2eeFJyzaRdqO2miX/BDz2Hh0VdkBbrWprgcQ+ItFmbdKYdbMjvg=="
|
||||
"integrity": "sha512-fXhui1fHdLrUR0KEyQsBzqdi3Z+MitnRcpI2eeFJyzaRdqO2miX/BDz2Hh0VdkBbrWprgcQ+ItFmbdKYdbMjvg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
@@ -21326,7 +21327,8 @@
|
||||
"@types/pako": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.1.tgz",
|
||||
"integrity": "sha512-fXhui1fHdLrUR0KEyQsBzqdi3Z+MitnRcpI2eeFJyzaRdqO2miX/BDz2Hh0VdkBbrWprgcQ+ItFmbdKYdbMjvg=="
|
||||
"integrity": "sha512-fXhui1fHdLrUR0KEyQsBzqdi3Z+MitnRcpI2eeFJyzaRdqO2miX/BDz2Hh0VdkBbrWprgcQ+ItFmbdKYdbMjvg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
|
||||
+1
-1
@@ -156,6 +156,7 @@
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
"@types/pako": "^2.0.1",
|
||||
"@types/react": "^18.0.33",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-outside-click-handler": "^1.3.1",
|
||||
@@ -232,7 +233,6 @@
|
||||
"@electron/fuses": "^1.6.2",
|
||||
"@node-steam/vdf": "^2.2.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@types/pako": "^2.0.1",
|
||||
"archiver": "^6.0.1",
|
||||
"color": "^4.2.3",
|
||||
"dateformat": "^5.0.3",
|
||||
|
||||
@@ -60,10 +60,6 @@ const createWindow = async (window: AppWindow = "launcher.html") => {
|
||||
await installExtensions();
|
||||
}
|
||||
WindowManagerService.getInstance().openWindow(window);
|
||||
|
||||
setTimeout(() => { // TODO : to remove (test)
|
||||
BsOculusDownloaderService.getInstance().downloadVersion({} as BSVersion).then(console.log).catch(console.error);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
const initServicesMustBeInitialized = () => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import JSZip from "jszip";
|
||||
import fetch from "node-fetch";
|
||||
import { CustomError } from "../../shared/models/exceptions/custom-error.class";
|
||||
import { mkdirs, createWriteStream, pathExists } from "fs-extra";
|
||||
import { mkdirs, createWriteStream, pathExists, writeFile } from "fs-extra";
|
||||
import path from "path";
|
||||
import { inflate } from "pako"
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { Observable, lastValueFrom, tap } from "rxjs";
|
||||
import { Progression, hashFile } from "../helpers/fs.helpers";
|
||||
|
||||
export class OculusDownloader {
|
||||
@@ -59,33 +59,32 @@ export class OculusDownloader {
|
||||
return file;
|
||||
}
|
||||
|
||||
private verifyIntegrity(manifest: OculusManifest, folder: string): Observable<Progression<OculusManifestFile[]>> {
|
||||
return new Observable<Progression<OculusManifestFile[]>>(sub => {
|
||||
private isFileIntegrityValid(file: OculusFileWithName, folder: string): Promise<boolean> {
|
||||
const [fileName, fileData] = file;
|
||||
const destination = path.join(folder, fileName);
|
||||
|
||||
return pathExists(destination).then(exists => {
|
||||
if(!exists){ return false; }
|
||||
return hashFile(destination, "sha256").then(hash => hash === fileData.sha256);
|
||||
});
|
||||
}
|
||||
|
||||
private verifyIntegrity(manifest: OculusManifest, folder: string): Observable<Progression<OculusFileWithName[]>> {
|
||||
return new Observable<Progression<OculusFileWithName[]>>(sub => {
|
||||
|
||||
const files = Object.entries(manifest.files);
|
||||
const progress: Progression<OculusManifestFile[]> = { current: 0, total: files.length, data: [] };
|
||||
const wrongFiles: OculusManifestFile[] = [];
|
||||
const progress: Progression<OculusFileWithName[]> = { current: 0, total: files.length, data: [] };
|
||||
const wrongFiles: OculusFileWithName[] = [];
|
||||
let canceled = false;
|
||||
|
||||
(async () => {
|
||||
|
||||
for(const [fileName, file] of files){
|
||||
for(const oculusFile of files){
|
||||
|
||||
if(canceled){ return; }
|
||||
|
||||
const destination = path.join(folder, fileName);
|
||||
|
||||
if(!pathExists(destination)){
|
||||
wrongFiles.push(file);
|
||||
progress.current++;
|
||||
sub.next(progress);
|
||||
continue;
|
||||
}
|
||||
|
||||
const fileSha256 = await hashFile(destination, "sha256");
|
||||
|
||||
if(fileSha256 !== file.sha256){
|
||||
wrongFiles.push(file);
|
||||
if(!(await this.isFileIntegrityValid(oculusFile, folder))){
|
||||
wrongFiles.push(oculusFile);
|
||||
}
|
||||
|
||||
progress.current++;
|
||||
@@ -115,6 +114,7 @@ export class OculusDownloader {
|
||||
this.isDownloading = true;
|
||||
|
||||
const progress: Progression = { current: 0, total: 0 };
|
||||
const intallPath = path.join("C:", "test", "test");
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -124,17 +124,22 @@ export class OculusDownloader {
|
||||
progress.total = files.reduce((acc, file) => { return acc + file[1].size }, 0)
|
||||
subscriber.next(progress);
|
||||
|
||||
for(const file of files){
|
||||
for(const [filename, file] of files){
|
||||
|
||||
if(this.isDownloading === false){ return; }
|
||||
|
||||
const destination = path.join("C:", "test", "test", file[0]);
|
||||
await this.downloadManifestFile(file[1], destination).catch(err => CustomError.throw(err, "DOWNLOAD_FILE_FAILED"));
|
||||
progress.current += file[1].size;
|
||||
if(!(await this.isFileIntegrityValid([filename, file], intallPath))){
|
||||
const target = path.join(intallPath, filename);
|
||||
await this.downloadManifestFile(file, target).catch(err => CustomError.throw(err, "DOWNLOAD_FILE_FAILED"));
|
||||
}
|
||||
|
||||
progress.current += file.size;
|
||||
subscriber.next(progress);
|
||||
}
|
||||
|
||||
const integrity = await lastValueFrom(this.verifyIntegrity(manifest, path.join("C:", "test", "test"))).catch(err => CustomError.throw(err, "VERIFY_INTEGRITY_FAILED"));
|
||||
await writeFile(path.join(intallPath, "type.info"), "oculus");
|
||||
|
||||
const integrity = await lastValueFrom(this.verifyIntegrity(manifest, intallPath)).catch(err => CustomError.throw(err, "VERIFY_INTEGRITY_FAILED"));
|
||||
|
||||
if(integrity.data.length > 0){
|
||||
throw new CustomError("Some files failed to download", "SOME_FILES_FAILED_TO_DOWNLOAD", integrity.data);
|
||||
@@ -148,10 +153,6 @@ export class OculusDownloader {
|
||||
});
|
||||
}
|
||||
|
||||
public async verifyApp(options: OculusDownloaderOptions){
|
||||
throw new CustomError("Not implemented", "NOT_IMPLEMENTED");
|
||||
}
|
||||
|
||||
public stopDownload(){
|
||||
this.isDownloading = false;
|
||||
}
|
||||
@@ -192,6 +193,8 @@ interface OculusManifestFile {
|
||||
|
||||
type OculusManifestFileSegment = [number, string, number];
|
||||
|
||||
type OculusFileWithName = [string, OculusManifestFile];
|
||||
|
||||
interface Logger {
|
||||
info: (...args: unknown[]) => void;
|
||||
warn: (...args: unknown[]) => void;
|
||||
|
||||
@@ -13,9 +13,10 @@ import { DownloadLinkType } from "shared/models/mods";
|
||||
import sanitize from "sanitize-filename";
|
||||
import { copyDirectoryWithJunctions, deleteFolder, getFoldersInFolder, pathExist } from "../helpers/fs.helpers";
|
||||
import { FolderLinkerService } from "./folder-linker.service";
|
||||
import { ReadStream, createReadStream } from "fs-extra";
|
||||
import { ReadStream, createReadStream, readFile } from "fs-extra";
|
||||
import readline from "readline";
|
||||
import { Observable, Subject } from "rxjs";
|
||||
import { BsStore } from "../../shared/models/bs-store.enum";
|
||||
|
||||
export class BSLocalVersionService {
|
||||
private static instance: BSLocalVersionService;
|
||||
@@ -109,6 +110,13 @@ export class BSLocalVersionService {
|
||||
folderVersion.ino = folderStats.ino;
|
||||
}
|
||||
|
||||
const type: string = await readFile(path.join(bsPath, "type.info"), "utf-8").catch(() => null);
|
||||
if(type === BsStore.OCULUS){
|
||||
folderVersion.downloadedFrom = BsStore.OCULUS;
|
||||
} else {
|
||||
folderVersion.downloadedFrom = BsStore.STEAM;
|
||||
}
|
||||
|
||||
const customVersion = this.getCustomVersions().find(customVersion => {
|
||||
return customVersion.BSVersion === folderVersion.BSVersion && customVersion.name === folderVersion.name;
|
||||
});
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { BSVersion } from "../../shared/bs-version.interface";
|
||||
import { WindowManagerService } from "./window-manager.service";
|
||||
import { minToMs } from "../../shared/helpers/time.helpers";
|
||||
import { minToMs, msToS } from "../../shared/helpers/time.helpers";
|
||||
import log from "electron-log";
|
||||
import { CustomError } from "../../shared/models/exceptions/custom-error.class";
|
||||
import { OculusDownloader } from "../models/oculus-downloader.class";
|
||||
import { Cookie, session } from "electron";
|
||||
import { pathExist } from "../helpers/fs.helpers";
|
||||
import { BSLocalVersionService } from "./bs-local-version.service";
|
||||
|
||||
export class BsOculusDownloaderService {
|
||||
|
||||
@@ -17,12 +20,14 @@ export class BsOculusDownloaderService {
|
||||
return BsOculusDownloaderService.instance;
|
||||
}
|
||||
|
||||
private readonly windows: WindowManagerService;
|
||||
|
||||
private readonly oculusDownloader: OculusDownloader;
|
||||
|
||||
private readonly windows: WindowManagerService;
|
||||
private readonly versions: BSLocalVersionService;
|
||||
|
||||
private constructor() {
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
this.versions = BSLocalVersionService.getInstance();
|
||||
|
||||
this.oculusDownloader = new OculusDownloader();
|
||||
}
|
||||
@@ -58,7 +63,27 @@ export class BsOculusDownloaderService {
|
||||
|
||||
}
|
||||
|
||||
public async getUserToken(): Promise<string>{
|
||||
private isCookieValid(cookie: Cookie): boolean {
|
||||
|
||||
if(!cookie){
|
||||
return false;
|
||||
}
|
||||
|
||||
return cookie.expirationDate > msToS(Date.now());
|
||||
}
|
||||
|
||||
private async getTokenFromCookie(): Promise<string | undefined> {
|
||||
const cookie = await session.defaultSession.cookies.get({ name: "oc_www_at" }).then(a => a.at(0));
|
||||
|
||||
if(this.isCookieValid(cookie) && this.isUserTokenValid(cookie.value)){
|
||||
return cookie.value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async getUserFromMetaAuth(saveToken: boolean): Promise<string>{
|
||||
|
||||
const redirectUrl = "https://developer.oculus.com/manage/";
|
||||
const loginUrl = `https://auth.oculus.com/login/?redirect_uri=${encodeURIComponent(redirectUrl)}`;
|
||||
const window = await this.windows.openWindow(loginUrl, { frame: true });
|
||||
@@ -70,7 +95,7 @@ export class BsOculusDownloaderService {
|
||||
reject(new CustomError("Trying to get Oculus user token timed out", "OCULUS_LOGIN_TIMED_OUT"));
|
||||
window.close();
|
||||
}, minToMs(5));
|
||||
|
||||
|
||||
window.webContents.on("did-navigate", async (_, url) => {
|
||||
if(!url.startsWith(redirectUrl)){ return; }
|
||||
|
||||
@@ -87,23 +112,70 @@ export class BsOculusDownloaderService {
|
||||
reject(new CustomError("Oculus login window closed by user", "OCULUS_LOGIN_WINDOW_CLOSED_BY_USER"));
|
||||
});
|
||||
}).finally(() => {
|
||||
|
||||
if(!saveToken){
|
||||
window.webContents.session.clearStorageData();
|
||||
}
|
||||
|
||||
if(!window.isDestroyed() && window.isClosable()){
|
||||
window.close();
|
||||
}
|
||||
|
||||
clearTimeout(timout);
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* DUPLICATION FROM BS-INSTALLER.SERVICE (TODO : need to be refactored)
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
private async getPathNotAleardyExist(path: string): Promise<string> {
|
||||
let destPath = path;
|
||||
let folderExist = await pathExist(destPath);
|
||||
let i = 0;
|
||||
|
||||
while (folderExist) {
|
||||
i++;
|
||||
destPath = `${path} (${i})`;
|
||||
folderExist = await pathExist(destPath);
|
||||
}
|
||||
|
||||
return destPath;
|
||||
}
|
||||
|
||||
public async downloadVersion(version: BSVersion){
|
||||
const token = await this.getUserToken();
|
||||
console.log(token);
|
||||
const s = this.oculusDownloader.downloadApp({ accessToken: token, binaryId: "5074476459318759", destination: "" }).subscribe({
|
||||
// await this.clearTokenCookie();
|
||||
const token = await this.getUserFromMetaAuth(true);
|
||||
const dest = await this.getPathNotAleardyExist(await this.versions.getVersionPath(version));
|
||||
|
||||
const s = this.oculusDownloader.downloadApp({ accessToken: token, binaryId: "1387243574708751", destination: dest }).subscribe({
|
||||
next: a => console.log(a),
|
||||
error: a => console.error(a),
|
||||
complete: () => console.log("complete")
|
||||
});
|
||||
}
|
||||
|
||||
public async autoDownloadVersion(version: BSVersion){
|
||||
const token = await this.getTokenFromCookie();
|
||||
|
||||
if(!token){
|
||||
throw new CustomError("No token has been found while try to auto download Beat Saber from Oculus", "TOKEN_NEEDED");
|
||||
}
|
||||
|
||||
const dest = await this.getPathNotAleardyExist(await this.versions.getVersionPath(version));
|
||||
|
||||
const s = this.oculusDownloader.downloadApp({ accessToken: token, binaryId: "1387243574708751", destination: dest }).subscribe({
|
||||
next: a => console.log(a),
|
||||
error: a => console.error(a),
|
||||
complete: () => console.log("complete")
|
||||
});
|
||||
}
|
||||
|
||||
public clearTokenCookie(): Promise<void>{
|
||||
return session.defaultSession.clearStorageData({ storages: ["cookies"], origin: ".oculus.com" })
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
import { ModalComponent, ModalExitCode } from "../../../../services/modale.service";
|
||||
import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component";
|
||||
import { SteamIcon } from "renderer/components/svgs/icons/steam-icon.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { BsStore } from "shared/models/bs-store.enum";
|
||||
import { useState } from "react";
|
||||
import tailwindConfig from "../../../../../../tailwind.config";
|
||||
import Color from "color";
|
||||
|
||||
export const ChooseStore: ModalComponent<BsStore> = ({ resolver }) => {
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const [oculusHover, setOculusHover] = useState(false);
|
||||
const [steamHover, setSteamHover] = useState(false);
|
||||
|
||||
const chooseStore = (store: BsStore) => {
|
||||
resolver({ exitCode: ModalExitCode.COMPLETED, data: store });
|
||||
}
|
||||
|
||||
const isDarkMode = document.documentElement.classList.contains("dark");
|
||||
|
||||
const bg = (() => {
|
||||
if(isDarkMode){
|
||||
return {
|
||||
bright: new Color(tailwindConfig.theme.colors["main-color"][1], "hex").hex(),
|
||||
dim: new Color(tailwindConfig.theme.colors["main-color"][1], "hex").darken(.2).hex()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
bright: new Color(tailwindConfig.theme.colors["main-color"][1], "hex").hex(),
|
||||
dim: new Color(tailwindConfig.theme.colors["main-color"][1], "hex").darken(.2).hex()
|
||||
}
|
||||
})();
|
||||
|
||||
return (
|
||||
<form className="flex flex-col gap-3">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center text-gray-800 dark:text-gray-200">{t("which platform ?")}</h1>
|
||||
<p className="max-w-sm text-gray-800 dark:text-gray-200 text-center">Select the platfrom where you own Beat Saber or from which you want to download it.</p>
|
||||
<div className="flex flex-row w-full flex-grow gap-4">
|
||||
<div className="flex flex-col flex-grow basis-0 gap-2 text-center px-5 pt-3 pb-1 rounded-md border-main-color-3 border-2 cursor-pointer" onMouseEnter={() => setOculusHover(true)} onMouseLeave={() => setOculusHover(false)} onClick={() => chooseStore(BsStore.OCULUS)} style={{backgroundColor: oculusHover ? bg.dim : bg.bright}}>
|
||||
<OculusIcon className="flex-grow aspect-square text-black bg-white rounded-full p-5"/>
|
||||
<h2 className="font-bold">Oculus PC</h2>
|
||||
</div>
|
||||
<div className="flex flex-col flex-grow basis-0 gap-2 text-center px-5 pt-3 pb-1 rounded-md border-main-color-3 border-2 cursor-pointer" onMouseEnter={() => setSteamHover(true)} onMouseLeave={() => setSteamHover(false)} onClick={() => chooseStore(BsStore.STEAM)} style={{backgroundColor: steamHover ? bg.dim : bg.bright}}>
|
||||
<SteamIcon className="flex-grow"/>
|
||||
<h2 className="font-bold">Steam</h2>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { BsDownloaderService } from "renderer/services/bs-downloader.service";
|
||||
import { SteamDownloaderService } from "renderer/services/bs-downgrade/steam-downloader.service";
|
||||
import { useState } from "react";
|
||||
import { distinctUntilChanged, map, of, Subscription, switchMap } from "rxjs";
|
||||
import { BSLauncherService, LaunchMods } from "renderer/services/bs-launcher.service";
|
||||
@@ -17,7 +17,7 @@ import equal from "fast-deep-equal";
|
||||
import { useOnUpdate } from "renderer/hooks/use-on-update.hook";
|
||||
|
||||
export function BsVersionItem(props: { version: BSVersion }) {
|
||||
const downloaderService = useService(BsDownloaderService);
|
||||
const downloaderService = useService(SteamDownloaderService);
|
||||
const verionManagerService = useService(BSVersionManagerService);
|
||||
const launcherService = useService(BSLauncherService);
|
||||
const configService = useService(ConfigurationService);
|
||||
|
||||
@@ -11,13 +11,13 @@ import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { BsDownloaderService } from "renderer/services/bs-downloader.service";
|
||||
import { SteamDownloaderService } from "renderer/services/bs-downgrade/steam-downloader.service";
|
||||
import { distinctUntilChanged } from "rxjs";
|
||||
import equal from "fast-deep-equal";
|
||||
|
||||
export function NavBar() {
|
||||
const versionManager = useService(BSVersionManagerService);
|
||||
const versionDownloader = useService(BsDownloaderService);
|
||||
const versionDownloader = useService(SteamDownloaderService);
|
||||
|
||||
const downloadingVersion = useObservable(versionDownloader.currentBsVersionDownload$.pipe(distinctUntilChanged(equal)));
|
||||
const installedVersions = useObservable(versionManager.installedVersions$);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CSSProperties } from "react";
|
||||
|
||||
export function OculusIcon(props: { className?: string; style?: CSSProperties }) {
|
||||
return (
|
||||
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" height="19" width="32">
|
||||
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M24.182 18.599c-0.427 0.297-0.901 0.474-1.411 0.552-0.51 0.083-1.016 0.068-1.521 0.068h-10.5c-0.51 0-1.016 0.021-1.526-0.068-0.51-0.083-0.979-0.255-1.411-0.552-0.854-0.604-1.365-1.563-1.365-2.604 0-1.057 0.516-2.016 1.37-2.599 0.417-0.297 0.896-0.479 1.396-0.557 0.5-0.083 1-0.083 1.526-0.083h10.5c0.5 0 1.016-0.016 1.516 0.063s0.984 0.26 1.401 0.542c0.865 0.578 1.365 1.557 1.365 2.599 0 1.036-0.526 2-1.38 2.599zM28.411 8.526c-1.125-0.906-2.417-1.531-3.818-1.865-0.802-0.193-1.604-0.281-2.432-0.307-0.599-0.021-1.198-0.010-1.818-0.010h-8.661c-0.609 0-1.224-0.010-1.833 0.010-0.823 0.026-1.63 0.109-2.432 0.307-1.401 0.339-2.698 0.964-3.818 1.865-2.281 1.823-3.599 4.568-3.599 7.474 0 2.911 1.318 5.656 3.583 7.474 1.13 0.906 2.422 1.531 3.823 1.87 0.802 0.193 1.609 0.281 2.432 0.302 0.599 0.021 1.198 0.016 1.818 0.016h8.661c0.599 0 1.219 0.005 1.818-0.016 0.823-0.021 1.62-0.109 2.417-0.302 1.401-0.344 2.682-0.969 3.823-1.87 2.307-1.823 3.625-4.568 3.625-7.474s-1.318-5.656-3.589-7.474z"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AvailableVersionsSlider } from "../components/available-versions/available-versions-slider.component";
|
||||
import { BsDownloaderService } from "../services/bs-downloader.service";
|
||||
import { SteamDownloaderService } from "../services/bs-downgrade/steam-downloader.service";
|
||||
import { Slideshow } from "renderer/components/slideshow/slideshow.component";
|
||||
import { createContext, useMemo, useState } from "react";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
@@ -16,28 +16,52 @@ import { lastValueFrom, map } from "rxjs";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
import { BsDownloaderService } from "renderer/services/bs-downgrade/bs-downloader.service";
|
||||
|
||||
export const AvailableVersionsContext = createContext<{ selectedVersion: BSVersion; setSelectedVersion: (version: BSVersion) => void }>(null);
|
||||
|
||||
export function AvailableVersionsList() {
|
||||
const bsDownloader = useService(BsDownloaderService);
|
||||
|
||||
const steamDownloader = useService(SteamDownloaderService);
|
||||
const versionManager = useService(BSVersionManagerService);
|
||||
const progressBar = useService(ProgressBarService);
|
||||
const modal = useService(ModalService);
|
||||
const ipc = useService(IpcService);
|
||||
const installer = useService(BsDownloaderService);
|
||||
const notification = useService(NotificationService);
|
||||
const config = useService(ConfigurationService);
|
||||
const bsDownloader = useService(BsDownloaderService);
|
||||
|
||||
const [selectedVersion, setSelectedVersion] = useState<BSVersion>(null);
|
||||
const contextValue = useMemo(() => ({ selectedVersion, setSelectedVersion }), [selectedVersion]);
|
||||
|
||||
const downloading = useObservable(bsDownloader.currentBsVersionDownload$.pipe(map(v => !!v)));
|
||||
const downloading = useObservable(steamDownloader.currentBsVersionDownload$.pipe(map(v => !!v)));
|
||||
const t = useTranslation();
|
||||
|
||||
const startDownload = () => {
|
||||
bsDownloader.downloadBsVersion(selectedVersion)
|
||||
const downloadFromSteam = (version: BSVersion) => {
|
||||
return steamDownloader.downloadBsVersion(version)
|
||||
.catch(() => {})
|
||||
.finally(() => setSelectedVersion(null));
|
||||
}
|
||||
|
||||
const downloadFromOculus = (version: BSVersion) => {
|
||||
return undefined; // TODO
|
||||
}
|
||||
|
||||
const startDownload = () => {
|
||||
|
||||
return bsDownloader.downloadVersion(selectedVersion);
|
||||
|
||||
if(config.get("last-downloaded-from") === "steam"){
|
||||
return downloadFromSteam(selectedVersion);
|
||||
}
|
||||
|
||||
if(config.get("last-downloaded-from") === "oculus"){
|
||||
return downloadFromOculus(selectedVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
const importVersion = async () => {
|
||||
@@ -63,7 +87,7 @@ export function AvailableVersionsList() {
|
||||
|
||||
const toImport = folderRes.filePaths.at(0);
|
||||
|
||||
const imported = await installer.importVersion(toImport);
|
||||
const imported = await steamDownloader.importVersion(toImport);
|
||||
|
||||
if (imported) {
|
||||
versionManager.askInstalledVersions();
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { BsmIconType } from "renderer/components/svgs/bsm-icon.component";
|
||||
import { DefaultConfigKey, ThemeConfig } from "renderer/config/default-configuration.config";
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { BsDownloaderService } from "renderer/services/bs-downloader.service";
|
||||
import { SteamDownloaderService } from "renderer/services/bs-downgrade/steam-downloader.service";
|
||||
import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
import { I18nService } from "renderer/services/i18n.service";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
@@ -43,7 +43,7 @@ export function SettingsPage() {
|
||||
const themeService = useService(ThemeService);
|
||||
const ipcService = useService(IpcService);
|
||||
const modalService = useService(ModalService);
|
||||
const downloaderService = useService(BsDownloaderService);
|
||||
const downloaderService = useService(SteamDownloaderService);
|
||||
const progressBarService = useService(ProgressBarService);
|
||||
const notificationService = useService(NotificationService);
|
||||
const i18nService = useService(I18nService);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BSUninstallerService } from "../services/bs-uninstaller.service";
|
||||
import { BSVersionManagerService } from "../services/bs-version-manager.service";
|
||||
import { ModalExitCode, ModalService } from "../services/modale.service";
|
||||
import DefautVersionImage from "../../../assets/images/default-version-img.jpg";
|
||||
import { BsDownloaderService } from "renderer/services/bs-downloader.service";
|
||||
import { SteamDownloaderService } from "renderer/services/bs-downgrade/steam-downloader.service";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { LaunchSlide } from "renderer/components/version-viewer/slides/launch/launch-slide.component";
|
||||
import { ModsSlide } from "renderer/components/version-viewer/slides/mods/mods-slide.component";
|
||||
@@ -27,7 +27,7 @@ export function VersionViewer() {
|
||||
const bsUninstallerService = useService(BSUninstallerService);
|
||||
const bsVersionManagerService = useService(BSVersionManagerService);
|
||||
const modalService = useService(ModalService);
|
||||
const bsDownloaderService = useService(BsDownloaderService);
|
||||
const bsDownloaderService = useService(SteamDownloaderService);
|
||||
const ipcService = useService(IpcService);
|
||||
const bsLauncher = useService(BSLauncherService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { BsStore } from "shared/models/bs-store.enum";
|
||||
import { ConfigurationService } from "../configuration.service";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { ModalExitCode, ModalService } from "../modale.service";
|
||||
import { ChooseStore } from "renderer/components/modal/modal-types/bs-downgrade/choose-store-modal.component";
|
||||
import { SteamDownloaderService } from "./steam-downloader.service";
|
||||
import { OculusDownloaderService } from "./oculus-downloader.service";
|
||||
import { CustomError } from "shared/models/exceptions/custom-error.class";
|
||||
|
||||
export class BsDownloaderService {
|
||||
|
||||
private static instance: BsDownloaderService;
|
||||
|
||||
public static getInstance(): BsDownloaderService {
|
||||
if (!BsDownloaderService.instance) {
|
||||
BsDownloaderService.instance = new BsDownloaderService();
|
||||
}
|
||||
|
||||
return BsDownloaderService.instance;
|
||||
}
|
||||
|
||||
private readonly config: ConfigurationService;
|
||||
private readonly modals: ModalService;
|
||||
private readonly steamDownloader: SteamDownloaderService;
|
||||
private readonly oculusDownloader: OculusDownloaderService; // TODO : create oculus downloader
|
||||
|
||||
private readonly downloadingVersion$ = new BehaviorSubject<BSVersion>(null); // <= TODO : will replace obs in SteamDownloaderService
|
||||
|
||||
private constructor(){
|
||||
this.config = ConfigurationService.getInstance();
|
||||
this.modals = ModalService.getInstance();
|
||||
}
|
||||
|
||||
public getLastStoreDownloadedFrom(): BsStore | undefined {
|
||||
const lastStore = this.config.get("lastStoreDownloadedFrom");
|
||||
|
||||
if(!lastStore){
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return lastStore as BsStore;
|
||||
}
|
||||
|
||||
private async chooseStoreToDownloadFrom(): Promise<BsStore | undefined> {
|
||||
const res = await this.modals.openModal(ChooseStore);
|
||||
|
||||
if(res.exitCode !== ModalExitCode.COMPLETED){
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return res.data;
|
||||
}
|
||||
|
||||
public async downloadVersion(version: BSVersion): Promise<BSVersion | undefined> {
|
||||
const store = this.getLastStoreDownloadedFrom() ?? await this.chooseStoreToDownloadFrom();
|
||||
|
||||
if(store === BsStore.STEAM){
|
||||
return this.steamDownloader.downloadBsVersion(version);
|
||||
}
|
||||
|
||||
if(store === BsStore.OCULUS){
|
||||
return this.oculusDownloader.downloadBsVersion(version);
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
public importVersion(): void {
|
||||
// TODO : open Modal
|
||||
// Will replace method in SteamDownloaderService
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
|
||||
export class OculusDownloaderService {
|
||||
|
||||
private static instance: OculusDownloaderService;
|
||||
|
||||
public static getInstance(): OculusDownloaderService {
|
||||
if (!OculusDownloaderService.instance) {
|
||||
OculusDownloaderService.instance = new OculusDownloaderService();
|
||||
}
|
||||
|
||||
return OculusDownloaderService.instance;
|
||||
}
|
||||
|
||||
private constructor(){}
|
||||
|
||||
public async downloadBsVersion(version: BSVersion): Promise<BSVersion> {
|
||||
return version;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-14
@@ -2,20 +2,20 @@ import { DownloadInfo } from "main/services/bs-installer.service";
|
||||
import { BehaviorSubject, Observable, ReplaySubject, Subscription, lastValueFrom, throwError } from "rxjs";
|
||||
import { filter, map, share, take, tap, throttleTime } from "rxjs/operators";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { AuthUserService } from "./auth-user.service";
|
||||
import { BSVersionManagerService } from "./bs-version-manager.service";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ModalExitCode, ModalService } from "./modale.service";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { ProgressBarService } from "./progress-bar.service";
|
||||
import { AuthUserService } from "../auth-user.service";
|
||||
import { BSVersionManagerService } from "../bs-version-manager.service";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { ModalExitCode, ModalService } from "../modale.service";
|
||||
import { NotificationService } from "../notification.service";
|
||||
import { ProgressBarService } from "../progress-bar.service";
|
||||
import { LoginModal } from "renderer/components/modal/modal-types/login-modal.component";
|
||||
import { GuardModal } from "renderer/components/modal/modal-types/guard-modal.component";
|
||||
import { LinkOpenerService } from "./link-opener.service";
|
||||
import { DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderInfoEvent, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model";
|
||||
import { LinkOpenerService } from "../link-opener.service";
|
||||
import { DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderInfoEvent, DepotDownloaderWarningEvent } from "../../../shared/models/depot-downloader.model";
|
||||
import { SteamMobileApproveModal } from "renderer/components/modal/modal-types/steam-mobile-approve-modal.component";
|
||||
|
||||
export class BsDownloaderService {
|
||||
private static instance: BsDownloaderService;
|
||||
export class SteamDownloaderService {
|
||||
private static instance: SteamDownloaderService;
|
||||
|
||||
private readonly modalService: ModalService;
|
||||
private readonly ipcService: IpcService;
|
||||
@@ -29,11 +29,11 @@ export class BsDownloaderService {
|
||||
public readonly currentBsVersionDownload$ = new BehaviorSubject<BSVersion>(null);
|
||||
public readonly downloadProgress$ = new BehaviorSubject(0);
|
||||
|
||||
public static getInstance(): BsDownloaderService {
|
||||
if (!BsDownloaderService.instance) {
|
||||
BsDownloaderService.instance = new BsDownloaderService();
|
||||
public static getInstance(): SteamDownloaderService {
|
||||
if (!SteamDownloaderService.instance) {
|
||||
SteamDownloaderService.instance = new SteamDownloaderService();
|
||||
}
|
||||
return BsDownloaderService.instance;
|
||||
return SteamDownloaderService.instance;
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
@@ -1,3 +1,5 @@
|
||||
import { BsStore } from "./models/bs-store.enum";
|
||||
|
||||
export interface PartialBSVersion {
|
||||
BSVersion: string,
|
||||
name?: string
|
||||
@@ -13,4 +15,7 @@ export interface BSVersion extends PartialBSVersion {
|
||||
steam?: boolean;
|
||||
oculus?: boolean;
|
||||
color?: string;
|
||||
downloadedFrom?: BsStore;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,3 +16,7 @@ export function hourToMin(hours: number): number {
|
||||
export function hourToS(hours: number): number {
|
||||
return hours * minToS(MINUTES_IN_HOUR);
|
||||
}
|
||||
|
||||
export function msToS(milliseconds: number): number {
|
||||
return milliseconds / 1000;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum BsStore {
|
||||
STEAM = "steam",
|
||||
OCULUS = "oculus",
|
||||
}
|
||||
Reference in New Issue
Block a user