Compare commits

..

107 Commits

Author SHA1 Message Date
Zamitto
bffe74f0c7 update pipe name 2024-05-21 20:07:34 -03:00
Zamitto
bf97d744e2 Merge pull request #466 from hydralauncher/feat/splash-screen-for-updates
Feat: splash screen for updates
2024-05-21 18:32:25 -03:00
Zamitto
d4bebd18e8 update seed and fix conditional order 2024-05-21 17:21:13 -03:00
Zamitto
b3480eb70b simplify events 2024-05-21 17:04:06 -03:00
Zamitto
e3da07141c hardcoding db path 2024-05-21 16:32:29 -03:00
Zamitto
7280429162 remove debug mock 2024-05-21 14:13:47 -03:00
Zamitto
0b0d2d6b10 update color for progress 2024-05-21 14:06:19 -03:00
Zamitto
551b0b3c91 removes percentage text; uses png without background; 2024-05-21 14:02:27 -03:00
Zamitto
d20d3d0b77 refactor to use html5 progress tag 2024-05-21 13:11:48 -03:00
Zamitto
a5dc101e6b update css 2024-05-21 00:02:23 -03:00
Zamitto
8957b1b1dd Merge branch 'main' into feat/splash-screen-for-updates 2024-05-20 22:43:20 -03:00
Zamitto
42626efd05 Merge pull request #469 from hydralauncher/chore/update-package-name
change package name to hydralauncher
2024-05-20 20:28:39 -03:00
Zamitto
69828e6926 revert package.json to original 2024-05-20 19:03:50 -03:00
Zamitto
9c28a6e9d0 rename function 2024-05-20 19:03:19 -03:00
Zamitto
a817a26be1 smoother way to show main window after splash 2024-05-20 19:03:19 -03:00
Zamitto
0b33cb339c update to hydralauncher 2024-05-20 18:53:26 -03:00
Zamitto
41908433c5 change package name linux to hydra-launcher
# Conflicts:
#	package.json
2024-05-20 16:40:33 -03:00
Zamitto
5667c813d9 feat: add strings to translations file 2024-05-20 16:06:47 -03:00
Zamitto
39ceb38ecd Merge branch 'main' into feat/splash-screen-for-updates 2024-05-20 15:54:18 -03:00
Zamitto
06f58291f7 Merge pull request #467 from hydralauncher/chore/update-python-link-on-readmes
update python version on README links
2024-05-20 15:53:58 -03:00
Zamitto
07cfbab77f remove un needed changes 2024-05-20 15:52:40 -03:00
Zamitto
3670c4f0ff update python version on README 2024-05-20 15:43:02 -03:00
Zamitto
485d396b91 fix for build 2024-05-20 15:12:55 -03:00
Zamitto
5aa6c72594 update python version on README 2024-05-20 14:58:28 -03:00
Zamitto
6fdb591784 refactor events 2024-05-20 14:57:23 -03:00
Zamitto
ae6edaa058 set current logger to log auto update 2024-05-20 13:57:42 -03:00
Zamitto
3062b88f4a feat: progress bar and trying to animate 2024-05-20 13:45:55 -03:00
Zamitto
f90dd82cbd feat: remove auto play 2024-05-20 13:17:19 -03:00
Zamitto
a8f072dd1b Merge branch 'main' into feat/splash-screen-for-updates
# Conflicts:
#	package.json
2024-05-20 12:22:11 -03:00
Zamitto
05a1cf9343 Merge pull request #465 from hydralauncher/chore/bumps-version
bump version to 1.2.3
2024-05-20 11:07:59 -03:00
Zamitto
399d47ca9d bump version to 1.2.3 2024-05-20 11:03:50 -03:00
Zamitto
317fe48927 Merge pull request #455 from v1mkss/polish
Adding a readme file for the Polish language
2024-05-19 23:34:06 -03:00
v1mkss
20bf7009e5 A small fix 2024-05-19 21:39:15 +03:00
v1mkss
a01a105afa Adding Polish readme 2024-05-19 21:35:59 +03:00
Zamitto
33c6203f29 prevent duplicate windows when running on dev 2024-05-19 14:56:06 -03:00
Zamitto
b9f5baef34 silent install and add more info 2024-05-19 14:39:44 -03:00
Zamitto
811878e364 feat: events working 2024-05-19 14:18:32 -03:00
Zamitto
3b17953a82 create electron event 2024-05-19 01:43:47 -03:00
Zamitto
484e79dba3 WIP: showing splash screen 2024-05-18 22:45:26 -03:00
Zamitto
7eee942dcb Merge branch 'main' into feat/splash-screen-for-updates 2024-05-18 22:28:54 -03:00
Chubby Granny Chaser
a89e6760da Merge pull request #442 from hydralauncher/feature/steam-client-icon-cache
feat: adding steam client icon cache
2024-05-18 23:31:42 +01:00
Zamitto
e2257d7ca5 Merge branch 'main' into feat/splash-screen-for-updates 2024-05-18 19:25:38 -03:00
Zamitto
be13ecc5aa fix: sanity check in case repack is null 2024-05-18 19:05:55 -03:00
Chubby Granny Chaser
5b864367e8 fix: adding alphabetical sort to steam games 2024-05-18 23:01:04 +01:00
Chubby Granny Chaser
0ccaed8d55 ci: adding portable to artifact 2024-05-18 22:26:02 +01:00
Chubby Granny Chaser
0491124a7d ci: adding portable to artifact 2024-05-18 22:24:35 +01:00
Chubby Granny Chaser
ac4956c25b ci: changing order of git hooks 2024-05-18 22:09:13 +01:00
Chubby Granny Chaser
c7920fe9f7 ci: changing order of git hooks 2024-05-18 22:08:52 +01:00
Chubby Granny Chaser
f31ae47ab2 Merge pull request #439 from hydralauncher/feat/replace-disable-hardware-acceleration-with-no-sandbox
feat: replace disableHardwareAcceleration with --no-sandbox
2024-05-18 22:08:31 +01:00
Chubby Granny Chaser
3f305eaca0 Merge branch 'feature/steam-client-icon-cache' of github.com:hydralauncher/hydra into feature/steam-client-icon-cache 2024-05-18 22:02:59 +01:00
Chubby Granny Chaser
9290d94e2a ci: changing order of git hooks 2024-05-18 22:02:06 +01:00
Chubby Granny Chaser
756cf19c23 ci: changing order of git hooks 2024-05-18 22:01:18 +01:00
Chubby Granny Chaser
7a13ecd2b7 Merge branch 'main' into feature/steam-client-icon-cache 2024-05-18 22:00:08 +01:00
Chubby Granny Chaser
19f022e0f6 feat: adding steam client icon cache 2024-05-18 21:55:12 +01:00
Zamitto
026729e8c9 Merge branch 'main' into feat/replace-disable-hardware-acceleration-with-no-sandbox 2024-05-18 16:36:40 -03:00
Zamitto
7f918aaaca Merge pull request #440 from hydralauncher/revert-270-feature/better-repack-modal
Revert "More friendly experience when presenting repack options"
2024-05-18 16:29:53 -03:00
Zamitto
d98a01df2f creares release workflow and change build workflow to run on PR 2024-05-18 16:28:44 -03:00
Zamitto
2cb76a9ad4 Revert "More friendly experience when presenting repack options" 2024-05-18 16:26:16 -03:00
Zamitto
250c6901b7 feat: replace disableHardwareAcceleration with --no-sandbox 2024-05-18 15:04:54 -03:00
Zamitto
e5fec91062 Merge pull request #270 from ChristoferMendes/feature/better-repack-modal
More friendly experience when presenting repack options
2024-05-18 15:00:50 -03:00
Zamitto
6fd38df79e Merge branch 'main' into feature/better-repack-modal 2024-05-18 14:57:54 -03:00
Zamitto
d924c64710 Update web-torrent-data.ts
Small adjustment to webTorrentData logic
2024-05-18 14:55:56 -03:00
Zamitto
10943408e9 messing around and testing 2024-05-18 00:13:43 -03:00
ChristoferMendes
d8937b3672 Merge branch 'main' into feature/better-repack-modal 2024-05-17 08:27:47 -03:00
ChristoferMendes
38d652c507 Merge branch 'main' into feature/better-repack-modal 2024-05-16 08:41:22 -03:00
ChristoferMendes
539f444ab5 feat(webTorrentHealth): update recursive function with a loop 2024-05-16 08:34:42 -03:00
ChristoferMendes
7a2b693397 refactor: Improve error handling and retry logic in getSeedersAndPeers function 2024-05-15 20:06:53 -03:00
Zamitto
04a5dbb71d Merge branch 'main' into feature/better-repack-modal 2024-05-15 17:48:42 -03:00
ChristoferMendes
7bdf7f8c2d Merge remote-tracking branch 'upstream/main' into feature/better-repack-modal 2024-05-14 15:36:26 -03:00
ChristoferMendes
95e802372f Merge branch 'main' of github.com:ChristoferMendes/hydra into feature/better-repack-modal 2024-05-13 22:31:45 -03:00
ChristoferMendes
9c261551c3 feat: Add toCapitalize function for capitalizing strings 2024-05-13 22:28:34 -03:00
ChristoferMendes
4e9e9deec1 style: Remove unnecessary whitespace and newline in translation.json 2024-05-13 22:15:44 -03:00
ChristoferMendes
1c56227fa3 feat(searcher): Add repacker check to isMultiplayerRepack function 2024-05-13 22:14:38 -03:00
Zamitto
81ea790d73 Merge branch 'main' into feature/better-repack-modal 2024-05-13 19:04:20 -03:00
ChristoferMendes
0d089bb5c4 Merge branch 'main' into feature/better-repack-modal 2024-05-13 08:27:31 -03:00
Christofer Luiz dos Santos Mendes
82edc6d438 Merge branch 'main' into feature/better-repack-modal 2024-05-12 22:40:08 -03:00
ChristoferMendes
26db88966f refactor: Update getRepackLanguageBasedOnRepacker function parameters and use user preferences 2024-05-12 21:54:03 -03:00
ChristoferMendes
f2af65d4cd style: Update formatting in various files 2024-05-12 21:40:30 -03:00
ChristoferMendes
e6b62399f7 fix: solve merge conflict markers 2024-05-12 21:35:10 -03:00
ChristoferMendes
713392ee29 style: Remove unnecessary code in translation.json 2024-05-12 21:34:23 -03:00
ChristoferMendes
c7da83cae1 Merge branch 'main' into feature/better-repack-modal 2024-05-12 21:33:12 -03:00
ChristoferMendes
f9343ca0c2 style: Remove lucide-react icons and replace them with SVG components 2024-05-12 21:29:06 -03:00
ChristoferMendes
6053b7cd67 refactor: Remove unused "repack_language_code" translations from multiple locale files 2024-05-12 21:20:56 -03:00
ChristoferMendes
0333282915 refactor: Update import paths and improve async function in get-magnet-health 2024-05-12 21:16:15 -03:00
ChristoferMendes
23ab98294a feat: Add webtorrent-health package to dependencies 2024-05-12 21:06:05 -03:00
ChristoferMendes
27bff9d2e6 fix: Replace getMagnetData with getMagnetHealth in references and implementations 2024-05-12 21:06:02 -03:00
ChristoferMendes
6b9f902b2c feat: Replace OpenWebTorrent service with WebTorrentData service 2024-05-12 21:05:46 -03:00
ChristoferMendes
4616f69a29 refactor: Update function names in repack tracker to use 'savePage' instead of 'saveRepacks' 2024-05-12 20:53:58 -03:00
ChristoferMendes
02417dda40 style: update tag component CSS formatting 2024-05-12 20:52:09 -03:00
ChristoferMendes
5f468d5b2e style: Update translation keys for "multi_player" to "multiplayer" in multiple language files 2024-05-12 20:50:55 -03:00
ChristoferMendes
0aa36c5a57 fix: update tag styles to match variables 2024-05-12 20:50:51 -03:00
ChristoferMendes
2f0cd24fb8 refactor: Improve the structure of useMagnetData function 2024-05-12 14:25:13 -03:00
ChristoferMendes
dce700b189 Merge branch 'main' into feature/better-repack-modal 2024-05-12 14:23:22 -03:00
ChristoferMendes
e55d41889d refactor: Simplify code by removing unnecessary try-catch block 2024-05-12 14:20:17 -03:00
ChristoferMendes
8f6922fc8a feat: Add multi-language and multiplayer tags in RepacksModal 2024-05-10 12:32:50 -03:00
ChristoferMendes
ff6a204686 feat: Add getMagnetData function to global declaration 2024-05-10 12:17:53 -03:00
ChristoferMendes
92f35bad9f refactor: Update function calls from savePage to saveRepacks in multiple files 2024-05-10 12:14:23 -03:00
ChristoferMendes
b84df28f39 feat: Add openWebTorrent service for fetching seeders and peers 2024-05-10 12:12:45 -03:00
ChristoferMendes
09bd7dcc36 feat: Add lucide-react package to dependencies 2024-05-10 12:11:30 -03:00
ChristoferMendes
06ed5e07bf feat: Add new functionality to display repack language and seeders/peers in RepacksModal 2024-05-10 12:10:43 -03:00
ChristoferMendes
ada218cea1 feat: Add functions for multiplayer repack, multi-language support, and repack language based on repacker 2024-05-10 12:10:28 -03:00
ChristoferMendes
2662ba3875 style: Add styling for tags container in repacks modal 2024-05-10 12:10:22 -03:00
ChristoferMendes
58693fdb00 feat: Add SeedersAndPeers component with skeleton loader 2024-05-10 12:10:08 -03:00
ChristoferMendes
1872ff1d24 feat: Add tooltip component with styles and visibility logic 2024-05-10 12:09:59 -03:00
ChristoferMendes
08c4906465 feat: Add new Tag component with styling for tags 2024-05-10 12:09:44 -03:00
ChristoferMendes
a0344ea491 feat(events): Add new event for getting magnet data 2024-05-10 11:43:36 -03:00
ChristoferMendes
02c4f0a0e6 feat: Add repack language codes to translation files 2024-05-10 11:42:53 -03:00
53 changed files with 796 additions and 215 deletions

View File

@@ -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
View 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 }}

View File

@@ -1,2 +1 @@
yarn lint
yarn typecheck
yarn format

View File

@@ -1 +1,2 @@
yarn format
yarn lint
yarn typecheck

View File

@@ -1,5 +1,6 @@
out
dist
seeds
pnpm-lock.yaml
LICENSE.md
tsconfig.json

View File

@@ -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

View File

@@ -13,11 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
![Hydra Catalogue](./docs/screenshot.png)
@@ -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
View 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>
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
![Hydra Catalogue](./docs/screenshot.png)
</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).

View File

@@ -13,12 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
![Hydra Catalogue](./docs/screenshot.png)
</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

View File

@@ -13,11 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
![Hydra Catalogue](./docs/screenshot.png)
@@ -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

View File

@@ -13,11 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
![Hydra Catalogue](./docs/screenshot.png)
@@ -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 залежності

View File

@@ -6,6 +6,7 @@ extraResources:
- hydra-download-manager
- hydra.db
- fastlist.exe
- seeds
files:
- "!**/.vscode/*"
- "!src/*"

BIN
hydra.db

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{
"name": "hydra",
"version": "1.2.2",
"name": "hydralauncher",
"version": "1.2.3",
"description": "Hydra",
"main": "./out/main/index.js",
"author": "Los Broxas",

1
seeds/steam-games.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -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"
}
}

View File

@@ -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"
}
}

View File

@@ -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");

View File

@@ -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,
});

View File

@@ -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;

View File

@@ -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";

View File

@@ -1,10 +0,0 @@
import { Column, Entity, PrimaryColumn } from "typeorm";
@Entity("steam_game")
export class SteamGame {
@PrimaryColumn()
id: number;
@Column()
name: string;
}

View 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);

View 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);

View 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);

View File

@@ -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,

View File

@@ -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());

View File

@@ -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 })
);
}
});
}
});
};

View File

@@ -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);

View File

@@ -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,

View File

@@ -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();
});
});
});

View File

@@ -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");

View File

@@ -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);

View 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");
}

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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);
};

View File

@@ -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;
};

View File

@@ -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();
}
});
};

View File

@@ -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);

View File

@@ -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[];

View File

@@ -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"),
});

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@@ -106,6 +106,8 @@ export const menuItemButtonLabel = style({
export const gameIcon = style({
width: "20px",
height: "20px",
minWidth: "20px",
minHeight: "20px",
borderRadius: "4px",
backgroundSize: "cover",
});

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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>
</>
);

View File

@@ -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();
}
}

View 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,
});

View 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>
);
}

View File

@@ -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" };