mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 13:56:16 +00:00
Compare commits
351 Commits
github/for
...
v2.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16c45692da | ||
|
|
30aa3f5470 | ||
|
|
ef16732c0a | ||
|
|
84c472a3fa | ||
|
|
2610f8b17b | ||
|
|
705b12019f | ||
|
|
39be8fdf53 | ||
|
|
cc7c3455fa | ||
|
|
d1f4bc7207 | ||
|
|
aa4ca25653 | ||
|
|
405ea0a824 | ||
|
|
43bc0cb08f | ||
|
|
3c200aa2eb | ||
|
|
cc5967814b | ||
|
|
ec16efed2f | ||
|
|
09d0e5b4ef | ||
|
|
5b18aba2b8 | ||
|
|
192008c76c | ||
|
|
1de3a9836c | ||
|
|
ee02811aea | ||
|
|
c21ebe1ce2 | ||
|
|
214e39adda | ||
|
|
8258127616 | ||
|
|
f9906bfe95 | ||
|
|
ff91284a91 | ||
|
|
b4f99418e9 | ||
|
|
3d132de860 | ||
|
|
8af91c1375 | ||
|
|
449ca2adc3 | ||
|
|
1ef7e58bb5 | ||
|
|
5757ec8b40 | ||
|
|
aa8b685108 | ||
|
|
09b0bfe832 | ||
|
|
d92a9ab410 | ||
|
|
5432ef311a | ||
|
|
9621702e19 | ||
|
|
19cb7c0627 | ||
|
|
91cfb42ff5 | ||
|
|
06d5ed4491 | ||
|
|
8799378bf2 | ||
|
|
b0876b93ed | ||
|
|
f2211ec6ce | ||
|
|
e3fa401667 | ||
|
|
939133fcc3 | ||
|
|
fcc24d6b94 | ||
|
|
00528b6ca1 | ||
|
|
806b086c7f | ||
|
|
268ac3d5a4 | ||
|
|
b122489b34 | ||
|
|
8037101a2b | ||
|
|
15e86338d9 | ||
|
|
92e43b90a2 | ||
|
|
378ad74b43 | ||
|
|
702b141f7b | ||
|
|
dbb7cac308 | ||
|
|
14b204b1c3 | ||
|
|
88a94bbb82 | ||
|
|
d15ca88714 | ||
|
|
f21c6848c6 | ||
|
|
608a53e8df | ||
|
|
f439b6809c | ||
|
|
7846ecbd4f | ||
|
|
6368bd66d3 | ||
|
|
6e543fecb4 | ||
|
|
3d5b41821c | ||
|
|
2b2b5afd79 | ||
|
|
2ea6285744 | ||
|
|
863a3b7d1f | ||
|
|
a03ac26b80 | ||
|
|
e8515e1990 | ||
|
|
797a09f583 | ||
|
|
a295003ad4 | ||
|
|
123812ad81 | ||
|
|
383578bca2 | ||
|
|
02ca506079 | ||
|
|
d9a7672113 | ||
|
|
b0bc754ffc | ||
|
|
813a46bf3e | ||
|
|
3199e56661 | ||
|
|
8f0003298f | ||
|
|
2304e19558 | ||
|
|
87cacdf16c | ||
|
|
ad3c2df024 | ||
|
|
b0164b6948 | ||
|
|
0fce444df8 | ||
|
|
5c363810c8 | ||
|
|
b8c8e534b4 | ||
|
|
2e82c29f4c | ||
|
|
262e95e4db | ||
|
|
ada7b452a0 | ||
|
|
4da116150f | ||
|
|
d2c7780b13 | ||
|
|
43ca4764bb | ||
|
|
53e5124521 | ||
|
|
83cba67c24 | ||
|
|
ba3001bc88 | ||
|
|
6caa9825bd | ||
|
|
59fd5f0347 | ||
|
|
69c39fe6c4 | ||
|
|
46ee202b7c | ||
|
|
57a43c6358 | ||
|
|
c311cc3fb6 | ||
|
|
f6f304ef6f | ||
|
|
ffdbf755f9 | ||
|
|
ae9111975b | ||
|
|
692e38cd7e | ||
|
|
5733f8ae6b | ||
|
|
4dd80bfc6b | ||
|
|
68051c76af | ||
|
|
0a3921bacf | ||
|
|
7e848a1869 | ||
|
|
5b7c9bf9c1 | ||
|
|
cc7738cf1b | ||
|
|
276a6d5c65 | ||
|
|
5b7bdbf4e7 | ||
|
|
1aa741f661 | ||
|
|
b87f1c1248 | ||
|
|
5e5585e7eb | ||
|
|
07913713fc | ||
|
|
1b9f763012 | ||
|
|
ebb17ea829 | ||
|
|
987cd2bf99 | ||
|
|
dc4aa0f608 | ||
|
|
40f4bbc124 | ||
|
|
5c5c9faf00 | ||
|
|
a05cd87542 | ||
|
|
6e60ab3c90 | ||
|
|
0617dfbb62 | ||
|
|
26f1839752 | ||
|
|
0abdeca93a | ||
|
|
8c874fc5a1 | ||
|
|
da0894e2b8 | ||
|
|
8f9eec124d | ||
|
|
44dab630f1 | ||
|
|
02907d84e1 | ||
|
|
6464cea576 | ||
|
|
74d3aa10cb | ||
|
|
6273ca1376 | ||
|
|
453378020b | ||
|
|
ff43f827b9 | ||
|
|
6b3d3c8f5b | ||
|
|
2dcfccedce | ||
|
|
88737cf80d | ||
|
|
158b878883 | ||
|
|
567d9f540d | ||
|
|
7659c9094b | ||
|
|
d4d94dfc4c | ||
|
|
40d2b36a20 | ||
|
|
70f120a62c | ||
|
|
f4cf33d369 | ||
|
|
15c21164e4 | ||
|
|
dab12cb316 | ||
|
|
d2d00516a8 | ||
|
|
f2c4598351 | ||
|
|
9e6484ad11 | ||
|
|
629f204714 | ||
|
|
7c08668a03 | ||
|
|
563e56e54d | ||
|
|
e4917c1a07 | ||
|
|
a809c84151 | ||
|
|
f4e4f7a61c | ||
|
|
5b493d8050 | ||
|
|
e6f296aba3 | ||
|
|
0b54a33084 | ||
|
|
75bc386048 | ||
|
|
7867b7c838 | ||
|
|
84c6951d30 | ||
|
|
89399a6da4 | ||
|
|
cc10186ec3 | ||
|
|
c553697df9 | ||
|
|
0bedb7c9b7 | ||
|
|
3293320926 | ||
|
|
9e02504e14 | ||
|
|
fb60c91c83 | ||
|
|
a608e11be2 | ||
|
|
c0babcfdca | ||
|
|
31adb77d9e | ||
|
|
c6e313f5ad | ||
|
|
f9979a38da | ||
|
|
5fcca9888d | ||
|
|
81aa25fa52 | ||
|
|
1542b346af | ||
|
|
52069f7036 | ||
|
|
cc9d254a32 | ||
|
|
54516c1a5a | ||
|
|
c72fa08d40 | ||
|
|
7e7c4dae1d | ||
|
|
24689cad5a | ||
|
|
aaf20b2aac | ||
|
|
ac6ff04e69 | ||
|
|
bab041b5f7 | ||
|
|
856a4c706a | ||
|
|
629b005ea4 | ||
|
|
bde396c7db | ||
|
|
5369274c6e | ||
|
|
5101684154 | ||
|
|
c1bd1d30d7 | ||
|
|
6c24a523b7 | ||
|
|
76d3fead66 | ||
|
|
73a12488cd | ||
|
|
c76ef630e1 | ||
|
|
7a9247278d | ||
|
|
42ea35441c | ||
|
|
c218070463 | ||
|
|
dd7229dc59 | ||
|
|
f7027f4319 | ||
|
|
bbe68a0aff | ||
|
|
3a3b7b908c | ||
|
|
3febe9b418 | ||
|
|
e31655a96e | ||
|
|
515a08a3a6 | ||
|
|
b1e263814c | ||
|
|
f3276dd8fe | ||
|
|
d809317d62 | ||
|
|
5cb57bd5b3 | ||
|
|
b4c260233f | ||
|
|
d098887c51 | ||
|
|
baf4eafa68 | ||
|
|
a99058805b | ||
|
|
80123d67e1 | ||
|
|
c549d53492 | ||
|
|
68b361e605 | ||
|
|
fbe3c1973a | ||
|
|
7e6b9ca825 | ||
|
|
fffea84ef7 | ||
|
|
51e86819c1 | ||
|
|
6806787ca0 | ||
|
|
1dcf746fa4 | ||
|
|
42a78802a6 | ||
|
|
e44c15e9e1 | ||
|
|
4a149aa62d | ||
|
|
f3f78248ef | ||
|
|
4b7a0ff402 | ||
|
|
4d60317475 | ||
|
|
19b1d29713 | ||
|
|
fab248de99 | ||
|
|
e1ef8a9193 | ||
|
|
070340b34f | ||
|
|
55635878a5 | ||
|
|
e851600814 | ||
|
|
c1454bfbe9 | ||
|
|
f75378a271 | ||
|
|
77280788a7 | ||
|
|
49ed55abfc | ||
|
|
78dfda0c93 | ||
|
|
a6d291a741 | ||
|
|
ba8201daba | ||
|
|
ae45547c17 | ||
|
|
d9c140b2ab | ||
|
|
f631cd3013 | ||
|
|
4dcd97bce8 | ||
|
|
c38422f635 | ||
|
|
d60242a62c | ||
|
|
b188e93343 | ||
|
|
c0198b49ef | ||
|
|
10d7e0e8aa | ||
|
|
15269f3908 | ||
|
|
00c46bc981 | ||
|
|
edf920fed3 | ||
|
|
304aa011ad | ||
|
|
102299e42f | ||
|
|
94bd691209 | ||
|
|
abdc9f6e98 | ||
|
|
a196b91cb9 | ||
|
|
010f07373d | ||
|
|
380143c780 | ||
|
|
4d001cca36 | ||
|
|
11c29355e3 | ||
|
|
e642bf71b1 | ||
|
|
6b8f2e6978 | ||
|
|
27610aa8cf | ||
|
|
91862cd2fe | ||
|
|
d350aa950d | ||
|
|
909e288bec | ||
|
|
6c5d3793ae | ||
|
|
43c5fdbab9 | ||
|
|
3952f106fc | ||
|
|
8a1931f75c | ||
|
|
2e386528a4 | ||
|
|
b6727be3cf | ||
|
|
05f9703c25 | ||
|
|
3d8c63bc40 | ||
|
|
8c0c3e617b | ||
|
|
929be48495 | ||
|
|
8c67dda84e | ||
|
|
6d277cd1d8 | ||
|
|
d4902a5ab1 | ||
|
|
004ccd0db5 | ||
|
|
e55dc20c7d | ||
|
|
7f3d7a56c3 | ||
|
|
d0406282ce | ||
|
|
c6e99f8599 | ||
|
|
5aec973882 | ||
|
|
49fd34c3c0 | ||
|
|
198a283752 | ||
|
|
46b12f2bc2 | ||
|
|
cb93fbcb72 | ||
|
|
22b66149b3 | ||
|
|
6f70b529a2 | ||
|
|
a81b016500 | ||
|
|
ef0699dbea | ||
|
|
b3f87d5662 | ||
|
|
6ff48605da | ||
|
|
0f0a1e98a3 | ||
|
|
007da03837 | ||
|
|
6cc8e8f5fe | ||
|
|
6ccbff0160 | ||
|
|
202f5b60de | ||
|
|
b9558907ec | ||
|
|
8a01352eab | ||
|
|
35879c7afe | ||
|
|
1366ca0087 | ||
|
|
e008478e53 | ||
|
|
6a195eb566 | ||
|
|
781e0f4102 | ||
|
|
b5b7fe31ae | ||
|
|
e2b089e0f8 | ||
|
|
b5af73cec4 | ||
|
|
d8e4eef107 | ||
|
|
2d09ea18a7 | ||
|
|
6c6fff71fe | ||
|
|
a9b92f3fc1 | ||
|
|
6822ed8447 | ||
|
|
5683a0ba49 | ||
|
|
18488490c1 | ||
|
|
2ee3fdc223 | ||
|
|
6fce60f9f7 | ||
|
|
c8aa9fd681 | ||
|
|
0f12dfae88 | ||
|
|
be48306ca2 | ||
|
|
ab81e21341 | ||
|
|
b7f94102da | ||
|
|
9e7b27afe6 | ||
|
|
c24523e8e6 | ||
|
|
b58330ed35 | ||
|
|
dde40f39e9 | ||
|
|
d2b3017de9 | ||
|
|
64f4dad7cc | ||
|
|
154d211b21 | ||
|
|
7905ef6c10 | ||
|
|
b09f2c055f | ||
|
|
2c5b3b4ffa | ||
|
|
fdefc0c165 | ||
|
|
47ca2535e3 | ||
|
|
f706836a43 | ||
|
|
d8158bb80e | ||
|
|
4e422bdf91 | ||
|
|
4be3db8007 | ||
|
|
29b64237ed | ||
|
|
d481164bf3 | ||
|
|
dc94a886e6 |
@@ -1,3 +1,4 @@
|
||||
MAIN_VITE_STEAMGRIDDB_API_KEY=YOUR_API_KEY
|
||||
MAIN_VITE_API_URL=API_URL
|
||||
MAIN_VITE_SENTRY_DSN=YOUR_SENTRY_DSN
|
||||
SENTRY_AUTH_TOKEN=
|
||||
|
||||
@@ -2,3 +2,4 @@ node_modules
|
||||
dist
|
||||
out
|
||||
.gitignore
|
||||
migration.stub
|
||||
|
||||
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -27,7 +27,7 @@ body:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
@@ -56,3 +56,12 @@ body:
|
||||
description: Please provide any additional information and context about your problem.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Before opening this Issue
|
||||
options:
|
||||
- label: I have searched the issues of this repository and believe that this is not a duplicate.
|
||||
required: true
|
||||
- label: I am aware that Hydra team does not offer any support or help regarding the downloaded games.
|
||||
required: true
|
||||
|
||||
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -35,10 +35,11 @@ jobs:
|
||||
|
||||
- name: Build Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: yarn build:linux
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libarchive-tools
|
||||
yarn build:linux
|
||||
env:
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
MAIN_VITE_API_URL: ${{ vars.MAIN_VITE_API_URL }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
MAIN_VITE_SENTRY_DSN: ${{ vars.MAIN_VITE_SENTRY_DSN }}
|
||||
@@ -48,8 +49,6 @@ jobs:
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: yarn build:win
|
||||
env:
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
MAIN_VITE_API_URL: ${{ vars.MAIN_VITE_API_URL }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
MAIN_VITE_SENTRY_DSN: ${{ vars.MAIN_VITE_SENTRY_DSN }}
|
||||
@@ -69,3 +68,4 @@ jobs:
|
||||
dist/*.tar.gz
|
||||
dist/*.yml
|
||||
dist/*.blockmap
|
||||
dist/*.pacman
|
||||
|
||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -37,10 +37,11 @@ jobs:
|
||||
|
||||
- name: Build Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: yarn build:linux
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libarchive-tools
|
||||
yarn build:linux
|
||||
env:
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
MAIN_VITE_API_URL: ${{ vars.MAIN_VITE_API_URL }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
MAIN_VITE_SENTRY_DSN: ${{ vars.MAIN_VITE_SENTRY_DSN }}
|
||||
@@ -50,8 +51,6 @@ jobs:
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: yarn build:win
|
||||
env:
|
||||
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
|
||||
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
|
||||
MAIN_VITE_API_URL: ${{ vars.MAIN_VITE_API_URL }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
MAIN_VITE_SENTRY_DSN: ${{ vars.MAIN_VITE_SENTRY_DSN }}
|
||||
@@ -72,5 +71,6 @@ jobs:
|
||||
dist/*.tar.gz
|
||||
dist/*.yml
|
||||
dist/*.blockmap
|
||||
dist/*.pacman
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
.vscode
|
||||
node_modules
|
||||
hydra-download-manager/
|
||||
aria2/
|
||||
fastlist.exe
|
||||
__pycache__
|
||||
dist
|
||||
|
||||
11
README.be.md
11
README.be.md
@@ -5,7 +5,7 @@
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra - гэта гульнявы лаўнчар з уласным убудаваным кліентам BitTorrent і самастойным scraper`ам для рэпакаў.</strong>
|
||||
</p>
|
||||
@@ -20,6 +20,9 @@
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,11 +30,12 @@
|
||||
|
||||
## Змест
|
||||
|
||||
- [Змест](#змест)
|
||||
- [Апісанне](#апісанне)
|
||||
- [Асаблівасці](#асаблівасці)
|
||||
- [Усталёўка](#усталёўка)
|
||||
- [Уклад](#contributing)
|
||||
- [Далучайцеся да нашага Telegram](#join-our-telegram)
|
||||
- [Уклад](#-уклад)
|
||||
- [Далучайцеся да нашага Telegram](#-далучайцеся-да-нашага-telegram)
|
||||
- [Форк і кланаванне рэпазітара](#форк-і-кланаванне-рэпазітара)
|
||||
- [Спосабы ўнесці свой уклад](#спосабы-ўнесці-свой-уклад)
|
||||
- [Структура праекту](#структура-праекту)
|
||||
@@ -47,6 +51,7 @@
|
||||
- [Зборка кліента BitTorrent](#зборка-кліента-bittorrent)
|
||||
- [Зборка прыкладання Electron](#зборка-прыкладання-electron)
|
||||
- [Удзельнікі](#удзельнікі)
|
||||
- [Ліцэнзія](#ліцэнзія)
|
||||
|
||||
## Апісанне
|
||||
|
||||
|
||||
185
README.cs.md
Normal file
185
README.cs.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 je herní launcher s vlastním vestavěným Bittorrent klientem.</strong>
|
||||
</p>
|
||||
|
||||
[](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.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Seznam obsahu
|
||||
|
||||
- [Seznam obsahu](#seznam-obsahu)
|
||||
- [O projektu](#o-projektu)
|
||||
- [Funkce](#funkce)
|
||||
- [Instalace](#instalace)
|
||||
- [Přispívání](#přispívání)
|
||||
- [Připoj se na náš telegram](#připoj-se-na-náš-telegram)
|
||||
- [Vytvořte fork a naklonujte svůj repozitář](#vytvořte-fork-a-naklonujte-svůj-repozitář)
|
||||
- [Způsoby jak můžete přispět](#způsoby-jak-můžete-přispět)
|
||||
- [Struktura projektu](#struktura-projektu)
|
||||
- [Sestavení ze zdroje](#sestavení-ze-zdroje)
|
||||
- [Instalace Node.js](#instalace-nodejs)
|
||||
- [Instalace Yarn](#instalace-yarn)
|
||||
- [Instalace Požadavků pro Node.js](#instalace-požadavků-pro-nodejs)
|
||||
- [Instalace Pythonu 3.9](#instalace-pythonu-39)
|
||||
- [Instalace Požadavků pro Python](#instalace-požadavků-pro-python)
|
||||
- [Proměnné prostředí](#proměnné-prostředí)
|
||||
- [Spuštění](#spuštění)
|
||||
- [Sestavení](#sestavení)
|
||||
- [Sestavení bittorrent klientu](#sestavení-bittorrent-klientu)
|
||||
- [Sestavení electron aplikace](#sestavení-electron-aplikace)
|
||||
- [Přispěvatelé](#přispěvatelé)
|
||||
- [Licence](#licence)
|
||||
|
||||
## O projektu
|
||||
|
||||
**Hydra** je **Herní Launcher** s jeho vlastním vestavěným **BitTorrent Klientem**.
|
||||
<br>
|
||||
Launcher je napsán v TypeScriptu (Electron) a Pythonu, který má na starosti torrentovací systém za pomocí knihovny libtorrent.
|
||||
|
||||
## Funkce
|
||||
|
||||
- Vlastní vestavěný BitTorrent klient
|
||||
- How Long To Beat (HLTB) integrace na stránce hry
|
||||
- Vlastní místa pro uložení hry
|
||||
- Windows a Linux podpora
|
||||
- Časté aktualizace
|
||||
- A další ...
|
||||
|
||||
## Instalace
|
||||
|
||||
Následuj kroky:
|
||||
|
||||
1. Stáhni nejnovější verzi Hydry ze stránky [Vydání](https://github.com/hydralauncher/hydra/releases/latest).
|
||||
- Stáhni .exe, pokud chceš instalovat Hydru na Windows.
|
||||
- Stáhni .deb nebo .rpm nebo .zip, pokud chceš instalovat Hydru na Linux. (záleží na tvé Linux distribuci)
|
||||
2. Spusť stažený instalační soubor.
|
||||
3. Užívej Hydru!
|
||||
|
||||
## <a name="contributing"> Přispívání
|
||||
|
||||
### <a name="join-our-telegram"></a> Připoj se na náš telegram
|
||||
|
||||
Vedeme diskuzi v našem [Telegramovém](https://t.me/hydralauncher) kanálu.
|
||||
|
||||
### Vytvořte fork a naklonujte svůj repozitář
|
||||
|
||||
1. Vytvoř fork repozitáře [(klikni sem pro vytvoření forku)](https://github.com/hydralauncher/hydra/fork)
|
||||
2. Naklonuj kód forku `git clone https://github.com/tvoje_jméno/hydra`
|
||||
3. Vytvoř nové odvětví (branch)
|
||||
4. Odešli svoje změny
|
||||
5. Odešli nový Pull Request
|
||||
|
||||
### Způsoby jak můžete přispět
|
||||
|
||||
- Překládání: Chceme, aby Hydra byla co nejvíce dostupná. Můžete přispět novým jazykem, nebo úpravou současného!
|
||||
- Kód: Hydra je postavena na Typescriptu, Electronu a trochou Pythonu. Pokud chceš přispět, připoj se na náš [Telegram](https://t.me/hydralauncher)!
|
||||
|
||||
### Struktura projektu
|
||||
|
||||
- torrent-client: Používáme libtorrent, Pythonovou knihovnu, pro správu torrent stahování
|
||||
- src/renderer: uživatelské rozhraní aplikace (UI)
|
||||
- src/main: celá logika projektu
|
||||
|
||||
## Sestavení ze zdroje
|
||||
|
||||
### Instalace Node.js
|
||||
|
||||
Ujistěte se, že máte Node.js nainstalován na svém zařízení. Pokud ne, stáhněte ho, a nainstalujte z [nodejs.org](https://nodejs.org/).
|
||||
|
||||
### Instalace Yarn
|
||||
|
||||
Yarn je balíčkový správce pro Node.js. Pokud ještě nemáte yarn, můžete ho stáhnout za pomoci pokynů na [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
|
||||
|
||||
### Instalace Požadavků pro Node.js
|
||||
|
||||
Jděte do složky projektu, otevřte v ní konzole a nainstalujte požadavky pro Node pomocí Yarn:
|
||||
|
||||
```bash
|
||||
cd hydra
|
||||
yarn
|
||||
```
|
||||
|
||||
### Instalace Pythonu 3.9
|
||||
|
||||
Ujistěte se, že máte Python 3.9 nainstalován na svém zařízení. Můžete ho stáhnout z [python.org](https://www.python.org/downloads/release/python-3913/).
|
||||
|
||||
### Instalace Požadavků pro Python
|
||||
|
||||
Nainstalujte požadavky pro Python za pomoci pip:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Proměnné prostředí
|
||||
|
||||
Budete potřebovat SteamGridDB API klíč, abyste mohli načítat ikony u her.
|
||||
|
||||
Jakmile ho máte, můžete zkopírovat, nebo přejmenovat `.env.example` soubor na `.env` a dát ho do `STEAMGRIDDB_API_KEY`.
|
||||
|
||||
## Spuštění
|
||||
|
||||
Jakmile máte vše nastaveno, můžete spustit jak Electron proces tak bittorrent client:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Sestavení
|
||||
|
||||
### Sestavení bittorrent klientu
|
||||
|
||||
Sestavit bittorrent klient můžete pomocí:
|
||||
|
||||
```bash
|
||||
python torrent-client/setup.py build
|
||||
```
|
||||
|
||||
### Sestavení electron aplikace
|
||||
|
||||
Sestavit Electron aplikaci můžete pomocí následujících kroků:
|
||||
|
||||
Na Windows:
|
||||
|
||||
```bash
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
Na Linux:
|
||||
|
||||
```bash
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## Přispěvatelé
|
||||
|
||||
<a href="https://github.com/hydralauncher/hydra/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hydralauncher/hydra" />
|
||||
</a>
|
||||
|
||||
## Licence
|
||||
|
||||
Hydra je licencována pod [MIT Licencí](LICENSE).
|
||||
183
README.de.md
Normal file
183
README.de.md
Normal file
@@ -0,0 +1,183 @@
|
||||
<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 ist ein Launcher für Spiele mit einem eigenen eingebetteten BitTorrent-Client.</strong>
|
||||
</p>
|
||||
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.md)
|
||||
[](README.be.md)
|
||||
[](README.pl.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
- [Über Hydra](#über-hydra)
|
||||
- [Eigenschaften](#eigenschaften)
|
||||
- [Installation](#installation)
|
||||
- [Mitwirken](#mitwirken)
|
||||
- [Tritt uns auf Telegram bei](#tritt-uns-auf-telegram-bei)
|
||||
- [Forke und klone dein Repo](#forke-und-klone-dein-repo)
|
||||
- [Wie du mitwirken kannst](#wie-du-mitwirken-kannst)
|
||||
- [Projektstruktur](#projektstruktur)
|
||||
- [Den Quellcode kompilieren](#den-quellcode-kompilieren)
|
||||
- [Installiere Node.js](#installiere-nodejs)
|
||||
- [Installiere Yarn](#installiere-yarn)
|
||||
- [Installiere Node-Abhängigkeiten](#installiere-node-abhängigkeiten)
|
||||
- [Installiere Python 3.9](#installiere-python-39)
|
||||
- [Installiere Python-Abhängigkeiten](#installiere-python-abhängigkeiten)
|
||||
- [Umgebungsvariablen](#umgebungsvariablen)
|
||||
- [Ausführung](#ausführung)
|
||||
- [Kompilation](#kompilation)
|
||||
- [Kompiliere den BitTorrent-Client](#kompiliere-den-bittorrent-client)
|
||||
- [Kompiliere die Electron-Applikation](#kompiliere-die-electron-applikation)
|
||||
- [Mitwirkende](#mitwirkende)
|
||||
|
||||
## Über Hydra
|
||||
|
||||
**Hydra** ist ein **Launcher für Spiele** mit einem eigenen eingebetteten **BitTorrent-Client**.
|
||||
<br>
|
||||
Der Launcher ist in TypeScript (Electron) und Python, womit das Torrentingsystem durch Einsatz von libtorrent geregelt ist, geschrieben.
|
||||
|
||||
## Eigenschaften
|
||||
|
||||
- Eigener eingebetteter BitTorrent-Client
|
||||
- How Long to Beat (HLTB) Integration auf der Spielseite
|
||||
- Anpassbarkeit des Downloadverzeichnisses
|
||||
- Unterstützung von Windows und Linux
|
||||
- Regelmäßig aktualisiert
|
||||
- Und mehr ...
|
||||
|
||||
## Installation
|
||||
|
||||
Die folgenden Schritte beschreiben den Installationsprozess:
|
||||
|
||||
1. Lade die neueste Version von Hydra von der [Releases](https://github.com/hydralauncher/hydra/releases/latest) Seite herunter.
|
||||
- Für die Installation von Hydra auf Windows, wähle die .exe Datei.
|
||||
- Für die Installation von Hydra auf Linux, wähle die .deb, .rpm oder .zip Datei. (Abhängig von deiner Linux-Distribution)
|
||||
2. Führe die heruntergeladene Datei aus.
|
||||
3. Genieße Hydra!
|
||||
|
||||
## Mitwirken
|
||||
|
||||
### Tritt uns auf Telegram bei
|
||||
|
||||
Wir konzentrieren unsere Diskussionen in unserem [Telegram](https://t.me/hydralauncher) Kanal.
|
||||
|
||||
### Forke und klone dein Repo
|
||||
|
||||
1. Forke das Repo [(Klicke hier, um direkt zu forken)](https://github.com/hydralauncher/hydra/fork)
|
||||
2. Klone deinen geforketen Code `git clone https://github.com/dein_nutzername/hydra`
|
||||
3. Erstelle einen neuen Branch
|
||||
4. Pushe deine Commits
|
||||
5. Stelle eine neue Pull-Anfrage
|
||||
|
||||
### Wie du mitwirken kannst
|
||||
|
||||
- Übersetzung: Wir wollen Hydra so vielen Menschen wie möglich zugänglich machen. Gerne kannst du uns helfen neue Sprachen zu übersetzen oder für Hydra bereits verfügbare Sprachen zu aktualisieren und verbessern.
|
||||
- Code: Hydra ist mit TypeScript, Electron und etwas Python gebaut. Wenn du mitwirken möchtest, tritt unserem [Telegram](https://t.me/hydralauncher) bei!
|
||||
|
||||
### Projektstruktur
|
||||
|
||||
- torrent-client: Wir verwenden die Python-Bibliothek libtorrent zur Verwaltung von Torrent-Downloads.
|
||||
- src/renderer: die UI der Applikation.
|
||||
- src/main: sämtliche Logik liegt hier.
|
||||
|
||||
## Den Quellcode kompilieren
|
||||
|
||||
### Installiere Node.js
|
||||
|
||||
Stelle sicher, dass du Node.js auf deinem System installiert hast. Falls nicht, installiere es von [nodejs.org](https://nodejs.org/).
|
||||
|
||||
### Installiere Yarn
|
||||
|
||||
Yarn ist ein Packetmanager für Node.js. Sollte er dir fehlen, installiere ihn mithilfe der Anleitung auf [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
|
||||
|
||||
### Installiere Node-Abhängigkeiten
|
||||
|
||||
Navigiere zum Projektverzeichnis und installiere die Node-Abhängigkeiten mit Yarn:
|
||||
|
||||
```bash
|
||||
cd hydra
|
||||
yarn
|
||||
```
|
||||
|
||||
### Installiere Python 3.9
|
||||
|
||||
Stelle sicher, dass du Python 3.9 auf deinem System installiert hast. Ansonsten kannst du es von [python.org](https://www.python.org/downloads/release/python-3913/) herunterladen und installieren.
|
||||
|
||||
### Installiere Python-Abhängigkeiten
|
||||
|
||||
Installiere die benötigten Python-Abhängigkeiten mit pip:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Umgebungsvariablen
|
||||
|
||||
Du wirst einen SteamGridDB API Schlüssel benötigen, um die Spielicons bei Installation abzurufen.
|
||||
|
||||
Sobald du einen hast, kannst du die .env.example Datei zu .env kopieren oder umbenennen und den Schlüssel bei STEAMGRIDDB_API_KEY einfügen.
|
||||
|
||||
## Ausführung
|
||||
|
||||
Sobald du alles eingerichtet hast, kannst du den folgenden Befehl nutzen, um sowohl den Electron-Prozess als auch den BitTorrent-Client zu starten:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Kompilation
|
||||
|
||||
### Kompiliere den BitTorrent-Client
|
||||
|
||||
Kompiliere den BitTorrent-Client mit folgendem Befehl:
|
||||
|
||||
```bash
|
||||
python torrent-client/setup.py build
|
||||
```
|
||||
|
||||
### Kompiliere die Electron-Applikation
|
||||
|
||||
Kompiliere die Electron-Applikation mit folgendem Befehl:
|
||||
|
||||
Auf Windows:
|
||||
|
||||
```bash
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
Auf Linux:
|
||||
|
||||
```bash
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## Mitwirkende
|
||||
|
||||
<a href="https://github.com/hydralauncher/hydra/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hydralauncher/hydra" />
|
||||
</a>
|
||||
|
||||
## Lizenz
|
||||
|
||||
Hydra ist unter der [MIT Lizenz](LICENSE) lizensiert.
|
||||
29
README.es.md
29
README.es.md
@@ -5,7 +5,7 @@
|
||||
[<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>
|
||||
@@ -13,13 +13,16 @@
|
||||
[](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.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,11 +30,12 @@
|
||||
|
||||
## Tabla de Contenidos
|
||||
|
||||
- [Tabla de Contenidos](#tabla-de-contenidos)
|
||||
- [Acerca de](#acerca-de)
|
||||
- [Características](#caracteristicas)
|
||||
- [Instalación](#Instalacion)
|
||||
- [Contribuir](#contribuir)
|
||||
- [Únete a nuestro Telegram](#unete-a-nuestro-telegram)
|
||||
- [Caracteristicas](#caracteristicas)
|
||||
- [Instalacion](#instalacion)
|
||||
- [Contribuir](#-contribuir)
|
||||
- [Unete 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)
|
||||
@@ -40,13 +44,14 @@
|
||||
- [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)
|
||||
- [Instalar Dependencias de Python](#instalar-dependencias-de-python)
|
||||
- [Variables del Entorno](#variables-del-entorno)
|
||||
- [Ejecución](#ejecucion)
|
||||
- [Compilación](#compilacion)
|
||||
- [Ejecucion](#ejecucion)
|
||||
- [Compilacion](#compilacion)
|
||||
- [Compilar el cliente de bittorrent](#compilar-el-cliente-de-bittorrent)
|
||||
- [Compilar la aplicación Electron](#compilar-la-aplicacion-electron)
|
||||
- [Compilar la aplicacion Electron](#compilar-la-aplicacion-electron)
|
||||
- [Colaboradores](#colaboradores)
|
||||
- [Licencia](#licencia)
|
||||
|
||||
## Acerca de
|
||||
|
||||
|
||||
13
README.fr.md
13
README.fr.md
@@ -5,7 +5,7 @@
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra est un lanceur de jeux avec son propre client bittorrent intégré et un scraper de repack auto-géré.</strong>
|
||||
</p>
|
||||
@@ -13,13 +13,16 @@
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.md)
|
||||
[](README.be.md)
|
||||
[](README.pl.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,6 +30,7 @@
|
||||
|
||||
## Table des Matières
|
||||
|
||||
- [Table des Matières](#table-des-matières)
|
||||
- [À propos](#à-propos)
|
||||
- [Fonctionnalités](#fonctionnalités)
|
||||
- [Installation](#installation)
|
||||
@@ -47,6 +51,7 @@
|
||||
- [Compiler le client bittorrent](#compiler-le-client-bittorrent)
|
||||
- [Compiler l'application Electron](#compiler-lapplication-electron)
|
||||
- [Contributeurs](#contributeurs)
|
||||
- [License](#license)
|
||||
|
||||
## À propos
|
||||
|
||||
|
||||
188
README.it.md
Normal file
188
README.it.md
Normal file
@@ -0,0 +1,188 @@
|
||||
<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 è un game launcher con il proprio client bittorrent e autogestore di repacks.</strong>
|
||||
</p>
|
||||
|
||||
[](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.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [A proposito](#a-proposito)
|
||||
- [Caratteristiche](#caratteristiche)
|
||||
- [Installazione](#installazione)
|
||||
- [Contribuire](#-contribuire)
|
||||
- [Unisciti su Telegram](#-unisciti-su-telegram)
|
||||
- [Forka e Clona la repository](#forka-e-clona-la-repository)
|
||||
- [Modi in cui contribuire](#modi-in-cui-contribuire)
|
||||
- [Struttura del Progetto](#struttura-del-progetto)
|
||||
- [Compilazione](#compilazione)
|
||||
- [Installa Node.js](#installa-nodejs)
|
||||
- [Installa Yarn](#installa-yarn)
|
||||
- [Installa le dipendenze Node](#installa-le-dipendenze-node)
|
||||
- [Installa Python 3.9](#installa-python-39)
|
||||
- [Installa le Dipendenze Python](#installa-le-dipendenze-python)
|
||||
- [Variabili d'ambiente](#variabili-dambiente)
|
||||
- [Esecuzione](#esecuzione)
|
||||
- [Compilazione](#compilazione-1)
|
||||
- [Compila il bittorrent](#compila-il-bittorrent)
|
||||
- [Compila l'applicazione Electron](#compila-lapplicazione-electron)
|
||||
- [Collaboratori](#collaboratori)
|
||||
- [Licenza](#licenza)
|
||||
|
||||
## A proposito
|
||||
|
||||
**Hydra** è un **Game Launcher** con il proprio **Client BitTorrent** e **autogestore di repack**.
|
||||
<br>
|
||||
Il launcher è scritto in TypeScript (Electron) and Python, che gestisce il sistema di torrenting appoggiandosi a libtorrent.
|
||||
|
||||
## Caratteristiche
|
||||
|
||||
- Motore di ricerca automatizzato sulle fonti di repack dal [Megathread]("https://www.reddit.com/r/Piracy/wiki/megathread/")
|
||||
- Client Bittorrent integrato
|
||||
- Integrazione How Long To Beat (HLTB) nella pagina del gioco
|
||||
- Percorso del download Personalizzato
|
||||
- Notifiche di aggiornamenti sulla list dei repacks
|
||||
- Supporto Windows e Linux
|
||||
- Costantemente Aggiornato
|
||||
- E molto altro ...
|
||||
|
||||
## Installazione
|
||||
|
||||
Segui i seguenti passi:
|
||||
|
||||
1. Scarica l'ultima versione di Hydra dalla pagina [Releases](https://github.com/hydralauncher/hydra/releases/latest).
|
||||
- Scarica solo il file .exe per installare Hydra su Windows.
|
||||
- Scarica il file .deb o .rpm o .zip per Linux. (Dipende dalla tua distro Linux)
|
||||
2. Esegui il file scaricato.
|
||||
3. Goditi Hydra!
|
||||
|
||||
## <a name="contribuire"> Contribuire
|
||||
|
||||
### <a name="unisciti-su-telegram"></a> Unisciti su Telegram
|
||||
|
||||
Puoi unirti alle nostre conversazioni sul canale [Telegram](https://t.me/hydralauncher).
|
||||
|
||||
### Forka e Clona la repository
|
||||
|
||||
1. Forka la repository [(clicca qui per forkare)](https://github.com/hydralauncher/hydra/fork)
|
||||
2. Clona il tuo codice forkato `git clone https://github.com/your_username/hydra`
|
||||
3. Crea un nuovo branch
|
||||
4. Aggiungi le modifiche (push)
|
||||
5. Invia la richiesta di pull
|
||||
|
||||
### Modi in cui contribuire
|
||||
|
||||
- Traduzione: Vogliamo rendere Hydra disponibile a più persone possibile. Sentiti libero di tradurre in altre lingue o aggiornare e migliorare quelle già disponibili su Hydra.
|
||||
- Programmazione: Hydra è programmato in TypeScript, Electron e un po' di Python. Se intendi contribuire unisciti al nostro [Telegram](https://t.me/hydralauncher)!
|
||||
|
||||
### Struttura del Progetto
|
||||
|
||||
- client-torrent: Usiamo libtorrent, una libreria Python, per gestire i download dei torrent
|
||||
- src/renderer: l'UI dell'applicazione
|
||||
- src/main: tutta la logica qui.
|
||||
|
||||
## Compilazione
|
||||
|
||||
### Installa Node.js
|
||||
|
||||
Assicurati di avere Node.js installato sulla tua macchina. Scaricalo e installalo da [nodejs.org](https://nodejs.org/).
|
||||
|
||||
### Installa Yarn
|
||||
|
||||
Yarn è un gestore di pacchetti per Node.js. Se non hai ancora installato Yarn segui le istruzioni su [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
|
||||
|
||||
### Installa le dipendenze Node
|
||||
|
||||
Naviga alla cartella del progetto e installa le dipendenze Node con Yarn:
|
||||
|
||||
```bash
|
||||
cd hydra
|
||||
yarn
|
||||
```
|
||||
|
||||
### Installa Python 3.9
|
||||
|
||||
Assicurati di avere Python 3.9 installato. Puoi scaricarlo da [python.org](https://www.python.org/downloads/release/python-3913/).
|
||||
|
||||
### Installa le Dipendenze Python
|
||||
|
||||
Installa le dipendenze con pip:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Variabili d'ambiente
|
||||
|
||||
Avrai bisogno di una chiave API SteamGridDB per poter caricare le icone di gioco.
|
||||
Se intendi avere onlinefix come repacker dovrai aggiungere le tue credenziali al file .env
|
||||
|
||||
Una volta ottenuta, puoi copiare e rinominare il file `.env.example` a `.env` e metterlo in `STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
|
||||
|
||||
## Esecuzione
|
||||
|
||||
Una volta impostato tutto, puoi eseguire il seguente comando per avviare il processo Electron e il client bittorrent:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Compilazione
|
||||
|
||||
### Compila il bittorrent
|
||||
|
||||
Usa il comando:
|
||||
|
||||
```bash
|
||||
python torrent-client/setup.py build
|
||||
```
|
||||
|
||||
### Compila l'applicazione Electron
|
||||
|
||||
Usa il comando:
|
||||
|
||||
Per Windows:
|
||||
|
||||
```bash
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
Per Linux:
|
||||
|
||||
```bash
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## Collaboratori
|
||||
|
||||
<a href="https://github.com/hydralauncher/hydra/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hydralauncher/hydra" />
|
||||
</a>
|
||||
|
||||
## Licenza
|
||||
|
||||
Hydra è concesso in licenza secondo la [MIT License](LICENSE).
|
||||
24
README.md
24
README.md
@@ -5,21 +5,24 @@
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra is a game launcher with its own embedded bittorrent client and a self-managed repack scraper.</strong>
|
||||
<strong>Hydra is a game launcher with its own embedded bittorrent client.</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.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,11 +30,12 @@
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [About](#about)
|
||||
- [Features](#features)
|
||||
- [Installation](#installation)
|
||||
- [Contributing](#contributing)
|
||||
- [Join our Telegram](#join-our-telegram)
|
||||
- [Contributing](#-contributing)
|
||||
- [Join our Telegram](#-join-our-telegram)
|
||||
- [Fork and clone your repository](#fork-and-clone-your-repository)
|
||||
- [Ways you can contribute](#ways-you-can-contribute)
|
||||
- [Project Structure](#project-structure)
|
||||
@@ -47,20 +51,19 @@
|
||||
- [Build the bittorrent client](#build-the-bittorrent-client)
|
||||
- [Build the Electron application](#build-the-electron-application)
|
||||
- [Contributors](#contributors)
|
||||
- [License](#license)
|
||||
|
||||
## About
|
||||
|
||||
**Hydra** is a **Game Launcher** with its own embedded **BitTorrent Client** and a **self-managed repack scraper**.
|
||||
**Hydra** is a **Game Launcher** with its own embedded **BitTorrent Client**.
|
||||
<br>
|
||||
The launcher is written in TypeScript (Electron) and Python, which handles the torrenting system by using libtorrent.
|
||||
|
||||
## Features
|
||||
|
||||
- Self-Managed repack scraper among all the most reliable websites on the [Megathread]("https://www.reddit.com/r/Piracy/wiki/megathread/")
|
||||
- Own embedded bittorrent client
|
||||
- How Long To Beat (HLTB) integration on game page
|
||||
- Downloads path customization
|
||||
- Repack list update notifications
|
||||
- Windows and Linux support
|
||||
- Constantly updated
|
||||
- And more ...
|
||||
@@ -134,9 +137,8 @@ pip install -r requirements.txt
|
||||
## Environment variables
|
||||
|
||||
You'll need an SteamGridDB API Key in order to fetch the game icons on installation.
|
||||
If you want to have onlinefix as a repacker you'll need to add your credentials to the .env
|
||||
|
||||
Once you have it, you can copy or rename the `.env.example` file to `.env` and put it on`STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
|
||||
Once you have it, you can copy or rename the `.env.example` file to `.env` and put it on`STEAMGRIDDB_API_KEY`.
|
||||
|
||||
## Running
|
||||
|
||||
|
||||
35
README.pl.md
35
README.pl.md
@@ -5,7 +5,7 @@
|
||||
[<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>
|
||||
@@ -13,13 +13,16 @@
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.be.md)
|
||||
[](README.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,26 +30,28 @@
|
||||
|
||||
## Zawartość.
|
||||
|
||||
- [Zawartość.](#zawartość)
|
||||
- [O nas](#o-nas)
|
||||
- [Cechy.](#cechy)
|
||||
- [Cechy](#cechy)
|
||||
- [Instalacja](#instalacja)
|
||||
- [Dokonaj wpłaty](#dokonaj-wpłaty)
|
||||
- [Dołącz do naszego kanału Telegram](#dołącz-do-naszego-kanału-telegram)
|
||||
- [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)
|
||||
- [Jak możesz pomóc](#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)
|
||||
- [Zainstaluj Node.js](#zainstaluj-nodejs)
|
||||
- [Zainstaluj Yarn](#zainstaluj-yarn)
|
||||
- [Zainstaluj zależności Node](#zainstaluj-zależności-node)
|
||||
- [Zainstaluj Python 3.9](#zainstaluj-python-39)
|
||||
- [Zainstaluj zależności Pythona](#zainstaluj-zależności-pythona)
|
||||
- [Zmienne środowiskowe](#zmienne-środowiskowe)
|
||||
- [Uruchomienie](#utwórz-kompilację-z-kodu-źródłowego)
|
||||
- [Run](#run)
|
||||
- [Tworzenie kompilacji](#tworzenie-kompilacji)
|
||||
- [Tworzenie klienta bittorrent](#zbuduj-klienta-bittorrent)
|
||||
- [Tworzenie kompilacji aplikacji Electron](#tworzenie-aplikacji-electron)
|
||||
- [Zbuduj klienta bittorrent](#zbuduj-klienta-bittorrent)
|
||||
- [Tworzenie aplikacji Electron](#tworzenie-aplikacji-electron)
|
||||
- [Współtwórcy](#współtwórcy)
|
||||
- [License](#license)
|
||||
|
||||
## O nas
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra é um Launcher de Jogos com seu próprio cliente de bittorrent integrado e um wrapper autogerenciado para busca de repacks.</strong>
|
||||
</p>
|
||||
@@ -13,13 +13,16 @@
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.be.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.md)
|
||||
[](README.pl.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,26 +30,28 @@
|
||||
|
||||
## Índice
|
||||
|
||||
- [Sobre](#about)
|
||||
- [Recursos](#features)
|
||||
- [Instalação](#installation)
|
||||
- [Contribuindo](#contributing)
|
||||
- [Junte-se ao nosso Telegram](#join-our-telegram)
|
||||
- [Fork e clone seu repositorio](#fork-and-clone-your-repository)
|
||||
- [Como contribuir](#ways-you-can-contribute)
|
||||
- [Estrutura do projeto](#project-structure)
|
||||
- [Compile a partir do código-fonte](#build-from-source)
|
||||
- [Instale Node.js](#install-nodejs)
|
||||
- [Instale Yarn](#install-yarn)
|
||||
- [Instale Node Dependencies](#install-node-dependencies)
|
||||
- [Instale Python 3.9](#install-python-39)
|
||||
- [Instale Python Dependencies](#install-python-dependencies)
|
||||
- [variaveis de ambiente](#environment-variables)
|
||||
- [Rodando o programa](#running)
|
||||
- [Compilando](#build)
|
||||
- [Compile o client bittorrent](#build-the-bittorrent-client)
|
||||
- [Compile a aplicação Electron](#build-the-electron-application)
|
||||
- [Contribuidores](#contributors)
|
||||
- [Índice](#índice)
|
||||
- [Sobre](#-sobre)
|
||||
- [Recursos](#-recursos)
|
||||
- [Instalação](#-instalação)
|
||||
- [Contribuindo](#-contribuindo)
|
||||
- [Junte-se ao nosso Telegram](#-junte-se-ao-nosso-telegram)
|
||||
- [Fork e clone o seu repositório](#-fork-e-clone-o-seu-repositório)
|
||||
- [Formas de contribuir](#-formas-de-contribuir)
|
||||
- [Estrutura do Projeto](#-estrutura-do-projeto)
|
||||
- [Compile a partir do código-fonte](#-compile-a-partir-do-código-fonte)
|
||||
- [Instale Node.js](#-instale-nodejs)
|
||||
- [Instale Yarn](#-instale-yarn)
|
||||
- [Instale Dependencias do Node](#-instale-dependencias-do-node)
|
||||
- [Instale Python 3.9](#-instale-python-39)
|
||||
- [Instale Python Dependencies](#-instale-python-dependencies)
|
||||
- [Environment variables](#-environment-variables)
|
||||
- [Running](#-running)
|
||||
- [Build](#-build)
|
||||
- [Build the bittorrent client](#-build-the-bittorrent-client)
|
||||
- [Build the Electron application](#-build-the-electron-application)
|
||||
- [Contributors](#-contributors)
|
||||
- [Licença](#-licença)
|
||||
|
||||
## <a name="about"> Sobre
|
||||
|
||||
|
||||
17
README.ru.md
17
README.ru.md
@@ -5,7 +5,7 @@
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra - это игровой лаунчер с собственным встроенным клиентом BitTorrent и самостоятельным scraper`ом для репаков.</strong>
|
||||
</p>
|
||||
@@ -13,13 +13,16 @@
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.be.md)
|
||||
[](README.md)
|
||||
[](README.pl.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,11 +30,12 @@
|
||||
|
||||
## Содержание
|
||||
|
||||
- [Содержание](#содержание)
|
||||
- [Описание](#описание)
|
||||
- [Особенности](#особенности)
|
||||
- [Установка](#установка)
|
||||
- [Вклад](#contributing)
|
||||
- [Присоединяйтесь к нашему Telegram](#join-our-telegram)
|
||||
- [Вклад](#-вклад)
|
||||
- [Присоединяйтесь к нашему Telegram](#-присоединяйтесь-к-нашему-telegram)
|
||||
- [Форк и клонирование репозитория](#форк-и-клонирование-репозитория)
|
||||
- [Способы внести свой вклад](#способы-внести-свой-вклад)
|
||||
- [Структура проекта](#структура-проекта)
|
||||
@@ -47,6 +51,7 @@
|
||||
- [Сборка клиента BitTorrent](#сборка-клиента-bittorrent)
|
||||
- [Сборка приложения Electron](#сборка-приложения-electron)
|
||||
- [Участники](#участники)
|
||||
- [License](#license)
|
||||
|
||||
## Описание
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[<img src="./resources/icon.png" width="144"/>](https://hydralauncher.site)
|
||||
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<strong>Hydra - це ігровий лаунчер з власним вбудованим bittorrent-клієнтом і самокерованим збирачем репаків.</strong>
|
||||
</p>
|
||||
@@ -13,13 +13,16 @@
|
||||
[](https://github.com/hydralauncher/hydra/actions)
|
||||
[](https://github.com/hydralauncher/hydra/releases)
|
||||
|
||||
[](README.be.md)
|
||||
[](README.md)
|
||||
[](README.pl.md)
|
||||
[](README.pt-BR.md)
|
||||
[](README.md)
|
||||
[](README.ru.md)
|
||||
[](README.uk-UA.md)
|
||||
[](README.be.md)
|
||||
[](README.es.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.it.md)
|
||||
[](README.cs.md)
|
||||
|
||||

|
||||
|
||||
@@ -27,11 +30,12 @@
|
||||
|
||||
## Зміст
|
||||
|
||||
- [Зміст](#зміст)
|
||||
- [Про нас](#про-нас)
|
||||
- [Функції](#функції)
|
||||
- [Встановлення](#встановлення)
|
||||
- [Зробити свій внесок](#contributing)
|
||||
- [Приєднуйтесь до нашого Telegram](#join-our-telegram)
|
||||
- [Зробити свій внесок](#-зробити-свій-внесок)
|
||||
- [Приєднуйтесь до нашого Telegram](#-приєднуйтесь-до-нашого-telegram)
|
||||
- [Форк і клонування вашого репозиторію](#форк-і-клонування-вашого-репозиторію)
|
||||
- [Як ви можете зробити свій внесок](#як-ви-можете-зробити-свій-внесок)
|
||||
- [Структура проекту](#структура-проекту)
|
||||
@@ -47,6 +51,7 @@
|
||||
- [Зробіть білд bittorrent client](#зробіть-білд-bittorrent-client)
|
||||
- [Зробіть білд Electron застосунку](#зробіть-білд-electron-застосунку)
|
||||
- [Контриб'ютори](#контрибютори)
|
||||
- [License](#license)
|
||||
|
||||
## Про нас
|
||||
|
||||
|
||||
68
SECURITY.md
Normal file
68
SECURITY.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Security Policy
|
||||
|
||||
## Purpose of the Policy
|
||||
|
||||
The purpose of this Security Policy is to ensure the security of our project and maintain the trust of the community.
|
||||
|
||||
## Who is Affected by the Policy
|
||||
|
||||
This policy applies to all members of our project community, including developers, testers, repository administrators, and users.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.0.x | :white_check_mark: |
|
||||
| < 1.2.0 | :x: |
|
||||
|
||||
## Development Recommendations
|
||||
|
||||
### Best Practices
|
||||
|
||||
- Follow secure coding principles.
|
||||
- Use well-established libraries and frameworks.
|
||||
- Regularly update dependencies.
|
||||
- Conduct thorough testing, including security-related tests.
|
||||
|
||||
### Unrecommended Practices
|
||||
|
||||
- Do not use known vulnerabilities that have not been patched.
|
||||
- Do not publish sensitive information such as API keys or passwords.
|
||||
- Do not vote for changes that degrade the security of the project.
|
||||
|
||||
### User-Generated Content
|
||||
|
||||
- Ensure that user-generated content does not contain hidden threats.
|
||||
- Be cautious when handling user data.
|
||||
|
||||
### Community Interaction
|
||||
|
||||
- Treat each other with respect and politeness.
|
||||
- Do not spread spam or spam bots.
|
||||
- Follow community guidelines.
|
||||
|
||||
### Vulnerability Discovery and Reporting
|
||||
|
||||
- If you discover a vulnerability, report it as an issue on GitHub.
|
||||
- Your report should contain detailed information about the vulnerability, including steps to resolve it.
|
||||
|
||||
### Reporting Method
|
||||
|
||||
To report a vulnerability, create a new issue on GitHub and use branch isolation to provide details about the vulnerability.
|
||||
|
||||
### Details to Provide
|
||||
|
||||
Please provide the following information about the vulnerability:
|
||||
|
||||
- Description of the vulnerability
|
||||
- Steps to resolve the vulnerability
|
||||
- Versions on which the vulnerability was found
|
||||
- Code examples illustrating the vulnerability (if it is safe to do so)
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
- If we accept the reported vulnerability, we will release a patch and update the security information on GitHub.
|
||||
- If we reject the reported vulnerability, we will provide an explanation.
|
||||
@@ -3,7 +3,6 @@ productName: Hydra
|
||||
directories:
|
||||
buildResources: build
|
||||
extraResources:
|
||||
- aria2
|
||||
- hydra-download-manager
|
||||
- seeds
|
||||
- from: node_modules/create-desktop-shortcuts/src/windows.vbs
|
||||
@@ -45,6 +44,7 @@ linux:
|
||||
- AppImage
|
||||
- snap
|
||||
- deb
|
||||
- pacman
|
||||
- rpm
|
||||
maintainer: electronjs.org
|
||||
category: Game
|
||||
|
||||
24
package.json
24
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydralauncher",
|
||||
"version": "2.0.2",
|
||||
"version": "2.1.4",
|
||||
"description": "Hydra",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "Los Broxas",
|
||||
@@ -23,28 +23,28 @@
|
||||
"start": "electron-vite preview",
|
||||
"dev": "electron-vite dev",
|
||||
"build": "npm run typecheck && electron-vite build",
|
||||
"postinstall": "electron-builder install-app-deps && node ./postinstall.cjs",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"build:unpack": "npm run build && electron-builder --dir",
|
||||
"build:win": "electron-vite build && electron-builder --win",
|
||||
"build:mac": "electron-vite build && electron-builder --mac",
|
||||
"build:linux": "electron-vite build && electron-builder --linux",
|
||||
"prepare": "husky",
|
||||
"typeorm:migration-create": "yarn typeorm migration:create"
|
||||
"knex:migrate:make": "knex --knexfile src/main/knexfile.ts migrate:make --esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron-toolkit/preload": "^3.0.0",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@fontsource/fira-mono": "^5.0.13",
|
||||
"@fontsource/fira-sans": "^5.0.20",
|
||||
"@fontsource/noto-sans": "^5.0.22",
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@primer/octicons-react": "^19.9.0",
|
||||
"@reduxjs/toolkit": "^2.2.3",
|
||||
"@sentry/electron": "^5.1.0",
|
||||
"@vanilla-extract/css": "^1.14.2",
|
||||
"@vanilla-extract/dynamic": "^2.1.1",
|
||||
"@vanilla-extract/recipes": "^0.5.2",
|
||||
"aria2": "^4.1.2",
|
||||
"auto-launch": "^5.0.6",
|
||||
"axios": "^1.6.8",
|
||||
"better-sqlite3": "^9.5.0",
|
||||
"axios": "^1.7.7",
|
||||
"better-sqlite3": "^11.2.1",
|
||||
"check-disk-space": "^3.4.0",
|
||||
"classnames": "^2.5.1",
|
||||
"color": "^4.2.3",
|
||||
@@ -54,18 +54,18 @@
|
||||
"electron-log": "^5.1.4",
|
||||
"electron-updater": "^6.1.8",
|
||||
"fetch-cookie": "^3.0.1",
|
||||
"file-type": "^19.0.0",
|
||||
"flexsearch": "^0.7.43",
|
||||
"i18next": "^23.11.2",
|
||||
"i18next-browser-languagedetector": "^7.2.1",
|
||||
"icojs": "^0.19.3",
|
||||
"iso-639-1": "3.1.2",
|
||||
"jsdom": "^24.0.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"knex": "^3.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lottie-react": "^2.4.0",
|
||||
"parse-torrent": "^11.0.16",
|
||||
"piscina": "^4.5.1",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-i18next": "^14.1.0",
|
||||
"react-loading-skeleton": "^3.4.0",
|
||||
"react-redux": "^9.1.1",
|
||||
@@ -74,6 +74,7 @@
|
||||
"typeorm": "^0.3.20",
|
||||
"user-agents": "^1.1.193",
|
||||
"yaml": "^2.4.1",
|
||||
"yup": "^1.4.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -96,7 +97,7 @@
|
||||
"@types/user-agents": "^1.0.4",
|
||||
"@vanilla-extract/vite-plugin": "^4.0.7",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"electron": "^30.0.9",
|
||||
"electron": "^30.3.0",
|
||||
"electron-builder": "^24.9.1",
|
||||
"electron-vite": "^2.0.0",
|
||||
"eslint": "^8.56.0",
|
||||
@@ -107,6 +108,7 @@
|
||||
"prettier": "^3.2.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.12",
|
||||
"vite-plugin-svgr": "^4.2.0"
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
const { default: axios } = require("axios");
|
||||
const util = require("node:util");
|
||||
const fs = require("node:fs");
|
||||
|
||||
const exec = util.promisify(require("node:child_process").exec);
|
||||
|
||||
const downloadAria2 = async () => {
|
||||
if (fs.existsSync("aria2")) {
|
||||
console.log("Aria2 already exists, skipping download...");
|
||||
return;
|
||||
}
|
||||
|
||||
const file =
|
||||
process.platform === "win32"
|
||||
? "aria2-1.37.0-win-64bit-build1.zip"
|
||||
: "aria2-1.37.0-1-x86_64.pkg.tar.zst";
|
||||
|
||||
const downloadUrl =
|
||||
process.platform === "win32"
|
||||
? `https://github.com/aria2/aria2/releases/download/release-1.37.0/${file}`
|
||||
: "https://archlinux.org/packages/extra/x86_64/aria2/download/";
|
||||
|
||||
console.log(`Downloading ${file}...`);
|
||||
|
||||
const response = await axios.get(downloadUrl, { responseType: "stream" });
|
||||
|
||||
const stream = response.data.pipe(fs.createWriteStream(file));
|
||||
|
||||
stream.on("finish", async () => {
|
||||
console.log(`Downloaded ${file}, extracting...`);
|
||||
|
||||
if (process.platform === "win32") {
|
||||
await exec(`npx extract-zip ${file}`);
|
||||
console.log("Extracted. Renaming folder...");
|
||||
|
||||
fs.renameSync(file.replace(".zip", ""), "aria2");
|
||||
} else {
|
||||
await exec(`tar --zstd -xvf ${file} usr/bin/aria2c`);
|
||||
console.log("Extracted. Copying binary file...");
|
||||
fs.mkdirSync("aria2");
|
||||
fs.copyFileSync("usr/bin/aria2c", "aria2/aria2c");
|
||||
fs.rmSync("usr", { recursive: true });
|
||||
}
|
||||
|
||||
console.log(`Extracted ${file}, removing compressed downloaded file...`);
|
||||
fs.rmSync(file);
|
||||
});
|
||||
};
|
||||
|
||||
downloadAria2();
|
||||
@@ -4,3 +4,4 @@ cx_Logging; sys_platform == 'win32'
|
||||
lief; sys_platform == 'win32'
|
||||
pywin32; sys_platform == 'win32'
|
||||
psutil
|
||||
Pillow
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "اَلْعَرَبِيَّةُ",
|
||||
"home": {
|
||||
"featured": "مميّز",
|
||||
"trending": "شائع",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "беларуская мова",
|
||||
"home": {
|
||||
"featured": "Рэкамэндаванае",
|
||||
"trending": "Актуальнае",
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"language_name": "Català",
|
||||
"app": {
|
||||
"successfully_signed_in": "Has entrat correctament"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Destacats",
|
||||
"trending": "Populars",
|
||||
@@ -14,7 +18,10 @@
|
||||
"paused": "{{title}} (Pausat)",
|
||||
"downloading": "{{title}} ({{percentage}} - S'està baixant…)",
|
||||
"filter": "Filtra la biblioteca",
|
||||
"home": "Inici"
|
||||
"home": "Inici",
|
||||
"queued": "{{title}} (En espera)",
|
||||
"game_has_no_executable": "El joc encara no té un executable seleccionat",
|
||||
"sign_in": "Entra"
|
||||
},
|
||||
"header": {
|
||||
"search": "Cerca jocs",
|
||||
@@ -29,7 +36,9 @@
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Cap baixada en curs",
|
||||
"downloading_metadata": "S'estan baixant les metadades de: {{title}}…",
|
||||
"downloading": "S'està baixant: {{title}}… ({{percentage}} complet) - Finalització: {{eta}} - {{speed}}"
|
||||
"downloading": "S'està baixant: {{title}}… ({{percentage}} complet) - Finalització: {{eta}} - {{speed}}",
|
||||
"calculating_eta": "Descarregant {{title}}… ({{percentage}} completat) - Calculant el temps restant…",
|
||||
"checking_files": "Comprovant els fitxers de {{title}}… ({{percentage}} completat)"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Pàgina següent",
|
||||
@@ -47,12 +56,14 @@
|
||||
"cancel": "Cancel·la",
|
||||
"remove": "Elimina",
|
||||
"space_left_on_disk": "{{space}} lliures al disc",
|
||||
"eta": "Finalització: {{eta}}",
|
||||
"eta": "Finalitza en: {{eta}}",
|
||||
"calculating_eta": "Calculant temps estimat…",
|
||||
"downloading_metadata": "S'estan baixant les metadades…",
|
||||
"filter": "Filtra els reempaquetats",
|
||||
"requirements": "Requisits del sistema",
|
||||
"minimum": "Mínims",
|
||||
"recommended": "Recomanats",
|
||||
"paused": "Paused",
|
||||
"release_date": "Publicat el {{date}}",
|
||||
"publisher": "Publicat per {{publisher}}",
|
||||
"hours": "hores",
|
||||
@@ -81,7 +92,29 @@
|
||||
"previous_screenshot": "Captura anterior",
|
||||
"next_screenshot": "Captura següent",
|
||||
"screenshot": "Captura {{number}}",
|
||||
"open_screenshot": "Obre la captura {{number}}"
|
||||
"open_screenshot": "Obre la captura {{number}}",
|
||||
"download_settings": "Configuració de descàrrega",
|
||||
"downloader": "Descarregador",
|
||||
"select_executable": "Selecciona",
|
||||
"no_executable_selected": "No hi ha executable selccionat",
|
||||
"open_folder": "Obre carpeta",
|
||||
"open_download_location": "Visualitzar fitxers descarregats",
|
||||
"create_shortcut": "Crear accés directe a l'escriptori",
|
||||
"remove_files": "Elimina fitxers",
|
||||
"remove_from_library_title": "Segur?",
|
||||
"remove_from_library_description": "Això eliminarà el videojoc {{game}} del teu catàleg",
|
||||
"options": "Opcions",
|
||||
"executable_section_title": "Executable",
|
||||
"executable_section_description": "Directori del fitxer des d'on s'executarà quan es cliqui a \"Executar\"",
|
||||
"downloads_secion_title": "Descàrregues",
|
||||
"downloads_section_description": "Comprova actualitzacions o altres versions del videojoc",
|
||||
"danger_zone_section_title": "Zona de perill",
|
||||
"danger_zone_section_description": "Elimina aquest videojoc del teu catàleg o els fitxers descarregats per Hydra",
|
||||
"download_in_progress": "Descàrrega en progrés",
|
||||
"download_paused": "Descàrrega en pausa",
|
||||
"last_downloaded_option": "Opció de l'última descàrrega",
|
||||
"create_shortcut_success": "Accés directe creat satisfactòriament",
|
||||
"create_shortcut_error": "Error al crear l'accés directe"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activa l'Hydra",
|
||||
@@ -98,6 +131,7 @@
|
||||
"paused": "Pausada",
|
||||
"verifying": "S'està verificant…",
|
||||
"completed": "Completada",
|
||||
"removed": "No descarregat",
|
||||
"cancel": "Cancel·la",
|
||||
"filter": "Filtra els jocs baixats",
|
||||
"remove": "Elimina",
|
||||
@@ -106,7 +140,14 @@
|
||||
"delete": "Elimina l'instal·lador",
|
||||
"delete_modal_title": "N'estàs segur?",
|
||||
"delete_modal_description": "S'eliminaran de l'ordinador tots els fitxers d'instal·lació",
|
||||
"install": "Instal·la"
|
||||
"install": "Instal·la",
|
||||
"download_in_progress": "En progrés",
|
||||
"queued_downloads": "Descàrregues en espera",
|
||||
"downloads_completed": "Completat",
|
||||
"queued": "En espera",
|
||||
"no_downloads_title": "Buit",
|
||||
"no_downloads_description": "No has descarregat res amb Hydra encara, però mai és tard per començar a fer-ho.",
|
||||
"checking_files": "Comprovant fitxers…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Ruta de baixades",
|
||||
@@ -119,16 +160,49 @@
|
||||
"launch_with_system": "Inicia l'Hydra quan s'iniciï el sistema",
|
||||
"general": "General",
|
||||
"behavior": "Comportament",
|
||||
"download_sources": "Fonts de descàrrega",
|
||||
"language": "Idioma",
|
||||
"real_debrid_api_token": "Testimoni API",
|
||||
"enable_real_debrid": "Activa el Real Debrid",
|
||||
"real_debrid_description": "Real-Debrid és un programa de descàrrega sense restriccions que us permet descarregar fitxers a l'instant i al màxim de la vostra velocitat d'Internet.",
|
||||
"real_debrid_invalid_token": "Invalida el testimoni de l'API",
|
||||
"real_debrid_api_token_hint": "Pots obtenir la teva clau de l'API <0>aquí</0>.",
|
||||
"save_changes": "Desa els canvis"
|
||||
"real_debrid_free_account_error": "L'usuari \"{{username}}\" és un compte gratuït. Si us plau subscriu-te a Real-Debrid",
|
||||
"real_debrid_linked_message": "Compte \"{{username}}\" vinculat",
|
||||
"save_changes": "Desa els canvis",
|
||||
"changes_saved": "Els canvis s'han desat correctament",
|
||||
"download_sources_description": "Hydra buscarà els enllaços de descàrrega d'aquestes fonts. L'URL d'origen ha de ser un enllaç directe a un fitxer .json que contingui els enllaços de descàrrega.",
|
||||
"validate_download_source": "Valida",
|
||||
"remove_download_source": "Elimina",
|
||||
"add_download_source": "Afegeix font",
|
||||
"download_count_zero": "No hi ha baixades a la llista",
|
||||
"download_count_one": "{{countFormatted}} a la llista de baixades",
|
||||
"download_count_other": "{{countFormatted}} baixades a la llista",
|
||||
"download_options_zero": "No hi ha cap descàrrega disponible",
|
||||
"download_options_one": "{{countFormatted}} descàrrega disponible",
|
||||
"download_options_other": "{{countFormatted}} baixades disponibles",
|
||||
"download_source_url": "Descarrega l'URL de la font",
|
||||
"add_download_source_description": "Inseriu la URL que conté el fitxer .json",
|
||||
"download_source_up_to_date": "Actualitzat",
|
||||
"download_source_errored": "S'ha produït un error",
|
||||
"sync_download_sources": "Sincronitza fonts",
|
||||
"removed_download_source": "S'ha eliminat la font de descàrrega",
|
||||
"added_download_source": "Added download source",
|
||||
"download_sources_synced": "Totes les fonts de descàrrega estan sincronitzades",
|
||||
"insert_valid_json_url": "Insereix una URL JSON vàlida",
|
||||
"found_download_option_zero": "No s'ha trobat cap opció de descàrrega",
|
||||
"found_download_option_one": "S'ha trobat l'opció de baixada de {{countFormatted}}",
|
||||
"found_download_option_other": "S'han trobat {{countFormatted}} opcions de baixada",
|
||||
"import": "Import"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "La baixada ha finalitzat",
|
||||
"game_ready_to_install": "{{title}} ja es pot instal·lar",
|
||||
"repack_list_updated": "S'ha actualitzat la llista de reempaquetats",
|
||||
"repack_count_one": "S'ha afegit {{count}} reempaquetat",
|
||||
"repack_count_other": "S'han afegit {{count}} reempaquetats"
|
||||
"repack_count_other": "S'han afegit {{count}} reempaquetats",
|
||||
"new_update_available": "Versió {{version}} disponible",
|
||||
"restart_to_install_update": "Reinicieu Hydra per instal·lar l'actualització"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Obre l'Hydra",
|
||||
@@ -144,5 +218,39 @@
|
||||
},
|
||||
"modal": {
|
||||
"close": "Botó de tancar"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Commuta la visibilitat de la contrasenya"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} hores",
|
||||
"amount_minutes": "{{amount}} minuts",
|
||||
"last_time_played": "Última partida {{period}}",
|
||||
"activity": "Activitat recent",
|
||||
"library": "Biblioteca",
|
||||
"total_play_time": "Temps total de joc:{{amount}}",
|
||||
"no_recent_activity_title": "Hmmm… encara no res",
|
||||
"no_recent_activity_description": "No has jugat a cap joc recentment. És el moment de canviar-ho!",
|
||||
"display_name": "Nom de visualització",
|
||||
"saving": "Desant",
|
||||
"save": "Desa",
|
||||
"edit_profile": "Edita el Perfil",
|
||||
"saved_successfully": "S'ha desat correctament",
|
||||
"try_again": "Siusplau torna-ho a provar",
|
||||
"sign_out_modal_title": "Segur?",
|
||||
"cancel": "Cancel·la",
|
||||
"successfully_signed_out": "S'ha tancat la sessió correctament",
|
||||
"sign_out": "Tanca sessió",
|
||||
"playing_for": "Jugant per {{amount}}",
|
||||
"sign_out_modal_text": "La vostra biblioteca està enllaçada amb el vostre compte actual. Quan tanqueu la sessió, la vostra biblioteca ja no serà visible i cap progrés no es desarà. Voleu continuar amb tancar la sessió?",
|
||||
"add_friends": "Afegeix amics",
|
||||
"add": "Afegeix",
|
||||
"friend_code": "Codi de l'amic",
|
||||
"see_profile": "Veure Perfil",
|
||||
"sending": "Enviant",
|
||||
"friend_request_sent": "Sol·licitud d'amistat enviada",
|
||||
"friends": "Amistats",
|
||||
"friends_list": "Llista d'amistats",
|
||||
"user_not_found": "Usuari no trobat"
|
||||
}
|
||||
}
|
||||
|
||||
272
src/locales/cs/translation.json
Normal file
272
src/locales/cs/translation.json
Normal file
@@ -0,0 +1,272 @@
|
||||
{
|
||||
"language_name": "Čeština",
|
||||
"app": {
|
||||
"successfully_signed_in": "Úspěšně přihlášen"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Doporučené",
|
||||
"trending": "Trendy",
|
||||
"surprise_me": "Překvap mě",
|
||||
"no_results": "Výsledek nenalezen"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Stažené",
|
||||
"settings": "Nastavení",
|
||||
"my_library": "Moje knihovna",
|
||||
"downloading_metadata": "{{title}} (Stahuji metadata…)",
|
||||
"paused": "{{title}} (Pozastaveno)",
|
||||
"downloading": "{{title}} ({{percentage}} - Stahuji…)",
|
||||
"filter": "Filtrovat knihovnu",
|
||||
"home": "Domov",
|
||||
"queued": "{{title}} (V řadě)",
|
||||
"game_has_no_executable": "Hra nemá zvolen žádný spustitelný soubor",
|
||||
"sign_in": "Přihlásit se"
|
||||
},
|
||||
"header": {
|
||||
"search": "Vyhledat hry",
|
||||
"home": "Domov",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Stažené",
|
||||
"search_results": "Výsledky vyhledávání",
|
||||
"settings": "Nastavení",
|
||||
"version_available_install": "Je dostupná nová verze: {{version}}. Klikni sem pro restart a instalaci.",
|
||||
"version_available_download": "Je dostupná nová verze: {{version}}. Klikni sem pro stažení."
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Neprobíhá žádné stahování",
|
||||
"downloading_metadata": "Stahuji metadata: {{title}}…",
|
||||
"downloading": "Stahuji {{title}}… ({{percentage}} staženo) - Odhadovaný čas {{eta}} - {{speed}}",
|
||||
"calculating_eta": "Stahuji {{title}}… ({{percentage}} staženo) - Počítám zbývající čas…",
|
||||
"checking_files": "Kontroluji soubory: {{title}}… ({{percentage}} ověřeno)"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Další strana",
|
||||
"previous_page": "Předchozí strana"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Otevřít možnosti stahování",
|
||||
"download_options_zero": "Žádné možnosti stahování",
|
||||
"download_options_one": "{{count}} možnost stažení",
|
||||
"download_options_other": "{{count}} možnosti stažení",
|
||||
"updated_at": "Aktualizováno {{updated_at}}",
|
||||
"install": "Instalovat",
|
||||
"resume": "Obnovit",
|
||||
"pause": "Pozastavit",
|
||||
"cancel": "Zrušit",
|
||||
"remove": "Odebrat",
|
||||
"space_left_on_disk": "{{space}} zbývá na disku",
|
||||
"eta": "Odhadovaný čas: {{eta}}",
|
||||
"calculating_eta": "Počítám zbývající čas…",
|
||||
"downloading_metadata": "Stahuji metadata…",
|
||||
"filter": "Filtrovat repacky",
|
||||
"requirements": "Systémové požadavky",
|
||||
"minimum": "Minimální",
|
||||
"recommended": "Doporučené",
|
||||
"paused": "Pozastaveno",
|
||||
"release_date": "Datum vydání: {{date}}",
|
||||
"publisher": "Publikováno: {{publisher}}",
|
||||
"hours": "hodiny",
|
||||
"minutes": "minuty",
|
||||
"amount_hours": "{{amount}} hodin",
|
||||
"amount_minutes": "{{amount}} minut",
|
||||
"accuracy": "Přesnost {{accuracy}}%",
|
||||
"add_to_library": "Přidat do knihovny",
|
||||
"remove_from_library": "Odebrat z knihovny",
|
||||
"no_downloads": "Žádné možnosti stahování nejsou dostupné",
|
||||
"play_time": "Odehraný čas: {{amount}}",
|
||||
"last_time_played": "Naposledy hráno {{period}}",
|
||||
"not_played_yet": "Ješte jste nehráli {{title}}",
|
||||
"next_suggestion": "Další doporučení",
|
||||
"play": "Hrát",
|
||||
"deleting": "Odstraňuji instalační program…",
|
||||
"close": "Zavřít",
|
||||
"playing_now": "Právě hraje",
|
||||
"change": "Změnit",
|
||||
"repacks_modal_description": "Vyber repack který chceš stáhnout",
|
||||
"select_folder_hint": "Pro změnu základní složky, jdi do <0>Nastavení</0>",
|
||||
"download_now": "Stáhnout",
|
||||
"no_shop_details": "Nepodařilo se mi načíst informace o obchodu.",
|
||||
"download_options": "Možnosti stahování",
|
||||
"download_path": "Umístění stahování",
|
||||
"previous_screenshot": "Předchozí snímek obrazovky",
|
||||
"next_screenshot": "Následující snímek obrazovky",
|
||||
"screenshot": "Snímek obrazovky {{number}}",
|
||||
"open_screenshot": "Otevřít snímek obrazovky {{number}}",
|
||||
"download_settings": "Nastavení stahování",
|
||||
"downloader": "Správce stahování",
|
||||
"select_executable": "Vybrat",
|
||||
"no_executable_selected": "Nebyl vybrán spustitelný soubor",
|
||||
"open_folder": "Otevřít složku",
|
||||
"open_download_location": "Zobrazit stažené soubory",
|
||||
"create_shortcut": "Vytvořit zástupce na ploše",
|
||||
"remove_files": "Odebrat soubory",
|
||||
"remove_from_library_title": "Jste si jisti?",
|
||||
"remove_from_library_description": "Tohle odstraní {{game}} z vaší knihovny",
|
||||
"options": "Možnosti",
|
||||
"executable_section_title": "Spustitelné",
|
||||
"executable_section_description": "Umístění souboru který bude spuštěn při kliknutí na \"Hrát\"",
|
||||
"downloads_secion_title": "Stažené soubory",
|
||||
"downloads_section_description": "Zkontrolovat jestli není nová / odlišná verze hry",
|
||||
"danger_zone_section_title": "Nebezpečná zóna",
|
||||
"danger_zone_section_description": "Odebrat hru z knihovny / soubory stažené Hydrou",
|
||||
"download_in_progress": "Probíhá stahování",
|
||||
"download_paused": "Stahování pozastaveno",
|
||||
"last_downloaded_option": "Poslední stažená možnost",
|
||||
"create_shortcut_success": "Zástupce vytvořen úspěšně",
|
||||
"create_shortcut_error": "Chyba při pokusu vytvořit zástupce"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Aktivovat hydru",
|
||||
"installation_id": "ID instalace:",
|
||||
"enter_activation_code": "Zadej svůj aktivační kód",
|
||||
"message": "Pokud nevíš, kde ten kód sehnat, tak by jsi k tomuhle neměl mít přístup.",
|
||||
"activate": "Aktivovat",
|
||||
"loading": "Načítání…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Pokračovat",
|
||||
"pause": "Pozastavit",
|
||||
"eta": "Odhadovaný čas: {{eta}}",
|
||||
"paused": "Pozastaveno",
|
||||
"verifying": "Ověřuji…",
|
||||
"completed": "Hotovo",
|
||||
"removed": "Není staženo",
|
||||
"cancel": "Zrušit",
|
||||
"filter": "Filtrovat stažené hry",
|
||||
"remove": "Odebrat",
|
||||
"downloading_metadata": "Stahuji metadata…",
|
||||
"deleting": "Odstraňuji instalační program…",
|
||||
"delete": "Odebrat instalační program",
|
||||
"delete_modal_title": "Jste si jisti?",
|
||||
"delete_modal_description": "Tohle odstraní všechny instalační soubory",
|
||||
"install": "Instalovat",
|
||||
"download_in_progress": "Probíhá stahování",
|
||||
"queued_downloads": "Stahování v řadě",
|
||||
"downloads_completed": "Dokončeno",
|
||||
"queued": "V řadě",
|
||||
"no_downloads_title": "Prázdno..",
|
||||
"no_downloads_description": "Ještě jsi zatím nic nestáhl přes Hydru, ale furt není pozdě začít.",
|
||||
"checking_files": "Kontroluji soubory…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Umístění stahování",
|
||||
"change": "Aktualizovat",
|
||||
"notifications": "Upozornění",
|
||||
"enable_download_notifications": "Až bude stahování dokončeno",
|
||||
"enable_repack_list_notifications": "Když bude přidán nový repack",
|
||||
"real_debrid_api_token_label": "Real-Debrid API token",
|
||||
"quit_app_instead_hiding": "Nezavírat Hydru při zavření okna",
|
||||
"launch_with_system": "Spustit Hydru při startu systému",
|
||||
"general": "Hlavní",
|
||||
"behavior": "Chování",
|
||||
"download_sources": "Zdroje stahování",
|
||||
"language": "Jazyk",
|
||||
"real_debrid_api_token": "API Token",
|
||||
"enable_real_debrid": "Povolit Real-Debrid",
|
||||
"real_debrid_description": "Real-Debrid je neomezený správce stahování, který umožňuje stahovat soubory v nejvyšší rychlosti vašeho internetu.",
|
||||
"real_debrid_invalid_token": "Neplatný API token",
|
||||
"real_debrid_api_token_hint": "API token můžeš sehnat <0>zde</0>",
|
||||
"real_debrid_free_account_error": "Účet \"{{username}}\" má základní úroveň. Prosím předplaťte si Real-Debrid",
|
||||
"real_debrid_linked_message": "Účet \"{{username}}\" je propojen",
|
||||
"save_changes": "Uložit změny",
|
||||
"changes_saved": "Změny úspěšně uloženy",
|
||||
"download_sources_description": "Hydra bude odsud sbírat soubory. Zdrojový odkaz musí být .json soubor obsahující odkazy na soubory.",
|
||||
"validate_download_source": "Ověřit",
|
||||
"remove_download_source": "Odebrat",
|
||||
"add_download_source": "Přidat zdroj",
|
||||
"download_count_zero": "Žádná možnost stažení",
|
||||
"download_count_one": "{{countFormatted}} možnost stažení",
|
||||
"download_count_other": "{{countFormatted}} možnosti stažení",
|
||||
"download_source_url": "Stáhnout zdrojový odkaz",
|
||||
"add_download_source_description": "Zadej odkaz odkazující na .json soubor",
|
||||
"download_source_up_to_date": "Aktuální",
|
||||
"download_source_errored": "Chyba",
|
||||
"sync_download_sources": "Synchronizovat zdroje",
|
||||
"removed_download_source": "Zdroj odebrán",
|
||||
"added_download_source": "Zdroj přidán",
|
||||
"download_sources_synced": "Všechny zdroje jsou synchronizovány",
|
||||
"insert_valid_json_url": "Zadej platnou JSON adresu",
|
||||
"found_download_option_zero": "Nenalezena žádná možnost stahování",
|
||||
"found_download_option_one": "Nalezena {{countFormatted}} možnost stahování",
|
||||
"found_download_option_other": "Nalezeny {{countFormatted}} možnosti stahování",
|
||||
"import": "Importovat"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Stahování dokončeno",
|
||||
"game_ready_to_install": "{{title}} je připraveno k instalaci",
|
||||
"repack_list_updated": "Seznam repacků byl aktualizován",
|
||||
"repack_count_one": "{{count}} repack přidán",
|
||||
"repack_count_other": "{{count}} repacky přidány",
|
||||
"new_update_available": "Version {{version}} je dostupná",
|
||||
"restart_to_install_update": "Restartuj Hydru pro aktualizaci"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Otevřít Hydru",
|
||||
"quit": "Odejít"
|
||||
},
|
||||
"game_card": {
|
||||
"no_downloads": "Žádné možnosti stahování nenalezeny"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Programy nenainstalovány",
|
||||
"description": "Spustitelné soubory Wine nebo Lutris nebyly nalezeny ve vašem systému",
|
||||
"instructions": "Zkonstroluj oficiální cestu jak je nainstalovat na tvoji Linux Distribuci, aby hry mohly běžet normálně"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Tlačítko zavřít"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Přepnout viditelnost hesla"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} hodin",
|
||||
"amount_minutes": "{{amount}} minut",
|
||||
"last_time_played": "Naposledy hráno {{period}}",
|
||||
"activity": "Nedávná aktivita",
|
||||
"library": "Knihovna",
|
||||
"total_play_time": "Celkový odehraný čas: {{amount}}",
|
||||
"no_recent_activity_title": "Hmmm… nic tu není",
|
||||
"no_recent_activity_description": "V poslední době si nehrál žádnout hru, můžeš to ale napravit!",
|
||||
"display_name": "Zobrazované jméno",
|
||||
"saving": "Ukládání",
|
||||
"save": "Uložit",
|
||||
"edit_profile": "Upravit profil",
|
||||
"saved_successfully": "Úspěšně uloženo",
|
||||
"try_again": "Prosím, zkuste to znovu",
|
||||
"sign_out_modal_title": "Jste si jisti?",
|
||||
"cancel": "Zrušit",
|
||||
"successfully_signed_out": "Úspěšně odhlášeno",
|
||||
"sign_out": "Odhlásit se",
|
||||
"playing_for": "Hraje po: {{amount}}",
|
||||
"sign_out_modal_text": "Vaše knihovna je propojena s vaším současným účtem. Po odhlášení vaše knihovna již nebude vidět, a postup nebude uložen. Pokračovat?",
|
||||
"add_friends": "Přidat přátele",
|
||||
"add": "Přidat",
|
||||
"friend_code": "Kód přítele",
|
||||
"see_profile": "Zobrazit profil",
|
||||
"sending": "Odesílání",
|
||||
"friend_request_sent": "Žádost odeslána",
|
||||
"friends": "Přátelé",
|
||||
"friends_list": "Seznam přátel",
|
||||
"user_not_found": "Uživatel nenalezen",
|
||||
"block_user": "Zablokovat uživatele",
|
||||
"add_friend": "Přidat přítele",
|
||||
"request_sent": "Žádost odeslána",
|
||||
"request_received": "Žádost obdržena",
|
||||
"accept_request": "Přijmout žádost",
|
||||
"ignore_request": "Ignorovat žádost",
|
||||
"cancel_request": "Zrušit žádost",
|
||||
"undo_friendship": "Odvolat přátelství",
|
||||
"request_accepted": "Žádost přijata",
|
||||
"user_blocked_successfully": "Uživatel úspěšně zablokován",
|
||||
"user_block_modal_text": "Tohle zablokuje {{displayName}}",
|
||||
"blocked_users": "Zablokovaní uživatelé",
|
||||
"unblock": "Odblokovat",
|
||||
"no_friends_added": "Nemáš přidané žádné přátele",
|
||||
"pending": "Odchozí",
|
||||
"no_pending_invites": "Nemáte žádné příchozí žádosti",
|
||||
"no_blocked_users": "Nemáte nikoho zablokovaného",
|
||||
"friend_code_copied": "Kód přítele zkopírován",
|
||||
"undo_friendship_modal_text": "Tímto zrušíte své přátelství s {{displayName}}"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Dansk",
|
||||
"home": {
|
||||
"featured": "Anbefalet",
|
||||
"trending": "Trender",
|
||||
|
||||
272
src/locales/de/translation.json
Normal file
272
src/locales/de/translation.json
Normal file
@@ -0,0 +1,272 @@
|
||||
{
|
||||
"language_name": "Deutsch",
|
||||
"app": {
|
||||
"successfully_signed_in": "Erfolgreich angemeldet"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Empfohlen",
|
||||
"trending": "Beliebt",
|
||||
"surprise_me": "Überrasche mich",
|
||||
"no_results": "Keine Ergebnisse gefunden"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Downloads",
|
||||
"settings": "Einstellungen",
|
||||
"my_library": "Meine Bibliothek",
|
||||
"downloading_metadata": "{{title}} (Metadaten werden heruntergeladen…)",
|
||||
"paused": "{{title}} (Pausiert)",
|
||||
"downloading": "{{title}} ({{percentage}} - Wird heruntergeladen…)",
|
||||
"filter": "Bibliothek filtern",
|
||||
"home": "Home",
|
||||
"queued": "{{title}} (In Warteschlange)",
|
||||
"game_has_no_executable": "Spiel hat keine ausführbare Datei gewählt",
|
||||
"sign_in": "Anmelden"
|
||||
},
|
||||
"header": {
|
||||
"search": "Spiele suchen",
|
||||
"home": "Home",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Downloads",
|
||||
"search_results": "Suchergebnisse",
|
||||
"settings": "Einstellungen",
|
||||
"version_available_install": "Version {{version}} verfügbar. Klicke hier, um neuzustarten und sie zu installieren.",
|
||||
"version_available_download": "Version {{version}} verfügbar. Klicke hier, um sie herunterzuladen."
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Keine aktive Downloads",
|
||||
"downloading_metadata": "Metadaten von {{title}} werden heruntergeladen…",
|
||||
"downloading": "{{title}} wird heruntergeladen… ({{percentage}} abgeschlossen) - Abschluss {{eta}} - {{speed}}",
|
||||
"calculating_eta": "{{title}} wird heruntergeladen… ({{percentage}} abgeschlossen) - Verbleibende Zeit wird berechnet…",
|
||||
"checking_files": "Prüfe Dateien von {{title}}… ({{percentage}} abgeschlossen)"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Nächste Seite",
|
||||
"previous_page": "Vorherige Seite"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Download-Optionen öffnen",
|
||||
"download_options_zero": "Keine Download-Optionen",
|
||||
"download_options_one": "{{count}} Download-Option",
|
||||
"download_options_other": "{{count}} Download-Optionen",
|
||||
"updated_at": "Aktualisiert {{updated_at}}",
|
||||
"install": "Installieren",
|
||||
"resume": "Fortfahren",
|
||||
"pause": "Pausieren",
|
||||
"cancel": "Abbrechen",
|
||||
"remove": "Entfernen",
|
||||
"space_left_on_disk": "{{space}} auf Festplatte verfügbar",
|
||||
"eta": "Abschluss {{eta}}",
|
||||
"calculating_eta": "Verbleibende Zeit wird berechnet…",
|
||||
"downloading_metadata": "Metadaten werden heruntergeladen…",
|
||||
"filter": "Repacks filtern",
|
||||
"requirements": "Systemanforderungen",
|
||||
"minimum": "Minimum",
|
||||
"recommended": "Empfohlen",
|
||||
"paused": "Pausiert",
|
||||
"release_date": "Veröffentlicht am {{date}}",
|
||||
"publisher": "Veröffentlicht von {{publisher}}",
|
||||
"hours": "Stunden",
|
||||
"minutes": "Minuten",
|
||||
"amount_hours": "{{amount}} Stunden",
|
||||
"amount_minutes": "{{amount}} Minuten",
|
||||
"accuracy": "{{accuracy}}% Genauigkeit",
|
||||
"add_to_library": "Zu Bibliothek hinzufügen",
|
||||
"remove_from_library": "Von Bibliothek entfernen",
|
||||
"no_downloads": "Keine Downloads verfügbar",
|
||||
"play_time": "{{amount}} lang gespielt",
|
||||
"last_time_played": "Zuletzt gespielt {{period}}",
|
||||
"not_played_yet": "{{title}} wurde noch nicht gespielt",
|
||||
"next_suggestion": "Nächste Empfehlung",
|
||||
"play": "Spielen",
|
||||
"deleting": "Installer wird gelöscht…",
|
||||
"close": "Schließen",
|
||||
"playing_now": "Spielt jetzt",
|
||||
"change": "Ändern",
|
||||
"repacks_modal_description": "Wähle das Repack, das du herunterladen möchtest",
|
||||
"select_folder_hint": "Um das Standardverzeichnis zu ändern, gehe zu den <0>Einstellungen</0>",
|
||||
"download_now": "Jetzt herunterladen",
|
||||
"no_shop_details": "Shop-Details konnten nicht abgerufen werden.",
|
||||
"download_options": "Download-Optionen",
|
||||
"download_path": "Download-Verzeichnis",
|
||||
"previous_screenshot": "Vorheriger Screenshot",
|
||||
"next_screenshot": "Nächster Screenshot",
|
||||
"screenshot": "Screenshot {{number}}",
|
||||
"open_screenshot": "Screenshot {{number}} öffnen",
|
||||
"download_settings": "Download-Einstellungen",
|
||||
"downloader": "Downloader",
|
||||
"select_executable": "Auswählen",
|
||||
"no_executable_selected": "Keine ausführbare Datei gewählt",
|
||||
"open_folder": "Verzeichnis öffnen",
|
||||
"open_download_location": "Heruntergeladene Dateien anzeigen",
|
||||
"create_shortcut": "Desktop-Verknüpfung erstellen",
|
||||
"remove_files": "Dateien entfernen",
|
||||
"remove_from_library_title": "Bist du dir sicher?",
|
||||
"remove_from_library_description": "Dies wird {{game}} aus deiner Bibliothek entfernen",
|
||||
"options": "Optionen",
|
||||
"executable_section_title": "Ausführbare Datei",
|
||||
"executable_section_description": "Pfad der Datei, die bei Klick auf \"Play\" ausgeführt wird",
|
||||
"downloads_secion_title": "Downloads",
|
||||
"downloads_section_description": "Sieh dir Updates oder andere Versionen dieses Spiels an",
|
||||
"danger_zone_section_title": "Gefahrenzone",
|
||||
"danger_zone_section_description": "Entferne dieses Spiel aus deiner Bibliothek oder die von Hydra heruntergeladenen Dateien",
|
||||
"download_in_progress": "Download erfolgt",
|
||||
"download_paused": "Download ist pausiert",
|
||||
"last_downloaded_option": "Letzte Download-Option",
|
||||
"create_shortcut_success": "Verknüpfung erfolgreich erstellt",
|
||||
"create_shortcut_error": "Fehler bei Erstellung von Verknüpfung"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Hydra aktivieren",
|
||||
"installation_id": "Installations ID:",
|
||||
"enter_activation_code": "Aktivierungscode eingeben",
|
||||
"message": "Wenn du nicht weißt wo du fragen musst, solltest du dies nicht haben.",
|
||||
"activate": "Aktivieren",
|
||||
"loading": "Lädt…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Fortfahren",
|
||||
"pause": "Pause",
|
||||
"eta": "Abschluss {{eta}}",
|
||||
"paused": "Pausiert",
|
||||
"verifying": "Verifiziere…",
|
||||
"completed": "Abgeschlossen",
|
||||
"removed": "Nicht heruntergeladen",
|
||||
"cancel": "Abbrechen",
|
||||
"filter": "Heruntergeladene Spiele filtern",
|
||||
"remove": "Entfernen",
|
||||
"downloading_metadata": "Metadaten werden heruntergeladen…",
|
||||
"deleting": "Installer wird entfernt…",
|
||||
"delete": "Installer entfernen",
|
||||
"delete_modal_title": "Bist du dir sicher?",
|
||||
"delete_modal_description": "Dies wird alle Installationsdateien von deinem Computer entfernen",
|
||||
"install": "Installieren",
|
||||
"download_in_progress": "Läuft",
|
||||
"queued_downloads": "Downloads in Warteschlange",
|
||||
"downloads_completed": "Abgeschlossen",
|
||||
"queued": "In Warteschlange",
|
||||
"no_downloads_title": "Welch Leere",
|
||||
"no_downloads_description": "Du hast mit Hydra noch nichts heruntergeladen, aber es ist nie zu spät anzufangen.",
|
||||
"checking_files": "Dateien werden überprüft…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Download-Pfad",
|
||||
"change": "Aktualisieren",
|
||||
"notifications": "Benachrichtigungen",
|
||||
"enable_download_notifications": "Wenn ein Download abgeschlossen wird",
|
||||
"enable_repack_list_notifications": "Wenn ein neues Repack hinzugefügt wird",
|
||||
"real_debrid_api_token_label": "Real-Debrid API Token",
|
||||
"quit_app_instead_hiding": "Hydra verlassen statt minimieren beim Schließen",
|
||||
"launch_with_system": "Hydra bei Systemstart starten",
|
||||
"general": "Allgemein",
|
||||
"behavior": "Verhalten",
|
||||
"download_sources": "Download-Quellen",
|
||||
"language": "Sprache",
|
||||
"real_debrid_api_token": "API Token",
|
||||
"enable_real_debrid": "Real-Debrid aktivieren",
|
||||
"real_debrid_description": "Real-Debrid ist ein unrestriktiver Downloader, der es dir ermöglicht Dateien sofort und mit deiner maximalen Internetgeschwindigkeit herunterzuladen.",
|
||||
"real_debrid_invalid_token": "API token nicht gültig",
|
||||
"real_debrid_api_token_hint": "<0>Hier</0> kannst du dir deinen API Token holen",
|
||||
"real_debrid_free_account_error": "Das Konto \"{{username}}\" ist ein gratis account. Bitte abonniere Real-Debrid",
|
||||
"real_debrid_linked_message": "Konto \"{{username}}\" verknüpft",
|
||||
"save_changes": "Änderungen speichern",
|
||||
"changes_saved": "Änderungen erfolgreich gespeichert",
|
||||
"download_sources_description": "Hydra wird die Download-Links von diesen Quellen abrufen. Die Quell-URL muss ein direkter Link zu einer .json Datei, welche die Download-Links enthält, sein.",
|
||||
"validate_download_source": "Validieren",
|
||||
"remove_download_source": "Entfernen",
|
||||
"add_download_source": "Quelle hinzufügen",
|
||||
"download_count_zero": "Keine Download-Option",
|
||||
"download_count_one": "{{countFormatted}} Download-Option",
|
||||
"download_count_other": "{{countFormatted}} Download-Optionen",
|
||||
"download_source_url": "Download Quell-URL",
|
||||
"add_download_source_description": "Füge die URL, welche die .json Datei enthält, ein",
|
||||
"download_source_up_to_date": "Auf aktuellem Stand",
|
||||
"download_source_errored": "Fehlgeschlagen",
|
||||
"sync_download_sources": "Quellen synchronisieren",
|
||||
"removed_download_source": "Download-Quelle entfernt",
|
||||
"added_download_source": "Download-Quelle hinzugefügt",
|
||||
"download_sources_synced": "Alle Download-Quellen sind synchronisiert",
|
||||
"insert_valid_json_url": "Füge eine gültige JSON URL ein",
|
||||
"found_download_option_zero": "Keine Download-Option gefunden",
|
||||
"found_download_option_one": "{{countFormatted}} Download-Option gefunden",
|
||||
"found_download_option_other": "{{countFormatted}} Download-Optionen gefunden",
|
||||
"import": "Importieren"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download abgeschlossen",
|
||||
"game_ready_to_install": "{{title}} ist bereit zur Installation",
|
||||
"repack_list_updated": "Repack-Liste aktualisiert",
|
||||
"repack_count_one": "{{count}} Repack hinzugefügt",
|
||||
"repack_count_other": "{{count}} Repacks hinzugefügt",
|
||||
"new_update_available": "Version {{version}} verfügbar",
|
||||
"restart_to_install_update": "Um das Update zu installieren, starte Hydra neu"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Hydra öffnen",
|
||||
"quit": "Schließen"
|
||||
},
|
||||
"game_card": {
|
||||
"no_downloads": "Keine Downloads verfügbar"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Programme nicht installiert",
|
||||
"description": "Ausführbare Dateien für Wine oder Lutris wurden auf deinem System nicht gefunden",
|
||||
"instructions": "Überprüfe die korrekte Installation dieser für deine Linux-Distro, damit das Spiel normal laufen kann"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Knopf schließen"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Sichtbarkeit des Passworts umschalten"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} Stunden",
|
||||
"amount_minutes": "{{amount}} Minuten",
|
||||
"last_time_played": "Zuletzt gespielt {{period}}",
|
||||
"activity": "Letzte Aktivität",
|
||||
"library": "Bibliothek",
|
||||
"total_play_time": "Gesamtspielzeit: {{amount}}",
|
||||
"no_recent_activity_title": "Hmmm… hier ist nichts",
|
||||
"no_recent_activity_description": "Du hast in letzter Zeit keine Spiele gespielt. Es wird Zeit das zu ändern!",
|
||||
"display_name": "Anzeigename",
|
||||
"saving": "Speichert",
|
||||
"save": "Speichern",
|
||||
"edit_profile": "Profil Bearbeiten",
|
||||
"saved_successfully": "Erfolgreich gespeichert",
|
||||
"try_again": "Bitte versuche es erneut",
|
||||
"sign_out_modal_title": "Bist du dir sicher?",
|
||||
"cancel": "Abbrechen",
|
||||
"successfully_signed_out": "Erfolgreich abgemeldet",
|
||||
"sign_out": "Abmelden",
|
||||
"playing_for": "Spielt {{amount}} lang",
|
||||
"sign_out_modal_text": "Deine Bibliothek ist mit deinem aktuellen Konto verknüpft. Wenn du dich abmeldest, wird deine Bibliothek nicht mehr sichtbar sein und jeglicher Fortschritt wird nicht gespeichert. Abmelden fortführen?",
|
||||
"add_friends": "Freunde hinzufügen",
|
||||
"add": "Hinzufügen",
|
||||
"friend_code": "Freundescode",
|
||||
"see_profile": "Profil anzeigen",
|
||||
"sending": "Sendet",
|
||||
"friend_request_sent": "Freundschaftsanfrage versendet",
|
||||
"friends": "Freunde",
|
||||
"friends_list": "Freundesliste",
|
||||
"user_not_found": "Nutzer nicht gefunden",
|
||||
"block_user": "Nutzer blockieren",
|
||||
"add_friend": "Freund hinzufügen",
|
||||
"request_sent": "Anfrage versendet",
|
||||
"request_received": "Anfrage erhalten",
|
||||
"accept_request": "Anfrage annehmen",
|
||||
"ignore_request": "Anfrage ignorieren",
|
||||
"cancel_request": "Anfrage zurückziehen",
|
||||
"undo_friendship": "Freundschaft kündigen",
|
||||
"request_accepted": "Anfrage akzeptiert",
|
||||
"user_blocked_successfully": "Nutzer erfolgreich blockiert",
|
||||
"user_block_modal_text": "{{displayName}} wird dadurch blockiert",
|
||||
"blocked_users": "Blockierte Nutzer",
|
||||
"unblock": "Freigeben",
|
||||
"no_friends_added": "Du hast noch keine Freunde hinzugefügt",
|
||||
"pending": "Ausstehend",
|
||||
"no_pending_invites": "Du hast keine ausstehenden Einladungen",
|
||||
"no_blocked_users": "Du hast keine blockierten Nutzer",
|
||||
"friend_code_copied": "Freundescode kopiert",
|
||||
"undo_friendship_modal_text": "Freundschaft mit {{displayName}} wird dadurch gekündigt"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "English",
|
||||
"app": {
|
||||
"successfully_signed_in": "Successfully signed in"
|
||||
},
|
||||
@@ -6,7 +7,10 @@
|
||||
"featured": "Featured",
|
||||
"trending": "Trending",
|
||||
"surprise_me": "Surprise me",
|
||||
"no_results": "No results found"
|
||||
"no_results": "No results found",
|
||||
"start_typing": "Starting typing to search...",
|
||||
"hot": "Hot now",
|
||||
"weekly": "📅 Top games of the week"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Catalogue",
|
||||
@@ -20,7 +24,8 @@
|
||||
"home": "Home",
|
||||
"queued": "{{title}} (Queued)",
|
||||
"game_has_no_executable": "Game has no executable selected",
|
||||
"sign_in": "Sign in"
|
||||
"sign_in": "Sign in",
|
||||
"friends": "Friends"
|
||||
},
|
||||
"header": {
|
||||
"search": "Search games",
|
||||
@@ -113,7 +118,19 @@
|
||||
"download_paused": "Download paused",
|
||||
"last_downloaded_option": "Last downloaded option",
|
||||
"create_shortcut_success": "Shortcut created successfully",
|
||||
"create_shortcut_error": "Error creating shortcut"
|
||||
"create_shortcut_error": "Error creating shortcut",
|
||||
"nsfw_content_title": "This game contains innapropriate content",
|
||||
"nsfw_content_description": "{{title}} contains content that may not be suitable for all ages. Are you sure you want to continue?",
|
||||
"allow_nsfw_content": "Continue",
|
||||
"refuse_nsfw_content": "Go back",
|
||||
"stats": "Stats",
|
||||
"download_count": "Downloads",
|
||||
"player_count": "Active players",
|
||||
"download_error": "This download option is not available",
|
||||
"download": "Download",
|
||||
"executable_path_in_use": "Executable already in use by \"{{game}}\"",
|
||||
"warning": "Warning:",
|
||||
"hydra_needs_to_remain_open": "for this download, Hydra needs to remain open util its conclusion. In case Hydra closes before the conclusion, you will lose your progress."
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activate Hydra",
|
||||
@@ -174,12 +191,9 @@
|
||||
"validate_download_source": "Validate",
|
||||
"remove_download_source": "Remove",
|
||||
"add_download_source": "Add source",
|
||||
"download_count_zero": "No downloads in list",
|
||||
"download_count_one": "{{countFormatted}} download in list",
|
||||
"download_count_other": "{{countFormatted}} downloads in list",
|
||||
"download_options_zero": "No download available",
|
||||
"download_options_one": "{{countFormatted}} download available",
|
||||
"download_options_other": "{{countFormatted}} downloads available",
|
||||
"download_count_zero": "No download options",
|
||||
"download_count_one": "{{countFormatted}} download option",
|
||||
"download_count_other": "{{countFormatted}} download options",
|
||||
"download_source_url": "Download source URL",
|
||||
"add_download_source_description": "Insert the URL containing the .json file",
|
||||
"download_source_up_to_date": "Up-to-date",
|
||||
@@ -192,14 +206,27 @@
|
||||
"found_download_option_zero": "No download option found",
|
||||
"found_download_option_one": "Found {{countFormatted}} download option",
|
||||
"found_download_option_other": "Found {{countFormatted}} download options",
|
||||
"import": "Import"
|
||||
"import": "Import",
|
||||
"public": "Public",
|
||||
"private": "Private",
|
||||
"friends_only": "Friends only",
|
||||
"privacy": "Privacy",
|
||||
"profile_visibility": "Profile visibility",
|
||||
"profile_visibility_description": "Choose who can see your profile and library",
|
||||
"required_field": "This field is required",
|
||||
"source_already_exists": "This source has been already added",
|
||||
"must_be_valid_url": "The source must be a valid URL",
|
||||
"blocked_users": "Blocked users",
|
||||
"user_unblocked": "User has been unblocked"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download complete",
|
||||
"game_ready_to_install": "{{title}} is ready to install",
|
||||
"repack_list_updated": "Repack list updated",
|
||||
"repack_count_one": "{{count}} repack added",
|
||||
"repack_count_other": "{{count}} repacks added"
|
||||
"repack_count_other": "{{count}} repacks added",
|
||||
"new_update_available": "Version {{version}} available",
|
||||
"restart_to_install_update": "Restart Hydra to install the update"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Open Hydra",
|
||||
@@ -239,6 +266,51 @@
|
||||
"successfully_signed_out": "Successfully signed out",
|
||||
"sign_out": "Sign out",
|
||||
"playing_for": "Playing for {{amount}}",
|
||||
"sign_out_modal_text": "Your library is linked with your current account. When signing out, your library will not be visible anymore, and any progress will not be saved. Continue with sign out?"
|
||||
"sign_out_modal_text": "Your library is linked with your current account. When signing out, your library will not be visible anymore, and any progress will not be saved. Continue with sign out?",
|
||||
"add_friends": "Add Friends",
|
||||
"add": "Add",
|
||||
"friend_code": "Friend code",
|
||||
"see_profile": "See profile",
|
||||
"sending": "Sending",
|
||||
"friend_request_sent": "Friend request sent",
|
||||
"friends": "Friends",
|
||||
"friends_list": "Friends list",
|
||||
"user_not_found": "User not found",
|
||||
"block_user": "Block user",
|
||||
"add_friend": "Add friend",
|
||||
"request_sent": "Request sent",
|
||||
"request_received": "Request received",
|
||||
"accept_request": "Accept request",
|
||||
"ignore_request": "Ignore request",
|
||||
"cancel_request": "Cancel request",
|
||||
"undo_friendship": "Undo friendship",
|
||||
"request_accepted": "Request accepted",
|
||||
"user_blocked_successfully": "User blocked successfully",
|
||||
"user_block_modal_text": "This will block {{displayName}}",
|
||||
"blocked_users": "Blocked users",
|
||||
"unblock": "Unblock",
|
||||
"no_friends_added": "You still don't have added friends",
|
||||
"pending": "Pending",
|
||||
"no_pending_invites": "You have no pending invites",
|
||||
"no_blocked_users": "You have no blocked users",
|
||||
"friend_code_copied": "Friend code copied",
|
||||
"undo_friendship_modal_text": "This will undo your friendship with {{displayName}}",
|
||||
"privacy_hint": "To adjust who can see this, go to the <0>Settings</0>",
|
||||
"locked_profile": "This profile is private",
|
||||
"image_process_failure": "Failure while processing the image",
|
||||
"required_field": "This field is required",
|
||||
"displayname_min_length": "Display name must be at least 3 characters long",
|
||||
"displayname_max_length": "Display name must be at most 50 characters long",
|
||||
"report_profile": "Report this profile",
|
||||
"report_reason": "Why are you reporting this profile?",
|
||||
"report_description": "Additional information",
|
||||
"report_description_placeholder": "Additional information",
|
||||
"report": "Report",
|
||||
"report_reason_hate": "Hate speech",
|
||||
"report_reason_sexual_content": "Sexual content",
|
||||
"report_reason_violence": "Violence",
|
||||
"report_reason_spam": "Spam",
|
||||
"report_reason_other": "Other",
|
||||
"profile_reported": "Profile reported"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Español",
|
||||
"app": {
|
||||
"successfully_signed_in": "Sesión iniciada correctamente"
|
||||
},
|
||||
@@ -6,7 +7,10 @@
|
||||
"featured": "Destacado",
|
||||
"trending": "Tendencias",
|
||||
"surprise_me": "¡Sorpréndeme!",
|
||||
"no_results": "No se encontraron resultados"
|
||||
"no_results": "No se encontraron resultados",
|
||||
"hot": "Caliente ahora",
|
||||
"weekly": "📅 Los mejores juegos de la semana",
|
||||
"start_typing": "Empieza a escribir para buscar..."
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Catálogo",
|
||||
@@ -20,7 +24,8 @@
|
||||
"home": "Inicio",
|
||||
"queued": "{{title}} (En Cola)",
|
||||
"game_has_no_executable": "El juego no tiene un ejecutable",
|
||||
"sign_in": "Iniciar sesión"
|
||||
"sign_in": "Iniciar sesión",
|
||||
"friends": "Amigos"
|
||||
},
|
||||
"header": {
|
||||
"search": "Buscar juegos",
|
||||
@@ -48,7 +53,7 @@
|
||||
"download_options_zero": "No hay opciones de descargas disponibles",
|
||||
"download_options_one": "{{count}} opción de descarga",
|
||||
"download_options_other": "{{count}} opciones de descargas",
|
||||
"updated_at": "Actualizado el {{updated_at}}",
|
||||
"updated_at": "Actualizado el: {{updated_at}}",
|
||||
"install": "Instalar",
|
||||
"resume": "Continuar",
|
||||
"pause": "Pausa",
|
||||
@@ -74,7 +79,7 @@
|
||||
"remove_from_library": "Eliminar de la biblioteca",
|
||||
"no_downloads": "No hay descargas disponibles",
|
||||
"play_time": "Jugado por {{amount}}",
|
||||
"last_time_played": "Jugado por última vez {{period}}",
|
||||
"last_time_played": "Jugado por última vez: {{period}}",
|
||||
"not_played_yet": "Aún no has jugado a {{title}}",
|
||||
"next_suggestion": "Siguiente sugerencia",
|
||||
"play": "Jugar",
|
||||
@@ -107,13 +112,23 @@
|
||||
"executable_section_description": "Ruta del archivo que se ejecutará cuando se presione \"Jugar\"",
|
||||
"downloads_secion_title": "Descargas",
|
||||
"downloads_section_description": "Buscar actualizaciones u otras versiones de este juego",
|
||||
"danger_zone_section_title": "Zona de Peligro",
|
||||
"danger_zone_section_description": "Eliminar este juego de tu librería o los archivos descargados por Hydra",
|
||||
"danger_zone_section_title": "Opciones Avanzadas",
|
||||
"danger_zone_section_description": "Eliminar este juego de tu librería o los archivos descargados por Hydra (Esto solo eliminará los archivos de instalación y no el juego instalado)",
|
||||
"download_in_progress": "Descarga en progreso",
|
||||
"download_paused": "Descarga pausada",
|
||||
"last_downloaded_option": "Última opción descargada",
|
||||
"create_shortcut_success": "Atajo creado con éxito",
|
||||
"create_shortcut_error": "Error al crear un atajo"
|
||||
"create_shortcut_error": "Error al crear un atajo",
|
||||
"allow_nsfw_content": "Continuar",
|
||||
"download": "Descargar",
|
||||
"download_count": "Descargas",
|
||||
"download_error": "Esta opción de descarga no está disponible.",
|
||||
"executable_path_in_use": "Ejecutable ya en uso por \"{{game}}\"",
|
||||
"nsfw_content_description": "{{title}} incluye contenido que puede no ser adecuado para todas las edades. \n¿Estás seguro de que quieres continuar?",
|
||||
"nsfw_content_title": "Este juego contiene contenido inapropiado.",
|
||||
"player_count": "Jugadores activos",
|
||||
"refuse_nsfw_content": "Volver",
|
||||
"stats": "Estadísticas"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activar Hydra",
|
||||
@@ -138,7 +153,7 @@
|
||||
"deleting": "Eliminando instalador…",
|
||||
"delete": "Eliminar instalador",
|
||||
"delete_modal_title": "¿Estás seguro?",
|
||||
"delete_modal_description": "Esto eliminará todos los archivos de instalación de tu computadora.",
|
||||
"delete_modal_description": "Esto eliminará todos los archivos de la instalación del repack del juego de tu computadora. (Si ya instalaste el juego, puedes eliminar esto, no afectará al juego)",
|
||||
"install": "Instalar",
|
||||
"download_in_progress": "En progreso",
|
||||
"queued_downloads": "Descargas en cola",
|
||||
@@ -177,9 +192,6 @@
|
||||
"download_count_zero": "No hay descargas en la lista",
|
||||
"download_count_one": "{{countFormatted}} descarga en la lista",
|
||||
"download_count_other": "{{countFormatted}} descargas en la lista",
|
||||
"download_options_zero": "No hay descargas disponibles",
|
||||
"download_options_one": "{{countFormatted}} descarga disponible",
|
||||
"download_options_other": "{{countFormatted}} descargas disponibles",
|
||||
"download_source_url": "Descargar URL de origen",
|
||||
"add_download_source_description": "Introduce la URL con el archivo .json",
|
||||
"download_source_up_to_date": "Al día",
|
||||
@@ -192,14 +204,30 @@
|
||||
"found_download_option_zero": "No se encontró una opción de descarga",
|
||||
"found_download_option_one": "Se encontró {{countFormatted}} opción de descarga",
|
||||
"found_download_option_other": "Se encontraron {{countFormatted}} opciones de descarga",
|
||||
"import": "Importar"
|
||||
"import": "Importar",
|
||||
"blocked_users": "Usuarios bloqueados",
|
||||
"download_options_one": "",
|
||||
"download_options_other": "",
|
||||
"download_options_zero": "",
|
||||
"friends_only": "solo amigos",
|
||||
"must_be_valid_url": "La fuente debe ser una URL válida.",
|
||||
"privacy": "Privacidad",
|
||||
"private": "Privado",
|
||||
"profile_visibility": "Visibilidad del perfil",
|
||||
"profile_visibility_description": "Elige quién puede ver tu perfil y biblioteca",
|
||||
"public": "Público",
|
||||
"required_field": "Este campo es obligatorio",
|
||||
"source_already_exists": "Esta fuente ya ha sido agregada.",
|
||||
"user_unblocked": "El usuario ha sido desbloqueado"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Descarga completada",
|
||||
"game_ready_to_install": "{{title}} está listo para instalarse",
|
||||
"repack_list_updated": "Lista de repacks actualizadas",
|
||||
"repack_count_one": "{{count}} repack ha sido añadido",
|
||||
"repack_count_other": "{{count}} repacks añadidos"
|
||||
"repack_count_other": "{{count}} repacks añadidos",
|
||||
"new_update_available": "Version {{version}} disponible",
|
||||
"restart_to_install_update": "Reinicia Hydra para instalar la actualización"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Abrir Hydra",
|
||||
@@ -222,13 +250,13 @@
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} horas",
|
||||
"amount_minutes": "{{amount}} minutos",
|
||||
"last_time_played": "Última vez jugado {{period}}",
|
||||
"last_time_played": "Última vez jugado: {{period}}",
|
||||
"activity": "Actividad reciente",
|
||||
"library": "Biblioteca",
|
||||
"total_play_time": "Total de tiempo jugado: {{amount}}",
|
||||
"no_recent_activity_title": "Que raro, no hay nada por acá, ¿que tal si jugamos algo para empezar?",
|
||||
"no_recent_activity_title": "Que raro, no hay nada por acá...",
|
||||
"no_recent_activity_description": "No has jugado ningún juego recientemente, ¡vamos a cambiar eso ahora!",
|
||||
"display_name": "Nombre a mostrar",
|
||||
"display_name": "Nombre en pantalla",
|
||||
"saving": "Guardando",
|
||||
"save": "Guardar",
|
||||
"edit_profile": "Editar perfil",
|
||||
@@ -239,6 +267,52 @@
|
||||
"successfully_signed_out": "Sesión cerrada exitosamente",
|
||||
"sign_out": "Cerrar sesión",
|
||||
"playing_for": "Jugando por {{amount}}",
|
||||
"sign_out_modal_text": "Tu biblioteca se ha vinculado con tu cuenta. Cuando cierres sesión, tú biblioteca ya no será visible y cualquier progreso no se guardará. ¿Continuar con el cierre de sesión?"
|
||||
"sign_out_modal_text": "Tu biblioteca se ha vinculado con tu cuenta. Cuando cierres sesión, tú biblioteca ya no será visible y cualquier progreso no se guardará. ¿Continuar con el cierre de sesión?",
|
||||
"add_friends": "Añadir amigos",
|
||||
"add": "Añadir",
|
||||
"friend_code": "Código de amigo",
|
||||
"see_profile": "Ver perfil",
|
||||
"sending": "Enviando",
|
||||
"friend_request_sent": "Solicitud de amistad enviada",
|
||||
"friends": "Amigos",
|
||||
"friends_list": "Lista de amigos",
|
||||
"user_not_found": "Usuario no encontrado",
|
||||
"block_user": "Bloquear usuario",
|
||||
"add_friend": "Añadir amigo",
|
||||
"request_sent": "Solicitud enviada",
|
||||
"request_received": "Solicitud recibida",
|
||||
"accept_request": "Aceptar solicitud",
|
||||
"ignore_request": "Ignorar solicitud",
|
||||
"cancel_request": "Cancelar solicitud",
|
||||
"undo_friendship": "Eliminar amistad",
|
||||
"request_accepted": "Solicitud aceptada",
|
||||
"user_blocked_successfully": "Usuario bloqueado exitosamente",
|
||||
"user_block_modal_text": "Esto va a bloquear a {{displayName}}",
|
||||
"blocked_users": "Usuarios bloqueados",
|
||||
"unblock": "Desbloquear",
|
||||
"no_friends_added": "Todavía no tienes amigos añadidos",
|
||||
"pending": "Pendiente",
|
||||
"no_pending_invites": "No tienes invitaciones pendientes",
|
||||
"no_blocked_users": "No has bloqueado a ningún usuario",
|
||||
"friend_code_copied": "Código de amigo copiado",
|
||||
"undo_friendship_modal_text": "Esto deshará tu amistad con {{displayName}}",
|
||||
"displayname_max_length": "El nombre para mostrar debe tener como máximo 50 caracteres",
|
||||
"displayname_min_length": "El nombre para mostrar debe tener al menos 3 caracteres",
|
||||
"locked_profile": "Este perfil es privado.",
|
||||
"privacy_hint": "Para ajustar quién puede ver esto, ve a <0>Configuración</0>.",
|
||||
"profile_locked": "",
|
||||
"profile_reported": "Perfil reportado",
|
||||
"report": "Informe",
|
||||
"report_description": "Información adicional",
|
||||
"report_description_placeholder": "Información adicional",
|
||||
"report_profile": "Reportar este perfil",
|
||||
"report_reason": "¿Por qué estás denunciando este perfil?",
|
||||
"report_reason_hate": "Discurso de odio",
|
||||
"report_reason_other": "Otro",
|
||||
"report_reason_sexual_content": "Contenido sexual",
|
||||
"report_reason_spam": "Correo basura",
|
||||
"report_reason_violence": "Violencia",
|
||||
"required_field": "Este campo es obligatorio",
|
||||
"image_process_failure": "Error al procesar la imagen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "فارسی",
|
||||
"home": {
|
||||
"featured": "پیشنهادی",
|
||||
"trending": "پرطرفدار",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Français",
|
||||
"home": {
|
||||
"featured": "En vedette",
|
||||
"trending": "Tendance",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Magyar",
|
||||
"home": {
|
||||
"featured": "Featured",
|
||||
"trending": "Népszerű",
|
||||
|
||||
@@ -1,134 +1,256 @@
|
||||
{
|
||||
"language_name": "Bahasa Indonesia",
|
||||
"app": {
|
||||
"successfully_signed_in": "Berhasil masuk"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Unggulan",
|
||||
"trending": "Trending",
|
||||
"surprise_me": "Kejutkan Saya",
|
||||
"no_results": "Tidak ada hasil"
|
||||
"trending": "Sedang Tren",
|
||||
"surprise_me": "Kejutkan saya",
|
||||
"no_results": "Tidak ada hasil ditemukan"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Unduhan",
|
||||
"settings": "Pengaturan",
|
||||
"my_library": "Koleksi saya",
|
||||
"my_library": "Perpustakaan saya",
|
||||
"downloading_metadata": "{{title}} (Mengunduh metadata…)",
|
||||
"paused": "{{title}} (Terhenti)",
|
||||
"paused": "{{title}} (Dijeda)",
|
||||
"downloading": "{{title}} ({{percentage}} - Mengunduh…)",
|
||||
"filter": "Filter koleksi",
|
||||
"home": "Beranda"
|
||||
"filter": "Filter perpustakaan",
|
||||
"home": "Beranda",
|
||||
"queued": "{{title}} (Antrian)",
|
||||
"game_has_no_executable": "Game tidak punya file eksekusi yang dipilih",
|
||||
"sign_in": "Masuk"
|
||||
},
|
||||
"header": {
|
||||
"search": "Pencarian",
|
||||
"search": "Cari game",
|
||||
"home": "Beranda",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Unduhan",
|
||||
"search_results": "Hasil pencarian",
|
||||
"settings": "Pengaturan"
|
||||
"settings": "Pengaturan",
|
||||
"version_available_install": "Versi {{version}} tersedia. Klik di sini untuk restart dan instal.",
|
||||
"version_available_download": "Versi {{version}} tersedia. Klik di sini untuk unduh."
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Tidak ada unduhan berjalan",
|
||||
"downloading_metadata": "Mengunduh metadata {{title}}...",
|
||||
"downloading": "Mengunduh {{title}}… ({{percentage}} selesai) - Perkiraan {{eta}} - {{speed}}"
|
||||
"no_downloads_in_progress": "Tidak ada unduhan yang sedang berjalan",
|
||||
"downloading_metadata": "Mengunduh metadata {{title}}…",
|
||||
"downloading": "Mengunduh {{title}}… ({{percentage}} selesai) - Estimasi selesai {{eta}} - {{speed}}",
|
||||
"calculating_eta": "Mengunduh {{title}}… ({{percentage}} selesai) - Menghitung waktu yang tersisa…",
|
||||
"checking_files": "Memeriksa file {{title}}… ({{percentage}} selesai)"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Halaman berikutnya",
|
||||
"previous_page": "Halaman sebelumnya"
|
||||
"next_page": "Halaman Berikutnya",
|
||||
"previous_page": "Halaman Sebelumnya"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Buka opsi unduhan",
|
||||
"download_options_zero": "Tidak ada opsi unduhan",
|
||||
"download_options_one": "{{count}} opsi unduhan",
|
||||
"download_options_other": "{{count}} opsi unduhan",
|
||||
"updated_at": "Diperbarui {{updated_at}}",
|
||||
"install": "Install",
|
||||
"updated_at": "Diperbarui pada {{updated_at}}",
|
||||
"install": "Instal",
|
||||
"resume": "Lanjutkan",
|
||||
"pause": "Hentikan sementara",
|
||||
"cancel": "Batalkan",
|
||||
"pause": "Jeda",
|
||||
"cancel": "Batal",
|
||||
"remove": "Hapus",
|
||||
"space_left_on_disk": "{{space}} tersisa pada disk",
|
||||
"eta": "Perkiraan {{eta}}",
|
||||
"space_left_on_disk": "{{space}} tersisa di disk",
|
||||
"eta": "Estimasi {{eta}}",
|
||||
"calculating_eta": "Menghitung waktu yang tersisa…",
|
||||
"downloading_metadata": "Mengunduh metadata…",
|
||||
"filter": "Saring repacks",
|
||||
"requirements": "Keperluan sistem",
|
||||
"filter": "Filter repack",
|
||||
"requirements": "Persyaratan sistem",
|
||||
"minimum": "Minimum",
|
||||
"recommended": "Rekomendasi",
|
||||
"recommended": "Dianjurkan",
|
||||
"paused": "Dijeda",
|
||||
"release_date": "Dirilis pada {{date}}",
|
||||
"publisher": "Dipublikasikan oleh {{publisher}}",
|
||||
"publisher": "Diterbitkan oleh {{publisher}}",
|
||||
"hours": "jam",
|
||||
"minutes": "menit",
|
||||
"amount_hours": "{{amount}} jam",
|
||||
"amount_minutes": "{{amount}} menit",
|
||||
"accuracy": "{{accuracy}}% akurasi",
|
||||
"add_to_library": "Tambahkan ke koleksi",
|
||||
"remove_from_library": "Hapus dari koleksi",
|
||||
"no_downloads": "Tidak ada unduhan tersedia",
|
||||
"add_to_library": "Tambah ke perpustakaan",
|
||||
"remove_from_library": "Hapus dari perpustakaan",
|
||||
"no_downloads": "Tidak ada yang bisa diunduh",
|
||||
"play_time": "Dimainkan selama {{amount}}",
|
||||
"last_time_played": "Terakhir dimainkan {{period}}",
|
||||
"not_played_yet": "Kamu belum memainkan {{title}}",
|
||||
"next_suggestion": "Rekomendasi berikutnya",
|
||||
"play": "Mainkan",
|
||||
"next_suggestion": "Saran berikutnya",
|
||||
"play": "Main",
|
||||
"deleting": "Menghapus installer…",
|
||||
"close": "Tutup",
|
||||
"playing_now": "Memainkan sekarang",
|
||||
"playing_now": "Sedang dimainkan",
|
||||
"change": "Ubah",
|
||||
"repacks_modal_description": "Pilih repack yang kamu ingin unduh",
|
||||
"select_folder_hint": "Untuk merubah folder bawaan, akses melalui",
|
||||
"download_now": "Unduh sekarang"
|
||||
"repacks_modal_description": "Pilih repack yang ingin kamu unduh",
|
||||
"select_folder_hint": "Untuk ganti folder default, buka <0>Pengaturan</0>",
|
||||
"download_now": "Unduh sekarang",
|
||||
"no_shop_details": "Gagal mendapatkan detail toko.",
|
||||
"download_options": "Opsi unduhan",
|
||||
"download_path": "Path unduhan",
|
||||
"previous_screenshot": "Screenshot sebelumnya",
|
||||
"next_screenshot": "Screenshot berikutnya",
|
||||
"screenshot": "Screenshot {{number}}",
|
||||
"open_screenshot": "Buka screenshot {{number}}",
|
||||
"download_settings": "Pengaturan unduhan",
|
||||
"downloader": "Pengunduh",
|
||||
"select_executable": "Pilih",
|
||||
"no_executable_selected": "Tidak ada file eksekusi yang dipilih",
|
||||
"open_folder": "Buka folder",
|
||||
"open_download_location": "Lihat file yang diunduh",
|
||||
"create_shortcut": "Buat pintasan desktop",
|
||||
"remove_files": "Hapus file",
|
||||
"remove_from_library_title": "Apa kamu yakin?",
|
||||
"remove_from_library_description": "Ini akan menghapus {{game}} dari perpustakaan kamu",
|
||||
"options": "Opsi",
|
||||
"executable_section_title": "Eksekusi",
|
||||
"executable_section_description": "Path file eksekusi saat \"Main\" diklik",
|
||||
"downloads_secion_title": "Unduhan",
|
||||
"downloads_section_description": "Cek update atau versi lain dari game ini",
|
||||
"danger_zone_section_title": "Zona Berbahaya",
|
||||
"danger_zone_section_description": "Hapus game ini dari perpustakaan kamu atau file yang diunduh oleh Hydra",
|
||||
"download_in_progress": "Sedang mengunduh",
|
||||
"download_paused": "Unduhan dijeda",
|
||||
"last_downloaded_option": "Opsi terakhir diunduh",
|
||||
"create_shortcut_success": "Pintasan berhasil dibuat",
|
||||
"create_shortcut_error": "Gagal membuat pintasan"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Aktivasi Hydra",
|
||||
"installation_id": "ID instalasi:",
|
||||
"enter_activation_code": "Masukkan kode aktivasi",
|
||||
"message": "Jika kamu tidak tau dimana bertanya untuk ini, maka kamu tidak seharusnya memiliki ini.",
|
||||
"title": "Aktifkan Hydra",
|
||||
"installation_id": "ID Instalasi:",
|
||||
"enter_activation_code": "Masukkan kode aktivasi kamu",
|
||||
"message": "Kalau tidak tahu harus tanya ke siapa, berarti kamu tidak perlu ini.",
|
||||
"activate": "Aktifkan",
|
||||
"loading": "Memuat…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Lanjutkan",
|
||||
"pause": "Hentikan sementara",
|
||||
"eta": "Perkiraan {{eta}}",
|
||||
"paused": "Terhenti sementara",
|
||||
"verifying": "Memeriksa…",
|
||||
"pause": "Jeda",
|
||||
"eta": "Estimasi {{eta}}",
|
||||
"paused": "Dijeda",
|
||||
"verifying": "Verifikasi…",
|
||||
"completed": "Selesai",
|
||||
"cancel": "Batalkan",
|
||||
"filter": "Saring game yang diunduh",
|
||||
"removed": "Tidak diunduh",
|
||||
"cancel": "Batal",
|
||||
"filter": "Filter game yang diunduh",
|
||||
"remove": "Hapus",
|
||||
"downloading_metadata": "Mengunduh metadata…",
|
||||
"deleting": "Menghapus file instalasi…",
|
||||
"delete": "Hapus file instalasi",
|
||||
"delete_modal_title": "Kamu yakin?",
|
||||
"delete_modal_description": "Proses ini akan menghapus semua file instalasi dari komputer kamu",
|
||||
"install": "Install"
|
||||
"deleting": "Menghapus installer…",
|
||||
"delete": "Hapus installer",
|
||||
"delete_modal_title": "Apa kamu yakin?",
|
||||
"delete_modal_description": "Ini akan menghapus semua file instalasi dari komputer kamu",
|
||||
"install": "Instal",
|
||||
"download_in_progress": "Sedang berlangsung",
|
||||
"queued_downloads": "Unduhan dalam antrian",
|
||||
"downloads_completed": "Selesai",
|
||||
"queued": "Dalam antrian",
|
||||
"no_downloads_title": "Kosong",
|
||||
"no_downloads_description": "Kamu belum mengunduh apa pun dengan Hydra, tapi belum terlambat untuk mulai.",
|
||||
"checking_files": "Memeriksa file…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Lokasi unduhan",
|
||||
"change": "Perbarui",
|
||||
"notifications": "Pengingat",
|
||||
"downloads_path": "Path unduhan",
|
||||
"change": "Ganti",
|
||||
"notifications": "Notifikasi",
|
||||
"enable_download_notifications": "Saat unduhan selesai",
|
||||
"enable_repack_list_notifications": "Saat repack terbaru ditambahkan",
|
||||
"enable_repack_list_notifications": "Saat ada repack baru",
|
||||
"real_debrid_api_token_label": "Token API Real-Debrid",
|
||||
"quit_app_instead_hiding": "Jangan sembunyikan Hydra saat ditutup",
|
||||
"launch_with_system": "Jalankan Hydra saat sistem dinyalakan",
|
||||
"general": "Umum",
|
||||
"behavior": "Perilaku",
|
||||
"quit_app_instead_hiding": "Tutup aplikasi alih-alih menyembunyikan aplikasi",
|
||||
"launch_with_system": "Jalankan saat memulai sistem"
|
||||
"download_sources": "Sumber unduhan",
|
||||
"language": "Bahasa",
|
||||
"real_debrid_api_token": "Token API",
|
||||
"enable_real_debrid": "Aktifkan Real-Debrid",
|
||||
"real_debrid_description": "Real-Debrid adalah downloader tanpa batas yang memungkinkan kamu untuk mengunduh file dengan cepat dan pada kecepatan terbaik dari Internet kamu.",
|
||||
"real_debrid_invalid_token": "Token API tidak valid",
|
||||
"real_debrid_api_token_hint": "Kamu bisa dapatkan token API di <0>sini</0>",
|
||||
"real_debrid_free_account_error": "Akun \"{{username}}\" adalah akun gratis. Silakan berlangganan Real-Debrid",
|
||||
"real_debrid_linked_message": "Akun \"{{username}}\" terhubung",
|
||||
"save_changes": "Simpan perubahan",
|
||||
"changes_saved": "Perubahan disimpan berhasil",
|
||||
"download_sources_description": "Hydra akan mencari link unduhan dari sini. URL harus menuju file .json dengan link unduhan.",
|
||||
"validate_download_source": "Validasi",
|
||||
"remove_download_source": "Hapus",
|
||||
"add_download_source": "Tambahkan sumber",
|
||||
"download_count_zero": "Tidak ada unduhan dalam daftar",
|
||||
"download_count_one": "{{countFormatted}} unduhan dalam daftar",
|
||||
"download_count_other": "{{countFormatted}} unduhan dalam daftar",
|
||||
"download_options_zero": "Tidak ada unduhan tersedia",
|
||||
"download_options_one": "{{countFormatted}} unduhan tersedia",
|
||||
"download_options_other": "{{countFormatted}} unduhan tersedia",
|
||||
"download_source_url": "URL sumber unduhan",
|
||||
"add_download_source_description": "Masukkan URL yang berisi file .json",
|
||||
"download_source_up_to_date": "Terkini",
|
||||
"download_source_errored": "Terjadi kesalahan",
|
||||
"sync_download_sources": "Sinkronkan sumber",
|
||||
"removed_download_source": "Sumber unduhan dihapus",
|
||||
"added_download_source": "Sumber unduhan ditambahkan",
|
||||
"download_sources_synced": "Semua sumber unduhan disinkronkan",
|
||||
"insert_valid_json_url": "Masukkan URL JSON yang valid",
|
||||
"found_download_option_zero": "Tidak ada opsi unduhan ditemukan",
|
||||
"found_download_option_one": "Ditemukan {{countFormatted}} opsi unduhan",
|
||||
"found_download_option_other": "Ditemukan {{countFormatted}} opsi unduhan",
|
||||
"import": "Impor"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Unduhan selesai",
|
||||
"game_ready_to_install": "{{title}} sudah siap untuk instalasi",
|
||||
"game_ready_to_install": "{{title}} siap untuk diinstal",
|
||||
"repack_list_updated": "Daftar repack diperbarui",
|
||||
"repack_count_one": "{{count}} repack ditambahkan",
|
||||
"repack_count_other": "{{count}} repack ditambahkan"
|
||||
"repack_count_other": "{{count}} repack ditambahkan",
|
||||
"new_update_available": "Versi {{version}} tersedia",
|
||||
"restart_to_install_update": "Restart Hydra untuk instal pembaruan"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Buka Hydra",
|
||||
"quit": "Tutup"
|
||||
"quit": "Keluar"
|
||||
},
|
||||
"game_card": {
|
||||
"no_downloads": "Tidak ada unduhan tersedia"
|
||||
"no_downloads": "Tidak ada unduhan yang tersedia"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Program tidak terinstal",
|
||||
"description": "Wine atau Lutris exe tidak ditemukan pada sistem kamu",
|
||||
"instructions": "Periksa cara instalasi yang benar pada Linux distro-mu agar game dapat dimainkan dengan benar"
|
||||
"title": "Program tidak terpasang",
|
||||
"description": "Executable Wine atau Lutris tidak ditemukan di sistem kamu",
|
||||
"instructions": "Cek cara instalasi yang benar di distro Linux kamu agar game bisa jalan normal"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Tombol tutup"
|
||||
"close": "Tutup"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Tampilkan/Sembunyikan kata sandi"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} jam",
|
||||
"amount_minutes": "{{amount}} menit",
|
||||
"last_time_played": "Terakhir dimainkan {{period}}",
|
||||
"activity": "Aktivitas terbaru",
|
||||
"library": "Perpustakaan",
|
||||
"total_play_time": "Total waktu bermain: {{amount}}",
|
||||
"no_recent_activity_title": "Hmm… kosong di sini",
|
||||
"no_recent_activity_description": "Kamu belum main game baru-baru ini. Yuk, mulai main!",
|
||||
"display_name": "Nama tampilan",
|
||||
"saving": "Menyimpan",
|
||||
"save": "Simpan",
|
||||
"edit_profile": "Edit Profil",
|
||||
"saved_successfully": "Berhasil disimpan",
|
||||
"try_again": "Coba lagi yuk",
|
||||
"sign_out_modal_title": "Apa kamu yakin?",
|
||||
"cancel": "Batal",
|
||||
"successfully_signed_out": "Berhasil keluar",
|
||||
"sign_out": "Keluar",
|
||||
"playing_for": "Bermain selama {{amount}}",
|
||||
"sign_out_modal_text": "Perpustakaan kamu terhubung dengan akun saat ini. Saat keluar, perpustakaan kamu tidak akan terlihat lagi, dan progres tidak akan disimpan. Lanjutkan keluar?",
|
||||
"add_friends": "Tambah Teman",
|
||||
"add": "Tambah",
|
||||
"friend_code": "Kode teman",
|
||||
"see_profile": "Lihat profil",
|
||||
"sending": "Mengirim",
|
||||
"friend_request_sent": "Permintaan teman terkirim",
|
||||
"friends": "Teman",
|
||||
"friends_list": "Daftar teman",
|
||||
"user_not_found": "Pengguna tidak ditemukan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,51 @@
|
||||
export { default as en } from "./en/translation.json";
|
||||
export { default as pt } from "./pt/translation.json";
|
||||
export { default as es } from "./es/translation.json";
|
||||
export { default as nl } from "./nl/translation.json";
|
||||
export { default as fr } from "./fr/translation.json";
|
||||
export { default as hu } from "./hu/translation.json";
|
||||
export { default as it } from "./it/translation.json";
|
||||
export { default as pl } from "./pl/translation.json";
|
||||
export { default as ru } from "./ru/translation.json";
|
||||
export { default as tr } from "./tr/translation.json";
|
||||
export { default as be } from "./be/translation.json";
|
||||
export { default as uk } from "./uk/translation.json";
|
||||
export { default as zh } from "./zh/translation.json";
|
||||
export { default as id } from "./id/translation.json";
|
||||
export { default as ko } from "./ko/translation.json";
|
||||
export { default as da } from "./da/translation.json";
|
||||
export { default as ar } from "./ar/translation.json";
|
||||
export { default as fa } from "./fa/translation.json";
|
||||
export { default as ro } from "./ro/translation.json";
|
||||
export { default as ca } from "./ca/translation.json";
|
||||
export { default as kk } from "./kk/translation.json";
|
||||
import en from "./en/translation.json";
|
||||
import ptPT from "./pt-PT/translation.json";
|
||||
import ptBR from "./pt-BR/translation.json";
|
||||
import es from "./es/translation.json";
|
||||
import nl from "./nl/translation.json";
|
||||
import fr from "./fr/translation.json";
|
||||
import hu from "./hu/translation.json";
|
||||
import it from "./it/translation.json";
|
||||
import de from "./de/translation.json";
|
||||
import pl from "./pl/translation.json";
|
||||
import ru from "./ru/translation.json";
|
||||
import tr from "./tr/translation.json";
|
||||
import be from "./be/translation.json";
|
||||
import uk from "./uk/translation.json";
|
||||
import zh from "./zh/translation.json";
|
||||
import id from "./id/translation.json";
|
||||
import ko from "./ko/translation.json";
|
||||
import da from "./da/translation.json";
|
||||
import ar from "./ar/translation.json";
|
||||
import fa from "./fa/translation.json";
|
||||
import ro from "./ro/translation.json";
|
||||
import ca from "./ca/translation.json";
|
||||
import kk from "./kk/translation.json";
|
||||
import cs from "./cs/translation.json";
|
||||
|
||||
export default {
|
||||
"pt-BR": ptBR,
|
||||
"pt-PT": ptPT,
|
||||
en,
|
||||
de,
|
||||
es,
|
||||
nl,
|
||||
fr,
|
||||
hu,
|
||||
it,
|
||||
pl,
|
||||
ru,
|
||||
tr,
|
||||
be,
|
||||
uk,
|
||||
zh,
|
||||
id,
|
||||
ko,
|
||||
da,
|
||||
ar,
|
||||
fa,
|
||||
ro,
|
||||
ca,
|
||||
kk,
|
||||
cs,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Italiano",
|
||||
"home": {
|
||||
"featured": "In primo piano",
|
||||
"trending": "Di tendenza",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "қазақ тілі",
|
||||
"app": {
|
||||
"successfully_signed_in": "Сәтті кіру"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "한국어",
|
||||
"home": {
|
||||
"featured": "추천",
|
||||
"trending": "인기",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Nederlands",
|
||||
"home": {
|
||||
"featured": "Uitgelicht",
|
||||
"trending": "Trending",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Polski",
|
||||
"home": {
|
||||
"featured": "Wyróżnione",
|
||||
"trending": "Trendujące",
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
{
|
||||
"language_name": "Português (Brasil)",
|
||||
"app": {
|
||||
"successfully_signed_in": "Autenticado com sucesso"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Destaques",
|
||||
"trending": "Populares",
|
||||
"hot": "Populares agora",
|
||||
"weekly": "📅 Mais baixados da semana",
|
||||
"surprise_me": "Surpreenda-me",
|
||||
"no_results": "Nenhum resultado encontrado"
|
||||
"no_results": "Nenhum resultado encontrado",
|
||||
"start_typing": "Comece a digitar para pesquisar…"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Catálogo",
|
||||
"downloads": "Downloads",
|
||||
"settings": "Ajustes",
|
||||
"my_library": "Minha biblioteca",
|
||||
"my_library": "Biblioteca",
|
||||
"downloading_metadata": "{{title}} (Baixando metadados…)",
|
||||
"paused": "{{title}} (Pausado)",
|
||||
"downloading": "{{title}} ({{percentage}} - Baixando…)",
|
||||
"filter": "Filtrar biblioteca",
|
||||
"filter": "Buscar",
|
||||
"home": "Início",
|
||||
"queued": "{{title}} (Na fila)",
|
||||
"game_has_no_executable": "Jogo não possui executável selecionado",
|
||||
"sign_in": "Login"
|
||||
"sign_in": "Login",
|
||||
"friends": "Amigos"
|
||||
},
|
||||
"header": {
|
||||
"search": "Buscar jogos",
|
||||
@@ -45,7 +50,7 @@
|
||||
"download_options_one": "{{count}} opção de download",
|
||||
"download_options_other": "{{count}} opções de download",
|
||||
"updated_at": "Atualizado {{updated_at}}",
|
||||
"resume": "Resumir",
|
||||
"resume": "Retomar",
|
||||
"pause": "Pausar",
|
||||
"cancel": "Cancelar",
|
||||
"remove": "Remover",
|
||||
@@ -54,7 +59,7 @@
|
||||
"calculating_eta": "Calculando tempo restante…",
|
||||
"downloading_metadata": "Baixando metadados…",
|
||||
"filter": "Filtrar repacks",
|
||||
"requirements": "Requisitos do sistema",
|
||||
"requirements": "Requisitos de sistema",
|
||||
"minimum": "Mínimos",
|
||||
"recommended": "Recomendados",
|
||||
"paused": "Pausado",
|
||||
@@ -68,16 +73,16 @@
|
||||
"add_to_library": "Adicionar à biblioteca",
|
||||
"remove_from_library": "Remover da biblioteca",
|
||||
"no_downloads": "Nenhum download disponível",
|
||||
"play_time": "Jogado por {{amount}}",
|
||||
"play_time": "Jogou por {{amount}}",
|
||||
"next_suggestion": "Próxima sugestão",
|
||||
"install": "Instalar",
|
||||
"last_time_played": "Jogou por último {{period}}",
|
||||
"last_time_played": "Última sessão {{period}}",
|
||||
"play": "Jogar",
|
||||
"not_played_yet": "Você ainda não jogou {{title}}",
|
||||
"close": "Fechar",
|
||||
"deleting": "Excluindo instalador…",
|
||||
"playing_now": "Jogando agora",
|
||||
"change": "Mudar",
|
||||
"change": "Explorar",
|
||||
"repacks_modal_description": "Escolha o repack do jogo que deseja baixar",
|
||||
"select_folder_hint": "Para trocar o diretório padrão, acesse a <0>Tela de Ajustes</0>",
|
||||
"download_now": "Iniciar download",
|
||||
@@ -90,13 +95,13 @@
|
||||
"open_screenshot": "Ver captura de tela {{number}}",
|
||||
"download_settings": "Ajustes do download",
|
||||
"downloader": "Downloader",
|
||||
"select_executable": "Selecionar",
|
||||
"select_executable": "Explorar",
|
||||
"no_executable_selected": "Nenhum executável selecionado",
|
||||
"open_folder": "Abrir pasta",
|
||||
"open_download_location": "Ver arquivos baixados",
|
||||
"create_shortcut": "Criar atalho na área de trabalho",
|
||||
"remove_files": "Remover arquivos",
|
||||
"options": "Opções",
|
||||
"options": "Gerenciar",
|
||||
"remove_from_library_description": "Isso irá remover {{game}} da sua biblioteca",
|
||||
"remove_from_library_title": "Tem certeza?",
|
||||
"executable_section_title": "Executável",
|
||||
@@ -109,7 +114,19 @@
|
||||
"download_paused": "Download pausado",
|
||||
"last_downloaded_option": "Última opção baixada",
|
||||
"create_shortcut_success": "Atalho criado com sucesso",
|
||||
"create_shortcut_error": "Erro ao criar atalho"
|
||||
"create_shortcut_error": "Erro ao criar atalho",
|
||||
"nsfw_content_title": "Este jogo contém conteúdo inapropriado",
|
||||
"nsfw_content_description": "{{title}} contém conteúdo que pode não ser apropriado para todas as idades. Você deseja continuar?",
|
||||
"allow_nsfw_content": "Continuar",
|
||||
"refuse_nsfw_content": "Voltar",
|
||||
"stats": "Estatísticas",
|
||||
"download_count": "Downloads",
|
||||
"player_count": "Jogadores ativos",
|
||||
"download_error": "Essa opção de download falhou",
|
||||
"download": "Baixar",
|
||||
"executable_path_in_use": "Executável em uso por \"{{game}}\"",
|
||||
"warning": "Aviso:",
|
||||
"hydra_needs_to_remain_open": "para este download, o Hydra precisa ficar aberto até a conclusão. Caso o Hydra encerre antes da conclusão, perderá seu progresso."
|
||||
},
|
||||
"activation": {
|
||||
"title": "Ativação",
|
||||
@@ -120,7 +137,7 @@
|
||||
"loading": "Carregando…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Resumir",
|
||||
"resume": "Retomar",
|
||||
"pause": "Pausar",
|
||||
"eta": "Conclusão {{eta}}",
|
||||
"paused": "Pausado",
|
||||
@@ -146,12 +163,12 @@
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Diretório dos downloads",
|
||||
"change": "Mudar",
|
||||
"change": "Explorar...",
|
||||
"notifications": "Notificações",
|
||||
"enable_download_notifications": "Quando um download for concluído",
|
||||
"enable_repack_list_notifications": "Quando a lista de repacks for atualizada",
|
||||
"real_debrid_api_token_label": "Token de API do Real-Debrid",
|
||||
"quit_app_instead_hiding": "Encerrar o Hydra ao invés de minimizá-lo ao fechar",
|
||||
"quit_app_instead_hiding": "Encerrar o Hydra em vez de apenas minimizá-lo ao fechar.",
|
||||
"launch_with_system": "Iniciar o Hydra junto com o sistema",
|
||||
"general": "Geral",
|
||||
"behavior": "Comportamento",
|
||||
@@ -166,7 +183,7 @@
|
||||
"real_debrid_linked_message": "Conta \"{{username}}\" vinculada",
|
||||
"save_changes": "Salvar mudanças",
|
||||
"changes_saved": "Ajustes salvos com sucesso",
|
||||
"download_sources_description": "Hydra vai buscar links de download em todas as fonte habilitadas. A URL da fonte deve ser um link direto para um arquivo .json contendo uma lista de links.",
|
||||
"download_sources_description": "Hydra vai buscar links de download em todas as fontes habilitadas. A URL da fonte deve ser um link direto para um arquivo .json contendo uma lista de links.",
|
||||
"validate_download_source": "Validar",
|
||||
"remove_download_source": "Remover",
|
||||
"add_download_source": "Adicionar fonte",
|
||||
@@ -188,14 +205,27 @@
|
||||
"found_download_option_zero": "Nenhuma opção de download encontrada",
|
||||
"found_download_option_one": "{{countFormatted}} opção de download encontrada",
|
||||
"found_download_option_other": "{{countFormatted}} opções de download encontradas",
|
||||
"import": "Importar"
|
||||
"import": "Importar",
|
||||
"privacy": "Privacidade",
|
||||
"private": "Privado",
|
||||
"friends_only": "Apenas amigos",
|
||||
"public": "Público",
|
||||
"profile_visibility": "Visibilidade do perfil",
|
||||
"profile_visibility_description": "Escolha quem pode ver seu perfil e biblioteca",
|
||||
"required_field": "Este campo é obrigatório",
|
||||
"source_already_exists": "Essa fonte já foi adicionada",
|
||||
"must_be_valid_url": "A fonte deve ser uma URL válida",
|
||||
"blocked_users": "Usuários bloqueados",
|
||||
"user_unblocked": "Usuário desbloqueado"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download concluído",
|
||||
"game_ready_to_install": "{{title}} está pronto para ser instalado",
|
||||
"repack_list_updated": "Lista de repacks atualizada",
|
||||
"repack_count_one": "{{count}} novo repack",
|
||||
"repack_count_other": "{{count}} novos repacks"
|
||||
"repack_count_other": "{{count}} novos repacks",
|
||||
"new_update_available": "Versão {{version}} disponível",
|
||||
"restart_to_install_update": "Reinicie o Hydra para instalar a nova versão"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Abrir Hydra",
|
||||
@@ -206,7 +236,7 @@
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Programas não instalados",
|
||||
"description": "Não foram encontrados no seu sistema os executáveis do Wine ou Lutris",
|
||||
"description": "Os executáveis do Wine ou Lutris não foram encontrados em seu sistema.",
|
||||
"instructions": "Verifique a forma correta de instalar algum deles no seu distro Linux, garantindo assim a execução normal do jogo"
|
||||
},
|
||||
"catalogue": {
|
||||
@@ -222,8 +252,8 @@
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} horas",
|
||||
"amount_minutes": "{{amount}} minutos",
|
||||
"last_time_played": "Jogou {{period}}",
|
||||
"activity": "Atividade recente",
|
||||
"last_time_played": "Última sessão {{period}}",
|
||||
"activity": "Atividades recentes",
|
||||
"library": "Biblioteca",
|
||||
"total_play_time": "Tempo total de jogo: {{amount}}",
|
||||
"no_recent_activity_title": "Hmmm… nada por aqui",
|
||||
@@ -231,14 +261,60 @@
|
||||
"display_name": "Nome de exibição",
|
||||
"saving": "Salvando…",
|
||||
"save": "Salvar",
|
||||
"edit_profile": "Editar Perfil",
|
||||
"edit_profile": "Editar perfil",
|
||||
"saved_successfully": "Salvo com sucesso",
|
||||
"try_again": "Por favor, tente novamente",
|
||||
"cancel": "Cancelar",
|
||||
"successfully_signed_out": "Deslogado com sucesso",
|
||||
"sign_out": "Sair da conta",
|
||||
"sign_out_modal_title": "Tem certeza?",
|
||||
"sign_out_modal_title": "Deseja mesmo sair?",
|
||||
"playing_for": "Jogando por {{amount}}",
|
||||
"sign_out_modal_text": "Sua biblioteca de jogos está associada com a sua conta atual. Ao sair, sua biblioteca não aparecerá mais no Hydra e qualquer progresso não será salvo. Deseja continuar?"
|
||||
"sign_out_modal_text": "Sua biblioteca de jogos está associada com a sua conta atual. Ao sair, sua biblioteca não aparecerá mais no Hydra e qualquer progresso não será salvo. Deseja continuar?",
|
||||
"add_friends": "Adicionar Amigos",
|
||||
"friend_code": "Código de amigo",
|
||||
"see_profile": "Ver perfil",
|
||||
"friend_request_sent": "Pedido de amizade enviado",
|
||||
"friends": "Amigos",
|
||||
"add": "Adicionar",
|
||||
"sending": "Enviando",
|
||||
"friends_list": "Lista de amigos",
|
||||
"user_not_found": "Usuário não encontrado",
|
||||
"block_user": "Bloquear",
|
||||
"add_friend": "Adicionar amigo",
|
||||
"request_sent": "Pedido enviado",
|
||||
"request_received": "Pedido recebido",
|
||||
"accept_request": "Aceitar pedido",
|
||||
"ignore_request": "Ignorar pedido",
|
||||
"cancel_request": "Cancelar pedido",
|
||||
"undo_friendship": "Desfazer amizade",
|
||||
"request_accepted": "Pedido de amizade aceito",
|
||||
"user_blocked_successfully": "Usuário bloqueado com sucesso",
|
||||
"user_block_modal_text": "Bloquear {{displayName}}",
|
||||
"blocked_users": "Usuários bloqueados",
|
||||
"unblock": "Desbloquear",
|
||||
"no_friends_added": "Você ainda não possui amigos adicionados",
|
||||
"pending": "Pendentes",
|
||||
"no_pending_invites": "Você não possui convites de amizade pendentes",
|
||||
"no_blocked_users": "Você não tem nenhum usuário bloqueado",
|
||||
"friend_code_copied": "Código de amigo copiado",
|
||||
"undo_friendship_modal_text": "Isso irá remover sua amizade com {{displayName}}",
|
||||
"privacy_hint": "Pra controlar quem pode ver seu perfil, acesse a <0>Tela de Configurações</0>",
|
||||
"profile_locked": "Este perfil é privado",
|
||||
"image_process_failure": "Falha ao processar a imagem",
|
||||
"required_field": "Este campo é obrigatório",
|
||||
"displayname_min_length": "Nome de exibição deve ter pelo menos 3 caracteres",
|
||||
"displayname_max_length": "Nome de exibição deve ter no máximo 50 caracteres",
|
||||
"locked_profile": "Este perfil é privado",
|
||||
"report_profile": "Reportar este perfil",
|
||||
"report_reason": "Por que você deseja reportar este perfil?",
|
||||
"report_description": "Informações adicionais",
|
||||
"report_description_placeholder": "Insira aqui",
|
||||
"report": "Reportar",
|
||||
"report_reason_hate": "Discurso de ódio",
|
||||
"report_reason_sexual_content": "Conteúdo sexual",
|
||||
"report_reason_violence": "Violência",
|
||||
"report_reason_spam": "Spam",
|
||||
"report_reason_other": "Outro",
|
||||
"profile_reported": "Perfil reportado"
|
||||
}
|
||||
}
|
||||
280
src/locales/pt-PT/translation.json
Normal file
280
src/locales/pt-PT/translation.json
Normal file
@@ -0,0 +1,280 @@
|
||||
{
|
||||
"language_name": "Português (Portugal)",
|
||||
"app": {
|
||||
"successfully_signed_in": "Sessão iniciada com sucesso"
|
||||
},
|
||||
"home": {
|
||||
"featured": "Destaques",
|
||||
"trending": "Populares",
|
||||
"surprise_me": "Surpreende-me",
|
||||
"no_results": "Nenhum resultado encontrado",
|
||||
"start_typing": "Comece a digitar para pesquisar…"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Catálogo",
|
||||
"downloads": "Transferências",
|
||||
"settings": "Definições",
|
||||
"my_library": "Biblioteca",
|
||||
"downloading_metadata": "{{title}} (A transferir metadados…)",
|
||||
"paused": "{{title}} (Pausado)",
|
||||
"downloading": "{{title}} ({{percentage}} - A transferir…)",
|
||||
"filter": "Procurar",
|
||||
"home": "Início",
|
||||
"queued": "{{title}} (Na fila)",
|
||||
"game_has_no_executable": "Jogo não tem executável selecionado",
|
||||
"sign_in": "Iniciar sessão"
|
||||
},
|
||||
"header": {
|
||||
"search": "Procurar jogos",
|
||||
"catalogue": "Catálogo",
|
||||
"downloads": "Transferências",
|
||||
"search_results": "Resultados da pesquisa",
|
||||
"settings": "Definições",
|
||||
"home": "Início",
|
||||
"version_available_install": "Versão {{version}} disponível. Clique aqui para reiniciar e instalar.",
|
||||
"version_available_download": "Versão {{version}} disponível. Clique aqui para fazer o download."
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Sem transferências em andamento",
|
||||
"downloading_metadata": "A transferir metadados de {{title}}…",
|
||||
"downloading": "A transferir {{title}}… ({{percentage}} concluído) - Conclusão {{eta}} - {{speed}}",
|
||||
"calculating_eta": "A transferir {{title}}… ({{percentage}} concluído) - A calcular tempo restante…",
|
||||
"checking_files": "A verificar ficheiros de {{title}}…"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Ver opções de transferência",
|
||||
"download_options_zero": "Sem opções de transferência",
|
||||
"download_options_one": "{{count}} opção de transferência",
|
||||
"download_options_other": "{{count}} opções de transferência",
|
||||
"updated_at": "Atualizado a {{updated_at}}",
|
||||
"resume": "Retomar",
|
||||
"pause": "Pausar",
|
||||
"cancel": "Cancelar",
|
||||
"remove": "Remover",
|
||||
"space_left_on_disk": "{{space}} livres no disco",
|
||||
"eta": "Conclusão {{eta}}",
|
||||
"calculating_eta": "A calcular tempo restante…",
|
||||
"downloading_metadata": "A transferir metadados…",
|
||||
"filter": "Filtrar repacks",
|
||||
"requirements": "Requisitos do sistema",
|
||||
"minimum": "Mínimos",
|
||||
"recommended": "Recomendados",
|
||||
"paused": "Pausado",
|
||||
"release_date": "Lançado em {{date}}",
|
||||
"publisher": "Publicado por {{publisher}}",
|
||||
"hours": "horas",
|
||||
"minutes": "minutos",
|
||||
"amount_hours": "{{amount}} horas",
|
||||
"amount_minutes": "{{amount}} minutos",
|
||||
"accuracy": "{{accuracy}}% de precisão",
|
||||
"add_to_library": "Adicionar à biblioteca",
|
||||
"remove_from_library": "Remover da biblioteca",
|
||||
"no_downloads": "Nenhuma transferência disponível",
|
||||
"play_time": "Jogou por {{amount}}",
|
||||
"next_suggestion": "Próxima sugestão",
|
||||
"install": "Instalar",
|
||||
"last_time_played": "Última sessão {{period}}",
|
||||
"play": "Jogar",
|
||||
"not_played_yet": "Ainda não jogou {{title}}",
|
||||
"close": "Fechar",
|
||||
"deleting": "A eliminar instalador…",
|
||||
"playing_now": "A jogar agora",
|
||||
"change": "Explorar",
|
||||
"repacks_modal_description": "Escolha o repack do jogo que deseja transferir",
|
||||
"select_folder_hint": "Para trocar o diretório padrão, aceda à <0>Tela de Definições</0>",
|
||||
"download_now": "Iniciar transferência",
|
||||
"no_shop_details": "Não foi possível obter os detalhes da loja.",
|
||||
"download_options": "Opções de transferência",
|
||||
"download_path": "Diretório de transferência",
|
||||
"previous_screenshot": "Captura de ecrã anterior",
|
||||
"next_screenshot": "Próxima captura de ecrã",
|
||||
"screenshot": "Captura de ecrã {{number}}",
|
||||
"open_screenshot": "Ver captura de ecrã {{number}}",
|
||||
"download_settings": "Definições de transferência",
|
||||
"downloader": "Downloader",
|
||||
"select_executable": "Explorar",
|
||||
"no_executable_selected": "Nenhum executável selecionado",
|
||||
"open_folder": "Abrir pasta",
|
||||
"open_download_location": "Ver ficheiros transferidos",
|
||||
"create_shortcut": "Criar atalho no ambiente de trabalho",
|
||||
"remove_files": "Remover ficheiros",
|
||||
"options": "Gerir",
|
||||
"remove_from_library_description": "Isto irá remover {{game}} da sua biblioteca",
|
||||
"remove_from_library_title": "Tem a certeza?",
|
||||
"executable_section_title": "Executável",
|
||||
"executable_section_description": "O caminho do ficheiro que será executado ao clicar em \"Jogar\"",
|
||||
"downloads_secion_title": "Transferências",
|
||||
"downloads_section_description": "Confira atualizações ou versões diferentes para este mesmo título",
|
||||
"danger_zone_section_title": "Zona de perigo",
|
||||
"danger_zone_section_description": "Remova o jogo da sua biblioteca ou os ficheiros que foram transferidos pelo Hydra",
|
||||
"download_in_progress": "Transferência em andamento",
|
||||
"download_paused": "Transferência pausada",
|
||||
"last_downloaded_option": "Última opção transferida",
|
||||
"create_shortcut_success": "Atalho criado com sucesso",
|
||||
"create_shortcut_error": "Erro ao criar atalho",
|
||||
"download": "Transferir",
|
||||
"executable_path_in_use": "Executável em uso por \"{{game}}\"",
|
||||
"warning": "Aviso:",
|
||||
"hydra_needs_to_remain_open": "para este download, o Hydra precisa ficar aberto até a conclusão. Caso o Hydra encerre antes da conclusão, perderá seu progresso."
|
||||
},
|
||||
"activation": {
|
||||
"title": "Ativação",
|
||||
"installation_id": "ID da instalação:",
|
||||
"enter_activation_code": "Insira o seu código de ativação",
|
||||
"message": "Se não sabe onde conseguir o código, talvez não devesse estar aqui.",
|
||||
"activate": "Ativar",
|
||||
"loading": "A carregar…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Retomar",
|
||||
"pause": "Pausar",
|
||||
"eta": "Conclusão {{eta}}",
|
||||
"paused": "Pausado",
|
||||
"verifying": "A verificar…",
|
||||
"completed": "Concluído",
|
||||
"removed": "Cancelado",
|
||||
"cancel": "Cancelar",
|
||||
"filter": "Filtrar jogos transferidos",
|
||||
"remove": "Remover",
|
||||
"downloading_metadata": "A transferir metadados…",
|
||||
"delete": "Remover instalador",
|
||||
"delete_modal_description": "Isto removerá todos os ficheiros de instalação do seu computador",
|
||||
"delete_modal_title": "Tem a certeza?",
|
||||
"deleting": "A eliminar instalador…",
|
||||
"install": "Instalar",
|
||||
"download_in_progress": "A transferir agora",
|
||||
"queued_downloads": "Na fila",
|
||||
"downloads_completed": "Concluído",
|
||||
"queued": "Na fila",
|
||||
"no_downloads_title": "Nada por aqui…",
|
||||
"no_downloads_description": "Ainda não transferiu nada pelo Hydra, mas nunca é tarde para começar.",
|
||||
"checking_files": "A verificar ficheiros…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Diretório das transferências",
|
||||
"change": "Explorar...",
|
||||
"notifications": "Notificações",
|
||||
"enable_download_notifications": "Quando uma transferência for concluída",
|
||||
"enable_repack_list_notifications": "Quando a lista de repacks for atualizada",
|
||||
"real_debrid_api_token_label": "Token de API do Real-Debrid",
|
||||
"quit_app_instead_hiding": "Encerrar o Hydra em vez de apenas minimizá-lo ao fechar.",
|
||||
"launch_with_system": "Iniciar o Hydra com o sistema",
|
||||
"general": "Geral",
|
||||
"behavior": "Comportamento",
|
||||
"download_sources": "Fontes de transferência",
|
||||
"language": "Idioma",
|
||||
"real_debrid_api_token": "Token de API",
|
||||
"enable_real_debrid": "Ativar Real-Debrid",
|
||||
"real_debrid_api_token_hint": "Pode obter o seu token de API <0>aqui</0>",
|
||||
"real_debrid_description": "O Real-Debrid é um downloader sem restrições que permite transferir ficheiros instantaneamente e com a melhor velocidade da sua Internet.",
|
||||
"real_debrid_invalid_token": "Token de API inválido",
|
||||
"real_debrid_free_account_error": "A conta \"{{username}}\" é uma conta gratuita. Por favor, subscreva o Real-Debrid",
|
||||
"real_debrid_linked_message": "Conta \"{{username}}\" vinculada",
|
||||
"save_changes": "Guardar alterações",
|
||||
"changes_saved": "Definições guardadas com sucesso",
|
||||
"download_sources_description": "O Hydra vai procurar links de transferência em todas as fontes ativadas. A URL da página de detalhes da loja não é guardada no seu dispositivo. Utilizamos um sistema de metadados criado pela comunidade para fornecer suporte a mais fontes de transferência de jogos.",
|
||||
"validate_download_source": "Validar",
|
||||
"remove_download_source": "Remover",
|
||||
"add_download_source": "Adicionar fonte",
|
||||
"download_count_zero": "Sem transferências na lista",
|
||||
"download_count_one": "{{countFormatted}} transferência na lista",
|
||||
"download_count_other": "{{countFormatted}} transferências na lista",
|
||||
"download_options_zero": "Sem transferências disponíveis",
|
||||
"download_options_one": "{{countFormatted}} transferência disponível",
|
||||
"download_options_other": "{{countFormatted}} transferências disponíveis",
|
||||
"download_source_url": "URL da fonte",
|
||||
"add_download_source_description": "Insira o URL contendo o arquivo .json",
|
||||
"download_source_up_to_date": "Sincronizada",
|
||||
"download_source_errored": "Falhou",
|
||||
"sync_download_sources": "Sincronizar",
|
||||
"removed_download_source": "Fonte removida",
|
||||
"added_download_source": "Fonte adicionada",
|
||||
"download_sources_synced": "As fontes foram sincronizadas",
|
||||
"insert_valid_json_url": "Insira o URL de um JSON válido",
|
||||
"found_download_option_zero": "Nenhuma opção de transferência encontrada",
|
||||
"found_download_option_one": "{{countFormatted}} opção de transferência encontrada",
|
||||
"found_download_option_other": "{{countFormatted}} opções de transferências encontradas",
|
||||
"import": "Importar"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Transferência concluída",
|
||||
"game_ready_to_install": "{{title}} está pronto para ser descarregado",
|
||||
"repack_list_updated": "Lista de repacks atualizada",
|
||||
"repack_count_one": "{{count}} novo repack",
|
||||
"repack_count_other": "{{count}} novos repacks",
|
||||
"new_update_available": "Versão {{version}} disponível",
|
||||
"restart_to_install_update": "Reinicie o Hydra para instalar a nova versão"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Abrir Hydra",
|
||||
"quit": "Fechar"
|
||||
},
|
||||
"game_card": {
|
||||
"no_downloads": "Sem transferências disponíveis"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Programas não instalados",
|
||||
"description": "Os executáveis do Wine ou Lutris não foram encontrados em seu sistema.",
|
||||
"instructions": "Verifique a forma correta de instalar algum deles na sua distro Linux, garantindo assim a execução normal do jogo."
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Próxima página",
|
||||
"previous_page": "Página anterior"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Botão de fechar"
|
||||
},
|
||||
"forms": {
|
||||
"toggle_password_visibility": "Alternar visibilidade da palavra-passe"
|
||||
},
|
||||
"user_profile": {
|
||||
"amount_hours": "{{amount}} horas",
|
||||
"amount_minutes": "{{amount}} minutos",
|
||||
"last_time_played": "Última sessão {{period}}",
|
||||
"activity": "Atividades recentes",
|
||||
"library": "Biblioteca",
|
||||
"total_play_time": "Tempo total de jogo: {{amount}}",
|
||||
"no_recent_activity_title": "Hmmm… nada por aqui",
|
||||
"no_recent_activity_description": "Parece que não jogaste nada recentemente. Que tal começar agora?",
|
||||
"display_name": "Nome de exibição",
|
||||
"saving": "a guardar…",
|
||||
"save": "Guardar",
|
||||
"edit_profile": "Editar perfil",
|
||||
"saved_successfully": "Guardado com sucesso",
|
||||
"try_again": "Por favor, tenta novamente",
|
||||
"cancel": "Cancelar",
|
||||
"successfully_signed_out": "Terminado com sucesso",
|
||||
"sign_out": "Terminar sessão",
|
||||
"sign_out_modal_title": "Tens a certeza?",
|
||||
"playing_for": "A jogar há {{amount}}",
|
||||
"sign_out_modal_text": "A tua biblioteca de jogos está associada com a tua conta atual. Ao sair, a tua biblioteca não aparecerá mais no Hydra e qualquer progresso não será guardado. Desejas continuar?",
|
||||
"add_friends": "Adicionar Amigos",
|
||||
"friend_code": "Código de amigo",
|
||||
"see_profile": "Ver perfil",
|
||||
"friend_request_sent": "Pedido de amizade enviado",
|
||||
"friends": "Amigos",
|
||||
"add": "Adicionar",
|
||||
"sending": "A enviar",
|
||||
"friends_list": "Lista de amigos",
|
||||
"user_not_found": "Utilizador não encontrado",
|
||||
"block_user": "Bloquear",
|
||||
"add_friend": "Adicionar amigo",
|
||||
"request_sent": "Pedido enviado",
|
||||
"request_received": "Pedido recebido",
|
||||
"accept_request": "Aceitar pedido",
|
||||
"ignore_request": "Ignorar pedido",
|
||||
"cancel_request": "Cancelar pedido",
|
||||
"undo_friendship": "Desfazer amizade",
|
||||
"request_accepted": "Pedido de amizade aceito",
|
||||
"user_blocked_successfully": "Utilizador bloqueado com sucesso",
|
||||
"user_block_modal_text": "Bloquear {{displayName}}",
|
||||
"blocked_users": "Utilizadores bloqueados",
|
||||
"unblock": "Desbloquear",
|
||||
"no_friends_added": "Ainda não adicionaste amigos",
|
||||
"pending": "Pendentes",
|
||||
"no_pending_invites": "Não tens convites de amizade pendentes",
|
||||
"no_blocked_users": "Não tens nenhum utilizador bloqueado",
|
||||
"friend_code_copied": "Código de amigo copiado",
|
||||
"image_process_failure": "Falha ao processar a imagem"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Română",
|
||||
"home": {
|
||||
"featured": "Recomandate",
|
||||
"trending": "Populare",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Русский",
|
||||
"app": {
|
||||
"successfully_signed_in": "Успешный вход"
|
||||
},
|
||||
@@ -6,7 +7,10 @@
|
||||
"featured": "Рекомендованное",
|
||||
"trending": "В тренде",
|
||||
"surprise_me": "Удиви меня",
|
||||
"no_results": "Ничего не найдено"
|
||||
"no_results": "Ничего не найдено",
|
||||
"hot": "Сейчас жарко",
|
||||
"start_typing": "Начинаю вводить текст для поиска...",
|
||||
"weekly": "📅 Лучшие игры недели"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Каталог",
|
||||
@@ -20,7 +24,8 @@
|
||||
"home": "Главная",
|
||||
"queued": "{{title}} (В очереди)",
|
||||
"game_has_no_executable": "Файл запуска игры не выбран",
|
||||
"sign_in": "Войти"
|
||||
"sign_in": "Войти",
|
||||
"friends": "Друзья"
|
||||
},
|
||||
"header": {
|
||||
"search": "Поиск",
|
||||
@@ -36,7 +41,8 @@
|
||||
"no_downloads_in_progress": "Нет активных загрузок",
|
||||
"downloading_metadata": "Загрузка метаданных {{title}}…",
|
||||
"downloading": "Загрузка {{title}}… ({{percentage}} завершено) - Окончание {{eta}} - {{speed}}",
|
||||
"calculating_eta": "Загрузка {{title}}… ({{percentage}} завершено) - Подсчёт оставшегося времени…"
|
||||
"calculating_eta": "Загрузка {{title}}… ({{percentage}} завершено) - Подсчёт оставшегося времени…",
|
||||
"checking_files": "Проверка файлов {{title}}… ({{percentage}} завершено)"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Следующая страница",
|
||||
@@ -112,7 +118,17 @@
|
||||
"download_paused": "Загрузка приостановлена",
|
||||
"last_downloaded_option": "Последний вариант загрузки",
|
||||
"create_shortcut_success": "Ярлык создан",
|
||||
"create_shortcut_error": "Не удалось создать ярлык"
|
||||
"create_shortcut_error": "Не удалось создать ярлык",
|
||||
"allow_nsfw_content": "Продолжать",
|
||||
"download": "Скачать",
|
||||
"download_count": "Загрузки",
|
||||
"download_error": "Этот вариант загрузки недоступен",
|
||||
"executable_path_in_use": "Исполняемый файл уже используется \"{{game}}\"",
|
||||
"nsfw_content_description": "{{title}} содержит контент, который может не подходить для всех возрастов. \nВы уверены, что хотите продолжить?",
|
||||
"nsfw_content_title": "Эта игра содержит неприемлемый контент",
|
||||
"player_count": "Активные игроки",
|
||||
"refuse_nsfw_content": "Возвращаться",
|
||||
"stats": "Статистика"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Активировать Hydra",
|
||||
@@ -144,7 +160,8 @@
|
||||
"downloads_completed": "Завершено",
|
||||
"queued": "В очереди",
|
||||
"no_downloads_title": "Здесь так пусто...",
|
||||
"no_downloads_description": "Вы ещё ничего не скачали через Hydra, но никогда не поздно начать."
|
||||
"no_downloads_description": "Вы ещё ничего не скачали через Hydra, но никогда не поздно начать.",
|
||||
"checking_files": "Проверка файлов…"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Путь загрузок",
|
||||
@@ -175,9 +192,6 @@
|
||||
"download_count_zero": "В списке нет загрузок",
|
||||
"download_count_one": "{{countFormatted}} загрузка в списке",
|
||||
"download_count_other": "{{countFormatted}} загрузок в списке",
|
||||
"download_options_zero": "Нет доступных загрузок",
|
||||
"download_options_one": "{{countFormatted}} вариант загрузки доступен",
|
||||
"download_options_other": "{{countFormatted}} вариантов загрузки доступно",
|
||||
"download_source_url": "Ссылка на источник",
|
||||
"add_download_source_description": "Вставьте ссылку на .json-файл",
|
||||
"download_source_up_to_date": "Обновлён",
|
||||
@@ -190,14 +204,30 @@
|
||||
"found_download_option_zero": "Не найдено вариантов загрузки",
|
||||
"found_download_option_one": "Найден {{countFormatted}} вариант загрузки",
|
||||
"found_download_option_other": "Найдено {{countFormatted}} вариантов загрузки",
|
||||
"import": "Импортировать"
|
||||
"import": "Импортировать",
|
||||
"blocked_users": "Заблокированные пользователи",
|
||||
"download_options_one": "",
|
||||
"download_options_other": "",
|
||||
"download_options_zero": "",
|
||||
"friends_only": "Только друзья",
|
||||
"must_be_valid_url": "Источник должен быть действительным URL-адресом.",
|
||||
"privacy": "Конфиденциальность",
|
||||
"private": "Частный",
|
||||
"profile_visibility": "Видимость профиля",
|
||||
"profile_visibility_description": "Выберите, кто может видеть ваш профиль и библиотеку",
|
||||
"public": "Общественный",
|
||||
"required_field": "Это поле обязательно к заполнению",
|
||||
"source_already_exists": "Этот источник уже добавлен",
|
||||
"user_unblocked": "Пользователь разблокирован"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Загрузка завершена",
|
||||
"game_ready_to_install": "{{title}} готова к установке",
|
||||
"repack_list_updated": "Список репаков обновлен",
|
||||
"repack_count_one": "{{count}} репак добавлен",
|
||||
"repack_count_other": "{{count}} репаков добавлено"
|
||||
"repack_count_other": "{{count}} репаков добавлено",
|
||||
"new_update_available": "Доступна версия {{version}}",
|
||||
"restart_to_install_update": "Перезапустите Hydra для установки обновления"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Открыть Hydra",
|
||||
@@ -237,6 +267,52 @@
|
||||
"successfully_signed_out": "Успешный выход из аккаунта",
|
||||
"sign_out": "Выйти",
|
||||
"playing_for": "Сыграно {{amount}}",
|
||||
"sign_out_modal_text": "Ваша библиотека связана с текущей учетной записью. При выходе из системы ваша библиотека станет недоступна, и прогресс не будет сохранен. Выйти?"
|
||||
"sign_out_modal_text": "Ваша библиотека связана с текущей учетной записью. При выходе из системы ваша библиотека станет недоступна, и прогресс не будет сохранен. Выйти?",
|
||||
"add_friends": "Добавить друзей",
|
||||
"add": "Добавить",
|
||||
"friend_code": "Код друга",
|
||||
"see_profile": "Просмотреть профиль",
|
||||
"sending": "Отправка",
|
||||
"friend_request_sent": "Запрос в друзья отправлен",
|
||||
"friends": "Друзья",
|
||||
"friends_list": "Список друзей",
|
||||
"user_not_found": "Пользователь не найден",
|
||||
"block_user": "Заблокировать пользователя",
|
||||
"add_friend": "Добавить друга",
|
||||
"request_sent": "Запрос отправлен",
|
||||
"request_received": "Запрос получен",
|
||||
"accept_request": "Принять запрос",
|
||||
"ignore_request": "Игнорировать запрос",
|
||||
"cancel_request": "Отменить запрос",
|
||||
"undo_friendship": "Удалить друга",
|
||||
"request_accepted": "Запрос принят",
|
||||
"user_blocked_successfully": "Пользователь успешно заблокирован",
|
||||
"user_block_modal_text": "{{displayName}} будет заблокирован",
|
||||
"blocked_users": "Заблокированные пользователи",
|
||||
"unblock": "Разблокировать",
|
||||
"no_friends_added": "Вы ещё не добавили ни одного друга",
|
||||
"pending": "Ожидание",
|
||||
"no_pending_invites": "У вас нет запросов ожидающих ответа",
|
||||
"no_blocked_users": "Вы не заблокировали ни одного пользователя",
|
||||
"friend_code_copied": "Код друга скопирован",
|
||||
"displayname_max_length": "Отображаемое имя должно содержать не более 50 символов.",
|
||||
"displayname_min_length": "Отображаемое имя должно содержать не менее 3 символов.",
|
||||
"image_process_failure": "Сбой при обработке изображения",
|
||||
"locked_profile": "Этот профиль является частным",
|
||||
"privacy_hint": "Чтобы указать, кто может это видеть, перейдите в <0>Настройки</0>.",
|
||||
"profile_locked": "",
|
||||
"profile_reported": "Профиль сообщил",
|
||||
"report": "Отчет",
|
||||
"report_description": "Дополнительная информация",
|
||||
"report_description_placeholder": "Дополнительная информация",
|
||||
"report_profile": "Пожаловаться на этот профиль",
|
||||
"report_reason": "Почему вы жалуетесь на этот профиль?",
|
||||
"report_reason_hate": "Разжигание ненависти",
|
||||
"report_reason_other": "Другой",
|
||||
"report_reason_sexual_content": "Сексуальный контент",
|
||||
"report_reason_spam": "Спам",
|
||||
"report_reason_violence": "Насилие",
|
||||
"required_field": "Это поле обязательно к заполнению",
|
||||
"undo_friendship_modal_text": "Это отменит вашу дружбу с {{displayName}}."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Türkçe",
|
||||
"home": {
|
||||
"featured": "Öne çıkan",
|
||||
"trending": "Popüler",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "Українська",
|
||||
"app": {
|
||||
"successfully_signed_in": "Успішний вхід в систему"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"language_name": "中文",
|
||||
"app": {
|
||||
"successfully_signed_in": "已成功登录"
|
||||
},
|
||||
|
||||
@@ -3,11 +3,8 @@ import path from "node:path";
|
||||
|
||||
export const defaultDownloadsPath = app.getPath("downloads");
|
||||
|
||||
export const databasePath = path.join(
|
||||
app.getPath("appData"),
|
||||
"hydra",
|
||||
"hydra.db"
|
||||
);
|
||||
export const databaseDirectory = path.join(app.getPath("appData"), "hydra");
|
||||
export const databasePath = path.join(databaseDirectory, "hydra.db");
|
||||
|
||||
export const logsPath = path.join(app.getPath("appData"), "hydra", "logs");
|
||||
|
||||
|
||||
@@ -6,32 +6,22 @@ import {
|
||||
GameShopCache,
|
||||
Repack,
|
||||
UserPreferences,
|
||||
UserAuth,
|
||||
} from "@main/entity";
|
||||
import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";
|
||||
|
||||
import { databasePath } from "./constants";
|
||||
import migrations from "./migrations";
|
||||
import { UserAuth } from "./entity/user-auth";
|
||||
|
||||
export const createDataSource = (
|
||||
options: Partial<BetterSqlite3ConnectionOptions>
|
||||
) =>
|
||||
new DataSource({
|
||||
type: "better-sqlite3",
|
||||
entities: [
|
||||
Game,
|
||||
Repack,
|
||||
UserPreferences,
|
||||
GameShopCache,
|
||||
DownloadSource,
|
||||
DownloadQueue,
|
||||
UserAuth,
|
||||
],
|
||||
synchronize: true,
|
||||
database: databasePath,
|
||||
...options,
|
||||
});
|
||||
|
||||
export const dataSource = createDataSource({
|
||||
migrations,
|
||||
export const dataSource = new DataSource({
|
||||
type: "better-sqlite3",
|
||||
entities: [
|
||||
Game,
|
||||
Repack,
|
||||
UserPreferences,
|
||||
GameShopCache,
|
||||
DownloadSource,
|
||||
DownloadQueue,
|
||||
UserAuth,
|
||||
],
|
||||
synchronize: false,
|
||||
database: databasePath,
|
||||
});
|
||||
|
||||
80
src/main/declaration.d.ts
vendored
80
src/main/declaration.d.ts
vendored
@@ -1,80 +0,0 @@
|
||||
declare module "aria2" {
|
||||
export type Aria2Status =
|
||||
| "active"
|
||||
| "waiting"
|
||||
| "paused"
|
||||
| "error"
|
||||
| "complete"
|
||||
| "removed";
|
||||
|
||||
export interface StatusResponse {
|
||||
gid: string;
|
||||
status: Aria2Status;
|
||||
totalLength: string;
|
||||
completedLength: string;
|
||||
uploadLength: string;
|
||||
bitfield: string;
|
||||
downloadSpeed: string;
|
||||
uploadSpeed: string;
|
||||
infoHash?: string;
|
||||
numSeeders?: string;
|
||||
seeder?: boolean;
|
||||
pieceLength: string;
|
||||
numPieces: string;
|
||||
connections: string;
|
||||
errorCode?: string;
|
||||
errorMessage?: string;
|
||||
followedBy?: string[];
|
||||
following: string;
|
||||
belongsTo: string;
|
||||
dir: string;
|
||||
files: {
|
||||
path: string;
|
||||
length: string;
|
||||
completedLength: string;
|
||||
selected: string;
|
||||
}[];
|
||||
bittorrent?: {
|
||||
announceList: string[][];
|
||||
comment: string;
|
||||
creationDate: string;
|
||||
mode: "single" | "multi";
|
||||
info: {
|
||||
name: string;
|
||||
verifiedLength: string;
|
||||
verifyIntegrityPending: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default class Aria2 {
|
||||
constructor(options: any);
|
||||
open: () => Promise<void>;
|
||||
call(
|
||||
method: "addUri",
|
||||
uris: string[],
|
||||
options: { dir: string }
|
||||
): Promise<string>;
|
||||
call(
|
||||
method: "tellStatus",
|
||||
gid: string,
|
||||
keys?: string[]
|
||||
): Promise<StatusResponse>;
|
||||
call(method: "pause", gid: string): Promise<string>;
|
||||
call(method: "forcePause", gid: string): Promise<string>;
|
||||
call(method: "unpause", gid: string): Promise<string>;
|
||||
call(method: "remove", gid: string): Promise<string>;
|
||||
call(method: "forceRemove", gid: string): Promise<string>;
|
||||
call(method: "pauseAll"): Promise<string>;
|
||||
call(method: "forcePauseAll"): Promise<string>;
|
||||
listNotifications: () => [
|
||||
"onDownloadStart",
|
||||
"onDownloadPause",
|
||||
"onDownloadStop",
|
||||
"onDownloadComplete",
|
||||
"onDownloadError",
|
||||
"onBtDownloadComplete",
|
||||
];
|
||||
on: (event: string, callback: (params: any) => void) => void;
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,12 @@ export class Repack {
|
||||
@Column("text", { unique: true })
|
||||
title: string;
|
||||
|
||||
/**
|
||||
* @deprecated Use uris instead
|
||||
*/
|
||||
@Column("text", { unique: true })
|
||||
magnet: string;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Column("int", { nullable: true })
|
||||
page: number;
|
||||
|
||||
@Column("text")
|
||||
repacker: string;
|
||||
|
||||
@@ -37,6 +34,9 @@ export class Repack {
|
||||
@ManyToOne(() => DownloadSource, { nullable: true, onDelete: "CASCADE" })
|
||||
downloadSource: DownloadSource;
|
||||
|
||||
@Column("text", { default: "[]" })
|
||||
uris: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import * as Sentry from "@sentry/electron/main";
|
||||
import { HydraApi, PythonInstance, gamesPlaytime } from "@main/services";
|
||||
import {
|
||||
DownloadManager,
|
||||
HydraApi,
|
||||
PythonInstance,
|
||||
gamesPlaytime,
|
||||
} from "@main/services";
|
||||
import { dataSource } from "@main/data-source";
|
||||
import { DownloadQueue, Game, UserAuth } from "@main/entity";
|
||||
|
||||
@@ -23,9 +28,14 @@ const signOut = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
/* Removes user from Sentry */
|
||||
Sentry.setUser(null);
|
||||
|
||||
/* Cancels any ongoing downloads */
|
||||
DownloadManager.cancelDownload();
|
||||
|
||||
/* Disconnects libtorrent */
|
||||
PythonInstance.killTorrent();
|
||||
|
||||
HydraApi.handleSignOut();
|
||||
|
||||
await Promise.all([
|
||||
databaseOperations,
|
||||
HydraApi.post("/auth/logout").catch(() => {}),
|
||||
|
||||
@@ -3,6 +3,7 @@ import { registerEvent } from "../register-event";
|
||||
import updater, { UpdateInfo } from "electron-updater";
|
||||
import { WindowManager } from "@main/services";
|
||||
import { app } from "electron";
|
||||
import { publishNotificationUpdateReadyToInstall } from "@main/services/notifications";
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
|
||||
@@ -20,13 +21,17 @@ const mockValuesForDebug = () => {
|
||||
sendEvent({ type: "update-downloaded" });
|
||||
};
|
||||
|
||||
const newVersionInfo = { version: "" };
|
||||
|
||||
const checkForUpdates = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
autoUpdater
|
||||
.once("update-available", (info: UpdateInfo) => {
|
||||
sendEvent({ type: "update-available", info });
|
||||
newVersionInfo.version = info.version;
|
||||
})
|
||||
.once("update-downloaded", () => {
|
||||
sendEvent({ type: "update-downloaded" });
|
||||
publishNotificationUpdateReadyToInstall(newVersionInfo.version);
|
||||
});
|
||||
|
||||
if (app.isPackaged) {
|
||||
|
||||
@@ -1,36 +1,44 @@
|
||||
import { getSteamAppAsset } from "@main/helpers";
|
||||
import type { CatalogueEntry, GameShop } from "@types";
|
||||
import type { GameShop } from "@types";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { RepacksManager, requestSteam250 } from "@main/services";
|
||||
import { formatName } from "@shared";
|
||||
import { HydraApi, RepacksManager } from "@main/services";
|
||||
import { CatalogueCategory, formatName, steamUrlBuilder } from "@shared";
|
||||
import { steamGamesWorker } from "@main/workers";
|
||||
|
||||
const resultSize = 12;
|
||||
const getCatalogue = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
category: CatalogueCategory
|
||||
) => {
|
||||
const params = new URLSearchParams({
|
||||
take: "12",
|
||||
skip: "0",
|
||||
});
|
||||
|
||||
const getCatalogue = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
const trendingGames = await requestSteam250("/90day");
|
||||
const results: CatalogueEntry[] = [];
|
||||
const response = await HydraApi.get<{ objectId: string; shop: GameShop }[]>(
|
||||
`/games/${category}?${params.toString()}`,
|
||||
{},
|
||||
{ needsAuth: false }
|
||||
);
|
||||
|
||||
for (let i = 0; i < resultSize; i++) {
|
||||
if (!trendingGames[i]) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
return Promise.all(
|
||||
response.map(async (game) => {
|
||||
const steamGame = await steamGamesWorker.run(Number(game.objectId), {
|
||||
name: "getById",
|
||||
});
|
||||
|
||||
const { title, objectID } = trendingGames[i]!;
|
||||
const repacks = RepacksManager.search({ query: formatName(title) });
|
||||
const repacks = RepacksManager.search({
|
||||
query: formatName(steamGame.name),
|
||||
});
|
||||
|
||||
const catalogueEntry = {
|
||||
objectID,
|
||||
title,
|
||||
shop: "steam" as GameShop,
|
||||
cover: getSteamAppAsset("library", objectID),
|
||||
};
|
||||
|
||||
results.push({ ...catalogueEntry, repacks });
|
||||
}
|
||||
|
||||
return results;
|
||||
return {
|
||||
title: steamGame.name,
|
||||
shop: game.shop,
|
||||
repacks,
|
||||
cover: steamUrlBuilder.library(game.objectId),
|
||||
objectID: game.objectId,
|
||||
};
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
registerEvent("getCatalogue", getCatalogue);
|
||||
|
||||
23
src/main/events/catalogue/get-game-stats.ts
Normal file
23
src/main/events/catalogue/get-game-stats.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { GameShop } from "@types";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import type { GameStats } from "@types";
|
||||
|
||||
const getGameStats = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
objectId: string,
|
||||
shop: GameShop
|
||||
) => {
|
||||
const params = new URLSearchParams({
|
||||
objectId,
|
||||
shop,
|
||||
});
|
||||
|
||||
const response = await HydraApi.get<GameStats>(
|
||||
`/games/stats?${params.toString()}`
|
||||
);
|
||||
return response;
|
||||
};
|
||||
|
||||
registerEvent("getGameStats", getGameStats);
|
||||
@@ -3,7 +3,7 @@ import { shuffle } from "lodash-es";
|
||||
import { getSteam250List } from "@main/services";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { searchSteamGames } from "../helpers/search-games";
|
||||
import { getSteamGameById } from "../helpers/search-games";
|
||||
import type { Steam250Game } from "@types";
|
||||
|
||||
const state = { games: Array<Steam250Game>(), index: 0 };
|
||||
@@ -12,14 +12,10 @@ const filterGames = async (games: Steam250Game[]) => {
|
||||
const results: Steam250Game[] = [];
|
||||
|
||||
for (const game of games) {
|
||||
const catalogue = await searchSteamGames({ query: game.title });
|
||||
const steamGame = await getSteamGameById(game.objectID);
|
||||
|
||||
if (catalogue.length) {
|
||||
const [steamGame] = catalogue;
|
||||
|
||||
if (steamGame.repacks.length) {
|
||||
results.push(game);
|
||||
}
|
||||
if (steamGame?.repacks.length) {
|
||||
results.push(game);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
22
src/main/events/catalogue/get-trending-games.ts
Normal file
22
src/main/events/catalogue/get-trending-games.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { userPreferencesRepository } from "@main/repository";
|
||||
import { TrendingGame } from "@types";
|
||||
|
||||
const getTrendingGames = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
const userPreferences = await userPreferencesRepository.findOne({
|
||||
where: { id: 1 },
|
||||
});
|
||||
|
||||
const language = userPreferences?.language || "en";
|
||||
|
||||
const trendingGames = await HydraApi.get<TrendingGame[]>(
|
||||
"/games/trending",
|
||||
{ language },
|
||||
{ needsAuth: false }
|
||||
).catch(() => []);
|
||||
|
||||
return trendingGames;
|
||||
};
|
||||
|
||||
registerEvent("getTrendingGames", getTrendingGames);
|
||||
@@ -1,10 +1,25 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { searchSteamGames } from "../helpers/search-games";
|
||||
import { convertSteamGameToCatalogueEntry } from "../helpers/search-games";
|
||||
import { CatalogueEntry } from "@types";
|
||||
import { HydraApi, RepacksManager } from "@main/services";
|
||||
|
||||
const searchGamesEvent = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
query: string
|
||||
): Promise<CatalogueEntry[]> => searchSteamGames({ query, limit: 12 });
|
||||
): Promise<CatalogueEntry[]> => {
|
||||
const games = await HydraApi.get<
|
||||
{ objectId: string; title: string; shop: string }[]
|
||||
>("/games/search", { title: query, take: 12, skip: 0 }, { needsAuth: false });
|
||||
|
||||
const steamGames = games.map((game) => {
|
||||
return convertSteamGameToCatalogueEntry({
|
||||
id: Number(game.objectId),
|
||||
name: game.title,
|
||||
clientIcon: null,
|
||||
});
|
||||
});
|
||||
|
||||
return RepacksManager.findRepacksForCatalogueEntries(steamGames);
|
||||
};
|
||||
|
||||
registerEvent("searchGames", searchGamesEvent);
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { downloadSourceRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
return downloadSourceRepository
|
||||
.createQueryBuilder("downloadSource")
|
||||
.leftJoin("downloadSource.repacks", "repacks")
|
||||
.orderBy("downloadSource.createdAt", "DESC")
|
||||
.loadRelationCountAndMap(
|
||||
"downloadSource.repackCount",
|
||||
"downloadSource.repacks"
|
||||
)
|
||||
.getMany();
|
||||
};
|
||||
const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) =>
|
||||
downloadSourceRepository.find({
|
||||
order: {
|
||||
createdAt: "DESC",
|
||||
},
|
||||
});
|
||||
|
||||
registerEvent("getDownloadSources", getDownloadSources);
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import axios from "axios";
|
||||
import { downloadSourceRepository } from "@main/repository";
|
||||
import { downloadSourceSchema } from "../helpers/validators";
|
||||
import { RepacksManager } from "@main/services";
|
||||
import { downloadSourceWorker } from "@main/workers";
|
||||
|
||||
const validateDownloadSource = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
url: string
|
||||
) => {
|
||||
const response = await axios.get(url);
|
||||
|
||||
const source = downloadSourceSchema.parse(response.data);
|
||||
|
||||
const existingSource = await downloadSourceRepository.findOne({
|
||||
where: { url },
|
||||
});
|
||||
@@ -21,14 +16,12 @@ const validateDownloadSource = async (
|
||||
|
||||
const repacks = RepacksManager.repacks;
|
||||
|
||||
const existingUris = source.downloads
|
||||
.flatMap((download) => download.uris)
|
||||
.filter((uri) => repacks.some((repack) => repack.magnet === uri));
|
||||
|
||||
return {
|
||||
name: source.name,
|
||||
downloadCount: source.downloads.length - existingUris.length,
|
||||
};
|
||||
return downloadSourceWorker.run(
|
||||
{ url, repacks },
|
||||
{
|
||||
name: "validateDownloadSource",
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
registerEvent("validateDownloadSource", validateDownloadSource);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { orderBy } from "lodash-es";
|
||||
import flexSearch from "flexsearch";
|
||||
|
||||
import type { GameShop, CatalogueEntry, SteamGame } from "@types";
|
||||
|
||||
import { getSteamAppAsset } from "@main/helpers";
|
||||
import { steamGamesWorker } from "@main/workers";
|
||||
import { RepacksManager } from "@main/services";
|
||||
import { steamUrlBuilder } from "@shared";
|
||||
|
||||
export interface SearchGamesArgs {
|
||||
query?: string;
|
||||
@@ -19,24 +16,22 @@ export const convertSteamGameToCatalogueEntry = (
|
||||
objectID: String(game.id),
|
||||
title: game.name,
|
||||
shop: "steam" as GameShop,
|
||||
cover: getSteamAppAsset("library", String(game.id)),
|
||||
cover: steamUrlBuilder.library(String(game.id)),
|
||||
repacks: [],
|
||||
});
|
||||
|
||||
export const searchSteamGames = async (
|
||||
options: flexSearch.SearchOptions
|
||||
): Promise<CatalogueEntry[]> => {
|
||||
const steamGames = (await steamGamesWorker.run(options, {
|
||||
name: "search",
|
||||
})) as SteamGame[];
|
||||
export const getSteamGameById = async (
|
||||
objectId: string
|
||||
): Promise<CatalogueEntry | null> => {
|
||||
const steamGame = await steamGamesWorker.run(Number(objectId), {
|
||||
name: "getById",
|
||||
});
|
||||
|
||||
const result = RepacksManager.findRepacksForCatalogueEntries(
|
||||
steamGames.map((game) => convertSteamGameToCatalogueEntry(game))
|
||||
);
|
||||
if (!steamGame) return null;
|
||||
|
||||
return orderBy(
|
||||
result,
|
||||
[({ repacks }) => repacks.length, "repacks"],
|
||||
["desc"]
|
||||
);
|
||||
const catalogueEntry = convertSteamGameToCatalogueEntry(steamGame);
|
||||
|
||||
const result = RepacksManager.findRepacksForCatalogueEntry(catalogueEntry);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@ import "./catalogue/get-how-long-to-beat";
|
||||
import "./catalogue/get-random-game";
|
||||
import "./catalogue/search-games";
|
||||
import "./catalogue/search-game-repacks";
|
||||
import "./catalogue/get-game-stats";
|
||||
import "./catalogue/get-trending-games";
|
||||
import "./hardware/get-disk-free-space";
|
||||
import "./library/add-game-to-library";
|
||||
import "./library/create-game-shortcut";
|
||||
@@ -20,6 +22,7 @@ import "./library/open-game-executable-path";
|
||||
import "./library/open-game-installer";
|
||||
import "./library/open-game-installer-path";
|
||||
import "./library/update-executable-path";
|
||||
import "./library/verify-executable-path";
|
||||
import "./library/remove-game";
|
||||
import "./library/remove-game-from-library";
|
||||
import "./misc/open-external";
|
||||
@@ -43,13 +46,23 @@ import "./auth/sign-out";
|
||||
import "./auth/open-auth-window";
|
||||
import "./auth/get-session-hash";
|
||||
import "./user/get-user";
|
||||
import "./user/get-blocked-users";
|
||||
import "./user/block-user";
|
||||
import "./user/unblock-user";
|
||||
import "./user/get-user-friends";
|
||||
import "./user/get-user-stats";
|
||||
import "./user/report-user";
|
||||
import "./profile/get-friend-requests";
|
||||
import "./profile/get-me";
|
||||
import "./profile/undo-friendship";
|
||||
import "./profile/update-friend-request";
|
||||
import "./profile/update-profile";
|
||||
import "./profile/process-profile-image";
|
||||
import "./profile/send-friend-request";
|
||||
import "./profile/sync-friend-requests";
|
||||
import { isPortableVersion } from "@main/helpers";
|
||||
|
||||
ipcMain.handle("ping", () => "pong");
|
||||
ipcMain.handle("getVersion", () => app.getVersion());
|
||||
ipcMain.handle(
|
||||
"isPortableVersion",
|
||||
() => process.env.PORTABLE_EXECUTABLE_FILE != null
|
||||
);
|
||||
ipcMain.handle("isPortableVersion", () => isPortableVersion());
|
||||
ipcMain.handle("getDefaultDownloadsPath", () => defaultDownloadsPath);
|
||||
|
||||
@@ -3,10 +3,11 @@ import { gameRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
|
||||
import { getFileBase64 } from "@main/helpers";
|
||||
|
||||
import { steamGamesWorker } from "@main/workers";
|
||||
import { createGame } from "@main/services/library-sync";
|
||||
import { steamUrlBuilder } from "@shared";
|
||||
|
||||
const addGameToLibrary = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -32,7 +33,7 @@ const addGameToLibrary = async (
|
||||
});
|
||||
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
|
||||
? steamUrlBuilder.icon(objectID, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
await gameRepository
|
||||
@@ -53,7 +54,7 @@ const addGameToLibrary = async (
|
||||
|
||||
const game = await gameRepository.findOne({ where: { objectID } });
|
||||
|
||||
createGame(game!);
|
||||
createGame(game!).catch(() => {});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const removeRemoveGameFromLibrary = async (gameId: number) => {
|
||||
const game = await gameRepository.findOne({ where: { id: gameId } });
|
||||
|
||||
if (game?.remoteId) {
|
||||
HydraApi.delete(`/games/${game.remoteId}`).catch(() => {});
|
||||
HydraApi.delete(`/profile/games/${game.remoteId}`).catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
13
src/main/events/library/verify-executable-path.ts
Normal file
13
src/main/events/library/verify-executable-path.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { gameRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const verifyExecutablePathInUse = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
executablePath: string
|
||||
) => {
|
||||
return gameRepository.findOne({
|
||||
where: { executablePath },
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("verifyExecutablePathInUse", verifyExecutablePathInUse);
|
||||
11
src/main/events/profile/get-friend-requests.ts
Normal file
11
src/main/events/profile/get-friend-requests.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { FriendRequest } from "@types";
|
||||
|
||||
const getFriendRequests = async (
|
||||
_event: Electron.IpcMainInvokeEvent
|
||||
): Promise<FriendRequest[]> => {
|
||||
return HydraApi.get(`/profile/friend-requests`).catch(() => []);
|
||||
};
|
||||
|
||||
registerEvent("getFriendRequests", getFriendRequests);
|
||||
@@ -1,17 +1,15 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import * as Sentry from "@sentry/electron/main";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { UserProfile } from "@types";
|
||||
import { ProfileVisibility, UserDetails } from "@types";
|
||||
import { userAuthRepository } from "@main/repository";
|
||||
import { UserNotLoggedInError } from "@shared";
|
||||
|
||||
const getMe = async (
|
||||
_event: Electron.IpcMainInvokeEvent
|
||||
): Promise<UserProfile | null> => {
|
||||
return HydraApi.get(`/profile/me`)
|
||||
.then((response) => {
|
||||
const me = response.data;
|
||||
|
||||
): Promise<UserDetails | null> => {
|
||||
return HydraApi.get<UserDetails>(`/profile/me`)
|
||||
.then(async (me) => {
|
||||
userAuthRepository.upsert(
|
||||
{
|
||||
id: 1,
|
||||
@@ -26,12 +24,24 @@ const getMe = async (
|
||||
|
||||
return me;
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(async (err) => {
|
||||
if (err instanceof UserNotLoggedInError) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return userAuthRepository.findOne({ where: { id: 1 } });
|
||||
const loggedUser = await userAuthRepository.findOne({ where: { id: 1 } });
|
||||
|
||||
if (loggedUser) {
|
||||
return {
|
||||
...loggedUser,
|
||||
id: loggedUser.userId,
|
||||
username: "",
|
||||
bio: "",
|
||||
profileVisibility: "PUBLIC" as ProfileVisibility,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
11
src/main/events/profile/process-profile-image.ts
Normal file
11
src/main/events/profile/process-profile-image.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { PythonInstance } from "@main/services";
|
||||
|
||||
const processProfileImage = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
path: string
|
||||
) => {
|
||||
return PythonInstance.processProfileImage(path);
|
||||
};
|
||||
|
||||
registerEvent("processProfileImage", processProfileImage);
|
||||
11
src/main/events/profile/send-friend-request.ts
Normal file
11
src/main/events/profile/send-friend-request.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const sendFriendRequest = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string
|
||||
) => {
|
||||
return HydraApi.post("/profile/friend-requests", { friendCode: userId });
|
||||
};
|
||||
|
||||
registerEvent("sendFriendRequest", sendFriendRequest);
|
||||
9
src/main/events/profile/sync-friend-requests.ts
Normal file
9
src/main/events/profile/sync-friend-requests.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { FriendRequestSync } from "@types";
|
||||
|
||||
const syncFriendRequests = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
return HydraApi.get<FriendRequestSync>(`/profile/friend-requests/sync`);
|
||||
};
|
||||
|
||||
registerEvent("syncFriendRequests", syncFriendRequests);
|
||||
11
src/main/events/profile/undo-friendship.ts
Normal file
11
src/main/events/profile/undo-friendship.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const undoFriendship = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string
|
||||
) => {
|
||||
await HydraApi.delete(`/profile/friends/${userId}`);
|
||||
};
|
||||
|
||||
registerEvent("undoFriendship", undoFriendship);
|
||||
19
src/main/events/profile/update-friend-request.ts
Normal file
19
src/main/events/profile/update-friend-request.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { FriendRequestAction } from "@types";
|
||||
|
||||
const updateFriendRequest = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string,
|
||||
action: FriendRequestAction
|
||||
) => {
|
||||
if (action == "CANCEL") {
|
||||
return HydraApi.delete(`/profile/friend-requests/${userId}`);
|
||||
}
|
||||
|
||||
return HydraApi.patch(`/profile/friend-requests/${userId}`, {
|
||||
requestState: action,
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("updateFriendRequest", updateFriendRequest);
|
||||
@@ -1,63 +1,56 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import axios from "axios";
|
||||
import { HydraApi, PythonInstance } from "@main/services";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileTypeFromFile } from "file-type";
|
||||
import { UserProfile } from "@types";
|
||||
import type { UpdateProfileRequest, UserProfile } from "@types";
|
||||
import { omit } from "lodash-es";
|
||||
import axios from "axios";
|
||||
|
||||
const patchUserProfile = async (
|
||||
displayName: string,
|
||||
profileImageUrl?: string
|
||||
) => {
|
||||
if (profileImageUrl) {
|
||||
return HydraApi.patch("/profile", {
|
||||
displayName,
|
||||
profileImageUrl,
|
||||
interface PresignedResponse {
|
||||
presignedUrl: string;
|
||||
profileImageUrl: string;
|
||||
}
|
||||
|
||||
const patchUserProfile = async (updateProfile: UpdateProfileRequest) => {
|
||||
return HydraApi.patch<UserProfile>("/profile", updateProfile);
|
||||
};
|
||||
|
||||
const getNewProfileImageUrl = async (localImageUrl: string) => {
|
||||
const { imagePath, mimeType } =
|
||||
await PythonInstance.processProfileImage(localImageUrl);
|
||||
|
||||
const stats = fs.statSync(imagePath);
|
||||
const fileBuffer = fs.readFileSync(imagePath);
|
||||
const fileSizeInBytes = stats.size;
|
||||
|
||||
const { presignedUrl, profileImageUrl } =
|
||||
await HydraApi.post<PresignedResponse>(`/presigned-urls/profile-image`, {
|
||||
imageExt: path.extname(imagePath).slice(1),
|
||||
imageLength: fileSizeInBytes,
|
||||
});
|
||||
} else {
|
||||
return HydraApi.patch("/profile", {
|
||||
displayName,
|
||||
});
|
||||
}
|
||||
|
||||
await axios.put(presignedUrl, fileBuffer, {
|
||||
headers: {
|
||||
"Content-Type": mimeType,
|
||||
},
|
||||
});
|
||||
|
||||
return profileImageUrl;
|
||||
};
|
||||
|
||||
const updateProfile = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
displayName: string,
|
||||
newProfileImagePath: string | null
|
||||
updateProfile: UpdateProfileRequest
|
||||
) => {
|
||||
if (!newProfileImagePath) {
|
||||
return patchUserProfile(displayName).then(
|
||||
(response) => response.data as UserProfile
|
||||
);
|
||||
if (!updateProfile.profileImageUrl) {
|
||||
return patchUserProfile(omit(updateProfile, "profileImageUrl"));
|
||||
}
|
||||
|
||||
const stats = fs.statSync(newProfileImagePath);
|
||||
const fileBuffer = fs.readFileSync(newProfileImagePath);
|
||||
const fileSizeInBytes = stats.size;
|
||||
const profileImageUrl = await getNewProfileImageUrl(
|
||||
updateProfile.profileImageUrl
|
||||
).catch(() => undefined);
|
||||
|
||||
const profileImageUrl = await HydraApi.post(`/presigned-urls/profile-image`, {
|
||||
imageExt: path.extname(newProfileImagePath).slice(1),
|
||||
imageLength: fileSizeInBytes,
|
||||
})
|
||||
.then(async (preSignedResponse) => {
|
||||
const { presignedUrl, profileImageUrl } = preSignedResponse.data;
|
||||
|
||||
const mimeType = await fileTypeFromFile(newProfileImagePath);
|
||||
|
||||
await axios.put(presignedUrl, fileBuffer, {
|
||||
headers: {
|
||||
"Content-Type": mimeType?.mime,
|
||||
},
|
||||
});
|
||||
return profileImageUrl;
|
||||
})
|
||||
.catch(() => undefined);
|
||||
|
||||
return patchUserProfile(displayName, profileImageUrl).then(
|
||||
(response) => response.data as UserProfile
|
||||
);
|
||||
return patchUserProfile({ ...updateProfile, profileImageUrl });
|
||||
};
|
||||
|
||||
registerEvent("updateProfile", updateProfile);
|
||||
|
||||
@@ -1,106 +1,123 @@
|
||||
import {
|
||||
downloadQueueRepository,
|
||||
gameRepository,
|
||||
repackRepository,
|
||||
} from "@main/repository";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { StartGameDownloadPayload } from "@types";
|
||||
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
|
||||
import { DownloadManager } from "@main/services";
|
||||
import { getFileBase64 } from "@main/helpers";
|
||||
import { DownloadManager, HydraApi, logger } from "@main/services";
|
||||
|
||||
import { Not } from "typeorm";
|
||||
import { steamGamesWorker } from "@main/workers";
|
||||
import { createGame } from "@main/services/library-sync";
|
||||
import { steamUrlBuilder } from "@shared";
|
||||
import { dataSource } from "@main/data-source";
|
||||
import { DownloadQueue, Game, Repack } from "@main/entity";
|
||||
|
||||
const startGameDownload = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
payload: StartGameDownloadPayload
|
||||
) => {
|
||||
const { repackId, objectID, title, shop, downloadPath, downloader } = payload;
|
||||
const { repackId, objectID, title, shop, downloadPath, downloader, uri } =
|
||||
payload;
|
||||
|
||||
const [game, repack] = await Promise.all([
|
||||
gameRepository.findOne({
|
||||
return dataSource.transaction(async (transactionalEntityManager) => {
|
||||
const gameRepository = transactionalEntityManager.getRepository(Game);
|
||||
const repackRepository = transactionalEntityManager.getRepository(Repack);
|
||||
const downloadQueueRepository =
|
||||
transactionalEntityManager.getRepository(DownloadQueue);
|
||||
|
||||
const [game, repack] = await Promise.all([
|
||||
gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
shop,
|
||||
},
|
||||
}),
|
||||
repackRepository.findOne({
|
||||
where: {
|
||||
id: repackId,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!repack) return;
|
||||
|
||||
await DownloadManager.pauseDownload();
|
||||
|
||||
await gameRepository.update(
|
||||
{ status: "active", progress: Not(1) },
|
||||
{ status: "paused" }
|
||||
);
|
||||
|
||||
if (game) {
|
||||
await gameRepository.update(
|
||||
{
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
status: "active",
|
||||
progress: 0,
|
||||
bytesDownloaded: 0,
|
||||
downloadPath,
|
||||
downloader,
|
||||
uri,
|
||||
isDeleted: false,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const steamGame = await steamGamesWorker.run(Number(objectID), {
|
||||
name: "getById",
|
||||
});
|
||||
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? steamUrlBuilder.icon(objectID, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
await gameRepository
|
||||
.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
downloader,
|
||||
shop,
|
||||
status: "active",
|
||||
downloadPath,
|
||||
uri,
|
||||
})
|
||||
.then((result) => {
|
||||
if (iconUrl) {
|
||||
getFileBase64(iconUrl).then((base64) =>
|
||||
gameRepository.update({ objectID }, { iconUrl: base64 })
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
const updatedGame = await gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
shop,
|
||||
},
|
||||
}),
|
||||
repackRepository.findOne({
|
||||
where: {
|
||||
id: repackId,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!repack) return;
|
||||
|
||||
await DownloadManager.pauseDownload();
|
||||
|
||||
await gameRepository.update(
|
||||
{ status: "active", progress: Not(1) },
|
||||
{ status: "paused" }
|
||||
);
|
||||
|
||||
if (game) {
|
||||
await gameRepository.update(
|
||||
{
|
||||
id: game.id,
|
||||
},
|
||||
{
|
||||
status: "active",
|
||||
progress: 0,
|
||||
bytesDownloaded: 0,
|
||||
downloadPath,
|
||||
downloader,
|
||||
uri: repack.magnet,
|
||||
isDeleted: false,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const steamGame = await steamGamesWorker.run(Number(objectID), {
|
||||
name: "getById",
|
||||
});
|
||||
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
|
||||
: null;
|
||||
createGame(updatedGame!).catch(() => {});
|
||||
|
||||
await gameRepository
|
||||
.insert({
|
||||
title,
|
||||
iconUrl,
|
||||
objectID,
|
||||
downloader,
|
||||
shop,
|
||||
status: "active",
|
||||
downloadPath,
|
||||
uri: repack.magnet,
|
||||
})
|
||||
.then((result) => {
|
||||
if (iconUrl) {
|
||||
getFileBase64(iconUrl).then((base64) =>
|
||||
gameRepository.update({ objectID }, { iconUrl: base64 })
|
||||
);
|
||||
}
|
||||
HydraApi.post(
|
||||
"/games/download",
|
||||
{
|
||||
objectId: updatedGame!.objectID,
|
||||
shop: updatedGame!.shop,
|
||||
},
|
||||
{ needsAuth: false }
|
||||
).catch((err) => {
|
||||
logger.error("Failed to create game download", err);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
await DownloadManager.cancelDownload(updatedGame!.id);
|
||||
await DownloadManager.startDownload(updatedGame!);
|
||||
|
||||
const updatedGame = await gameRepository.findOne({
|
||||
where: {
|
||||
objectID,
|
||||
},
|
||||
await downloadQueueRepository.delete({ game: { id: updatedGame!.id } });
|
||||
await downloadQueueRepository.insert({ game: { id: updatedGame!.id } });
|
||||
});
|
||||
|
||||
createGame(updatedGame!);
|
||||
|
||||
await downloadQueueRepository.delete({ game: { id: updatedGame!.id } });
|
||||
await downloadQueueRepository.insert({ game: { id: updatedGame!.id } });
|
||||
|
||||
await DownloadManager.startDownload(updatedGame!);
|
||||
};
|
||||
|
||||
registerEvent("startGameDownload", startGameDownload);
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import AutoLaunch from "auto-launch";
|
||||
import { app } from "electron";
|
||||
import path from "path";
|
||||
import fs from "node:fs";
|
||||
import { logger } from "@main/services";
|
||||
|
||||
const windowsStartupPath = path.join(
|
||||
app.getPath("appData"),
|
||||
"Microsoft",
|
||||
"Windows",
|
||||
"Start Menu",
|
||||
"Programs",
|
||||
"Startup"
|
||||
);
|
||||
|
||||
const autoLaunch = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -13,9 +25,17 @@ const autoLaunch = async (
|
||||
});
|
||||
|
||||
if (enabled) {
|
||||
appLauncher.enable().catch(() => {});
|
||||
appLauncher.enable().catch((err) => {
|
||||
logger.error(err);
|
||||
});
|
||||
} else {
|
||||
appLauncher.disable().catch(() => {});
|
||||
if (process.platform == "win32") {
|
||||
fs.rm(path.join(windowsStartupPath, "Hydra.vbs"), () => {});
|
||||
}
|
||||
|
||||
appLauncher.disable().catch((err) => {
|
||||
logger.error(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
11
src/main/events/user/block-user.ts
Normal file
11
src/main/events/user/block-user.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const blockUser = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string
|
||||
) => {
|
||||
await HydraApi.post(`/users/${userId}/block`);
|
||||
};
|
||||
|
||||
registerEvent("blockUser", blockUser);
|
||||
13
src/main/events/user/get-blocked-users.ts
Normal file
13
src/main/events/user/get-blocked-users.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { UserBlocks } from "@types";
|
||||
|
||||
export const getBlockedUsers = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
take: number,
|
||||
skip: number
|
||||
): Promise<UserBlocks> => {
|
||||
return HydraApi.get(`/profile/blocks`, { take, skip });
|
||||
};
|
||||
|
||||
registerEvent("getBlockedUsers", getBlockedUsers);
|
||||
29
src/main/events/user/get-user-friends.ts
Normal file
29
src/main/events/user/get-user-friends.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { userAuthRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { UserFriends } from "@types";
|
||||
|
||||
export const getUserFriends = async (
|
||||
userId: string,
|
||||
take: number,
|
||||
skip: number
|
||||
): Promise<UserFriends> => {
|
||||
const loggedUser = await userAuthRepository.findOne({ where: { id: 1 } });
|
||||
|
||||
if (loggedUser?.userId === userId) {
|
||||
return HydraApi.get(`/profile/friends`, { take, skip });
|
||||
}
|
||||
|
||||
return HydraApi.get(`/users/${userId}/friends`, { take, skip });
|
||||
};
|
||||
|
||||
const getUserFriendsEvent = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string,
|
||||
take: number,
|
||||
skip: number
|
||||
) => {
|
||||
return getUserFriends(userId, take, skip);
|
||||
};
|
||||
|
||||
registerEvent("getUserFriends", getUserFriendsEvent);
|
||||
12
src/main/events/user/get-user-stats.ts
Normal file
12
src/main/events/user/get-user-stats.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import type { UserStats } from "@types";
|
||||
|
||||
export const getUserStats = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string
|
||||
): Promise<UserStats> => {
|
||||
return HydraApi.get(`/users/${userId}/stats`);
|
||||
};
|
||||
|
||||
registerEvent("getUserStats", getUserStats);
|
||||
@@ -1,54 +1,79 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
import { HydraApi, logger } from "@main/services";
|
||||
import { steamGamesWorker } from "@main/workers";
|
||||
import { UserProfile } from "@types";
|
||||
import { convertSteamGameToCatalogueEntry } from "../helpers/search-games";
|
||||
import { getSteamAppAsset } from "@main/helpers";
|
||||
import type { UserProfile } from "@types";
|
||||
import { steamUrlBuilder } from "@shared";
|
||||
|
||||
const getSteamGame = async (objectId: string) => {
|
||||
try {
|
||||
const steamGame = await steamGamesWorker.run(Number(objectId), {
|
||||
name: "getById",
|
||||
});
|
||||
|
||||
return {
|
||||
title: steamGame.name,
|
||||
iconUrl: steamUrlBuilder.icon(objectId, steamGame.clientIcon),
|
||||
};
|
||||
} catch (err) {
|
||||
logger.error("Failed to get Steam game", err);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const getUser = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string
|
||||
): Promise<UserProfile | null> => {
|
||||
try {
|
||||
const response = await HydraApi.get(`/user/${userId}`);
|
||||
const profile = response.data;
|
||||
const profile = await HydraApi.get<UserProfile | null>(`/users/${userId}`);
|
||||
|
||||
if (!profile) return null;
|
||||
|
||||
const recentGames = await Promise.all(
|
||||
profile.recentGames.map(async (game) => {
|
||||
const steamGame = await steamGamesWorker.run(Number(game.objectId), {
|
||||
name: "getById",
|
||||
});
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? getSteamAppAsset("icon", game.objectId, steamGame.clientIcon)
|
||||
: null;
|
||||
profile.recentGames
|
||||
.map(async (game) => {
|
||||
const steamGame = await getSteamGame(game.objectId);
|
||||
|
||||
return {
|
||||
...game,
|
||||
...convertSteamGameToCatalogueEntry(steamGame),
|
||||
iconUrl,
|
||||
};
|
||||
})
|
||||
return {
|
||||
...game,
|
||||
...steamGame,
|
||||
};
|
||||
})
|
||||
.filter((game) => game)
|
||||
);
|
||||
|
||||
const libraryGames = await Promise.all(
|
||||
profile.libraryGames.map(async (game) => {
|
||||
const steamGame = await steamGamesWorker.run(Number(game.objectId), {
|
||||
name: "getById",
|
||||
});
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? getSteamAppAsset("icon", game.objectId, steamGame.clientIcon)
|
||||
: null;
|
||||
profile.libraryGames
|
||||
.map(async (game) => {
|
||||
const steamGame = await getSteamGame(game.objectId);
|
||||
|
||||
return {
|
||||
...game,
|
||||
...convertSteamGameToCatalogueEntry(steamGame),
|
||||
iconUrl,
|
||||
};
|
||||
})
|
||||
return {
|
||||
...game,
|
||||
...steamGame,
|
||||
};
|
||||
})
|
||||
.filter((game) => game)
|
||||
);
|
||||
|
||||
return { ...profile, libraryGames, recentGames };
|
||||
if (profile.currentGame) {
|
||||
const steamGame = await getSteamGame(profile.currentGame.objectId);
|
||||
|
||||
if (steamGame) {
|
||||
profile.currentGame = {
|
||||
...profile.currentGame,
|
||||
...steamGame,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...profile,
|
||||
libraryGames,
|
||||
recentGames,
|
||||
};
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
16
src/main/events/user/report-user.ts
Normal file
16
src/main/events/user/report-user.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
export const reportUser = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string,
|
||||
reason: string,
|
||||
description: string
|
||||
): Promise<void> => {
|
||||
return HydraApi.post(`/users/${userId}/report`, {
|
||||
reason,
|
||||
description,
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("reportUser", reportUser);
|
||||
11
src/main/events/user/unblock-user.ts
Normal file
11
src/main/events/user/unblock-user.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const unblockUser = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
userId: string
|
||||
) => {
|
||||
await HydraApi.post(`/users/${userId}/unblock`);
|
||||
};
|
||||
|
||||
registerEvent("unblockUser", unblockUser);
|
||||
@@ -17,7 +17,8 @@ export const insertDownloadsFromSource = async (
|
||||
const repacks: QueryDeepPartialEntity<Repack>[] = downloads.map(
|
||||
(download) => ({
|
||||
title: download.title,
|
||||
magnet: download.uris[0],
|
||||
uris: JSON.stringify(download.uris),
|
||||
magnet: download.uris[0]!,
|
||||
fileSize: download.fileSize,
|
||||
repacker: downloadSource.name,
|
||||
uploadDate: download.uploadDate,
|
||||
|
||||
@@ -1,23 +1,7 @@
|
||||
import axios from "axios";
|
||||
import { JSDOM } from "jsdom";
|
||||
import UserAgent from "user-agents";
|
||||
|
||||
export const getSteamAppAsset = (
|
||||
category: "library" | "hero" | "logo" | "icon",
|
||||
objectID: string,
|
||||
clientIcon?: string
|
||||
) => {
|
||||
if (category === "library")
|
||||
return `https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/header.jpg`;
|
||||
|
||||
if (category === "hero")
|
||||
return `https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/library_hero.jpg`;
|
||||
|
||||
if (category === "logo")
|
||||
return `https://cdn.cloudflare.steamstatic.com/steam/apps/${objectID}/logo.png`;
|
||||
|
||||
return `https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/${objectID}/${clientIcon}.ico`;
|
||||
};
|
||||
|
||||
export const getFileBuffer = async (url: string) =>
|
||||
fetch(url, { method: "GET" }).then((response) =>
|
||||
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
||||
@@ -33,28 +17,25 @@ export const getFileBase64 = async (url: string) =>
|
||||
})
|
||||
);
|
||||
|
||||
export const steamUrlBuilder = {
|
||||
library: (objectID: string) =>
|
||||
`https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/header.jpg`,
|
||||
libraryHero: (objectID: string) =>
|
||||
`https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/library_hero.jpg`,
|
||||
logo: (objectID: string) =>
|
||||
`https://cdn.cloudflare.steamstatic.com/steam/apps/${objectID}/logo.png`,
|
||||
};
|
||||
|
||||
export const sleep = (ms: number) =>
|
||||
new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export const requestWebPage = async (url: string) => {
|
||||
const userAgent = new UserAgent();
|
||||
|
||||
return axios
|
||||
const data = await axios
|
||||
.get(url, {
|
||||
headers: {
|
||||
"User-Agent": userAgent.toString(),
|
||||
},
|
||||
})
|
||||
.then((response) => response.data);
|
||||
|
||||
const { window } = new JSDOM(data);
|
||||
return window.document;
|
||||
};
|
||||
|
||||
export const isPortableVersion = () =>
|
||||
process.env.PORTABLE_EXECUTABLE_FILE != null;
|
||||
|
||||
export * from "./download-source";
|
||||
|
||||
@@ -4,11 +4,14 @@ import updater from "electron-updater";
|
||||
import i18n from "i18next";
|
||||
import path from "node:path";
|
||||
import url from "node:url";
|
||||
import fs from "node:fs";
|
||||
import { electronApp, optimizer } from "@electron-toolkit/utils";
|
||||
import { logger, PythonInstance, WindowManager } from "@main/services";
|
||||
import { dataSource } from "@main/data-source";
|
||||
import * as resources from "@locales";
|
||||
import resources from "@locales";
|
||||
import { userPreferencesRepository } from "@main/repository";
|
||||
import { knexClient, migrationConfig } from "./knex-client";
|
||||
import { databaseDirectory } from "./constants";
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
|
||||
@@ -52,6 +55,22 @@ if (process.defaultApp) {
|
||||
app.setAsDefaultProtocolClient(PROTOCOL);
|
||||
}
|
||||
|
||||
const runMigrations = async () => {
|
||||
if (!fs.existsSync(databaseDirectory)) {
|
||||
fs.mkdirSync(databaseDirectory, { recursive: true });
|
||||
}
|
||||
|
||||
await knexClient.migrate.list(migrationConfig).then((result) => {
|
||||
logger.log(
|
||||
"Migrations to run:",
|
||||
result[1].map((migration) => migration.name)
|
||||
);
|
||||
});
|
||||
|
||||
await knexClient.migrate.latest(migrationConfig);
|
||||
await knexClient.destroy();
|
||||
};
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
@@ -63,8 +82,15 @@ app.whenReady().then(async () => {
|
||||
return net.fetch(url.pathToFileURL(decodeURI(filePath)).toString());
|
||||
});
|
||||
|
||||
await runMigrations()
|
||||
.then(() => {
|
||||
logger.log("Migrations executed successfully");
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.log("Migrations failed to run:", err);
|
||||
});
|
||||
|
||||
await dataSource.initialize();
|
||||
await dataSource.runMigrations();
|
||||
|
||||
await import("./main");
|
||||
|
||||
@@ -86,10 +112,15 @@ app.on("browser-window-created", (_, window) => {
|
||||
|
||||
const handleDeepLinkPath = (uri?: string) => {
|
||||
if (!uri) return;
|
||||
const url = new URL(uri);
|
||||
|
||||
if (url.host === "install-source") {
|
||||
WindowManager.redirect(`settings${url.search}`);
|
||||
try {
|
||||
const url = new URL(uri);
|
||||
|
||||
if (url.host === "install-source") {
|
||||
WindowManager.redirect(`settings${url.search}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error handling deep link", uri, error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
38
src/main/knex-client.ts
Normal file
38
src/main/knex-client.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import knex, { Knex } from "knex";
|
||||
import { databasePath } from "./constants";
|
||||
import { Hydra2_0_3 } from "./migrations/20240830143811_Hydra_2_0_3";
|
||||
import { RepackUris } from "./migrations/20240830143906_RepackUris";
|
||||
import { UpdateUserLanguage } from "./migrations/20240913213944_update_user_language";
|
||||
import { EnsureRepackUris } from "./migrations/20240915035339_ensure_repack_uris";
|
||||
import { app } from "electron";
|
||||
|
||||
export type HydraMigration = Knex.Migration & { name: string };
|
||||
|
||||
class MigrationSource implements Knex.MigrationSource<HydraMigration> {
|
||||
getMigrations(): Promise<HydraMigration[]> {
|
||||
return Promise.resolve([
|
||||
Hydra2_0_3,
|
||||
RepackUris,
|
||||
UpdateUserLanguage,
|
||||
EnsureRepackUris,
|
||||
]);
|
||||
}
|
||||
getMigrationName(migration: HydraMigration): string {
|
||||
return migration.name;
|
||||
}
|
||||
getMigration(migration: HydraMigration): Promise<Knex.Migration> {
|
||||
return Promise.resolve(migration);
|
||||
}
|
||||
}
|
||||
|
||||
export const knexClient = knex({
|
||||
debug: !app.isPackaged,
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: databasePath,
|
||||
},
|
||||
});
|
||||
|
||||
export const migrationConfig: Knex.MigratorConfig = {
|
||||
migrationSource: new MigrationSource(),
|
||||
};
|
||||
10
src/main/knexfile.ts
Normal file
10
src/main/knexfile.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
const config = {
|
||||
development: {
|
||||
migrations: {
|
||||
extension: "ts",
|
||||
stub: "migrations/migration.stub",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -18,12 +18,13 @@ import { HydraApi } from "./services/hydra-api";
|
||||
import { uploadGamesBatch } from "./services/library-sync";
|
||||
|
||||
const loadState = async (userPreferences: UserPreferences | null) => {
|
||||
await RepacksManager.updateRepacks();
|
||||
RepacksManager.updateRepacks();
|
||||
|
||||
import("./events");
|
||||
|
||||
if (userPreferences?.realDebridApiToken)
|
||||
if (userPreferences?.realDebridApiToken) {
|
||||
RealDebridClient.authorize(userPreferences?.realDebridApiToken);
|
||||
}
|
||||
|
||||
HydraApi.setupApi().then(() => {
|
||||
uploadGamesBatch();
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class FixRepackUploadDate1715900413313 implements MigrationInterface {
|
||||
public async up(_: QueryRunner): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
public async down(_: QueryRunner): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { Game } from "@main/entity";
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AlterLastTimePlayedToDatime1716776027208
|
||||
implements MigrationInterface
|
||||
{
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// 2024-05-27 02:08:17
|
||||
// Mon, 27 May 2024 02:08:17 GMT
|
||||
const updateLastTimePlayedValues = `
|
||||
UPDATE game SET lastTimePlayed = (SELECT
|
||||
SUBSTR(lastTimePlayed, 13, 4) || '-' || -- Year
|
||||
CASE SUBSTR(lastTimePlayed, 9, 3)
|
||||
WHEN 'Jan' THEN '01'
|
||||
WHEN 'Feb' THEN '02'
|
||||
WHEN 'Mar' THEN '03'
|
||||
WHEN 'Apr' THEN '04'
|
||||
WHEN 'May' THEN '05'
|
||||
WHEN 'Jun' THEN '06'
|
||||
WHEN 'Jul' THEN '07'
|
||||
WHEN 'Aug' THEN '08'
|
||||
WHEN 'Sep' THEN '09'
|
||||
WHEN 'Oct' THEN '10'
|
||||
WHEN 'Nov' THEN '11'
|
||||
WHEN 'Dec' THEN '12'
|
||||
END || '-' || -- Month
|
||||
SUBSTR(lastTimePlayed, 6, 2) || ' ' || -- Day
|
||||
SUBSTR(lastTimePlayed, 18, 8) -- hh:mm:ss;
|
||||
FROM game)
|
||||
WHERE lastTimePlayed IS NOT NULL;
|
||||
`;
|
||||
|
||||
await queryRunner.query(updateLastTimePlayedValues);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
const queryBuilder = queryRunner.manager.createQueryBuilder(Game, "game");
|
||||
|
||||
const result = await queryBuilder.getMany();
|
||||
|
||||
for (const game of result) {
|
||||
if (!game.lastTimePlayed) continue;
|
||||
await queryRunner.query(
|
||||
`UPDATE game set lastTimePlayed = ? WHERE id = ?;`,
|
||||
[game.lastTimePlayed.toUTCString(), game.id]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
171
src/main/migrations/20240830143811_Hydra_2_0_3.ts
Normal file
171
src/main/migrations/20240830143811_Hydra_2_0_3.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import type { HydraMigration } from "@main/knex-client";
|
||||
import type { Knex } from "knex";
|
||||
|
||||
export const Hydra2_0_3: HydraMigration = {
|
||||
name: "Hydra_2_0_3",
|
||||
up: async (knex: Knex) => {
|
||||
const timestamp = new Date().getTime();
|
||||
|
||||
await knex.schema.hasTable("migrations").then(async (exists) => {
|
||||
if (exists) {
|
||||
await knex.schema.dropTable("migrations");
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("download_source").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("download_source", (table) => {
|
||||
table.increments("id").primary();
|
||||
table
|
||||
.text("url")
|
||||
.unique({ indexName: "download_source_url_unique_" + timestamp });
|
||||
table.text("name").notNullable();
|
||||
table.text("etag");
|
||||
table.integer("downloadCount").notNullable().defaultTo(0);
|
||||
table.text("status").notNullable().defaultTo(0);
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("repack").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("repack", (table) => {
|
||||
table.increments("id").primary();
|
||||
table
|
||||
.text("title")
|
||||
.notNullable()
|
||||
.unique({ indexName: "repack_title_unique_" + timestamp });
|
||||
table
|
||||
.text("magnet")
|
||||
.notNullable()
|
||||
.unique({ indexName: "repack_magnet_unique_" + timestamp });
|
||||
table.integer("page");
|
||||
table.text("repacker").notNullable();
|
||||
table.text("fileSize").notNullable();
|
||||
table.datetime("uploadDate").notNullable();
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
table
|
||||
.integer("downloadSourceId")
|
||||
.references("download_source.id")
|
||||
.onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("game").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("game", (table) => {
|
||||
table.increments("id").primary();
|
||||
table
|
||||
.text("objectID")
|
||||
.notNullable()
|
||||
.unique({ indexName: "game_objectID_unique_" + timestamp });
|
||||
table
|
||||
.text("remoteId")
|
||||
.unique({ indexName: "game_remoteId_unique_" + timestamp });
|
||||
table.text("title").notNullable();
|
||||
table.text("iconUrl");
|
||||
table.text("folderName");
|
||||
table.text("downloadPath");
|
||||
table.text("executablePath");
|
||||
table.integer("playTimeInMilliseconds").notNullable().defaultTo(0);
|
||||
table.text("shop").notNullable();
|
||||
table.text("status");
|
||||
table.integer("downloader").notNullable().defaultTo(1);
|
||||
table.float("progress").notNullable().defaultTo(0);
|
||||
table.integer("bytesDownloaded").notNullable().defaultTo(0);
|
||||
table.datetime("lastTimePlayed");
|
||||
table.float("fileSize").notNullable().defaultTo(0);
|
||||
table.text("uri");
|
||||
table.boolean("isDeleted").notNullable().defaultTo(0);
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
table
|
||||
.integer("repackId")
|
||||
.references("repack.id")
|
||||
.unique("repack_repackId_unique_" + timestamp);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("user_preferences").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("user_preferences", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("downloadsPath");
|
||||
table.text("language").notNullable().defaultTo("en");
|
||||
table.text("realDebridApiToken");
|
||||
table
|
||||
.boolean("downloadNotificationsEnabled")
|
||||
.notNullable()
|
||||
.defaultTo(0);
|
||||
table
|
||||
.boolean("repackUpdatesNotificationsEnabled")
|
||||
.notNullable()
|
||||
.defaultTo(0);
|
||||
table.boolean("preferQuitInsteadOfHiding").notNullable().defaultTo(0);
|
||||
table.boolean("runAtStartup").notNullable().defaultTo(0);
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("game_shop_cache").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("game_shop_cache", (table) => {
|
||||
table.text("objectID").primary().notNullable();
|
||||
table.text("shop").notNullable();
|
||||
table.text("serializedData");
|
||||
table.text("howLongToBeatSerializedData");
|
||||
table.text("language");
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("download_queue").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("download_queue", (table) => {
|
||||
table.increments("id").primary();
|
||||
table
|
||||
.integer("gameId")
|
||||
.references("game.id")
|
||||
.unique("download_queue_gameId_unique_" + timestamp);
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await knex.schema.hasTable("user_auth").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.createTable("user_auth", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.text("userId").notNullable().defaultTo("");
|
||||
table.text("displayName").notNullable().defaultTo("");
|
||||
table.text("profileImageUrl");
|
||||
table.text("accessToken").notNullable().defaultTo("");
|
||||
table.text("refreshToken").notNullable().defaultTo("");
|
||||
table.integer("tokenExpirationTimestamp").notNullable().defaultTo(0);
|
||||
table.datetime("createdAt").notNullable().defaultTo(knex.fn.now());
|
||||
table.datetime("updatedAt").notNullable().defaultTo(knex.fn.now());
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
down: async (knex: Knex) => {
|
||||
await knex.schema.dropTableIfExists("game");
|
||||
await knex.schema.dropTableIfExists("repack");
|
||||
await knex.schema.dropTableIfExists("download_queue");
|
||||
await knex.schema.dropTableIfExists("user_auth");
|
||||
await knex.schema.dropTableIfExists("game_shop_cache");
|
||||
await knex.schema.dropTableIfExists("user_preferences");
|
||||
await knex.schema.dropTableIfExists("download_source");
|
||||
},
|
||||
};
|
||||
18
src/main/migrations/20240830143906_RepackUris.ts
Normal file
18
src/main/migrations/20240830143906_RepackUris.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { HydraMigration } from "@main/knex-client";
|
||||
import type { Knex } from "knex";
|
||||
|
||||
export const RepackUris: HydraMigration = {
|
||||
name: "RepackUris",
|
||||
up: async (knex: Knex) => {
|
||||
await knex.schema.alterTable("repack", (table) => {
|
||||
table.text("uris").notNullable().defaultTo("[]");
|
||||
});
|
||||
},
|
||||
|
||||
down: async (knex: Knex) => {
|
||||
await knex.schema.alterTable("repack", (table) => {
|
||||
table.integer("page");
|
||||
table.dropColumn("uris");
|
||||
});
|
||||
},
|
||||
};
|
||||
13
src/main/migrations/20240913213944_update_user_language.ts
Normal file
13
src/main/migrations/20240913213944_update_user_language.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { HydraMigration } from "@main/knex-client";
|
||||
import type { Knex } from "knex";
|
||||
|
||||
export const UpdateUserLanguage: HydraMigration = {
|
||||
name: "UpdateUserLanguage",
|
||||
up: async (knex: Knex) => {
|
||||
await knex("user_preferences")
|
||||
.update("language", "pt-BR")
|
||||
.where("language", "pt");
|
||||
},
|
||||
|
||||
down: async (_knex: Knex) => {},
|
||||
};
|
||||
17
src/main/migrations/20240915035339_ensure_repack_uris.ts
Normal file
17
src/main/migrations/20240915035339_ensure_repack_uris.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { HydraMigration } from "@main/knex-client";
|
||||
import type { Knex } from "knex";
|
||||
|
||||
export const EnsureRepackUris: HydraMigration = {
|
||||
name: "EnsureRepackUris",
|
||||
up: async (knex: Knex) => {
|
||||
await knex.schema.hasColumn("repack", "uris").then(async (exists) => {
|
||||
if (!exists) {
|
||||
await knex.schema.table("repack", (table) => {
|
||||
table.text("uris").notNullable().defaultTo("[]");
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
down: async (_knex: Knex) => {},
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import { FixRepackUploadDate1715900413313 } from "./1715900413313-fix_repack_uploadDate";
|
||||
import { AlterLastTimePlayedToDatime1716776027208 } from "./1716776027208-alter_lastTimePlayed_to_datime";
|
||||
|
||||
export default [
|
||||
FixRepackUploadDate1715900413313,
|
||||
AlterLastTimePlayedToDatime1716776027208,
|
||||
];
|
||||
11
src/main/migrations/migration.stub
Normal file
11
src/main/migrations/migration.stub
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { HydraMigration } from "@main/knex-client";
|
||||
import type { Knex } from "knex";
|
||||
|
||||
export const MigrationName: HydraMigration = {
|
||||
name: "MigrationName",
|
||||
up: async (knex: Knex) => {
|
||||
await knex.schema.createTable("table_name", (table) => {});
|
||||
},
|
||||
|
||||
down: async (knex: Knex) => {},
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import path from "node:path";
|
||||
import { spawn } from "node:child_process";
|
||||
import { app } from "electron";
|
||||
|
||||
export const startAria2 = () => {
|
||||
const binaryPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "aria2", "aria2c")
|
||||
: path.join(__dirname, "..", "..", "aria2", "aria2c");
|
||||
|
||||
return spawn(
|
||||
binaryPath,
|
||||
[
|
||||
"--enable-rpc",
|
||||
"--rpc-listen-all",
|
||||
"--file-allocation=none",
|
||||
"--allow-overwrite=true",
|
||||
],
|
||||
{ stdio: "inherit", windowsHide: true }
|
||||
);
|
||||
};
|
||||
@@ -6,17 +6,22 @@ import { downloadQueueRepository, gameRepository } from "@main/repository";
|
||||
import { publishDownloadCompleteNotification } from "../notifications";
|
||||
import { RealDebridDownloader } from "./real-debrid-downloader";
|
||||
import type { DownloadProgress } from "@types";
|
||||
import { GofileApi, QiwiApi } from "../hosters";
|
||||
import { GenericHttpDownloader } from "./generic-http-downloader";
|
||||
|
||||
export class DownloadManager {
|
||||
private static currentDownloader: Downloader | null = null;
|
||||
private static downloadingGameId: number | null = null;
|
||||
|
||||
public static async watchDownloads() {
|
||||
let status: DownloadProgress | null = null;
|
||||
|
||||
if (this.currentDownloader === Downloader.RealDebrid) {
|
||||
if (this.currentDownloader === Downloader.Torrent) {
|
||||
status = await PythonInstance.getStatus();
|
||||
} else if (this.currentDownloader === Downloader.RealDebrid) {
|
||||
status = await RealDebridDownloader.getStatus();
|
||||
} else {
|
||||
status = await PythonInstance.getStatus();
|
||||
status = await GenericHttpDownloader.getStatus();
|
||||
}
|
||||
|
||||
if (status) {
|
||||
@@ -62,44 +67,73 @@ export class DownloadManager {
|
||||
}
|
||||
|
||||
static async pauseDownload() {
|
||||
if (this.currentDownloader === Downloader.RealDebrid) {
|
||||
if (this.currentDownloader === Downloader.Torrent) {
|
||||
await PythonInstance.pauseDownload();
|
||||
} else if (this.currentDownloader === Downloader.RealDebrid) {
|
||||
await RealDebridDownloader.pauseDownload();
|
||||
} else {
|
||||
await PythonInstance.pauseDownload();
|
||||
await GenericHttpDownloader.pauseDownload();
|
||||
}
|
||||
|
||||
WindowManager.mainWindow?.setProgressBar(-1);
|
||||
this.currentDownloader = null;
|
||||
this.downloadingGameId = null;
|
||||
}
|
||||
|
||||
static async resumeDownload(game: Game) {
|
||||
if (game.downloader === Downloader.RealDebrid) {
|
||||
RealDebridDownloader.startDownload(game);
|
||||
this.currentDownloader = Downloader.RealDebrid;
|
||||
} else {
|
||||
PythonInstance.startDownload(game);
|
||||
this.currentDownloader = Downloader.Torrent;
|
||||
}
|
||||
return this.startDownload(game);
|
||||
}
|
||||
|
||||
static async cancelDownload(gameId: number) {
|
||||
if (this.currentDownloader === Downloader.RealDebrid) {
|
||||
static async cancelDownload(gameId = this.downloadingGameId!) {
|
||||
if (this.currentDownloader === Downloader.Torrent) {
|
||||
PythonInstance.cancelDownload(gameId);
|
||||
} else if (this.currentDownloader === Downloader.RealDebrid) {
|
||||
RealDebridDownloader.cancelDownload(gameId);
|
||||
} else {
|
||||
PythonInstance.cancelDownload(gameId);
|
||||
GenericHttpDownloader.cancelDownload(gameId);
|
||||
}
|
||||
|
||||
WindowManager.mainWindow?.setProgressBar(-1);
|
||||
this.currentDownloader = null;
|
||||
this.downloadingGameId = null;
|
||||
}
|
||||
|
||||
static async startDownload(game: Game) {
|
||||
if (game.downloader === Downloader.RealDebrid) {
|
||||
RealDebridDownloader.startDownload(game);
|
||||
this.currentDownloader = Downloader.RealDebrid;
|
||||
} else {
|
||||
PythonInstance.startDownload(game);
|
||||
this.currentDownloader = Downloader.Torrent;
|
||||
switch (game.downloader) {
|
||||
case Downloader.Gofile: {
|
||||
const id = game!.uri!.split("/").pop();
|
||||
|
||||
const token = await GofileApi.authorize();
|
||||
const downloadLink = await GofileApi.getDownloadLink(id!);
|
||||
|
||||
GenericHttpDownloader.startDownload(game, downloadLink, {
|
||||
Cookie: `accountToken=${token}`,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case Downloader.PixelDrain: {
|
||||
const id = game!.uri!.split("/").pop();
|
||||
|
||||
await GenericHttpDownloader.startDownload(
|
||||
game,
|
||||
`https://pixeldrain.com/api/file/${id}?download`
|
||||
);
|
||||
break;
|
||||
}
|
||||
case Downloader.Qiwi: {
|
||||
const downloadUrl = await QiwiApi.getDownloadUrl(game.uri!);
|
||||
|
||||
await GenericHttpDownloader.startDownload(game, downloadUrl);
|
||||
break;
|
||||
}
|
||||
case Downloader.Torrent:
|
||||
PythonInstance.startDownload(game);
|
||||
break;
|
||||
case Downloader.RealDebrid:
|
||||
RealDebridDownloader.startDownload(game);
|
||||
}
|
||||
|
||||
this.currentDownloader = game.downloader;
|
||||
this.downloadingGameId = game.id;
|
||||
}
|
||||
}
|
||||
|
||||
109
src/main/services/download/generic-http-downloader.ts
Normal file
109
src/main/services/download/generic-http-downloader.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { Game } from "@main/entity";
|
||||
import { gameRepository } from "@main/repository";
|
||||
import { calculateETA } from "./helpers";
|
||||
import { DownloadProgress } from "@types";
|
||||
import { HttpDownload } from "./http-download";
|
||||
|
||||
export class GenericHttpDownloader {
|
||||
public static downloads = new Map<number, HttpDownload>();
|
||||
public static downloadingGame: Game | null = null;
|
||||
|
||||
public static async getStatus() {
|
||||
if (this.downloadingGame) {
|
||||
const download = this.downloads.get(this.downloadingGame.id)!;
|
||||
const status = download.getStatus();
|
||||
|
||||
if (status) {
|
||||
const progress =
|
||||
Number(status.completedLength) / Number(status.totalLength);
|
||||
|
||||
await gameRepository.update(
|
||||
{ id: this.downloadingGame!.id },
|
||||
{
|
||||
bytesDownloaded: Number(status.completedLength),
|
||||
fileSize: Number(status.totalLength),
|
||||
progress,
|
||||
status: "active",
|
||||
folderName: status.folderName,
|
||||
}
|
||||
);
|
||||
|
||||
const result = {
|
||||
numPeers: 0,
|
||||
numSeeds: 0,
|
||||
downloadSpeed: status.downloadSpeed,
|
||||
timeRemaining: calculateETA(
|
||||
status.totalLength,
|
||||
status.completedLength,
|
||||
status.downloadSpeed
|
||||
),
|
||||
isDownloadingMetadata: false,
|
||||
isCheckingFiles: false,
|
||||
progress,
|
||||
gameId: this.downloadingGame!.id,
|
||||
} as DownloadProgress;
|
||||
|
||||
if (progress === 1) {
|
||||
this.downloads.delete(this.downloadingGame.id);
|
||||
this.downloadingGame = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static async pauseDownload() {
|
||||
if (this.downloadingGame) {
|
||||
const httpDownload = this.downloads.get(this.downloadingGame!.id!);
|
||||
|
||||
if (httpDownload) {
|
||||
await httpDownload.pauseDownload();
|
||||
}
|
||||
|
||||
this.downloadingGame = null;
|
||||
}
|
||||
}
|
||||
|
||||
static async startDownload(
|
||||
game: Game,
|
||||
downloadUrl: string,
|
||||
headers?: Record<string, string>
|
||||
) {
|
||||
this.downloadingGame = game;
|
||||
|
||||
if (this.downloads.has(game.id)) {
|
||||
await this.resumeDownload(game.id!);
|
||||
return;
|
||||
}
|
||||
|
||||
const httpDownload = new HttpDownload(
|
||||
game.downloadPath!,
|
||||
downloadUrl,
|
||||
headers
|
||||
);
|
||||
|
||||
httpDownload.startDownload();
|
||||
|
||||
this.downloads.set(game.id!, httpDownload);
|
||||
}
|
||||
|
||||
static async cancelDownload(gameId: number) {
|
||||
const httpDownload = this.downloads.get(gameId);
|
||||
|
||||
if (httpDownload) {
|
||||
await httpDownload.cancelDownload();
|
||||
this.downloads.delete(gameId);
|
||||
}
|
||||
}
|
||||
|
||||
static async resumeDownload(gameId: number) {
|
||||
const httpDownload = this.downloads.get(gameId);
|
||||
|
||||
if (httpDownload) {
|
||||
await httpDownload.resumeDownload();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +1,54 @@
|
||||
import type { ChildProcess } from "node:child_process";
|
||||
import { logger } from "../logger";
|
||||
import { sleep } from "@main/helpers";
|
||||
import { startAria2 } from "../aria2c";
|
||||
import Aria2 from "aria2";
|
||||
import { WindowManager } from "../window-manager";
|
||||
import path from "node:path";
|
||||
|
||||
export class HttpDownload {
|
||||
private static connected = false;
|
||||
private static aria2c: ChildProcess | null = null;
|
||||
private downloadItem: Electron.DownloadItem;
|
||||
|
||||
private static aria2 = new Aria2({});
|
||||
constructor(
|
||||
private downloadPath: string,
|
||||
private downloadUrl: string,
|
||||
private headers?: Record<string, string>
|
||||
) {}
|
||||
|
||||
private static async connect() {
|
||||
this.aria2c = startAria2();
|
||||
|
||||
let retries = 0;
|
||||
|
||||
while (retries < 4 && !this.connected) {
|
||||
try {
|
||||
await this.aria2.open();
|
||||
logger.log("Connected to aria2");
|
||||
|
||||
this.connected = true;
|
||||
} catch (err) {
|
||||
await sleep(100);
|
||||
logger.log("Failed to connect to aria2, retrying...");
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static getStatus(gid: string) {
|
||||
if (this.connected) {
|
||||
return this.aria2.call("tellStatus", gid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static disconnect() {
|
||||
if (this.aria2c) {
|
||||
this.aria2c.kill();
|
||||
this.connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
static async cancelDownload(gid: string) {
|
||||
await this.aria2.call("forceRemove", gid);
|
||||
}
|
||||
|
||||
static async pauseDownload(gid: string) {
|
||||
await this.aria2.call("forcePause", gid);
|
||||
}
|
||||
|
||||
static async resumeDownload(gid: string) {
|
||||
await this.aria2.call("unpause", gid);
|
||||
}
|
||||
|
||||
static async startDownload(downloadPath: string, downloadUrl: string) {
|
||||
if (!this.connected) await this.connect();
|
||||
|
||||
const options = {
|
||||
dir: downloadPath,
|
||||
public getStatus() {
|
||||
return {
|
||||
completedLength: this.downloadItem.getReceivedBytes(),
|
||||
totalLength: this.downloadItem.getTotalBytes(),
|
||||
downloadSpeed: this.downloadItem.getCurrentBytesPerSecond(),
|
||||
folderName: this.downloadItem.getFilename(),
|
||||
};
|
||||
}
|
||||
|
||||
return this.aria2.call("addUri", [downloadUrl], options);
|
||||
async cancelDownload() {
|
||||
this.downloadItem.cancel();
|
||||
}
|
||||
|
||||
async pauseDownload() {
|
||||
this.downloadItem.pause();
|
||||
}
|
||||
|
||||
async resumeDownload() {
|
||||
this.downloadItem.resume();
|
||||
}
|
||||
|
||||
async startDownload() {
|
||||
return new Promise((resolve) => {
|
||||
const options = this.headers ? { headers: this.headers } : {};
|
||||
WindowManager.mainWindow?.webContents.downloadURL(
|
||||
this.downloadUrl,
|
||||
options
|
||||
);
|
||||
|
||||
WindowManager.mainWindow?.webContents.session.once(
|
||||
"will-download",
|
||||
(_event, item, _webContents) => {
|
||||
this.downloadItem = item;
|
||||
|
||||
item.setSavePath(path.join(this.downloadPath, item.getFilename()));
|
||||
|
||||
resolve(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user