mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 22:06:17 +00:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83c32de0c2 | ||
|
|
00ba2e01d1 | ||
|
|
274377f119 | ||
|
|
48cebe729e | ||
|
|
19e26cba28 | ||
|
|
cdb876fa72 | ||
|
|
2099d72840 | ||
|
|
8924f25d7c | ||
|
|
7c9e15e75c | ||
|
|
5031ee47ca | ||
|
|
bffe74f0c7 | ||
|
|
bf97d744e2 | ||
|
|
d4bebd18e8 | ||
|
|
b3480eb70b | ||
|
|
e3da07141c | ||
|
|
7280429162 | ||
|
|
0b0d2d6b10 | ||
|
|
551b0b3c91 | ||
|
|
d20d3d0b77 | ||
|
|
a5dc101e6b | ||
|
|
8957b1b1dd | ||
|
|
42626efd05 | ||
|
|
69828e6926 | ||
|
|
9c28a6e9d0 | ||
|
|
a817a26be1 | ||
|
|
0b33cb339c | ||
|
|
41908433c5 | ||
|
|
5667c813d9 | ||
|
|
39ceb38ecd | ||
|
|
06f58291f7 | ||
|
|
07cfbab77f | ||
|
|
3670c4f0ff | ||
|
|
485d396b91 | ||
|
|
5aa6c72594 | ||
|
|
6fdb591784 | ||
|
|
ae6edaa058 | ||
|
|
3062b88f4a | ||
|
|
f90dd82cbd | ||
|
|
a8f072dd1b | ||
|
|
05a1cf9343 | ||
|
|
399d47ca9d | ||
|
|
317fe48927 | ||
|
|
20bf7009e5 | ||
|
|
a01a105afa | ||
|
|
33c6203f29 | ||
|
|
b9f5baef34 | ||
|
|
811878e364 | ||
|
|
3b17953a82 | ||
|
|
484e79dba3 | ||
|
|
7eee942dcb | ||
|
|
a89e6760da | ||
|
|
e2257d7ca5 | ||
|
|
be13ecc5aa | ||
|
|
5b864367e8 | ||
|
|
0ccaed8d55 | ||
|
|
0491124a7d | ||
|
|
ac4956c25b | ||
|
|
c7920fe9f7 | ||
|
|
f31ae47ab2 | ||
|
|
3f305eaca0 | ||
|
|
9290d94e2a | ||
|
|
756cf19c23 | ||
|
|
7a13ecd2b7 | ||
|
|
19f022e0f6 | ||
|
|
026729e8c9 | ||
|
|
7f918aaaca | ||
|
|
d98a01df2f | ||
|
|
2cb76a9ad4 | ||
|
|
250c6901b7 | ||
|
|
e5fec91062 | ||
|
|
6fd38df79e | ||
|
|
d924c64710 | ||
|
|
10943408e9 | ||
|
|
d8937b3672 | ||
|
|
38d652c507 | ||
|
|
539f444ab5 | ||
|
|
7a2b693397 | ||
|
|
04a5dbb71d | ||
|
|
7bdf7f8c2d | ||
|
|
95e802372f | ||
|
|
9c261551c3 | ||
|
|
4e9e9deec1 | ||
|
|
1c56227fa3 | ||
|
|
81ea790d73 | ||
|
|
0d089bb5c4 | ||
|
|
82edc6d438 | ||
|
|
26db88966f | ||
|
|
f2af65d4cd | ||
|
|
e6b62399f7 | ||
|
|
713392ee29 | ||
|
|
c7da83cae1 | ||
|
|
f9343ca0c2 | ||
|
|
6053b7cd67 | ||
|
|
0333282915 | ||
|
|
23ab98294a | ||
|
|
27bff9d2e6 | ||
|
|
6b9f902b2c | ||
|
|
4616f69a29 | ||
|
|
02417dda40 | ||
|
|
5f468d5b2e | ||
|
|
0aa36c5a57 | ||
|
|
2f0cd24fb8 | ||
|
|
dce700b189 | ||
|
|
e55d41889d | ||
|
|
8f6922fc8a | ||
|
|
ff6a204686 | ||
|
|
92f35bad9f | ||
|
|
b84df28f39 | ||
|
|
09bd7dcc36 | ||
|
|
06ed5e07bf | ||
|
|
ada218cea1 | ||
|
|
2662ba3875 | ||
|
|
58693fdb00 | ||
|
|
1872ff1d24 | ||
|
|
08c4906465 | ||
|
|
a0344ea491 | ||
|
|
02c4f0a0e6 |
26
.github/workflows/build.yml
vendored
26
.github/workflows/build.yml
vendored
@@ -1,8 +1,6 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -39,7 +37,6 @@ jobs:
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: yarn build:linux
|
||||
env:
|
||||
MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }}
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -48,7 +45,6 @@ jobs:
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: yarn build:win
|
||||
env:
|
||||
MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }}
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -58,7 +54,7 @@ jobs:
|
||||
with:
|
||||
name: Build-${{ matrix.os }}
|
||||
path: |
|
||||
dist/*.exe
|
||||
dist/win-unpacked/**
|
||||
dist/*.zip
|
||||
dist/*.dmg
|
||||
dist/*.deb
|
||||
@@ -66,21 +62,3 @@ jobs:
|
||||
dist/*.tar.gz
|
||||
dist/*.yml
|
||||
dist/*.blockmap
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
dist/*.exe
|
||||
dist/*.zip
|
||||
dist/*.dmg
|
||||
dist/*.AppImage
|
||||
dist/*.snap
|
||||
dist/*.deb
|
||||
dist/*.rpm
|
||||
dist/*.tar.gz
|
||||
dist/*.yml
|
||||
dist/*.blockmap
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
70
.github/workflows/release.yml
vendored
Normal file
70
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.11.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
- name: Build with cx_Freeze
|
||||
run: python torrent-client/setup.py build
|
||||
|
||||
- name: Build Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: yarn build:linux
|
||||
env:
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: yarn build:win
|
||||
env:
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
dist/*.exe
|
||||
dist/*.zip
|
||||
dist/*.dmg
|
||||
dist/*.AppImage
|
||||
dist/*.snap
|
||||
dist/*.deb
|
||||
dist/*.rpm
|
||||
dist/*.tar.gz
|
||||
dist/*.yml
|
||||
dist/*.blockmap
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,2 +1 @@
|
||||
yarn lint
|
||||
yarn typecheck
|
||||
yarn format
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
yarn format
|
||||
yarn lint
|
||||
yarn typecheck
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
out
|
||||
dist
|
||||
seeds
|
||||
pnpm-lock.yaml
|
||||
LICENSE.md
|
||||
tsconfig.json
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
182
README.es.md
Normal file
182
README.es.md
Normal file
@@ -0,0 +1,182 @@
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra es un launcher de juegos con su propio cliente de bittorrent y gestor propio de repacks.</strong>
|
||||
</p>
|
||||
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.be.md)
|
||||
[](README.pl.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.es.md)
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Tabla de Contenidos
|
||||
|
||||
- [Acerca de](#acerca-de)
|
||||
- [Características](#caracteristicas)
|
||||
- [Instalación](#Instalacion)
|
||||
- [Contribuir](#contribuir)
|
||||
- [Únete a nuestro Telegram](#unete-a-nuestro-telegram)
|
||||
- [Haz un fork y clona tu repositorio](#haz-un-fork-y-clona-tu-repositorio)
|
||||
- [Maneras en las que puedes contribuir](#maneras-en-las-que-puedes-contribuir)
|
||||
- [Estructura del proyecto](#estructura-del-proyecto)
|
||||
- [Compilar desde el código fuente](#compilar-desde-el-código-fuente)
|
||||
- [Instalar Node.js](#instalar-nodejs)
|
||||
- [Instalar Yarn](#instalar-yarn)
|
||||
- [Instalar Dependencias de Node](#instalar-dependencias-de-node)
|
||||
- [Instalar Python 3.9](#instalar-python-39)
|
||||
- [Instalar Dependencias de Python](#Instalar-dependencias-de-python)
|
||||
- [Variables del Entorno](#variables-del-entorno)
|
||||
- [Ejecución](#ejecucion)
|
||||
- [Compilación](#compilacion)
|
||||
- [Compilar el cliente de bittorrent](#compilar-el-cliente-de-bittorrent)
|
||||
- [Compilar la aplicación Electron](#compilar-la-aplicacion-electron)
|
||||
- [Colaboradores](#colaboradores)
|
||||
|
||||
## Acerca de
|
||||
|
||||
**Hydra** es un **Launcher de Juegos** con su propio **Cliente Bittorrent** y **autogestor de Repacks**.
|
||||
<br>
|
||||
El launcher está escrito en TypeScript (Electron) y Python, el cuál se encarga del sistema de torrent usando libtorrent.
|
||||
|
||||
## Caracteristicas
|
||||
|
||||
- Buscador e instalador autogestionado de repacks a través de las páginas más confiables en él [Megahilo](https://www.reddit.com/r/Piracy/wiki/megathread/)
|
||||
- Cliente propio de bittorrent integrado
|
||||
- Integración de How Long To Beat (HLTB) en la página del juego
|
||||
- Customización de rutas de descargas
|
||||
- Notificaciones en actualizaciones a listas de repacks
|
||||
- Soporte a Windows y Linux
|
||||
- En constante actualización
|
||||
- Y mucho más ...
|
||||
|
||||
## Instalacion
|
||||
|
||||
Sigue los pasos de abajo para instalar:
|
||||
|
||||
1. Descarga la última versión de Hydra desde la página de [Releases](https://github.com/hydralauncher/hydra/releases/latest).
|
||||
- Descarga solo el .exe si quieres instalar Hydra en Windows.
|
||||
- Descarga el .deb o .rpm o .zip si quieres instalar Hydra en Linux. (Depende de tu distro de Linux)
|
||||
2. Ejecuta el archivo descargado.
|
||||
3. ¡Disfruta de Hydra!
|
||||
|
||||
## <a name="contribuir"> Contribuir
|
||||
|
||||
### <a name="unete-a-nuestro-telegram"></a> Unete a nuestro Telegram
|
||||
|
||||
Puedes unirte a nuestra conversación y discusiones en nuestro canal de [Telegram](https://t.me/hydralauncher).
|
||||
|
||||
### Haz un fork y clona tu repositorio
|
||||
|
||||
1. Rea;iza un fork del repositorio [(Haz click acá para hacer un fork ahora)](https://github.com/hydralauncher/hydra/fork)
|
||||
2. Clona el código forkeado `git clone https://github.com/tu_nombredeusuario/hydra`
|
||||
3. Crea una nueva rama
|
||||
4. Sube tus commits
|
||||
5. Envía nuevas solicitudes de pull
|
||||
|
||||
### Maneras en las que puedes contribuir
|
||||
|
||||
- Traducción: Queremos que Hydra esté disponible para todas las personas que sean posible. Siéntete libre de ayudarnos a traducirlo a nuevos lenguajes o actualizar y mejorar las ya disponibles en Hydra.
|
||||
- Código: Hydra está hecho con Typescript, Electron y un poquito de Python. Si quieres contribuir, ¡únete a nuestro [Telegram](https://t.me/hydralauncher)!
|
||||
|
||||
### Estructura del proyecto
|
||||
|
||||
- torrent-client: Usamos libtorrent, una librería de Python que se encarga de manejar las descargas torrent
|
||||
- src/renderer: El UI de la aplicación
|
||||
- src/main: El resto de la lógica va acá.
|
||||
|
||||
## Compilar desde el código fuente
|
||||
|
||||
### Instalar Node.js
|
||||
|
||||
Asegúrate que tienes Node.js instalado en tú máquina. Si no es así, puedes descargarlo e instalarlo desde [nodejs.org](https://nodejs.org/).
|
||||
|
||||
### Instalar Yarn
|
||||
|
||||
Yarn es un gestor de paquetes para Node.js. Si no tienes aún instalado Yarn todavía, puedes hacerlo siguiendo las instrucciones en [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
|
||||
|
||||
### Instalar Dependencias de Node
|
||||
|
||||
Dirígete hasta el directorio del proyecto e instala las dependencias de Node usando Yarn:
|
||||
|
||||
```bash
|
||||
cd hydra
|
||||
yarn
|
||||
```
|
||||
|
||||
### Instalar Python 3.9
|
||||
|
||||
Asegúrate que tienes Python 3.9 instalado en tu máquina. Puedes descargarlo e instalarlo desde [python.org](https://www.python.org/downloads/release/python-3913/).
|
||||
|
||||
### Instalar Dependencias de Python
|
||||
|
||||
Instala las dependencias de Python requeridas usando pip:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Variables del Entorno
|
||||
|
||||
Necesitas una llave API de SteamGridDB para así poder obtener los íconos de los juegos en la instalación.
|
||||
Si quieres también tener los repacks de onlinefix, necesitarás añadir tus credenciales al .env
|
||||
|
||||
Una vez que los tengas, puedes copiar o renombrar el archivo `.env.example` cómo `.env` y colocarlo en `STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
|
||||
|
||||
## Ejecucion
|
||||
|
||||
Una vez que tengas todas las cosas listas, puedes ejecutar el siguiente comando para así iniciar el proceso de Electron y el cliente de bittorrent:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Compilacion
|
||||
|
||||
### Compilar el cliente de bittorrent
|
||||
|
||||
Crea el cliente bittorrent usando este comando:
|
||||
|
||||
```bash
|
||||
python torrent-client/setup.py build
|
||||
```
|
||||
|
||||
### Compilar la aplicacion Electron
|
||||
|
||||
Crea la aplicación de Electron usando este comando:
|
||||
|
||||
En Windows:
|
||||
|
||||
```bash
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
En Linux:
|
||||
|
||||
```bash
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## Colaboradores
|
||||
|
||||
<a href="https://github.com/hydralauncher/hydra/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hydralauncher/hydra" />
|
||||
</a>
|
||||
|
||||
## Licencia
|
||||
|
||||
Hydra está licenciado bajo la [MIT License](LICENSE).
|
||||
@@ -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
|
||||
|
||||
|
||||
185
README.pl.md
Normal file
185
README.pl.md
Normal file
@@ -0,0 +1,185 @@
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra - to program uruchamiający gry z własnym wbudowanym klientem bittorrent i samodzielnie zarządzanym repackagerem..</strong>
|
||||
</p>
|
||||
|
||||
[](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)
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## 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**.
|
||||
<br>
|
||||
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ą!
|
||||
|
||||
## <a name="contributing"> Dokonaj wpłaty
|
||||
|
||||
### <a name="join-our-telegram"></a> 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
|
||||
|
||||
<a href="https://github.com/hydralauncher/hydra/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hydralauncher/hydra" />
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
Hydra posiada licencję [MIT License](LICENSE).
|
||||
@@ -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)
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
@@ -119,7 +118,7 @@ yarn
|
||||
|
||||
### <a name="install-python-39"></a> 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/).
|
||||
|
||||
### <a name="install-python-dependencies"></a> Instale Python Dependencies
|
||||
|
||||
|
||||
10
README.ru.md
10
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
|
||||
|
||||
|
||||
@@ -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 залежності
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ extraResources:
|
||||
- hydra-download-manager
|
||||
- hydra.db
|
||||
- fastlist.exe
|
||||
- seeds
|
||||
files:
|
||||
- "!**/.vscode/*"
|
||||
- "!src/*"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydra",
|
||||
"version": "1.2.2",
|
||||
"name": "hydralauncher",
|
||||
"version": "1.2.4",
|
||||
"description": "Hydra",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "Los Broxas",
|
||||
|
||||
1
seeds/steam-games.json
Normal file
1
seeds/steam-games.json
Normal file
File diff suppressed because one or more lines are too long
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,5 +176,11 @@
|
||||
},
|
||||
"modal": {
|
||||
"close": "Botón de cierre"
|
||||
},
|
||||
"splash": {
|
||||
"downloading_version": "Descargando versión {{version}}",
|
||||
"searching_updates": "Buscando actualizaciones",
|
||||
"update_found": "Actualización {{version}} encontrada",
|
||||
"restarting_and_applying": "Reiniciando y aplicando actualización"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,14 @@ export const repackers = [
|
||||
"onlinefix",
|
||||
] as const;
|
||||
|
||||
export const months = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
|
||||
export const defaultDownloadsPath = app.getPath("downloads");
|
||||
|
||||
export const databasePath = path.join(
|
||||
app.getPath("appData"),
|
||||
app.getName(),
|
||||
"hydra",
|
||||
"hydra.db"
|
||||
);
|
||||
|
||||
export const INSTALLATION_ID_LENGTH = 6;
|
||||
export const ACTIVATION_KEY_MULTIPLIER = 7;
|
||||
export const seedsPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "seeds")
|
||||
: path.join(__dirname, "..", "..", "seeds");
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import { DataSource } from "typeorm";
|
||||
import {
|
||||
Game,
|
||||
GameShopCache,
|
||||
Repack,
|
||||
UserPreferences,
|
||||
SteamGame,
|
||||
} from "@main/entity";
|
||||
import type { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
|
||||
import { Game, GameShopCache, Repack, UserPreferences } from "@main/entity";
|
||||
import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";
|
||||
|
||||
import { databasePath } from "./constants";
|
||||
import migrations from "./migrations";
|
||||
|
||||
export const createDataSource = (options: Partial<SqliteConnectionOptions>) =>
|
||||
export const createDataSource = (
|
||||
options: Partial<BetterSqlite3ConnectionOptions>
|
||||
) =>
|
||||
new DataSource({
|
||||
type: "better-sqlite3",
|
||||
database: databasePath,
|
||||
entities: [Game, Repack, UserPreferences, GameShopCache, SteamGame],
|
||||
entities: [Game, Repack, UserPreferences, GameShopCache],
|
||||
synchronize: true,
|
||||
database: databasePath,
|
||||
...options,
|
||||
});
|
||||
|
||||
export const dataSource = createDataSource({
|
||||
migrations: migrations,
|
||||
migrations,
|
||||
});
|
||||
|
||||
@@ -23,8 +23,8 @@ export class Game {
|
||||
@Column("text")
|
||||
title: string;
|
||||
|
||||
@Column("text")
|
||||
iconUrl: string;
|
||||
@Column("text", { nullable: true })
|
||||
iconUrl: string | null;
|
||||
|
||||
@Column("text", { nullable: true })
|
||||
folderName: string | null;
|
||||
|
||||
@@ -2,4 +2,3 @@ export * from "./game.entity";
|
||||
export * from "./repack.entity";
|
||||
export * from "./user-preferences.entity";
|
||||
export * from "./game-shop-cache.entity";
|
||||
export * from "./steam-game.entity";
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Column, Entity, PrimaryColumn } from "typeorm";
|
||||
|
||||
@Entity("steam_game")
|
||||
export class SteamGame {
|
||||
@PrimaryColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
}
|
||||
48
src/main/events/autoupdater/check-for-updates.ts
Normal file
48
src/main/events/autoupdater/check-for-updates.ts
Normal file
@@ -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);
|
||||
12
src/main/events/autoupdater/continue-to-main-window.ts
Normal file
12
src/main/events/autoupdater/continue-to-main-window.ts
Normal file
@@ -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);
|
||||
17
src/main/events/autoupdater/restart-and-install-update.ts
Normal file
17
src/main/events/autoupdater/restart-and-install-update.ts
Normal file
@@ -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);
|
||||
@@ -1,9 +1,10 @@
|
||||
import { gameShopCacheRepository, steamGameRepository } from "@main/repository";
|
||||
import { gameShopCacheRepository } from "@main/repository";
|
||||
import { getSteamAppDetails } from "@main/services";
|
||||
|
||||
import type { ShopDetails, GameShop, SteamAppDetails } from "@types";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
const getLocalizedSteamAppDetails = (
|
||||
objectID: string,
|
||||
@@ -13,10 +14,11 @@ const getLocalizedSteamAppDetails = (
|
||||
return getSteamAppDetails(objectID, language);
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
steamGameRepository.findOne({ where: { id: Number(objectID) } }),
|
||||
getSteamAppDetails(objectID, language),
|
||||
]).then(([steamGame, localizedAppDetails]) => {
|
||||
return getSteamAppDetails(objectID, language).then((localizedAppDetails) => {
|
||||
const steamGame = stateManager
|
||||
.getValue("steamGames")
|
||||
.find((game) => game.id === Number(objectID));
|
||||
|
||||
if (steamGame && localizedAppDetails) {
|
||||
return {
|
||||
...localizedAppDetails,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -3,8 +3,8 @@ import { gameRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import { getFileBase64 } from "@main/helpers";
|
||||
import { getSteamGameIconUrl } from "@main/services";
|
||||
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
const addGameToLibrary = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -27,17 +27,29 @@ const addGameToLibrary = async (
|
||||
)
|
||||
.then(async ({ affected }) => {
|
||||
if (!affected) {
|
||||
const iconUrl = await getFileBase64(
|
||||
await getSteamGameIconUrl(objectID)
|
||||
);
|
||||
const steamGame = stateManager
|
||||
.getValue("steamGames")
|
||||
.find((game) => game.id === Number(objectID));
|
||||
|
||||
await gameRepository.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
shop: gameShop,
|
||||
executablePath,
|
||||
});
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
await gameRepository
|
||||
.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
shop: gameShop,
|
||||
executablePath,
|
||||
})
|
||||
.then(() => {
|
||||
if (iconUrl) {
|
||||
getFileBase64(iconUrl).then((base64) =>
|
||||
gameRepository.update({ objectID }, { iconUrl: base64 })
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { getSteamGameIconUrl } from "@main/services";
|
||||
import {
|
||||
gameRepository,
|
||||
repackRepository,
|
||||
@@ -8,10 +7,11 @@ import {
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import { getFileBase64 } from "@main/helpers";
|
||||
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
|
||||
import { In } from "typeorm";
|
||||
import { DownloadManager } from "@main/services";
|
||||
import { Downloader, GameStatus } from "@shared";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
const startGameDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -76,18 +76,34 @@ const startGameDownload = async (
|
||||
|
||||
return game;
|
||||
} else {
|
||||
const iconUrl = await getFileBase64(await getSteamGameIconUrl(objectID));
|
||||
const steamGame = stateManager
|
||||
.getValue("steamGames")
|
||||
.find((game) => game.id === Number(objectID));
|
||||
|
||||
const createdGame = await gameRepository.save({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
downloader,
|
||||
shop: gameShop,
|
||||
status: GameStatus.Downloading,
|
||||
downloadPath,
|
||||
repack: { id: repackId },
|
||||
});
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
const createdGame = await gameRepository
|
||||
.save({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
downloader,
|
||||
shop: gameShop,
|
||||
status: GameStatus.Downloading,
|
||||
downloadPath,
|
||||
repack: { id: repackId },
|
||||
})
|
||||
.then((result) => {
|
||||
if (iconUrl) {
|
||||
getFileBase64(iconUrl).then((base64) =>
|
||||
gameRepository.update({ objectID }, { iconUrl: base64 })
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
DownloadManager.downloadGame(createdGame.id);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
gogFormatter,
|
||||
onlinefixFormatter,
|
||||
} from "./formatters";
|
||||
import { months, repackers } from "../constants";
|
||||
import { repackers } from "../constants";
|
||||
|
||||
export const pipe =
|
||||
<T>(...fns: ((arg: T) => any)[]) =>
|
||||
@@ -44,19 +44,6 @@ export const repackerFormatter: Record<
|
||||
onlinefix: onlinefixFormatter,
|
||||
};
|
||||
|
||||
export const formatUploadDate = (str: string) => {
|
||||
const date = new Date();
|
||||
|
||||
const [month, day, year] = str.split(" ");
|
||||
|
||||
date.setMonth(months.indexOf(month.replace(".", "")));
|
||||
date.setDate(Number(day.substring(0, 2)));
|
||||
date.setFullYear(Number("20" + year.replace("'", "")));
|
||||
date.setHours(0, 0, 0, 0);
|
||||
|
||||
return date;
|
||||
};
|
||||
|
||||
export const getSteamAppAsset = (
|
||||
category: "library" | "hero" | "logo" | "icon",
|
||||
objectID: string,
|
||||
|
||||
@@ -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,10 +15,12 @@ autoUpdater.setFeedURL({
|
||||
repo: "hydra",
|
||||
});
|
||||
|
||||
autoUpdater.logger = logger;
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
if (!gotTheLock) app.quit();
|
||||
|
||||
app.disableHardwareAcceleration();
|
||||
app.commandLine.appendSwitch("--no-sandbox");
|
||||
|
||||
i18n.init({
|
||||
resources,
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { stateManager } from "./state-manager";
|
||||
import { repackersOn1337x } from "./constants";
|
||||
import { repackersOn1337x, seedsPath } from "./constants";
|
||||
import {
|
||||
getNewGOGGames,
|
||||
getNewRepacksFromUser,
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
import {
|
||||
gameRepository,
|
||||
repackRepository,
|
||||
steamGameRepository,
|
||||
userPreferencesRepository,
|
||||
} from "./repository";
|
||||
import { TorrentDownloader } from "./services";
|
||||
@@ -20,7 +19,11 @@ import { Notification } from "electron";
|
||||
import { t } from "i18next";
|
||||
import { GameStatus } from "@shared";
|
||||
import { In } from "typeorm";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { RealDebridClient } from "./services/real-debrid";
|
||||
import { orderBy } from "lodash-es";
|
||||
import { SteamGame } from "@types";
|
||||
|
||||
startProcessWatcher();
|
||||
|
||||
@@ -69,21 +72,18 @@ const checkForNewRepacks = async (userPreferences: UserPreferences | null) => {
|
||||
};
|
||||
|
||||
const loadState = async (userPreferences: UserPreferences | null) => {
|
||||
const [repacks, steamGames] = await Promise.all([
|
||||
repackRepository.find({
|
||||
order: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
}),
|
||||
steamGameRepository.find({
|
||||
order: {
|
||||
name: "asc",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
const repacks = await repackRepository.find({
|
||||
order: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
const steamGames = JSON.parse(
|
||||
fs.readFileSync(path.join(seedsPath, "steam-games.json"), "utf-8")
|
||||
) as SteamGame[];
|
||||
|
||||
stateManager.setValue("repacks", repacks);
|
||||
stateManager.setValue("steamGames", steamGames);
|
||||
stateManager.setValue("steamGames", orderBy(steamGames, ["name"], "asc"));
|
||||
|
||||
import("./events");
|
||||
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { dataSource } from "./data-source";
|
||||
import {
|
||||
Game,
|
||||
GameShopCache,
|
||||
Repack,
|
||||
UserPreferences,
|
||||
SteamGame,
|
||||
} from "@main/entity";
|
||||
import { Game, GameShopCache, Repack, UserPreferences } from "@main/entity";
|
||||
|
||||
export const gameRepository = dataSource.getRepository(Game);
|
||||
|
||||
@@ -15,5 +9,3 @@ export const userPreferencesRepository =
|
||||
dataSource.getRepository(UserPreferences);
|
||||
|
||||
export const gameShopCacheRepository = dataSource.getRepository(GameShopCache);
|
||||
|
||||
export const steamGameRepository = dataSource.getRepository(SteamGame);
|
||||
|
||||
40
src/main/scripts/get-games-icon-hash.ts
Normal file
40
src/main/scripts/get-games-icon-hash.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
|
||||
import { getSteamGameClientIcon, logger } from "@main/services";
|
||||
import { chunk } from "lodash-es";
|
||||
import { seedsPath } from "@main/constants";
|
||||
|
||||
import type { SteamGame } from "@types";
|
||||
|
||||
const steamGamesPath = path.join(seedsPath, "steam-games.json");
|
||||
|
||||
const steamGames = JSON.parse(
|
||||
fs.readFileSync(steamGamesPath, "utf-8")
|
||||
) as SteamGame[];
|
||||
|
||||
const chunks = chunk(steamGames, 1500);
|
||||
|
||||
for (const chunk of chunks) {
|
||||
await Promise.all(
|
||||
chunk.map(async (steamGame) => {
|
||||
if (steamGame.clientIcon) return;
|
||||
|
||||
const index = steamGames.findIndex((game) => game.id === steamGame.id);
|
||||
|
||||
try {
|
||||
const clientIcon = await getSteamGameClientIcon(String(steamGame.id));
|
||||
|
||||
steamGames[index].clientIcon = clientIcon;
|
||||
|
||||
logger.log("info", `Set ${steamGame.name} client icon`);
|
||||
} catch (err) {
|
||||
steamGames[index].clientIcon = null;
|
||||
logger.log("info", `Could not set icon for ${steamGame.name}`);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
fs.writeFileSync(steamGamesPath, JSON.stringify(steamGames));
|
||||
logger.log("info", "Updated steam games");
|
||||
}
|
||||
@@ -1,13 +1,39 @@
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
import { formatUploadDate } from "@main/helpers";
|
||||
|
||||
import { Repack } from "@main/entity";
|
||||
import { requestWebPage, savePage } from "./helpers";
|
||||
|
||||
const months = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
|
||||
export const request1337x = async (path: string) =>
|
||||
requestWebPage(`https://1337xx.to${path}`);
|
||||
|
||||
const formatUploadDate = (str: string) => {
|
||||
const date = new Date();
|
||||
|
||||
const [month, day, year] = str.split(" ");
|
||||
|
||||
date.setMonth(months.indexOf(month.replace(".", "")));
|
||||
date.setDate(Number(day.substring(0, 2)));
|
||||
date.setFullYear(Number("20" + year.replace("'", "")));
|
||||
date.setHours(0, 0, 0, 0);
|
||||
|
||||
return date;
|
||||
};
|
||||
|
||||
/* TODO: $a will often be null */
|
||||
const getTorrentDetails = async (path: string) => {
|
||||
const response = await request1337x(path);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import axios from "axios";
|
||||
import { getSteamAppAsset } from "@main/helpers";
|
||||
|
||||
export interface SteamGridResponse {
|
||||
success: boolean;
|
||||
@@ -59,16 +58,11 @@ export const getSteamGridGameById = async (
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getSteamGameIconUrl = async (objectID: string) => {
|
||||
export const getSteamGameClientIcon = async (objectID: string) => {
|
||||
const {
|
||||
data: { id: steamGridGameId },
|
||||
} = await getSteamGridData(objectID, "games", "steam");
|
||||
|
||||
const steamGridGame = await getSteamGridGameById(steamGridGameId);
|
||||
|
||||
return getSteamAppAsset(
|
||||
"icon",
|
||||
objectID,
|
||||
steamGridGame.data.platforms.steam.metadata.clienticon
|
||||
);
|
||||
return steamGridGame.data.platforms.steam.metadata.clienticon;
|
||||
};
|
||||
|
||||
@@ -4,8 +4,8 @@ import { app } from "electron";
|
||||
import { chunk } from "lodash-es";
|
||||
|
||||
import { createDataSource } from "@main/data-source";
|
||||
import { Repack, SteamGame } from "@main/entity";
|
||||
import { repackRepository, steamGameRepository } from "@main/repository";
|
||||
import { Repack } from "@main/entity";
|
||||
import { repackRepository } from "@main/repository";
|
||||
|
||||
export const resolveDatabaseUpdates = async () => {
|
||||
const updateDataSource = createDataSource({
|
||||
@@ -16,12 +16,8 @@ export const resolveDatabaseUpdates = async () => {
|
||||
|
||||
return updateDataSource.initialize().then(async () => {
|
||||
const updateRepackRepository = updateDataSource.getRepository(Repack);
|
||||
const updateSteamGameRepository = updateDataSource.getRepository(SteamGame);
|
||||
|
||||
const [updateRepacks, updateSteamGames] = await Promise.all([
|
||||
updateRepackRepository.find(),
|
||||
updateSteamGameRepository.find(),
|
||||
]);
|
||||
const updateRepacks = await updateRepackRepository.find();
|
||||
|
||||
const updateRepacksChunks = chunk(updateRepacks, 800);
|
||||
|
||||
@@ -33,16 +29,5 @@ export const resolveDatabaseUpdates = async () => {
|
||||
.orIgnore()
|
||||
.execute();
|
||||
}
|
||||
|
||||
const steamGamesChunks = chunk(updateSteamGames, 800);
|
||||
|
||||
for (const chunk of steamGamesChunks) {
|
||||
await steamGameRepository
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.values(chunk)
|
||||
.orIgnore()
|
||||
.execute();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Repack, SteamGame } from "@main/entity";
|
||||
import type { Repack } from "@main/entity";
|
||||
import type { SteamGame } from "@types";
|
||||
|
||||
interface State {
|
||||
repacks: Repack[];
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
GameShop,
|
||||
TorrentProgress,
|
||||
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"),
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>Hydra</title>
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
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; media-src 'self' data: 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://shared.akamai.steamstatic.com https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com https://shared.akamai.steamstatic.com;"
|
||||
/>
|
||||
</head>
|
||||
<body style="background-color: #1c1c1c">
|
||||
|
||||
@@ -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,
|
||||
@@ -27,7 +27,7 @@ export interface AppProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function App({ children }: AppProps) {
|
||||
export function App() {
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const { updateLibrary } = useLibrary();
|
||||
|
||||
@@ -128,7 +128,7 @@ export function App({ children }: AppProps) {
|
||||
/>
|
||||
|
||||
<section ref={contentRef} className={styles.content}>
|
||||
{children}
|
||||
<Outlet />
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
BIN
src/renderer/src/assets/icon.png
Normal file
BIN
src/renderer/src/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -106,6 +106,8 @@ export const menuItemButtonLabel = style({
|
||||
export const gameIcon = style({
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
minWidth: "20px",
|
||||
minHeight: "20px",
|
||||
borderRadius: "4px",
|
||||
backgroundSize: "cover",
|
||||
});
|
||||
|
||||
@@ -13,6 +13,8 @@ import * as styles from "./sidebar.css";
|
||||
import { GameStatus, GameStatusHelper } from "@shared";
|
||||
import { buildGameDetailsPath } from "@renderer/helpers";
|
||||
|
||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||
|
||||
const SIDEBAR_MIN_WIDTH = 200;
|
||||
const SIDEBAR_INITIAL_WIDTH = 250;
|
||||
const SIDEBAR_MAX_WIDTH = 450;
|
||||
@@ -191,11 +193,16 @@ export function Sidebar() {
|
||||
handleSidebarItemClick(buildGameDetailsPath(game))
|
||||
}
|
||||
>
|
||||
<img
|
||||
className={styles.gameIcon}
|
||||
src={game.iconUrl}
|
||||
alt={game.title}
|
||||
/>
|
||||
{game.iconUrl ? (
|
||||
<img
|
||||
className={styles.gameIcon}
|
||||
src={game.iconUrl}
|
||||
alt={game.title}
|
||||
/>
|
||||
) : (
|
||||
<SteamLogo className={styles.gameIcon} />
|
||||
)}
|
||||
|
||||
<span className={styles.menuItemButtonLabel}>
|
||||
{getGameTitle(game)}
|
||||
</span>
|
||||
|
||||
9
src/renderer/src/declaration.d.ts
vendored
9
src/renderer/src/declaration.d.ts
vendored
@@ -1,4 +1,5 @@
|
||||
import type {
|
||||
AppUpdaterEvents,
|
||||
CatalogueCategory,
|
||||
CatalogueEntry,
|
||||
Game,
|
||||
@@ -90,6 +91,14 @@ declare global {
|
||||
options: Electron.OpenDialogOptions
|
||||
) => Promise<Electron.OpenDialogReturnValue>;
|
||||
platform: NodeJS.Platform;
|
||||
|
||||
/* Splash */
|
||||
onAutoUpdaterEvent: (
|
||||
cb: (event: AppUpdaterEvents) => void
|
||||
) => () => Electron.IpcRenderer;
|
||||
checkForUpdates: () => Promise<void>;
|
||||
restartAndInstallUpdate: () => Promise<void>;
|
||||
continueToMainWindow: () => Promise<void>;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
||||
@@ -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(
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<HashRouter>
|
||||
<App>
|
||||
<Routes>
|
||||
<Routes>
|
||||
<Route path="/splash" Component={Splash} />
|
||||
<Route element={<App />}>
|
||||
<Route path="/" Component={Home} />
|
||||
<Route path="/catalogue" Component={Catalogue} />
|
||||
<Route path="/downloads" Component={Downloads} />
|
||||
<Route path="/game/:shop/:objectID" Component={GameDetails} />
|
||||
<Route path="/search" Component={SearchResults} />
|
||||
<Route path="/settings" Component={Settings} />
|
||||
</Routes>
|
||||
</App>
|
||||
</Route>
|
||||
</Routes>
|
||||
</HashRouter>
|
||||
</Provider>
|
||||
</React.StrictMode>
|
||||
|
||||
@@ -105,7 +105,7 @@ export function Downloads() {
|
||||
if (GameStatusHelper.isReady(game?.status)) {
|
||||
return (
|
||||
<>
|
||||
<p>{game?.repack.title}</p>
|
||||
<p>{game?.repack?.title}</p>
|
||||
<p>{t("completed")}</p>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -58,9 +58,7 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
49
src/renderer/src/pages/splash/splash.css.ts
Normal file
49
src/renderer/src/pages/splash/splash.css.ts
Normal file
@@ -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,
|
||||
});
|
||||
82
src/renderer/src/pages/splash/splash.tsx
Normal file
82
src/renderer/src/pages/splash/splash.tsx
Normal file
@@ -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<AppUpdaterEvents | null>(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 (
|
||||
<>
|
||||
<p>{t("downloading_version", { version: newVersion })}</p>
|
||||
<progress
|
||||
className={styles.progressBar}
|
||||
max="100"
|
||||
value={status.info.percent}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case "checking-for-updates":
|
||||
return <p>{t("searching_updates")}</p>;
|
||||
case "update-available":
|
||||
return <p>{t("update_found", { version: newVersion })}</p>;
|
||||
case "update-downloaded":
|
||||
return <p>{t("restarting_and_applying")}</p>;
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<img src={icon} className={styles.splashIcon} alt="Hydra Launcher Logo" />
|
||||
<section className={styles.updateInfoSection}>
|
||||
{renderUpdateInfo()}
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Downloader, GameStatus } from "@shared";
|
||||
import { ProgressInfo, UpdateInfo } from "electron-updater";
|
||||
|
||||
export type GameShop = "steam" | "epic";
|
||||
export type CatalogueCategory = "recently_added" | "trending";
|
||||
@@ -95,7 +96,7 @@ export interface Game extends Omit<CatalogueEntry, "cover"> {
|
||||
folderName: string;
|
||||
downloadPath: string | null;
|
||||
repacks: GameRepack[];
|
||||
repack: GameRepack;
|
||||
repack: GameRepack | null;
|
||||
progress: number;
|
||||
fileVerificationProgress: number;
|
||||
decompressionProgress: number;
|
||||
@@ -137,3 +138,18 @@ export interface Steam250Game {
|
||||
title: string;
|
||||
objectID: string;
|
||||
}
|
||||
|
||||
export interface SteamGame {
|
||||
id: number;
|
||||
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" };
|
||||
|
||||
Reference in New Issue
Block a user