diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4eee0aad..cd91c635 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,4 +1,4 @@
-name: Build
+name: Release
on:
push:
diff --git a/README.be.md b/README.be.md
index d74e3291..c5848f79 100644
--- a/README.be.md
+++ b/README.be.md
@@ -119,7 +119,7 @@ yarn
### Усталёўка Python 3.9
-Упэўніцеся, што ў вас усталяваны Python 3.9 на вашым кампутары. Вы можаце загрузіць і ўсталяваць яго з [python.org](https://www.python.org/downloads/release/python-3919/).
+Упэўніцеся, што ў вас усталяваны Python 3.9 на вашым кампутары. Вы можаце загрузіць і ўсталяваць яго з [python.org](https://www.python.org/downloads/release/python-3913/).
### Усталёўка залежнасцяў Python
diff --git a/README.md b/README.md
index 2162b75b..ab608f37 100644
--- a/README.md
+++ b/README.md
@@ -13,11 +13,11 @@
[](https://github.com/hydralauncher/hydra/actions)
[](https://github.com/hydralauncher/hydra/releases)
+[](README.be.md)
+[](README.pl.md)
[](README.pt-BR.md)
-[](README.md)
[](README.ru.md)
[](README.uk-UA.md)
-[](README.be.md)

@@ -119,7 +119,7 @@ yarn
### Install Python 3.9
-Ensure you have Python 3.9 installed on your machine. You can download and install it from [python.org](https://www.python.org/downloads/release/python-3919/).
+Ensure you have Python 3.9 installed on your machine. You can download and install it from [python.org](https://www.python.org/downloads/release/python-3913/).
### Install Python Dependencies
diff --git a/README.pl.md b/README.pl.md
new file mode 100644
index 00000000..4fa7449e
--- /dev/null
+++ b/README.pl.md
@@ -0,0 +1,185 @@
+
+
+
+
+[
](https://hydralauncher.site)
+
+
Hydra Launcher
+
+
+ Hydra - to program uruchamiający gry z własnym wbudowanym klientem bittorrent i samodzielnie zarządzanym repackagerem..
+
+
+[](https://github.com/hydralauncher/hydra/actions)
+[](https://github.com/hydralauncher/hydra/releases)
+
+[](README.be.md)
+[](README.md)
+[](README.pt-BR.md)
+[](README.ru.md)
+[](README.uk-UA.md)
+
+
+
+
+
+## Zawartość.
+
+- [O nas](#o-nas)
+- [Cechy.](#cechy)
+- [Instalacja](#instalacja)
+- [Dokonaj wpłaty](#dokonaj-wpłaty)
+ - [Dołącz do naszego kanału Telegram](#dołącz-do-naszego-kanału-telegram)
+ - [Rozwidlenie i sklonowanie repozytorium](#rozwidlenie-i-sklonowanie-repozytorium)
+ - [Jak możesz wnieść swój wkład](#jak-możesz-pomóc)
+ - [Struktura projektu](#struktura-projektu)
+- [Utwórz kompilację z kodu źródłowego](#utwórz-kompilację-z-kodu-źródłowego)
+ - [Instalacja Node.js](#zainstaluj-nodejs)
+ - [Instalacja Yarn](#zainstaluj-yarn)
+ - [Instalacja Node zależności](#zainstaluj-zależności-node)
+ - [Instalacja Python 3.9](#zainstaluj-python-39)
+ - [Instalacja Python zależności](#zainstaluj-zależności-pythona)
+- [Zmienne środowiskowe](#zmienne-środowiskowe)
+- [Uruchomienie](#utwórz-kompilację-z-kodu-źródłowego)
+- [Tworzenie kompilacji](#tworzenie-kompilacji)
+ - [Tworzenie klienta bittorrent](#zbuduj-klienta-bittorrent)
+ - [Tworzenie kompilacji aplikacji Electron](#tworzenie-aplikacji-electron)
+- [Współtwórcy](#współtwórcy)
+
+## O nas
+
+**Hydra** - jest **programem uruchamiającym gry** z wbudowanym **klientem BitTorrent** i **samozarządzającym się repackagerem**.
+
+Ten launcher jest napisany w TypeScript (Electron) i Pythonie, który współpracuje z systemem torrent przy użyciu libtorrent.
+
+## Cechy
+
+- Samodzielnie zarządzany repackager wśród wszystkich najbardziej zaufanych stron na [Megathread]("https://www.reddit.com/r/Piracy/wiki/megathread/").
+- Własny wbudowany klient bittorrent
+- Integracja funkcji How Long To Beat (HLTB) na stronie gry
+- Personalizacja folderu pobierania
+- Powiadomienia o aktualizacjach listy repacków
+- Wsparcie dla systemów Windows i Linux
+- Stała aktualizacja
+- I nie tylko ...
+
+## Instalacja
+
+Aby zainstalować, wykonaj poniższe czynności:
+
+1. Pobierz najnowszą wersję programu Hydra ze strony [Wydania](https://github.com/hydralauncher/hydra/releases/latest).
+ - Pobierz .exe tylko, jeśli chcesz zainstalować Hydrę w systemie Windows.
+ - Pobierz .deb lub .rpm lub .zip, jeśli chcesz zainstalować Hydrę w systemie Linux (zależy od dystrybucji systemu Linux).
+2. Uruchom pobrany plik.
+3. Ciesz się Hydrą!
+
+## Dokonaj wpłaty
+
+### Dołącz do naszego kanału Telegram
+
+Skupiamy nasze dyskusje na naszym kanale [Telegram](https://t.me/hydralauncher).
+
+1. Dołącz do naszego kanału
+2. Przejdź do kanału ról i wybierz rolę Pracownik.
+3. Wejdź na kanał dev, komunikuj się z nami i dziel się swoimi pomysłami.
+
+### Rozwidlenie i sklonowanie repozytorium
+
+1. Rozwidlenie repozytorium [(kliknij tutaj, aby rozwidlić teraz)](https://github.com/hydralauncher/hydra/fork)
+2. Sklonuj swój rozwidlony kod `git clone https://github.com/your_username/hydra`.
+3. Utwórz nowy brunch
+4. Wypchnij swoje zatwierdzenia
+5. Wyślij nowy Pull Request
+
+### Jak możesz pomóc
+
+- Tłumaczenie: Chcemy, aby Hydra była dostępna dla jak największej liczby osób. Zachęcamy do pomocy w tłumaczeniu na nowe języki lub aktualizowaniu i ulepszaniu tych, które są już dostępne na Hydrze.
+- Kod: Hydra jest zbudowana przy użyciu Typescript, Electron i odrobiny Pythona. Jeśli chcesz wnieść swój wkład, dołącz do naszego kanału Telegram!
+
+### Struktura projektu
+
+- Klient torrent: Używamy libtorrent, biblioteki Pythona, do zarządzania pobieraniem torrentów.
+- src/renderer: interfejs aplikacji
+- src/main: cała logika jest tutaj.
+
+## Utwórz kompilację z kodu źródłowego
+
+### Zainstaluj Node.js
+
+Upewnij się, że masz zainstalowany Node.js na swoim komputerze. Jeśli nie, pobierz i zainstaluj go ze strony [nodejs.org](https://nodejs.org/).
+
+### Zainstaluj Yarn
+
+Yarn to menedżer pakietów dla Node.js. Jeśli jeszcze nie zainstalowałeś Yarn, możesz to zrobić, postępując zgodnie z instrukcjami na stronie [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
+
+### Zainstaluj zależności Node
+
+Przejdź do katalogu projektu i zainstaluj zależności Node za pomocą Yarn:
+
+```bash
+cd hydra
+yarn
+```
+
+### Zainstaluj Python 3.9
+
+Upewnij się, że masz zainstalowany Python 3.9 na swoim komputerze. Można go pobrać i zainstalować ze strony [python.org](https://www.python.org/downloads/release/python-3913/).
+
+### Zainstaluj zależności Pythona
+
+Zainstaluj niezbędne zależności Pythona za pomocą pip:
+
+```bash
+pip install -r requirements.txt
+```
+
+## Zmienne środowiskowe
+
+Będziesz potrzebował klucza API SteamGridDB, aby uzyskać ikony gier podczas instalacji.
+Jeśli chcesz użyć onlinefix jako repackagera, musisz dodać swoje dane uwierzytelniające do .env
+
+Po jego uzyskaniu można skopiować plik lub zmienić jego nazwę `.env.example` na `.env` i umieść go na`STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
+
+## Run
+
+Po skonfigurowaniu wszystkiego można uruchomić następujące polecenie, aby uruchomić zarówno proces Electron, jak i klienta bittorrent:
+
+```bash
+yarn dev
+```
+
+## Tworzenie kompilacji
+
+### Zbuduj klienta bittorrent
+
+Zbuduj klienta bittorrent za pomocą tego poleceniaи:
+
+```bash
+python torrent-client/setup.py build
+```
+
+### Tworzenie aplikacji Electron
+
+Zbuduj aplikację Electron za pomocą tego polecenia:
+
+W systemie Windows:
+
+```bash
+yarn build:win
+```
+
+W systemie Linux:
+
+```bash
+yarn build:linux
+```
+
+## Współtwórcy
+
+
+
+
+
+## License
+
+Hydra posiada licencję [MIT License](LICENSE).
diff --git a/README.pt-BR.md b/README.pt-BR.md
index 5d04e48b..07c89e96 100644
--- a/README.pt-BR.md
+++ b/README.pt-BR.md
@@ -13,12 +13,11 @@
[](https://github.com/hydralauncher/hydra/actions)
[](https://github.com/hydralauncher/hydra/releases)
-[](README.pt-BR.md)
+[](README.be.md)
[](README.md)
+[](README.pl.md)
[](README.ru.md)
[](README.uk-UA.md)
-[](README.be.md)
-

@@ -119,7 +118,7 @@ yarn
### Instale Python 3.9
-Certifique-se de ter o Python 3.9 instalado em sua máquina. Você pode baixá-lo e instalá-lo em [python.org](https://www.python.org/downloads/release/python-3919/).
+Certifique-se de ter o Python 3.9 instalado em sua máquina. Você pode baixá-lo e instalá-lo em [python.org](https://www.python.org/downloads/release/python-3913/).
### Instale Python Dependencies
diff --git a/README.ru.md b/README.ru.md
index 03ecf379..704a8c90 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -13,11 +13,11 @@
[](https://github.com/hydralauncher/hydra/actions)
[](https://github.com/hydralauncher/hydra/releases)
-[](README.pt-BR.md)
-[](README.md)
-[](README.ru.md)
-[](README.uk-UA.md)
[](README.be.md)
+[](README.md)
+[](README.pl.md)
+[](README.pt-BR.md)
+[](README.uk-UA.md)

@@ -119,7 +119,7 @@ yarn
### Установка Python 3.9
-Убедитесь, что у вас установлен Python 3.9 на вашем компьютере. Вы можете загрузить и установить его с [python.org](https://www.python.org/downloads/release/python-3919/).
+Убедитесь, что у вас установлен Python 3.9 на вашем компьютере. Вы можете загрузить и установить его с [python.org](https://www.python.org/downloads/release/python-3913/).
### Установка зависимостей Python
diff --git a/README.uk-UA.md b/README.uk-UA.md
index 99b5ca3c..c8451bc2 100644
--- a/README.uk-UA.md
+++ b/README.uk-UA.md
@@ -13,11 +13,11 @@
[](https://github.com/hydralauncher/hydra/actions)
[](https://github.com/hydralauncher/hydra/releases)
-[](README.pt-BR.md)
-[](README.md)
-[](README.ru.md)
-[](README.uk-UA.md)
[](README.be.md)
+[](README.md)
+[](README.pl.md)
+[](README.pt-BR.md)
+[](README.ru.md)

@@ -123,7 +123,7 @@ yarn
### Встановіть Python 3.9
-Переконайтеся, що на вашому комп'ютері встановлено Python 3.9. Ви можете завантажити та встановити його з [python.org](https://www.python.org/downloads/release/python-3919/).
+Переконайтеся, що на вашому комп'ютері встановлено Python 3.9. Ви можете завантажити та встановити його з [python.org](https://www.python.org/downloads/release/python-3913/).
### Встановіть Python залежності
diff --git a/package.json b/package.json
index 97944d50..3c787f4d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
- "name": "hydra",
- "version": "1.2.2",
+ "name": "hydralauncher",
+ "version": "1.2.3",
"description": "Hydra",
"main": "./out/main/index.js",
"author": "Los Broxas",
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index ac695bca..ee9fb16b 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -176,5 +176,11 @@
},
"modal": {
"close": "Close button"
+ },
+ "splash": {
+ "downloading_version": "Downloading version {{version}}",
+ "searching_updates": "Searching for updates",
+ "update_found": "Update {{version}} found",
+ "restarting_and_applying": "Restarting and applying update"
}
}
diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json
index bc3190db..d5f92a9f 100644
--- a/src/locales/pt/translation.json
+++ b/src/locales/pt/translation.json
@@ -176,5 +176,11 @@
},
"modal": {
"close": "Botão de fechar"
+ },
+ "splash": {
+ "downloading_version": "Baixando versão {{version}}",
+ "searching_updates": "Buscando atualizações",
+ "update_found": "Versão {{version}} encontrada",
+ "restarting_and_applying": "Reiniciando e aplicando atualização"
}
}
diff --git a/src/main/constants.ts b/src/main/constants.ts
index 4d43518b..17eea7ca 100644
--- a/src/main/constants.ts
+++ b/src/main/constants.ts
@@ -22,7 +22,7 @@ export const defaultDownloadsPath = app.getPath("downloads");
export const databasePath = path.join(
app.getPath("appData"),
- app.getName(),
+ "hydra",
"hydra.db"
);
diff --git a/src/main/events/autoupdater/check-for-updates.ts b/src/main/events/autoupdater/check-for-updates.ts
new file mode 100644
index 00000000..aa63575f
--- /dev/null
+++ b/src/main/events/autoupdater/check-for-updates.ts
@@ -0,0 +1,48 @@
+import { AppUpdaterEvents } from "@types";
+import { registerEvent } from "../register-event";
+import updater, { ProgressInfo, UpdateInfo } from "electron-updater";
+import { WindowManager } from "@main/services";
+import { app } from "electron";
+
+const { autoUpdater } = updater;
+
+const sendEvent = (event: AppUpdaterEvents) => {
+ WindowManager.splashWindow?.webContents.send("autoUpdaterEvent", event);
+};
+
+const mockValuesForDebug = async () => {
+ sendEvent({ type: "update-downloaded" });
+};
+
+const checkForUpdates = async (_event: Electron.IpcMainInvokeEvent) => {
+ autoUpdater
+ .addListener("error", () => {
+ sendEvent({ type: "error" });
+ })
+ .addListener("checking-for-update", () => {
+ sendEvent({ type: "checking-for-updates" });
+ })
+ .addListener("update-not-available", () => {
+ sendEvent({ type: "update-not-available" });
+ })
+ .addListener("update-available", (info: UpdateInfo) => {
+ sendEvent({ type: "update-available", info });
+ })
+ .addListener("update-downloaded", () => {
+ sendEvent({ type: "update-downloaded" });
+ })
+ .addListener("download-progress", (info: ProgressInfo) => {
+ sendEvent({ type: "download-progress", info });
+ })
+ .addListener("update-cancelled", () => {
+ sendEvent({ type: "update-cancelled" });
+ });
+
+ if (app.isPackaged) {
+ autoUpdater.checkForUpdates();
+ } else {
+ await mockValuesForDebug();
+ }
+};
+
+registerEvent("checkForUpdates", checkForUpdates);
diff --git a/src/main/events/autoupdater/continue-to-main-window.ts b/src/main/events/autoupdater/continue-to-main-window.ts
new file mode 100644
index 00000000..6a8965f9
--- /dev/null
+++ b/src/main/events/autoupdater/continue-to-main-window.ts
@@ -0,0 +1,12 @@
+import { WindowManager } from "@main/services";
+import { registerEvent } from "../register-event";
+import updater from "electron-updater";
+
+const { autoUpdater } = updater;
+
+const continueToMainWindow = async (_event: Electron.IpcMainInvokeEvent) => {
+ autoUpdater.removeAllListeners();
+ WindowManager.prepareMainWindowAndCloseSplash();
+};
+
+registerEvent("continueToMainWindow", continueToMainWindow);
diff --git a/src/main/events/autoupdater/restart-and-install-update.ts b/src/main/events/autoupdater/restart-and-install-update.ts
new file mode 100644
index 00000000..be301c18
--- /dev/null
+++ b/src/main/events/autoupdater/restart-and-install-update.ts
@@ -0,0 +1,17 @@
+import { app } from "electron";
+import { registerEvent } from "../register-event";
+import updater from "electron-updater";
+import { WindowManager } from "@main/services";
+
+const { autoUpdater } = updater;
+
+const restartAndInstallUpdate = async (_event: Electron.IpcMainInvokeEvent) => {
+ if (app.isPackaged) {
+ autoUpdater.quitAndInstall(true, true);
+ } else {
+ autoUpdater.removeAllListeners();
+ WindowManager.prepareMainWindowAndCloseSplash();
+ }
+};
+
+registerEvent("restartAndInstallUpdate", restartAndInstallUpdate);
diff --git a/src/main/events/index.ts b/src/main/events/index.ts
index 5d721c62..debca0e4 100644
--- a/src/main/events/index.ts
+++ b/src/main/events/index.ts
@@ -27,6 +27,9 @@ import "./torrenting/start-game-download";
import "./user-preferences/get-user-preferences";
import "./user-preferences/update-user-preferences";
import "./user-preferences/auto-launch";
+import "./autoupdater/check-for-updates";
+import "./autoupdater/restart-and-install-update";
+import "./autoupdater/continue-to-main-window";
ipcMain.handle("ping", () => "pong");
ipcMain.handle("getVersion", () => app.getVersion());
diff --git a/src/main/index.ts b/src/main/index.ts
index dabdeb4e..22c13388 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -3,11 +3,10 @@ import updater from "electron-updater";
import i18n from "i18next";
import path from "node:path";
import { electronApp, optimizer } from "@electron-toolkit/utils";
-import { resolveDatabaseUpdates, WindowManager } from "@main/services";
+import { logger, resolveDatabaseUpdates, WindowManager } from "@main/services";
import { dataSource } from "@main/data-source";
import * as resources from "@locales";
import { userPreferencesRepository } from "@main/repository";
-
const { autoUpdater } = updater;
autoUpdater.setFeedURL({
@@ -16,6 +15,8 @@ autoUpdater.setFeedURL({
repo: "hydra",
});
+autoUpdater.logger = logger;
+
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) app.quit();
@@ -63,12 +64,8 @@ app.whenReady().then(() => {
where: { id: 1 },
});
- WindowManager.createMainWindow();
+ WindowManager.createSplashScreen();
WindowManager.createSystemTray(userPreferences?.language || "en");
-
- WindowManager.mainWindow?.on("ready-to-show", () => {
- autoUpdater.checkForUpdatesAndNotify();
- });
});
});
diff --git a/src/main/services/repack-tracker/online-fix.ts b/src/main/services/repack-tracker/online-fix.ts
index 38864a8b..265f6b70 100644
--- a/src/main/services/repack-tracker/online-fix.ts
+++ b/src/main/services/repack-tracker/online-fix.ts
@@ -148,9 +148,10 @@ export const getNewRepacksFromOnlineFix = async (
);
if (!newRepacks.length) return;
- if (page === totalPages) return;
await savePage(newRepacks);
+ if (page === totalPages) return;
+
return getNewRepacksFromOnlineFix(existingRepacks, page + 1, cookieJar);
};
diff --git a/src/main/services/repack-tracker/xatab.ts b/src/main/services/repack-tracker/xatab.ts
index 34ebfa4c..e765bebf 100644
--- a/src/main/services/repack-tracker/xatab.ts
+++ b/src/main/services/repack-tracker/xatab.ts
@@ -111,9 +111,10 @@ export const getNewRepacksFromXatab = async (
);
if (!newRepacks.length) return;
- if (page === totalPages) return;
await savePage(newRepacks);
+ if (page === totalPages) return;
+
return getNewRepacksFromXatab(existingRepacks, page + 1);
};
diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts
index 973a0c64..e435ddb2 100644
--- a/src/main/services/window-manager.ts
+++ b/src/main/services/window-manager.ts
@@ -17,6 +17,8 @@ import { IsNull, Not } from "typeorm";
export class WindowManager {
public static mainWindow: Electron.BrowserWindow | null = null;
+ public static splashWindow: Electron.BrowserWindow | null = null;
+ public static isReadyToShowMainWindow = false;
private static loadURL(hash = "") {
// HMR for renderer base on electron-vite cli.
@@ -35,13 +37,51 @@ export class WindowManager {
}
}
+ private static loadSplashURL() {
+ // HMR for renderer base on electron-vite cli.
+ // Load the remote URL for development or the local html file for production.
+ if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
+ this.splashWindow?.loadURL(
+ `${process.env["ELECTRON_RENDERER_URL"]}#/splash`
+ );
+ } else {
+ this.splashWindow?.loadFile(
+ path.join(__dirname, "../renderer/index.html"),
+ {
+ hash: "splash",
+ }
+ );
+ }
+ }
+
+ public static createSplashScreen() {
+ if (this.splashWindow) return;
+
+ this.splashWindow = new BrowserWindow({
+ width: 380,
+ height: 380,
+ frame: false,
+ resizable: false,
+ backgroundColor: "#1c1c1c",
+ webPreferences: {
+ preload: path.join(__dirname, "../preload/index.mjs"),
+ sandbox: false,
+ },
+ });
+
+ this.loadSplashURL();
+ this.splashWindow.removeMenu();
+ }
+
public static createMainWindow() {
- // Create the browser window.
+ if (this.mainWindow || !this.isReadyToShowMainWindow) return;
+
this.mainWindow = new BrowserWindow({
width: 1200,
height: 720,
minWidth: 1024,
minHeight: 540,
+ backgroundColor: "#1c1c1c",
titleBarStyle: "hidden",
...(process.platform === "linux" ? { icon } : {}),
trafficLightPosition: { x: 16, y: 16 },
@@ -75,6 +115,12 @@ export class WindowManager {
});
}
+ public static prepareMainWindowAndCloseSplash() {
+ this.isReadyToShowMainWindow = true;
+ this.splashWindow?.close();
+ this.createMainWindow();
+ }
+
public static redirect(hash: string) {
if (!this.mainWindow) this.createMainWindow();
this.loadURL(hash);
diff --git a/src/preload/index.ts b/src/preload/index.ts
index 0e397a4a..c808d8fc 100644
--- a/src/preload/index.ts
+++ b/src/preload/index.ts
@@ -7,6 +7,7 @@ import type {
GameShop,
DownloadProgress,
UserPreferences,
+ AppUpdaterEvents,
} from "@types";
contextBridge.exposeInMainWorld("electron", {
@@ -112,4 +113,21 @@ contextBridge.exposeInMainWorld("electron", {
showOpenDialog: (options: Electron.OpenDialogOptions) =>
ipcRenderer.invoke("showOpenDialog", options),
platform: process.platform,
+
+ /* Splash */
+ onAutoUpdaterEvent: (cb: (value: AppUpdaterEvents) => void) => {
+ const listener = (
+ _event: Electron.IpcRendererEvent,
+ value: AppUpdaterEvents
+ ) => cb(value);
+
+ ipcRenderer.on("autoUpdaterEvent", listener);
+
+ return () => {
+ ipcRenderer.removeListener("autoUpdaterEvent", listener);
+ };
+ },
+ checkForUpdates: () => ipcRenderer.invoke("checkForUpdates"),
+ restartAndInstallUpdate: () => ipcRenderer.invoke("restartAndInstallUpdate"),
+ continueToMainWindow: () => ipcRenderer.invoke("continueToMainWindow"),
});
diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx
index adb2a613..3a10b98c 100644
--- a/src/renderer/src/app.tsx
+++ b/src/renderer/src/app.tsx
@@ -12,7 +12,7 @@ import {
import * as styles from "./app.css";
import { themeClass } from "./theme.css";
-import { useLocation, useNavigate } from "react-router-dom";
+import { Outlet, useLocation, useNavigate } from "react-router-dom";
import {
setSearch,
clearSearch,
@@ -26,7 +26,7 @@ export interface AppProps {
children: React.ReactNode;
}
-export function App({ children }: AppProps) {
+export function App() {
const contentRef = useRef(null);
const { updateLibrary } = useLibrary();
@@ -127,7 +127,7 @@ export function App({ children }: AppProps) {
/>
diff --git a/src/renderer/src/assets/icon.png b/src/renderer/src/assets/icon.png
new file mode 100644
index 00000000..9254a8fb
Binary files /dev/null and b/src/renderer/src/assets/icon.png differ
diff --git a/src/renderer/src/components/toast/toast.css.ts b/src/renderer/src/components/toast/toast.css.ts
index 9035c8e8..bc8d5377 100644
--- a/src/renderer/src/components/toast/toast.css.ts
+++ b/src/renderer/src/components/toast/toast.css.ts
@@ -3,7 +3,7 @@ import { keyframes, style } from "@vanilla-extract/css";
import { SPACING_UNIT, vars } from "../../theme.css";
import { recipe } from "@vanilla-extract/recipes";
-const TOAST_HEIGHT = 60;
+const TOAST_HEIGHT = 55;
export const slideIn = keyframes({
"0%": { transform: `translateY(${TOAST_HEIGHT + SPACING_UNIT * 2}px)` },
diff --git a/src/renderer/src/components/toast/toast.tsx b/src/renderer/src/components/toast/toast.tsx
index 8ae9f934..1228653e 100644
--- a/src/renderer/src/components/toast/toast.tsx
+++ b/src/renderer/src/components/toast/toast.tsx
@@ -85,6 +85,7 @@ export function Toast({ visible, message, type, onClose }: ToastProps) {
type="button"
className={styles.closeButton}
onClick={startAnimateClosing}
+ aria-label="Close toast"
>
diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts
index 508a56b3..8a4e1c93 100644
--- a/src/renderer/src/declaration.d.ts
+++ b/src/renderer/src/declaration.d.ts
@@ -1,4 +1,5 @@
import type {
+ AppUpdaterEvents,
CatalogueCategory,
CatalogueEntry,
Game,
@@ -90,6 +91,14 @@ declare global {
options: Electron.OpenDialogOptions
) => Promise;
platform: NodeJS.Platform;
+
+ /* Splash */
+ onAutoUpdaterEvent: (
+ cb: (event: AppUpdaterEvents) => void
+ ) => () => Electron.IpcRenderer;
+ checkForUpdates: () => Promise;
+ restartAndInstallUpdate: () => Promise;
+ continueToMainWindow: () => Promise;
}
interface Window {
diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx
index f44653cb..3608af8d 100644
--- a/src/renderer/src/main.tsx
+++ b/src/renderer/src/main.tsx
@@ -27,6 +27,7 @@ import {
import { store } from "./store";
import * as resources from "@locales";
+import Splash from "./pages/splash/splash";
i18n
.use(LanguageDetector)
@@ -46,16 +47,17 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
+
+
+ }>
-
-
+
+
diff --git a/src/renderer/src/pages/game-details/gallery-slider.tsx b/src/renderer/src/pages/game-details/gallery-slider.tsx
index 486f56f8..75502df8 100644
--- a/src/renderer/src/pages/game-details/gallery-slider.tsx
+++ b/src/renderer/src/pages/game-details/gallery-slider.tsx
@@ -57,9 +57,7 @@ export function GallerySlider() {
if (hasMovies && mediaContainerRef.current) {
mediaContainerRef.current.childNodes.forEach((node, index) => {
if (node instanceof HTMLVideoElement) {
- if (index == mediaIndex) {
- node.play();
- } else {
+ if (index !== mediaIndex) {
node.pause();
}
}
diff --git a/src/renderer/src/pages/game-details/modals/select-folder-modal.css.tsx b/src/renderer/src/pages/game-details/modals/select-folder-modal.css.tsx
index fe369301..e63603c2 100644
--- a/src/renderer/src/pages/game-details/modals/select-folder-modal.css.tsx
+++ b/src/renderer/src/pages/game-details/modals/select-folder-modal.css.tsx
@@ -17,3 +17,12 @@ export const hintText = style({
fontSize: "12px",
color: vars.color.bodyText,
});
+
+export const downloaders = style({
+ display: "flex",
+ gap: `${SPACING_UNIT}px`,
+});
+
+export const downloaderOption = style({
+ flex: "1",
+});
diff --git a/src/renderer/src/pages/game-details/modals/select-folder-modal.tsx b/src/renderer/src/pages/game-details/modals/select-folder-modal.tsx
index 9c1d18e1..4b43c74d 100644
--- a/src/renderer/src/pages/game-details/modals/select-folder-modal.tsx
+++ b/src/renderer/src/pages/game-details/modals/select-folder-modal.tsx
@@ -80,8 +80,24 @@ export function SelectFolderModal({
onClose={onClose}
>
+
+
Download method
+
+
+
+ Torrent
+
+ Real Debrid
+
+
+
-
+
+
+
{t("download_now")}
diff --git a/src/renderer/src/pages/settings/settings.tsx b/src/renderer/src/pages/settings/settings.tsx
index b5a03ff3..fe7638c6 100644
--- a/src/renderer/src/pages/settings/settings.tsx
+++ b/src/renderer/src/pages/settings/settings.tsx
@@ -28,6 +28,8 @@ export function Settings() {
const handleUpdateUserPreferences = async (
values: Partial
) => {
+ setIsToastVisible(false);
+
await window.electron.updateUserPreferences(values);
window.electron.getUserPreferences().then((userPreferences) => {
setUserPreferences(userPreferences);
diff --git a/src/renderer/src/pages/splash/splash.css.ts b/src/renderer/src/pages/splash/splash.css.ts
new file mode 100644
index 00000000..36aacfff
--- /dev/null
+++ b/src/renderer/src/pages/splash/splash.css.ts
@@ -0,0 +1,49 @@
+import { style } from "@vanilla-extract/css";
+import { SPACING_UNIT, vars } from "../../theme.css";
+
+export const main = style({
+ width: "100%",
+ height: "100%",
+ display: "flex",
+ flexDirection: "column",
+ padding: `${SPACING_UNIT * 3}px`,
+ flex: "1",
+ overflowY: "auto",
+ alignItems: "center",
+});
+
+export const splashIcon = style({
+ width: "75%",
+});
+
+export const updateInfoSection = style({
+ width: "100%",
+ display: "flex",
+ flexDirection: "column",
+ gap: `${SPACING_UNIT * 2}px`,
+ flex: "1",
+ overflowY: "auto",
+ alignItems: "center",
+ justifyContent: "center",
+});
+
+export const progressBar = style({
+ WebkitAppearance: "none",
+ appearance: "none",
+ borderRadius: "4px",
+ width: "100%",
+ border: `solid 1px ${vars.color.border}`,
+ overflow: "hidden",
+ height: "18px",
+ "::-webkit-progress-value": {
+ backgroundColor: vars.color.muted,
+ transition: "width 0.2s",
+ },
+ "::-webkit-progress-bar": {
+ backgroundColor: vars.color.darkBackground,
+ },
+});
+
+export const progressBarText = style({
+ zIndex: 2,
+});
diff --git a/src/renderer/src/pages/splash/splash.tsx b/src/renderer/src/pages/splash/splash.tsx
new file mode 100644
index 00000000..dec308c4
--- /dev/null
+++ b/src/renderer/src/pages/splash/splash.tsx
@@ -0,0 +1,82 @@
+import icon from "@renderer/assets/icon.png";
+import * as styles from "./splash.css";
+import { themeClass } from "../../theme.css";
+
+import "../../app.css";
+import { useEffect, useState } from "react";
+import { AppUpdaterEvents } from "@types";
+import { useTranslation } from "react-i18next";
+
+document.body.classList.add(themeClass);
+
+export default function Splash() {
+ const [status, setStatus] = useState(null);
+ const [newVersion, setNewVersion] = useState("");
+
+ const { t } = useTranslation("splash");
+
+ useEffect(() => {
+ const unsubscribe = window.electron.onAutoUpdaterEvent(
+ (event: AppUpdaterEvents) => {
+ setStatus(event);
+
+ switch (event.type) {
+ case "error":
+ window.electron.continueToMainWindow();
+ break;
+ case "update-available":
+ setNewVersion(event.info.version);
+ break;
+ case "update-cancelled":
+ window.electron.continueToMainWindow();
+ break;
+ case "update-downloaded":
+ window.electron.restartAndInstallUpdate();
+ break;
+ case "update-not-available":
+ window.electron.continueToMainWindow();
+ break;
+ }
+ }
+ );
+
+ window.electron.checkForUpdates();
+
+ return () => {
+ unsubscribe();
+ };
+ }, []);
+
+ const renderUpdateInfo = () => {
+ switch (status?.type) {
+ case "download-progress":
+ return (
+ <>
+ {t("downloading_version", { version: newVersion })}
+
+ >
+ );
+ case "checking-for-updates":
+ return {t("searching_updates")}
;
+ case "update-available":
+ return {t("update_found", { version: newVersion })}
;
+ case "update-downloaded":
+ return {t("restarting_and_applying")}
;
+ default:
+ return <>>;
+ }
+ };
+
+ return (
+
+
+
+
+ );
+}
diff --git a/src/types/index.ts b/src/types/index.ts
index 7abc90fd..cdddd278 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,5 +1,6 @@
-import type { Downloader } from "@shared";
import type { Aria2Status } from "aria2";
+import type { Downloader } from "@shared";
+import { ProgressInfo, UpdateInfo } from "electron-updater";
export type GameShop = "steam" | "epic";
export type CatalogueCategory = "recently_added" | "trending";
@@ -146,3 +147,12 @@ export interface SteamGame {
name: string;
clientIcon: string | null;
}
+
+export type AppUpdaterEvents =
+ | { type: "error" }
+ | { type: "checking-for-updates" }
+ | { type: "update-not-available" }
+ | { type: "update-available"; info: UpdateInfo }
+ | { type: "update-downloaded" }
+ | { type: "download-progress"; info: ProgressInfo }
+ | { type: "update-cancelled" };