From 1be3b7af311c7abf4867525261d6a8bcacab834b Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sat, 5 Aug 2023 03:50:04 +0200 Subject: [PATCH] [feature] Add notifications for BS download --- assets/jsons/translations/de.json | 6 +- assets/jsons/translations/en.json | 6 +- assets/jsons/translations/es.json | 6 +- assets/jsons/translations/fr.json | 9 +-- assets/jsons/translations/ru.json | 6 +- src/main/models/depot-downloader.class.ts | 22 ++++++-- .../pages/settings-page.component.tsx | 12 +++- .../pages/version-viewer.component.tsx | 2 +- .../services/bs-downloader.service.ts | 56 ++++++++++++++----- src/shared/models/depot-downloader.model.ts | 11 ++-- 10 files changed, 84 insertions(+), 52 deletions(-) diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index 57287cd0..6031f682 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -232,7 +232,6 @@ "404": "Steam-Server können nicht kontaktiert werden.", "Password": "Passwort ist ungültig.", "InvalidCredentials": "Deine E-Mail oder Passwort ist ungültig 😴", - "InvalidPassword": "Dein Passwort ist ungültig 😕", "NoManifest": "Es wurde keine Manifest gefunden", "DirectoryCreate": "Die erforderlichen Ordner können nicht installiert werden.", "NotAvailableApp": "Versuchst du, Beat Saber herunterzuladen, wenn Du es nicht hast? 🤣", @@ -248,10 +247,9 @@ "SteamLib": "Wenn dieser Fehler auftritt, melde den Fehler auf Github mit Protokollen, bitte.", "ConnectionError": "Kann nach 10 Versuchen keine Verbindung zu Steam herstellen 🤯", "LicenceError": "Die Liste der Lizenzen kann nicht abgerufen werden.", - "verification-failed": "Verifikation fehlgeschlagen, versuche es später erneut.", "RateLimitExceeded": "Du hast es zu oft versucht, warte eine Weile und versuche es später erneut.", - "AlreadyDownloading": "Ein Download ist bereits im Gange", - "no-internet": "Keine Internet Verbindung", + "TokenRejected": "BeatSaber kann nicht heruntergeladen werden 😥 versuche es später noch einmal 😕", + "AccessDenied": "Der Zugang zu Steam wurde verweigert.", "dotnet-required": ".NET 6 Runtime muss installiert sein, um eine Version von BeatSaber herunterzuladen. Lade es herunter, indem Du auf die Schaltfläche unten klickst." }, "actions": { diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index daf45831..b5180113 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -232,7 +232,6 @@ "404": "Unable to contact Steam servers.", "Password": "Password is invalid.", "InvalidCredentials": "Your e-mail or password is invalid 😴", - "InvalidPassword": "Your password is invalid 😕", "NoManifest": "No manifest was found", "DirectoryCreate": "Unable to install the necessary folders.", "NotAvailableApp": "Are you trying to download Beat Saber when you don't have it? 🤣", @@ -248,10 +247,9 @@ "SteamLib": "If you have this error, report the bug on GitHub with the logs pls.", "ConnectionError": "Unable to connect to Steam after 10 tries 🤯", "LicenceError": "Unable to get the list of licenses.", - "verification-failed": "Verification failed, try again later.", "RateLimitExceeded": "You've tried too many times, wait a while and try again later.", - "AlreadyDownloading": "A download is already in progress", - "no-internet": "No internet connection.", + "TokenRejected": "Unable to download Beat Saber 😥 try again later 😕", + "AccessDenied": "Access to Steam has been denied.", "dotnet-required": ".NET 6 Runtime must be installed in order to download a version of Beat Saber. Download it by clicking the button below." }, "actions": { diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index 9cbeaaf4..d212a5e9 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -231,7 +231,6 @@ "404": "No se puede contactar con los servidores de Steam", "Password": "La contraseña es inválida.", "InvalidCredentials": "Su correo electrónico o contraseña no son válidos 😴", - "InvalidPassword": "Su contraseña no es válida 😕", "NoManifest": "No se ha encontrado el manifiesto", "DirectoryCreate": "No se pueden instalar las carpetas necesarias.", "NotAvailableApp": "¿Intentas descargar BeatSaber cuando no lo tienes? 🤣", @@ -247,10 +246,9 @@ "SteamLib": "Si tienes este error, reporta el bug en GitHub con los logs por favor.", "ConnectionError": "No se puede conectar a Steam después de 10 intentos 🤯", "LicenceError": "No se puede obtener la lista de licencias.", - "verification-failed": "Verificación fallida, inténtelo más tarde.", "RateLimitExceeded": "Lo has intentado demasiadas veces, espera un poco y vuelve a intentarlo más tarde.", - "AlreadyDownloading": "La descarga ya está en curso", - "no-internet": "Sin conexión a Internet.", + "TokenRejected": "No se puede descargar BeatSaber 😥 inténtalo más tarde 😕", + "AccessDenied": "El acceso a Steam ha sido denegado.", "dotnet-required": "Se debe instalar el tiempo de ejecución de .NET 6 para descargar una versión de BeatSaber. Descárguelo haciendo clic en el botón de abajo." }, "actions": { diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index 7524ec91..4f8f6f4a 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -215,10 +215,7 @@ }, "warnings": { "msg": { - "ManifestChecksum": "Le manifest téléchargé précédemment ne correspond pas au nouveau 🤔", "ConnectionTimeout": "Ta connexion internet semble instable 🥶", - "ConnectionLost": "La connexion a été perdue, nouvelle tentative...", - "ConnectionError": "Impossible de se connecter à Steam, nouvelle tentative...", "Unknown": "Quelque chose d'étrange s'est produit 🤔 Votre connexion est surement instable." } }, @@ -231,7 +228,6 @@ "404": "Impossible de contacter les serveurs de Steam.", "Password": "Le mot de passe est invalide.", "InvalidCredentials": "Ton e-mail ou mot de passe est invalide 😴", - "InvalidPassword": "Ton mot de passe est invalide 😕", "NoManifest": "Aucun manifest n'a été trouvé.", "DirectoryCreate": "Impossible d'installer les dossiers nécessaires.", "NotAvailableApp": "Tu essayes de télécharger Beat Saber alors que tu ne l'as pas ? 🤣", @@ -247,10 +243,9 @@ "SteamLib": "Si tu as cette erreur, signale le bug sur GitHub avec les logs stp.", "ConnectionError": "Impossible de se connecter à Steam après 10 essais 🤯", "LicenceError": "Impossible d'obtenir la liste des licences.", - "verification-failed": "La vérification a échoué, réessaye plus tard.", "RateLimitExceeded": "Tu as essayé trop de fois attends un peu et recommence plus tard.", - "AlreadyDownloading": "Un téléchargement est déjà en cours", - "no-internet": "Pas de connexion internet.", + "TokenRejected": "Impossible de télécharger Beat Saber 😥 réessaye plus tard 😕", + "AccessDenied": "L'accès à Steam a été refusé.", "dotnet-required": ".NET 6 Runtime doit être installé pour pouvoir télécharger une version de Beat Saber. Télécharge-le en cliquant sur le bouton ci-dessous." }, "actions": { diff --git a/assets/jsons/translations/ru.json b/assets/jsons/translations/ru.json index cabdd6a4..cf2caff4 100644 --- a/assets/jsons/translations/ru.json +++ b/assets/jsons/translations/ru.json @@ -232,7 +232,6 @@ "404": "Нет связи с серверами Steam.", "Password": "Неверный пароль.", "InvalidCredentials": "Ваша почта или пароль неверны 😴", - "InvalidPassword": "Ваш пароль неверен 😕", "NoManifest": "Файл манифеста не найден", "DirectoryCreate": "Не смогли создать нужные папки.", "NotAvailableApp": "Вы пытаетесь скачать Beat Saber, не купив её? 🤣", @@ -248,10 +247,9 @@ "SteamLib": "Если вы это видите, пожалуйста, сообщите о баге на GitHub с файлом логов.", "ConnectionError": "Не удалось подключиться к Steam за 10 попыток 🤯", "LicenceError": "Не удалось проверить наличие лицензии.", - "verification-failed": "Верификация провалена, повторите попытку позже.", "RateLimitExceeded": "Слишком много попыток, вернитесь позже и попробуйте снова.", - "AlreadyDownloading": "Скачивание уже в процессе", - "no-internet": "Нет интернета.", + "TokenRejected": "Не удалось скачать Beat Saber 😥 повторите попытку позже 😕", + "AccessDenied": "Доступ к Steam был отклонен.", "dotnet-required": "Среда запуска .NET 6 должна быть установлена, чтобы скачать Beat Saber. Скачайте её с помощью кнопки ниже." }, "actions": { diff --git a/src/main/models/depot-downloader.class.ts b/src/main/models/depot-downloader.class.ts index 50ac2849..fdc57937 100644 --- a/src/main/models/depot-downloader.class.ts +++ b/src/main/models/depot-downloader.class.ts @@ -1,6 +1,7 @@ import { ChildProcessWithoutNullStreams, SpawnOptionsWithoutStdio, spawn } from "child_process"; import { Observable, ReplaySubject, Subscriber, filter, map, share } from "rxjs"; -import { DepotDownloaderArgsOptions, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderEventTypes, DepotDownloaderSubTypeOfEventType } from "../../shared/models/depot-downloader.model"; +import { DepotDownloaderArgsOptions, DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderEventTypes, DepotDownloaderInfoEvent, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model"; +import { DownloadEvent } from "main/services/bs-installer.service"; export class DepotDownloader { @@ -22,7 +23,11 @@ export class DepotDownloader { subscriber.next(`[Info]|[Start]|${JSON.stringify(options.echoStartData) ?? ""}`); - this.process.stdout.on("data", data => subscriber.next(data.toString())); + this.process.stdout.on("data", data => { + const lines: string[] = data.toString().split("\n"); + lines.forEach(line => subscriber.next(line)); + }); + this.process.stderr.on("error", error => subscriber.error(error)); this.process.on("exit", code => subscriber.complete()); @@ -36,9 +41,18 @@ export class DepotDownloader { } public $events(): Observable>{ + + const eventTypesArr = Object.values(DepotDownloaderEventType); + + const DepotDownloaderSubTypeOfEventType: {[key in DepotDownloaderEventType]: DepotDownloaderEventTypes[]} = { + [DepotDownloaderEventType.Error]: Object.values(DepotDownloaderErrorEvent), + [DepotDownloaderEventType.Warning]: Object.values(DepotDownloaderWarningEvent), + [DepotDownloaderEventType.Info]: Object.values(DepotDownloaderInfoEvent), + } + return this.processOut$.pipe(map(line => { - console.log(line.toString()); + console.log(line); const matched = (line.toString() as string).match(/(?:\[(.*?)\])\|(?:\[(.*?)\]\|)?(.*?)(?=$|\[)/gm)?.[0] ?? null; @@ -46,7 +60,7 @@ export class DepotDownloader { const splitedLine = matched.split("|").map(str => str.trim().replaceAll("[", "").replaceAll("]", "")) as [DepotDownloaderEventType, DepotDownloaderEventTypes, unknown]; - if(!Object.values(DepotDownloaderEventType).includes(splitedLine[0]) || !Object.values(DepotDownloaderSubTypeOfEventType[splitedLine[0]]).includes(splitedLine[1])){ + if(!eventTypesArr.includes(splitedLine[0] as DepotDownloaderEventType) || !DepotDownloaderSubTypeOfEventType[splitedLine[0]].includes(splitedLine[1])){ return null; } diff --git a/src/renderer/pages/settings-page.component.tsx b/src/renderer/pages/settings-page.component.tsx index 1f87b81e..7b29906b 100644 --- a/src/renderer/pages/settings-page.component.tsx +++ b/src/renderer/pages/settings-page.component.tsx @@ -35,6 +35,7 @@ import { useService } from "renderer/hooks/use-service.hook"; import { lastValueFrom } from "rxjs"; import { BsmException } from "shared/models/bsm-exception.model"; import { useObservable } from "renderer/hooks/use-observable.hook"; +import { AuthUserService } from "renderer/services/auth-user.service"; export function SettingsPage() { @@ -51,6 +52,7 @@ export function SettingsPage() { const playlistsManager = useService(PlaylistsManagerService); const modelsManager = useService(ModelsManagerService); const versionLinker = useService(VersionFolderLinkerService); + const authService = useService(AuthUserService); const { firstColor, secondColor } = useThemeColor(); @@ -67,6 +69,9 @@ export function SettingsPage() { }) .sort((a, b) => a.text.localeCompare(b.text)); + const nav = useNavigate(); + const t = useTranslation(); + const [themeIdSelected, setThemeIdSelected] = useState(themeItem.find(e => e.value === themeService.getTheme()).id); const [languageSelected, setLanguageSelected] = useState(languagesItems.find(e => e.value === i18nService.currentLanguage).id); const [installationFolder, setInstallationFolder] = useState(null); @@ -75,8 +80,7 @@ export function SettingsPage() { const [playlistsDeepLinkEnabled, setPlaylistsDeepLinkEnabled] = useState(false); const [modelsDeepLinkEnabled, setModelsDeepLinkEnabled] = useState(false); const appVersion = useObservable(ipcService.sendV2("current-version")); - const nav = useNavigate(); - const t = useTranslation(); + const steamSessionExist = useObservable(authService.sessionExist$); useEffect(() => { loadInstallationFolder(); @@ -203,6 +207,10 @@ export function SettingsPage() { nav(-1)} icon="close" withBar={false} /> + + authService.deleteSteamSession()} className="w-fit px-3 py-[2px] text-white rounded-md" withBar={false} text="pages.settings.steam.logout" typeColor="error" disabled={!steamSessionExist}/> + +
diff --git a/src/renderer/pages/version-viewer.component.tsx b/src/renderer/pages/version-viewer.component.tsx index 1a46c903..340aa6cf 100644 --- a/src/renderer/pages/version-viewer.component.tsx +++ b/src/renderer/pages/version-viewer.component.tsx @@ -43,7 +43,7 @@ export function VersionViewer() { navigate(`/bs-version/${version.BSVersion}`, { state: version }); }; const openFolder = () => ipcService.sendLazy("bs-version.open-folder", { args: state }); - const verifyFiles = () => bsDownloaderService.download(state, true); + const verifyFiles = () => bsDownloaderService.verifyBsVersionFiles(state); const uninstall = async () => { const modalCompleted = await modalService.openModal(UninstallModal, state); diff --git a/src/renderer/services/bs-downloader.service.ts b/src/renderer/services/bs-downloader.service.ts index ccfbf2cc..b8b72e9b 100644 --- a/src/renderer/services/bs-downloader.service.ts +++ b/src/renderer/services/bs-downloader.service.ts @@ -1,7 +1,6 @@ -import { DownloadEvent, DownloadInfo } from "main/services/bs-installer.service"; -import { BehaviorSubject, Observable, Subscription, identity, lastValueFrom, of, throwError } from "rxjs"; -import { distinctUntilChanged, filter, map, take, tap, throttleTime } from "rxjs/operators"; -import { IpcResponse } from "shared/models/ipc"; +import { DownloadInfo } from "main/services/bs-installer.service"; +import { BehaviorSubject, Observable, ReplaySubject, Subscription, lastValueFrom, throwError } from "rxjs"; +import { distinctUntilChanged, 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"; @@ -12,7 +11,7 @@ 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, DepotDownloaderSubTypeOfEventType, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model"; +import { DepotDownloaderErrorEvent, DepotDownloaderEvent, DepotDownloaderEventType, DepotDownloaderInfoEvent, DepotDownloaderWarningEvent } from "../../shared/models/depot-downloader.model"; import equal from "fast-deep-equal"; import { SteamMobileApproveModal } from "renderer/components/modal/modal-types/steam-mobile-approve-modal.component"; @@ -146,7 +145,10 @@ export class BsDownloaderService { filter(event => event.subType === DepotDownloaderInfoEvent.Finished), take(1), ).subscribe(() => { - console.log("show success notification"); + if(this.isVerification){ + return this.notificationService.notifySuccess({title: "notifications.bs-download.success.titles.verification-finished"}); + } + return this.notificationService.notifySuccess({title: "notifications.bs-download.success.titles.download-success"}); })); return subs; @@ -154,24 +156,37 @@ export class BsDownloaderService { private handleWarningEvents(events$: Observable): Subscription[] { const subs: Subscription[] = []; + + const handledWarnings = Object.values(DepotDownloaderWarningEvent); + + subs.push(events$.pipe( + filter(event => handledWarnings.includes(event.subType as DepotDownloaderWarningEvent)), + ).subscribe(event => { + this.notificationService.notifyWarning({title: "notifications.types.warning", desc: `notifications.bs-download.warnings.msg.${event.subType}`}); + })); + return subs; } - private hanndleErrorEvents(events$: Observable): Subscription[] { - const subs: Subscription[] = []; - return subs; + private hanndleErrorEvent(errorEvent: DepotDownloaderEvent) { + const handledErrors = Object.values(DepotDownloaderErrorEvent); + + if(handledErrors.includes(errorEvent?.subType as DepotDownloaderErrorEvent)){ + return this.notificationService.notifyError({title: "notifications.types.error", desc: `notifications.bs-download.errors.msg.${errorEvent.subType}`}); + } + + return this.notificationService.notifyError({title: "notifications.types.error", desc: `notifications.bs-download.errors.msg.${DepotDownloaderErrorEvent.Unknown}`}); } - private wrapDownload(download$: Observable): Observable { + private wrapDownload(download$: Observable, silent?: boolean): Observable { return new Observable(sub => { - const downloadSub = download$.subscribe(sub); + const downloadSub = download$.subscribe({next: n => sub.next(n), error: e => sub.error(e), complete: () => sub.complete()}); const subs = [ ...this.handleInfoEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Info))), - ...this.handleWarningEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Warning))), - ...this.hanndleErrorEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Error))) + ...this.handleWarningEvents(download$.pipe(filter(event => event.type === DepotDownloaderEventType.Warning), throttleTime(10_000))), ]; return () => { @@ -180,7 +195,13 @@ export class BsDownloaderService { } }).pipe( - tap({error: () => this.authService.deleteSteamSession()}) + tap({ + error: (e) => { + this.authService.deleteSteamSession(); + !silent && this.hanndleErrorEvent(e) + } + }), + share({connector: () => new ReplaySubject(1)}) ); } @@ -193,7 +214,8 @@ export class BsDownloaderService { const infos: DownloadInfo = {...downloadInfo, username: this.authService.getSteamUsername()} return this.wrapDownload( - this.ipcService.sendV2("auto-download-bs-version", { args: infos }) + this.ipcService.sendV2("auto-download-bs-version", { args: infos }), + true ); } @@ -272,6 +294,10 @@ export class BsDownloaderService { return this.doDownloadBsVersion(version).then(() => version); } + public verifyBsVersionFiles(version: BSVersion): Promise { + return this.doDownloadBsVersion(version, true).then(() => version); + } + public verifyBsVersion(version: BSVersion): Promise { return this.doDownloadBsVersion(version, true).then(() => version); } diff --git a/src/shared/models/depot-downloader.model.ts b/src/shared/models/depot-downloader.model.ts index 01f5ecd8..ae701b79 100644 --- a/src/shared/models/depot-downloader.model.ts +++ b/src/shared/models/depot-downloader.model.ts @@ -35,7 +35,7 @@ export enum DepotDownloaderErrorEvent { DepotNotFound = "DepotNotFound", NotCompleted = "NotCompleted", InvalidManifest = "InvalidManifest", - NoValidKeys = "NoValidKeys", + NoValidKeys = "NoValidKey", NoManifestCode = "NoManifestCode", _401 = "401", _404 = "404", @@ -46,17 +46,14 @@ export enum DepotDownloaderErrorEvent { ConnectionError = "ConnectionError", TokenRejected = "TokenRejected", LicenceError = "LicenceError", + AccessDenied = "AccessDenied", Unknown = "Unknown", } export enum DepotDownloaderWarningEvent { ManifestChecksum = "ManifestChecksum", -} - -export const DepotDownloaderSubTypeOfEventType = { - [DepotDownloaderEventType.Error]: DepotDownloaderErrorEvent, - [DepotDownloaderEventType.Warning]: DepotDownloaderWarningEvent, - [DepotDownloaderEventType.Info]: DepotDownloaderInfoEvent, + ConnectionTimeout = "ConnectionTimeout", + Unknown = "Unknown", } export interface DepotDownloaderArgsOptions {