mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Merge branch 'main' of https://github.com/hydralauncher/hydra
This commit is contained in:
commit
2033951505
31 changed files with 1447 additions and 1484 deletions
|
@ -197,6 +197,13 @@ yarn make
|
||||||
<br />
|
<br />
|
||||||
<sub><b>Firdavs</b></sub>
|
<sub><b>Firdavs</b></sub>
|
||||||
</a>
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://github.com/userMacieG">
|
||||||
|
<img src="https://avatars.githubusercontent.com/u/24211405?v=4" width="100;" alt="userMacieG"/>
|
||||||
|
<br />
|
||||||
|
<sub><b>Maciej Ratyński</b></sub>
|
||||||
|
</a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<!-- readme: contributors -end -->
|
<!-- readme: contributors -end -->
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
"checking_files": "{{title}} ({{percentage}} - Analizando archivos…)",
|
"checking_files": "{{title}} ({{percentage}} - Analizando archivos…)",
|
||||||
"paused": "{{title}} (Pausado)",
|
"paused": "{{title}} (Pausado)",
|
||||||
"downloading": "{{title}} ({{percentage}} - Descargando…)",
|
"downloading": "{{title}} ({{percentage}} - Descargando…)",
|
||||||
"filter": "Filtrar biblioteca",
|
"filter": "Buscar en la biblioteca",
|
||||||
|
"follow_us": "Síguenos",
|
||||||
"home": "Inicio",
|
"home": "Inicio",
|
||||||
"follow_us": "Síguenos"
|
"discord": "Únete a nuestro Discord",
|
||||||
|
"x": "Síguenos en X",
|
||||||
|
"github": "Contribuye en GitHub"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
|
@ -45,7 +48,7 @@
|
||||||
"remove": "Eliminar",
|
"remove": "Eliminar",
|
||||||
"remove_from_list": "Quitar",
|
"remove_from_list": "Quitar",
|
||||||
"space_left_on_disk": "{{space}} restantes en el disco",
|
"space_left_on_disk": "{{space}} restantes en el disco",
|
||||||
"eta": "Finalizando {{eta}}",
|
"eta": "Finalizando en {{eta}}",
|
||||||
"downloading_metadata": "Descargando metadatos…",
|
"downloading_metadata": "Descargando metadatos…",
|
||||||
"checking_files": "Analizando archivos…",
|
"checking_files": "Analizando archivos…",
|
||||||
"filter": "Filtrar repacks",
|
"filter": "Filtrar repacks",
|
||||||
|
@ -55,14 +58,12 @@
|
||||||
"no_minimum_requirements": "Sin requisitos mínimos para {{title}}",
|
"no_minimum_requirements": "Sin requisitos mínimos para {{title}}",
|
||||||
"no_recommended_requirements": "{{title}} no tiene requisitos recomendados",
|
"no_recommended_requirements": "{{title}} no tiene requisitos recomendados",
|
||||||
"paused_progress": "{{progress}} (Pausado)",
|
"paused_progress": "{{progress}} (Pausado)",
|
||||||
"release_date": "Fecha de lanzamiento {{date}}",
|
"release_date": "Fecha de lanzamiento: {{date}}",
|
||||||
"publisher": "Publicado por {{publisher}}",
|
"publisher": "Publicado por: {{publisher}}",
|
||||||
"copy_link_to_clipboard": "Copiar enlace",
|
"copy_link_to_clipboard": "Copiar enlace",
|
||||||
"copied_link_to_clipboard": "Enlace copiado",
|
"copied_link_to_clipboard": "Enlace copiado",
|
||||||
"hours": "horas",
|
"hours": "horas",
|
||||||
"minutes": "minutos",
|
"minutes": "minutos",
|
||||||
"amount_hours": "{{amount}} horas",
|
|
||||||
"amount_minutes": "{{amount}} minutos",
|
|
||||||
"accuracy": "{{accuracy}}% precisión",
|
"accuracy": "{{accuracy}}% precisión",
|
||||||
"add_to_library": "Agregar a la biblioteca",
|
"add_to_library": "Agregar a la biblioteca",
|
||||||
"remove_from_library": "Eliminar de la biblioteca",
|
"remove_from_library": "Eliminar de la biblioteca",
|
||||||
|
@ -75,7 +76,21 @@
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
"deleting": "Eliminando instalador…",
|
"deleting": "Eliminando instalador…",
|
||||||
"playing_now": "Jugando ahora",
|
"playing_now": "Jugando ahora",
|
||||||
"last_time_played": "Jugado por última vez {{period}}"
|
"last_time_played": "Jugado por última vez {{period}}",
|
||||||
|
"got_it": "Entendido",
|
||||||
|
"change": "Cambiar",
|
||||||
|
"repacks_modal_description": "Selecciona el repack que quieres descargar",
|
||||||
|
"downloads_path": "Ruta de descarga",
|
||||||
|
"select_folder_hint": "Para cambiar la carpeta predeterminada, accede a",
|
||||||
|
"settings": "Ajustes",
|
||||||
|
"download_now": "Descargar ahora",
|
||||||
|
"installation_instructions": "Instrucciones de instalación",
|
||||||
|
"installation_instructions_description": "Se requieren de pasos adicionales para instalar este juego",
|
||||||
|
"online_fix_instruction": "Los juegos de OnlineFix requieren una contraseña para ser extraídos. Cuando se requiera, usa la siguiente contraseña:",
|
||||||
|
"dodi_installation_instruction": "Cuando abras el instalador de DODI, presiona la tecla hacia arriba del teclado <0 /> para iniciar el proceso de instalación:",
|
||||||
|
"dont_show_it_again": "No mostrar de nuevo",
|
||||||
|
"copy_to_clipboard": "Copiar",
|
||||||
|
"copied_to_clipboard": "Copiado"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Activar Hydra",
|
"title": "Activar Hydra",
|
||||||
|
@ -88,7 +103,7 @@
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"resume": "Resumir",
|
"resume": "Resumir",
|
||||||
"pause": "Pausa",
|
"pause": "Pausa",
|
||||||
"eta": "Finalizando {{eta}}",
|
"eta": "Finalizando en {{eta}}",
|
||||||
"paused": "En Pausa",
|
"paused": "En Pausa",
|
||||||
"verifying": "Verificando…",
|
"verifying": "Verificando…",
|
||||||
"completed_at": "Completado el {{date}}",
|
"completed_at": "Completado el {{date}}",
|
||||||
|
@ -103,8 +118,8 @@
|
||||||
"starting_download": "Iniciando descarga…",
|
"starting_download": "Iniciando descarga…",
|
||||||
"remove_from_list": "Eliminar",
|
"remove_from_list": "Eliminar",
|
||||||
"delete": "Eliminar instalador",
|
"delete": "Eliminar instalador",
|
||||||
"delete_modal_description": "Esto eliminará todos los archivos de instalación de su computadora.",
|
"delete_modal_description": "Esto eliminará todos los archivos de instalación de tu computadora.",
|
||||||
"delete_modal_title": "¿Está seguro?",
|
"delete_modal_title": "¿Estás seguro?",
|
||||||
"deleting": "Eliminando instalador…",
|
"deleting": "Eliminando instalador…",
|
||||||
"install": "Instalar"
|
"install": "Instalar"
|
||||||
},
|
},
|
||||||
|
@ -137,6 +152,9 @@
|
||||||
"description": "Los ejecutables de Wine o Lutris no se encontraron en su sistema",
|
"description": "Los ejecutables de Wine o Lutris no se encontraron en su sistema",
|
||||||
"instructions": "Comprueba como instalar de forma correcta uno de los dos en tu distro de Linux para ejecutar el juego con normalidad"
|
"instructions": "Comprueba como instalar de forma correcta uno de los dos en tu distro de Linux para ejecutar el juego con normalidad"
|
||||||
},
|
},
|
||||||
|
"modal": {
|
||||||
|
"close": "Botón de cierre"
|
||||||
|
},
|
||||||
"catalogue": {
|
"catalogue": {
|
||||||
"next_page": "Siguiente página",
|
"next_page": "Siguiente página",
|
||||||
"previous_page": "Pagina anterior"
|
"previous_page": "Pagina anterior"
|
||||||
|
|
|
@ -4,4 +4,5 @@ export { default as es } from "./es/translation.json";
|
||||||
export { default as fr } from "./fr/translation.json";
|
export { default as fr } from "./fr/translation.json";
|
||||||
export { default as hu } from "./hu/translation.json";
|
export { default as hu } from "./hu/translation.json";
|
||||||
export { default as it } from "./it/translation.json";
|
export { default as it } from "./it/translation.json";
|
||||||
|
export { default as pl } from "./pl/translation.json";
|
||||||
export { default as ru } from "./ru/translation.json";
|
export { default as ru } from "./ru/translation.json";
|
||||||
|
|
147
src/locales/pl/translation.json
Normal file
147
src/locales/pl/translation.json
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
{
|
||||||
|
"home": {
|
||||||
|
"featured": "Wyróżnione",
|
||||||
|
"recently_added": "Ostatnio dodane",
|
||||||
|
"trending": "Trendujące",
|
||||||
|
"surprise_me": "Zaskocz mnie",
|
||||||
|
"no_results": "Nie znaleziono wyników"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"catalogue": "Katalog",
|
||||||
|
"downloads": "Pobrane",
|
||||||
|
"settings": "Ustawienia",
|
||||||
|
"my_library": "Moja biblioteka",
|
||||||
|
"downloading_metadata": "{{title}} (Pobieranie metadata…)",
|
||||||
|
"checking_files": "{{title}} ({{percentage}} - Sprawdzanie plików…)",
|
||||||
|
"paused": "{{title}} (Zatrzymano)",
|
||||||
|
"downloading": "{{title}} ({{percentage}} - Pobieranie…)",
|
||||||
|
"filter": "Filtruj biblioteke",
|
||||||
|
"follow_us": "Śledź nas",
|
||||||
|
"home": "Główna"
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"search": "Szukaj",
|
||||||
|
"home": "Główna",
|
||||||
|
"catalogue": "Katalog",
|
||||||
|
"downloads": "Pobrane",
|
||||||
|
"search_results": "Wyniki wyszukiwania",
|
||||||
|
"settings": "Ustawienia"
|
||||||
|
},
|
||||||
|
"bottom_panel": {
|
||||||
|
"no_downloads_in_progress": "Brak pobierań w toku",
|
||||||
|
"downloading_metadata": "Pobieranie {{title}} metadata…",
|
||||||
|
"checking_files": "Sprawdzanie {{title}} plików… (ukończone w {{percentage}})",
|
||||||
|
"downloading": "Pobieranie {{title}}… (ukończone w {{percentage}}) - Podsumowanie {{eta}} - {{speed}}"
|
||||||
|
},
|
||||||
|
"catalogue": {
|
||||||
|
"next_page": "Następna strona",
|
||||||
|
"previous_page": "Poprzednia strona"
|
||||||
|
},
|
||||||
|
"game_details": {
|
||||||
|
"open_download_options": "Otwórz opcje pobierania",
|
||||||
|
"download_options_zero": "Brak opcji pobierania",
|
||||||
|
"download_options_one": "{{count}} opcja pobierania",
|
||||||
|
"download_options_other": "{{count}} opcji pobierania",
|
||||||
|
"updated_at": "Zaktualizowano {{updated_at}}",
|
||||||
|
"install": "Instaluj",
|
||||||
|
"resume": "Wznów",
|
||||||
|
"pause": "Zatrzymaj",
|
||||||
|
"cancel": "Anuluj",
|
||||||
|
"remove": "Usuń",
|
||||||
|
"remove_from_list": "Usuń",
|
||||||
|
"space_left_on_disk": "{{space}} wolnego na dysku",
|
||||||
|
"eta": "Podsumowanie {{eta}}",
|
||||||
|
"downloading_metadata": "Pobieranie metadata…",
|
||||||
|
"checking_files": "Sprawdzanie plików…",
|
||||||
|
"filter": "Filtruj repacki",
|
||||||
|
"requirements": "Wymagania systemowe",
|
||||||
|
"minimum": "Minimalne",
|
||||||
|
"recommended": "Zalecane",
|
||||||
|
"no_minimum_requirements": "{{title}} nie zawiera informacji o minimalnych wymaganiach",
|
||||||
|
"no_recommended_requirements": "{{title}} nie zawiera informacji o zalecanych wymaganiach",
|
||||||
|
"paused_progress": "{{progress}} (Zatrzymano)",
|
||||||
|
"release_date": "Wydano w {{date}}",
|
||||||
|
"publisher": "Opublikowany przez {{publisher}}",
|
||||||
|
"copy_link_to_clipboard": "Kopiuj łącze",
|
||||||
|
"copied_link_to_clipboard": "Skopiowano łącze",
|
||||||
|
"hours": "godzin",
|
||||||
|
"minutes": "minut",
|
||||||
|
"accuracy": "{{accuracy}}% dokładność",
|
||||||
|
"add_to_library": "Dodaj do biblioteki",
|
||||||
|
"remove_from_library": "Usuń z biblioteki",
|
||||||
|
"no_downloads": "Brak dostępnych plików do pobrania",
|
||||||
|
"play_time": "Grano przez {{amount}}",
|
||||||
|
"last_time_played": "Ostatnio grano {{period}}",
|
||||||
|
"not_played_yet": "Nie grano {{title}}",
|
||||||
|
"next_suggestion": "Następna sugestia",
|
||||||
|
"play": "Graj",
|
||||||
|
"deleting": "Usuwanie instalatora…",
|
||||||
|
"close": "Zamknij",
|
||||||
|
"playing_now": "Granie teraz",
|
||||||
|
"change": "Zmień",
|
||||||
|
"repacks_modal_description": "Wybierz repack, który chcesz pobrać",
|
||||||
|
"downloads_path": "Ścieżka pobierania",
|
||||||
|
"select_folder_hint": "Aby zmienić domyślny folder, przejdź do",
|
||||||
|
"settings": "Ustawienia Hydra",
|
||||||
|
"download_now": "Pobierz teraz"
|
||||||
|
},
|
||||||
|
"activation": {
|
||||||
|
"title": "Aktywuj Hydra",
|
||||||
|
"installation_id": "Identyfikator instalacji:",
|
||||||
|
"enter_activation_code": "Enter your activation code",
|
||||||
|
"message": "Jeśli nie wiesz, gdzie o to poprosić, to nie powinieneś/aś tego mieć.",
|
||||||
|
"activate": "Aktywuj",
|
||||||
|
"loading": "Ładowanie…"
|
||||||
|
},
|
||||||
|
"downloads": {
|
||||||
|
"resume": "Wznów",
|
||||||
|
"pause": "Zatrzymaj",
|
||||||
|
"eta": "Podsumowanie {{eta}}",
|
||||||
|
"paused": "Zatrzymano",
|
||||||
|
"verifying": "Weryfikowanie…",
|
||||||
|
"completed_at": "Zakończono w {{date}}",
|
||||||
|
"completed": "Zakończono",
|
||||||
|
"cancelled": "Anulowano",
|
||||||
|
"download_again": "Pobierz ponownie",
|
||||||
|
"cancel": "Anuluj",
|
||||||
|
"filter": "Filtruj pobrane gry",
|
||||||
|
"remove": "Usuń",
|
||||||
|
"downloading_metadata": "Pobieranie metadata…",
|
||||||
|
"checking_files": "Sprawdzanie plików…",
|
||||||
|
"starting_download": "Rozpoczęto pobieranie…",
|
||||||
|
"deleting": "Usuwanie instalatora…",
|
||||||
|
"delete": "Usuń instalator",
|
||||||
|
"remove_from_list": "Usuń",
|
||||||
|
"delete_modal_title": "Czy na pewno?",
|
||||||
|
"delete_modal_description": "Spowoduje to usunięcie wszystkich plików instalacyjnych z komputera",
|
||||||
|
"install": "Instaluj"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"downloads_path": "Ścieżka pobierania",
|
||||||
|
"change": "Aktualizuj",
|
||||||
|
"notifications": "Powiadomienia",
|
||||||
|
"enable_download_notifications": "Gdy pobieranie zostanie zakończone",
|
||||||
|
"enable_repack_list_notifications": "Gdy dodawany jest nowy repack",
|
||||||
|
"telemetry": "Telemetria",
|
||||||
|
"telemetry_description": "Włącz anonimowe statystyki użycia"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"download_complete": "Pobieranie zakończone",
|
||||||
|
"game_ready_to_install": "{{title}} jest gotowe do zainstalowania",
|
||||||
|
"repack_list_updated": "Lista repacków zaktualizowana",
|
||||||
|
"repack_count_one": "{{count}} repack dodany",
|
||||||
|
"repack_count_other": "{{count}} repacki dodane"
|
||||||
|
},
|
||||||
|
"system_tray": {
|
||||||
|
"open": "Otwórz Hydra",
|
||||||
|
"quit": "Wyjdź"
|
||||||
|
},
|
||||||
|
"game_card": {
|
||||||
|
"no_downloads": "Brak dostępnych plików do pobrania"
|
||||||
|
},
|
||||||
|
"binary_not_found_modal": {
|
||||||
|
"title": "Programy nie są zainstalowane",
|
||||||
|
"description": "Pliki wykonywalne Wine lub Lutris nie zostały znalezione na twoim systemie",
|
||||||
|
"instructions": "Sprawdź prawidłowy sposób instalacji dowolnego z nich w swojej dystrybucji Linuksa, aby gra działała normalnie"
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ import "./library/open-game";
|
||||||
import "./library/open-game-installer";
|
import "./library/open-game-installer";
|
||||||
import "./library/remove-game";
|
import "./library/remove-game";
|
||||||
import "./library/remove-game-from-library";
|
import "./library/remove-game-from-library";
|
||||||
import "./misc/get-or-cache-image";
|
|
||||||
import "./misc/open-external";
|
import "./misc/open-external";
|
||||||
import "./misc/show-open-dialog";
|
import "./misc/show-open-dialog";
|
||||||
import "./torrenting/cancel-game-download";
|
import "./torrenting/cancel-game-download";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { gameRepository } from "@main/repository";
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
|
|
||||||
import type { GameShop } from "@types";
|
import type { GameShop } from "@types";
|
||||||
import { getImageBase64 } from "@main/helpers";
|
import { getFileBase64 } from "@main/helpers";
|
||||||
import { getSteamGameIconUrl } from "@main/services";
|
import { getSteamGameIconUrl } from "@main/services";
|
||||||
|
|
||||||
const addGameToLibrary = async (
|
const addGameToLibrary = async (
|
||||||
|
@ -11,7 +11,7 @@ const addGameToLibrary = async (
|
||||||
objectID: string,
|
objectID: string,
|
||||||
title: string,
|
title: string,
|
||||||
gameShop: GameShop,
|
gameShop: GameShop,
|
||||||
executablePath: string
|
executablePath: string | null
|
||||||
) => {
|
) => {
|
||||||
const game = await gameRepository.findOne({
|
const game = await gameRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
|
@ -31,7 +31,7 @@ const addGameToLibrary = async (
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
const iconUrl = await getFileBase64(await getSteamGameIconUrl(objectID));
|
||||||
|
|
||||||
return gameRepository.insert({
|
return gameRepository.insert({
|
||||||
title,
|
title,
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import crypto from "node:crypto";
|
|
||||||
import fs from "node:fs";
|
|
||||||
import path from "node:path";
|
|
||||||
|
|
||||||
import { registerEvent } from "../register-event";
|
|
||||||
import { getFileBuffer } from "@main/helpers";
|
|
||||||
import { logger } from "@main/services";
|
|
||||||
import { imageCachePath } from "@main/constants";
|
|
||||||
|
|
||||||
const getOrCacheImage = async (
|
|
||||||
_event: Electron.IpcMainInvokeEvent,
|
|
||||||
url: string
|
|
||||||
) => {
|
|
||||||
if (!fs.existsSync(imageCachePath)) fs.mkdirSync(imageCachePath);
|
|
||||||
|
|
||||||
const extname = path.extname(url);
|
|
||||||
|
|
||||||
const checksum = crypto.createHash("sha256").update(url).digest("hex");
|
|
||||||
const cachePath = path.join(imageCachePath, `${checksum}${extname}`);
|
|
||||||
|
|
||||||
const cache = fs.existsSync(cachePath);
|
|
||||||
|
|
||||||
if (cache) return `hydra://${cachePath}`;
|
|
||||||
|
|
||||||
getFileBuffer(url).then((buffer) =>
|
|
||||||
fs.writeFile(cachePath, buffer, (err) => {
|
|
||||||
if (err) {
|
|
||||||
logger.error(`Failed to cache image`, err, {
|
|
||||||
method: "getOrCacheImage",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return url;
|
|
||||||
};
|
|
||||||
|
|
||||||
registerEvent(getOrCacheImage, {
|
|
||||||
name: "getOrCacheImage",
|
|
||||||
});
|
|
|
@ -5,7 +5,11 @@ import { registerEvent } from "../register-event";
|
||||||
const showOpenDialog = async (
|
const showOpenDialog = async (
|
||||||
_event: Electron.IpcMainInvokeEvent,
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
options: Electron.OpenDialogOptions
|
options: Electron.OpenDialogOptions
|
||||||
) => dialog.showOpenDialog(WindowManager.mainWindow, options);
|
) => {
|
||||||
|
if (WindowManager.mainWindow) {
|
||||||
|
dialog.showOpenDialog(WindowManager.mainWindow, options);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
registerEvent(showOpenDialog, {
|
registerEvent(showOpenDialog, {
|
||||||
name: "showOpenDialog",
|
name: "showOpenDialog",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { gameRepository, repackRepository } from "@main/repository";
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
|
|
||||||
import type { GameShop } from "@types";
|
import type { GameShop } from "@types";
|
||||||
import { getImageBase64 } from "@main/helpers";
|
import { getFileBase64 } from "@main/helpers";
|
||||||
import { In } from "typeorm";
|
import { In } from "typeorm";
|
||||||
import { Downloader } from "@main/services/downloaders/downloader";
|
import { Downloader } from "@main/services/downloaders/downloader";
|
||||||
import { GameStatus } from "@globals";
|
import { GameStatus } from "@globals";
|
||||||
|
@ -68,7 +68,7 @@ const startGameDownload = async (
|
||||||
|
|
||||||
return game;
|
return game;
|
||||||
} else {
|
} else {
|
||||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
const iconUrl = await getFileBase64(await getSteamGameIconUrl(objectID));
|
||||||
|
|
||||||
const createdGame = await gameRepository.save({
|
const createdGame = await gameRepository.save({
|
||||||
title,
|
title,
|
||||||
|
|
|
@ -79,10 +79,24 @@ export const getFileBuffer = async (url: string) =>
|
||||||
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getImageBase64 = async (url: string) =>
|
export const getFileBase64 = async (url: string) =>
|
||||||
getFileBuffer(url).then((buffer) => {
|
fetch(url, { method: "GET" }).then((response) =>
|
||||||
return `data:image/jpeg;base64,${Buffer.from(buffer).toString("base64")}`;
|
response.arrayBuffer().then((buffer) => {
|
||||||
});
|
const base64 = Buffer.from(buffer).toString("base64");
|
||||||
|
const contentType = response.headers.get("content-type");
|
||||||
|
|
||||||
|
return `data:${contentType};base64,${base64}`;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export const steamUrlBuilder = {
|
||||||
|
library: (objectID: string) =>
|
||||||
|
`https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/header.jpg`,
|
||||||
|
libraryHero: (objectID: string) =>
|
||||||
|
`https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/library_hero.jpg`,
|
||||||
|
logo: (objectID: string) =>
|
||||||
|
`https://cdn.cloudflare.steamstatic.com/steam/apps/${objectID}/logo.png`,
|
||||||
|
};
|
||||||
|
|
||||||
export * from "./formatters";
|
export * from "./formatters";
|
||||||
export * from "./ps";
|
export * from "./ps";
|
||||||
|
|
|
@ -85,7 +85,7 @@ app.on("second-instance", (_event, commandLine) => {
|
||||||
WindowManager.createMainWindow();
|
WindowManager.createMainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, path] = commandLine.pop()!.split("://");
|
const [, path] = commandLine.pop()?.split("://") ?? [];
|
||||||
if (path) WindowManager.redirect(path);
|
if (path) WindowManager.redirect(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,8 @@ export const getSteam250List = async () => {
|
||||||
).flat();
|
).flat();
|
||||||
|
|
||||||
const gamesMap: Map<string, Steam250Game> = gamesList.reduce((map, item) => {
|
const gamesMap: Map<string, Steam250Game> = gamesList.reduce((map, item) => {
|
||||||
map.set(item.objectID, item);
|
if (item) map.set(item.objectID, item);
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}, new Map());
|
}, new Map());
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,15 @@ export class WindowManager {
|
||||||
this.loadURL();
|
this.loadURL();
|
||||||
this.mainWindow.removeMenu();
|
this.mainWindow.removeMenu();
|
||||||
|
|
||||||
const userPreferences = await userPreferencesRepository.findOne({
|
this.mainWindow.on("ready-to-show", () => {
|
||||||
where: { id: 1 },
|
if (!app.isPackaged) WindowManager.mainWindow?.webContents.openDevTools();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mainWindow.on("close", () => {
|
this.mainWindow.on("close", async () => {
|
||||||
|
const userPreferences = await userPreferencesRepository.findOne({
|
||||||
|
where: { id: 1 },
|
||||||
|
});
|
||||||
|
|
||||||
if (userPreferences?.preferQuitInsteadOfHiding) {
|
if (userPreferences?.preferQuitInsteadOfHiding) {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { parentPort } from "worker_threads";
|
import { parentPort } from "worker_threads";
|
||||||
import parseTorrent from "parse-torrent";
|
import parseTorrent from "parse-torrent";
|
||||||
import { getFileBuffer } from "@main/helpers";
|
|
||||||
|
|
||||||
const port = parentPort;
|
const port = parentPort;
|
||||||
if (!port) throw new Error("IllegalState");
|
if (!port) throw new Error("IllegalState");
|
||||||
|
|
||||||
|
export const getFileBuffer = async (url: string) =>
|
||||||
|
fetch(url, { method: "GET" }).then((response) =>
|
||||||
|
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
||||||
|
);
|
||||||
|
|
||||||
port.on("message", async (url: string) => {
|
port.on("message", async (url: string) => {
|
||||||
const buffer = await getFileBuffer(url);
|
const buffer = await getFileBuffer(url);
|
||||||
const torrent = await parseTorrent(buffer);
|
const torrent = await parseTorrent(buffer);
|
||||||
|
|
||||||
port.postMessage(torrent);
|
port.postMessage(torrent);
|
||||||
});
|
});
|
||||||
|
|
1
src/preload/index.d.ts
vendored
1
src/preload/index.d.ts
vendored
|
@ -94,7 +94,6 @@ contextBridge.exposeInMainWorld("electron", {
|
||||||
getDiskFreeSpace: () => ipcRenderer.invoke("getDiskFreeSpace"),
|
getDiskFreeSpace: () => ipcRenderer.invoke("getDiskFreeSpace"),
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url),
|
|
||||||
ping: () => ipcRenderer.invoke("ping"),
|
ping: () => ipcRenderer.invoke("ping"),
|
||||||
getVersion: () => ipcRenderer.invoke("getVersion"),
|
getVersion: () => ipcRenderer.invoke("getVersion"),
|
||||||
getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"),
|
getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"),
|
||||||
|
|
|
@ -104,7 +104,6 @@ contextBridge.exposeInMainWorld("electron", {
|
||||||
ipcRenderer.invoke("getDiskFreeSpace", path),
|
ipcRenderer.invoke("getDiskFreeSpace", path),
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url),
|
|
||||||
ping: () => ipcRenderer.invoke("ping"),
|
ping: () => ipcRenderer.invoke("ping"),
|
||||||
getVersion: () => ipcRenderer.invoke("getVersion"),
|
getVersion: () => ipcRenderer.invoke("getVersion"),
|
||||||
getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"),
|
getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"),
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<title>Hydra</title>
|
<title>Hydra</title>
|
||||||
<meta
|
<meta
|
||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: hydra: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com;"
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com;"
|
||||||
/>
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body style="background-color: #1c1c1c">
|
<body style="background-color: #1c1c1c">
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { forwardRef, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
export interface AsyncImageProps
|
|
||||||
extends React.DetailedHTMLProps<
|
|
||||||
React.ImgHTMLAttributes<HTMLImageElement>,
|
|
||||||
HTMLImageElement
|
|
||||||
> {
|
|
||||||
onSettled?: (url: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AsyncImage = forwardRef<HTMLImageElement, AsyncImageProps>(
|
|
||||||
({ onSettled, ...props }, ref) => {
|
|
||||||
const [source, setSource] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.src && props.src.startsWith("http")) {
|
|
||||||
window.electron.getOrCacheImage(props.src).then((url) => {
|
|
||||||
setSource(url);
|
|
||||||
|
|
||||||
if (onSettled) onSettled(url);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [props.src, onSettled]);
|
|
||||||
|
|
||||||
return <img ref={ref} {...props} src={source ?? props.src} />;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AsyncImage.displayName = "AsyncImage";
|
|
|
@ -4,8 +4,6 @@ import type { CatalogueEntry } from "@types";
|
||||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||||
import EpicGamesLogo from "@renderer/assets/epic-games-logo.svg?react";
|
import EpicGamesLogo from "@renderer/assets/epic-games-logo.svg?react";
|
||||||
|
|
||||||
import { AsyncImage } from "../async-image/async-image";
|
|
||||||
|
|
||||||
import * as styles from "./game-card.css";
|
import * as styles from "./game-card.css";
|
||||||
import { useAppSelector } from "@renderer/hooks";
|
import { useAppSelector } from "@renderer/hooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
@ -43,11 +41,7 @@ export function GameCard({ game, disabled, ...props }: GameCardProps) {
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<div className={styles.backdrop}>
|
<div className={styles.backdrop}>
|
||||||
<AsyncImage
|
<img src={game.cover} alt={game.title} className={styles.cover} />
|
||||||
src={game.cover}
|
|
||||||
alt={game.title}
|
|
||||||
className={styles.cover}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div className={styles.titleContainer}>
|
<div className={styles.titleContainer}>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { AsyncImage } from "@renderer/components";
|
|
||||||
import * as styles from "./hero.css";
|
import * as styles from "./hero.css";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { ShopDetails } from "@types";
|
import { ShopDetails } from "@types";
|
||||||
|
@ -35,14 +34,14 @@ export function Hero() {
|
||||||
className={styles.hero}
|
className={styles.hero}
|
||||||
>
|
>
|
||||||
<div className={styles.backdrop}>
|
<div className={styles.backdrop}>
|
||||||
<AsyncImage
|
<img
|
||||||
src="https://cdn2.steamgriddb.com/hero/4ef10445b952a8b3c93a9379d581146a.jpg"
|
src="https://cdn2.steamgriddb.com/hero/4ef10445b952a8b3c93a9379d581146a.jpg"
|
||||||
alt={featuredGameDetails?.name}
|
alt={featuredGameDetails?.name}
|
||||||
className={styles.heroMedia}
|
className={styles.heroMedia}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<AsyncImage
|
<img
|
||||||
src={steamUrlBuilder.logo(FEATURED_GAME_ID)}
|
src={steamUrlBuilder.logo(FEATURED_GAME_ID)}
|
||||||
width="250px"
|
width="250px"
|
||||||
alt={featuredGameDetails?.name}
|
alt={featuredGameDetails?.name}
|
||||||
|
|
|
@ -5,6 +5,5 @@ export * from "./header/header";
|
||||||
export * from "./hero/hero";
|
export * from "./hero/hero";
|
||||||
export * from "./modal/modal";
|
export * from "./modal/modal";
|
||||||
export * from "./sidebar/sidebar";
|
export * from "./sidebar/sidebar";
|
||||||
export * from "./async-image/async-image";
|
|
||||||
export * from "./text-field/text-field";
|
export * from "./text-field/text-field";
|
||||||
export * from "./checkbox-field/checkbox-field";
|
export * from "./checkbox-field/checkbox-field";
|
||||||
|
|
|
@ -74,7 +74,6 @@ export const menuItem = recipe({
|
||||||
active: {
|
active: {
|
||||||
true: {
|
true: {
|
||||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||||
fontWeight: "bold",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
muted: {
|
muted: {
|
||||||
|
@ -97,11 +96,6 @@ export const menuItemButton = style({
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
padding: `9px ${SPACING_UNIT}px`,
|
padding: `9px ${SPACING_UNIT}px`,
|
||||||
selectors: {
|
|
||||||
[`${menuItem({ active: true }).split(" ")[1]} &`]: {
|
|
||||||
fontWeight: "bold",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const menuItemButtonLabel = style({
|
export const menuItemButtonLabel = style({
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import type { Game } from "@types";
|
import type { Game } from "@types";
|
||||||
|
|
||||||
import { AsyncImage, TextField } from "@renderer/components";
|
import { TextField } from "@renderer/components";
|
||||||
import { useDownload, useLibrary } from "@renderer/hooks";
|
import { useDownload, useLibrary } from "@renderer/hooks";
|
||||||
|
|
||||||
import { routes } from "./routes";
|
import { routes } from "./routes";
|
||||||
|
@ -214,7 +214,11 @@ export function Sidebar() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<AsyncImage className={styles.gameIcon} src={game.iconUrl} />
|
<img
|
||||||
|
className={styles.gameIcon}
|
||||||
|
src={game.iconUrl}
|
||||||
|
alt={game.title}
|
||||||
|
/>
|
||||||
<span className={styles.menuItemButtonLabel}>
|
<span className={styles.menuItemButtonLabel}>
|
||||||
{getGameTitle(game)}
|
{getGameTitle(game)}
|
||||||
</span>
|
</span>
|
||||||
|
|
3
src/renderer/src/declaration.d.ts
vendored
3
src/renderer/src/declaration.d.ts
vendored
|
@ -56,7 +56,7 @@ declare global {
|
||||||
objectID: string,
|
objectID: string,
|
||||||
title: string,
|
title: string,
|
||||||
shop: GameShop,
|
shop: GameShop,
|
||||||
executablePath: string
|
executablePath: string | null
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getLibrary: () => Promise<Game[]>;
|
getLibrary: () => Promise<Game[]>;
|
||||||
getRepackersFriendlyNames: () => Promise<Record<string, string>>;
|
getRepackersFriendlyNames: () => Promise<Record<string, string>>;
|
||||||
|
@ -79,7 +79,6 @@ declare global {
|
||||||
getDiskFreeSpace: (path: string) => Promise<DiskSpace>;
|
getDiskFreeSpace: (path: string) => Promise<DiskSpace>;
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
getOrCacheImage: (url: string) => Promise<string>;
|
|
||||||
openExternal: (src: string) => Promise<void>;
|
openExternal: (src: string) => Promise<void>;
|
||||||
getVersion: () => Promise<string>;
|
getVersion: () => Promise<string>;
|
||||||
ping: () => string;
|
ping: () => string;
|
||||||
|
|
|
@ -24,5 +24,7 @@ export const getSteamLanguage = (language: string) => {
|
||||||
if (language.startsWith("ru")) return "russian";
|
if (language.startsWith("ru")) return "russian";
|
||||||
if (language.startsWith("it")) return "italian";
|
if (language.startsWith("it")) return "italian";
|
||||||
if (language.startsWith("hu")) return "hungarian";
|
if (language.startsWith("hu")) return "hungarian";
|
||||||
|
if (language.startsWith("pl")) return "polish";
|
||||||
|
|
||||||
return "english";
|
return "english";
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import { AsyncImage, Button, TextField } from "@renderer/components";
|
import { Button, TextField } from "@renderer/components";
|
||||||
import { formatDownloadProgress, steamUrlBuilder } from "@renderer/helpers";
|
import { formatDownloadProgress, steamUrlBuilder } from "@renderer/helpers";
|
||||||
import { useDownload, useLibrary } from "@renderer/hooks";
|
import { useDownload, useLibrary } from "@renderer/hooks";
|
||||||
import type { Game } from "@types";
|
import type { Game } from "@types";
|
||||||
|
@ -116,6 +116,8 @@ export function Downloads() {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDeleteModal = (gameId: number) => {
|
const openDeleteModal = (gameId: number) => {
|
||||||
|
@ -211,6 +213,12 @@ export function Downloads() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteGame = () => {
|
||||||
|
if (gameToBeDeleted.current) {
|
||||||
|
deleteGame(gameToBeDeleted.current).then(updateLibrary);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.downloadsContainer}>
|
<section className={styles.downloadsContainer}>
|
||||||
<BinaryNotFoundModal
|
<BinaryNotFoundModal
|
||||||
|
@ -220,9 +228,7 @@ export function Downloads() {
|
||||||
<DeleteModal
|
<DeleteModal
|
||||||
visible={showDeleteModal}
|
visible={showDeleteModal}
|
||||||
onClose={() => setShowDeleteModal(false)}
|
onClose={() => setShowDeleteModal(false)}
|
||||||
deleteGame={() =>
|
deleteGame={handleDeleteGame}
|
||||||
deleteGame(gameToBeDeleted.current).then(updateLibrary)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField placeholder={t("filter")} onChange={handleFilter} />
|
<TextField placeholder={t("filter")} onChange={handleFilter} />
|
||||||
|
@ -236,7 +242,7 @@ export function Downloads() {
|
||||||
cancelled: game.status === GameStatus.Cancelled,
|
cancelled: game.status === GameStatus.Cancelled,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AsyncImage
|
<img
|
||||||
src={steamUrlBuilder.library(game.objectID)}
|
src={steamUrlBuilder.library(game.objectID)}
|
||||||
className={styles.downloadCover}
|
className={styles.downloadCover}
|
||||||
alt={game.title}
|
alt={game.title}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import type {
|
||||||
SteamAppDetails,
|
SteamAppDetails,
|
||||||
} from "@types";
|
} from "@types";
|
||||||
|
|
||||||
import { AsyncImage, Button } from "@renderer/components";
|
import { Button } from "@renderer/components";
|
||||||
import { setHeaderTitle } from "@renderer/features";
|
import { setHeaderTitle } from "@renderer/features";
|
||||||
import { getSteamLanguage, steamUrlBuilder } from "@renderer/helpers";
|
import { getSteamLanguage, steamUrlBuilder } from "@renderer/helpers";
|
||||||
import { useAppDispatch, useDownload } from "@renderer/hooks";
|
import { useAppDispatch, useDownload } from "@renderer/hooks";
|
||||||
|
@ -69,14 +69,16 @@ export function GameDetails() {
|
||||||
|
|
||||||
const { game: gameDownloading, startDownload, isDownloading } = useDownload();
|
const { game: gameDownloading, startDownload, isDownloading } = useDownload();
|
||||||
|
|
||||||
const handleImageSettled = useCallback((url: string) => {
|
const heroImage = steamUrlBuilder.libraryHero(objectID!);
|
||||||
average(url, { amount: 1, format: "hex" })
|
|
||||||
|
const handleHeroLoad = () => {
|
||||||
|
average(heroImage, { amount: 1, format: "hex" })
|
||||||
.then((color) => {
|
.then((color) => {
|
||||||
const darkColor = new Color(color).darken(0.6).toString() as string;
|
const darkColor = new Color(color).darken(0.6).toString() as string;
|
||||||
setColor({ light: color as string, dark: darkColor });
|
setColor({ light: color as string, dark: darkColor });
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
const getGame = useCallback(() => {
|
const getGame = useCallback(() => {
|
||||||
window.electron
|
window.electron
|
||||||
|
@ -218,15 +220,15 @@ export function GameDetails() {
|
||||||
) : (
|
) : (
|
||||||
<section className={styles.container}>
|
<section className={styles.container}>
|
||||||
<div className={styles.hero}>
|
<div className={styles.hero}>
|
||||||
<AsyncImage
|
<img
|
||||||
src={steamUrlBuilder.libraryHero(objectID!)}
|
src={heroImage}
|
||||||
className={styles.heroImage}
|
className={styles.heroImage}
|
||||||
alt={game?.title}
|
alt={game?.title}
|
||||||
onSettled={handleImageSettled}
|
onLoad={handleHeroLoad}
|
||||||
/>
|
/>
|
||||||
<div className={styles.heroBackdrop}>
|
<div className={styles.heroBackdrop}>
|
||||||
<div className={styles.heroContent}>
|
<div className={styles.heroContent}>
|
||||||
<AsyncImage
|
<img
|
||||||
src={steamUrlBuilder.logo(objectID!)}
|
src={steamUrlBuilder.logo(objectID!)}
|
||||||
style={{ width: 300, alignSelf: "flex-end" }}
|
style={{ width: 300, alignSelf: "flex-end" }}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -69,7 +69,7 @@ export function HeroPanelActions({
|
||||||
try {
|
try {
|
||||||
if (game) {
|
if (game) {
|
||||||
await removeGameFromLibrary(game.id);
|
await removeGameFromLibrary(game.id);
|
||||||
} else {
|
} else if (gameDetails) {
|
||||||
const gameExecutablePath = await selectGameExecutable();
|
const gameExecutablePath = await selectGameExecutable();
|
||||||
|
|
||||||
await window.electron.addGameToLibrary(
|
await window.electron.addGameToLibrary(
|
||||||
|
@ -88,30 +88,37 @@ export function HeroPanelActions({
|
||||||
};
|
};
|
||||||
|
|
||||||
const openGameInstaller = () => {
|
const openGameInstaller = () => {
|
||||||
window.electron.openGameInstaller(game.id).then((isBinaryInPath) => {
|
if (game) {
|
||||||
if (!isBinaryInPath) openBinaryNotFoundModal();
|
window.electron.openGameInstaller(game.id).then((isBinaryInPath) => {
|
||||||
updateLibrary();
|
if (!isBinaryInPath) openBinaryNotFoundModal();
|
||||||
});
|
updateLibrary();
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const openGame = async () => {
|
const openGame = async () => {
|
||||||
if (game.executablePath) {
|
if (game) {
|
||||||
window.electron.openGame(game.id, game.executablePath);
|
if (game.executablePath) {
|
||||||
return;
|
window.electron.openGame(game.id, game.executablePath);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (game?.executablePath) {
|
if (game?.executablePath) {
|
||||||
window.electron.openGame(game.id, game.executablePath);
|
window.electron.openGame(game.id, game.executablePath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gameExecutablePath = await selectGameExecutable();
|
const gameExecutablePath = await selectGameExecutable();
|
||||||
window.electron.openGame(game.id, gameExecutablePath);
|
if (gameExecutablePath)
|
||||||
|
window.electron.openGame(game.id, gameExecutablePath);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeGame = () => window.electron.closeGame(game.id);
|
const closeGame = () => {
|
||||||
|
if (game) window.electron.closeGame(game.id);
|
||||||
|
};
|
||||||
|
|
||||||
const deleting = isGameDeleting(game?.id);
|
const deleting = game ? isGameDeleting(game?.id) : false;
|
||||||
|
|
||||||
const toggleGameOnLibraryButton = (
|
const toggleGameOnLibraryButton = (
|
||||||
<Button
|
<Button
|
||||||
|
@ -125,7 +132,7 @@ export function HeroPanelActions({
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isGameDownloading) {
|
if (game && isGameDownloading) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -99,7 +99,7 @@ export function HeroPanel({
|
||||||
return <p>{t("deleting")}</p>;
|
return <p>{t("deleting")}</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGameDownloading) {
|
if (isGameDownloading && gameDownloading?.status) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p className={styles.downloadDetailsRow}>
|
<p className={styles.downloadDetailsRow}>
|
||||||
|
@ -107,14 +107,14 @@ export function HeroPanel({
|
||||||
{eta && <small>{t("eta", { eta })}</small>}
|
{eta && <small>{t("eta", { eta })}</small>}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{gameDownloading?.status !== GameStatus.Downloading ? (
|
{gameDownloading.status !== GameStatus.Downloading ? (
|
||||||
<>
|
<>
|
||||||
<p>{t(gameDownloading?.status)}</p>
|
<p>{t(gameDownloading.status)}</p>
|
||||||
{eta && <small>{t("eta", { eta })}</small>}
|
{eta && <small>{t("eta", { eta })}</small>}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p className={styles.downloadDetailsRow}>
|
<p className={styles.downloadDetailsRow}>
|
||||||
{formatBytes(gameDownloading?.bytesDownloaded)} /{" "}
|
{formatBytes(gameDownloading.bytesDownloaded)} /{" "}
|
||||||
{finalDownloadSize}
|
{finalDownloadSize}
|
||||||
<small>
|
<small>
|
||||||
{numPeers} peers / {numSeeds} seeds
|
{numPeers} peers / {numSeeds} seeds
|
||||||
|
@ -149,7 +149,7 @@ export function HeroPanel({
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
{t("play_time", {
|
{t("play_time", {
|
||||||
amount: formatPlayTime(game.playTimeInMilliseconds),
|
amount: formatPlayTime(),
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,9 @@ export function RepacksModal({
|
||||||
<p style={{ color: "#DADBE1" }}>{repack.title}</p>
|
<p style={{ color: "#DADBE1" }}>{repack.title}</p>
|
||||||
<p style={{ fontSize: "12px" }}>
|
<p style={{ fontSize: "12px" }}>
|
||||||
{repack.fileSize} - {repackersFriendlyNames[repack.repacker]} -{" "}
|
{repack.fileSize} - {repackersFriendlyNames[repack.repacker]} -{" "}
|
||||||
{format(repack.uploadDate, "dd/MM/yyyy")}
|
{repack.uploadDate
|
||||||
|
? format(repack.uploadDate, "dd/MM/yyyy")
|
||||||
|
: ""}
|
||||||
</p>
|
</p>
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue