Compare commits

..

179 Commits

Author SHA1 Message Date
Zamitto
83c32de0c2 Merge pull request #494 from hydralauncher/fix/add-new-steam-cdn-url
fix: add updated steam cdn url
2024-05-23 18:09:34 -03:00
Zamitto
00ba2e01d1 update version to 1.2.4 2024-05-23 18:00:48 -03:00
Zamitto
274377f119 add new steam cdn url 2024-05-23 18:00:20 -03:00
Zamitto
48cebe729e Merge pull request #482 from Lianela/main
Updated Spanish translation
2024-05-22 15:54:29 -03:00
Lianela
19e26cba28 Final README.es.md
Added a fully translated Spanish readme
Added "es" badge: (https://img.shields.io/badge/lang-es-red)
2024-05-22 12:47:16 -06:00
Lianela
cdb876fa72 Add files via upload 2024-05-22 12:45:22 -06:00
Lianela
2099d72840 Update translation.json 2024-05-21 22:05:33 -06:00
Lianela
8924f25d7c Update translation.json 2024-05-21 22:04:25 -06:00
Lianela
7c9e15e75c Update translation.json 2024-05-21 22:00:43 -06:00
Lianela
5031ee47ca Update translation.json
Added new splash translation
2024-05-21 21:53:44 -06:00
Zamitto
bffe74f0c7 update pipe name 2024-05-21 20:07:34 -03:00
Zamitto
bf97d744e2 Merge pull request #466 from hydralauncher/feat/splash-screen-for-updates
Feat: splash screen for updates
2024-05-21 18:32:25 -03:00
Zamitto
d4bebd18e8 update seed and fix conditional order 2024-05-21 17:21:13 -03:00
Zamitto
b3480eb70b simplify events 2024-05-21 17:04:06 -03:00
Zamitto
e3da07141c hardcoding db path 2024-05-21 16:32:29 -03:00
Zamitto
7280429162 remove debug mock 2024-05-21 14:13:47 -03:00
Zamitto
0b0d2d6b10 update color for progress 2024-05-21 14:06:19 -03:00
Zamitto
551b0b3c91 removes percentage text; uses png without background; 2024-05-21 14:02:27 -03:00
Zamitto
d20d3d0b77 refactor to use html5 progress tag 2024-05-21 13:11:48 -03:00
Zamitto
a5dc101e6b update css 2024-05-21 00:02:23 -03:00
Zamitto
8957b1b1dd Merge branch 'main' into feat/splash-screen-for-updates 2024-05-20 22:43:20 -03:00
Zamitto
42626efd05 Merge pull request #469 from hydralauncher/chore/update-package-name
change package name to hydralauncher
2024-05-20 20:28:39 -03:00
Zamitto
69828e6926 revert package.json to original 2024-05-20 19:03:50 -03:00
Zamitto
9c28a6e9d0 rename function 2024-05-20 19:03:19 -03:00
Zamitto
a817a26be1 smoother way to show main window after splash 2024-05-20 19:03:19 -03:00
Zamitto
0b33cb339c update to hydralauncher 2024-05-20 18:53:26 -03:00
Zamitto
41908433c5 change package name linux to hydra-launcher
# Conflicts:
#	package.json
2024-05-20 16:40:33 -03:00
Zamitto
5667c813d9 feat: add strings to translations file 2024-05-20 16:06:47 -03:00
Zamitto
39ceb38ecd Merge branch 'main' into feat/splash-screen-for-updates 2024-05-20 15:54:18 -03:00
Zamitto
06f58291f7 Merge pull request #467 from hydralauncher/chore/update-python-link-on-readmes
update python version on README links
2024-05-20 15:53:58 -03:00
Zamitto
07cfbab77f remove un needed changes 2024-05-20 15:52:40 -03:00
Zamitto
3670c4f0ff update python version on README 2024-05-20 15:43:02 -03:00
Zamitto
485d396b91 fix for build 2024-05-20 15:12:55 -03:00
Zamitto
5aa6c72594 update python version on README 2024-05-20 14:58:28 -03:00
Zamitto
6fdb591784 refactor events 2024-05-20 14:57:23 -03:00
Zamitto
ae6edaa058 set current logger to log auto update 2024-05-20 13:57:42 -03:00
Zamitto
3062b88f4a feat: progress bar and trying to animate 2024-05-20 13:45:55 -03:00
Zamitto
f90dd82cbd feat: remove auto play 2024-05-20 13:17:19 -03:00
Zamitto
a8f072dd1b Merge branch 'main' into feat/splash-screen-for-updates
# Conflicts:
#	package.json
2024-05-20 12:22:11 -03:00
Zamitto
05a1cf9343 Merge pull request #465 from hydralauncher/chore/bumps-version
bump version to 1.2.3
2024-05-20 11:07:59 -03:00
Zamitto
399d47ca9d bump version to 1.2.3 2024-05-20 11:03:50 -03:00
Zamitto
317fe48927 Merge pull request #455 from v1mkss/polish
Adding a readme file for the Polish language
2024-05-19 23:34:06 -03:00
v1mkss
20bf7009e5 A small fix 2024-05-19 21:39:15 +03:00
v1mkss
a01a105afa Adding Polish readme 2024-05-19 21:35:59 +03:00
Zamitto
33c6203f29 prevent duplicate windows when running on dev 2024-05-19 14:56:06 -03:00
Zamitto
b9f5baef34 silent install and add more info 2024-05-19 14:39:44 -03:00
Zamitto
811878e364 feat: events working 2024-05-19 14:18:32 -03:00
Zamitto
3b17953a82 create electron event 2024-05-19 01:43:47 -03:00
Zamitto
484e79dba3 WIP: showing splash screen 2024-05-18 22:45:26 -03:00
Zamitto
7eee942dcb Merge branch 'main' into feat/splash-screen-for-updates 2024-05-18 22:28:54 -03:00
Chubby Granny Chaser
a89e6760da Merge pull request #442 from hydralauncher/feature/steam-client-icon-cache
feat: adding steam client icon cache
2024-05-18 23:31:42 +01:00
Zamitto
e2257d7ca5 Merge branch 'main' into feat/splash-screen-for-updates 2024-05-18 19:25:38 -03:00
Zamitto
be13ecc5aa fix: sanity check in case repack is null 2024-05-18 19:05:55 -03:00
Chubby Granny Chaser
5b864367e8 fix: adding alphabetical sort to steam games 2024-05-18 23:01:04 +01:00
Chubby Granny Chaser
0ccaed8d55 ci: adding portable to artifact 2024-05-18 22:26:02 +01:00
Chubby Granny Chaser
0491124a7d ci: adding portable to artifact 2024-05-18 22:24:35 +01:00
Chubby Granny Chaser
ac4956c25b ci: changing order of git hooks 2024-05-18 22:09:13 +01:00
Chubby Granny Chaser
c7920fe9f7 ci: changing order of git hooks 2024-05-18 22:08:52 +01:00
Chubby Granny Chaser
f31ae47ab2 Merge pull request #439 from hydralauncher/feat/replace-disable-hardware-acceleration-with-no-sandbox
feat: replace disableHardwareAcceleration with --no-sandbox
2024-05-18 22:08:31 +01:00
Chubby Granny Chaser
3f305eaca0 Merge branch 'feature/steam-client-icon-cache' of github.com:hydralauncher/hydra into feature/steam-client-icon-cache 2024-05-18 22:02:59 +01:00
Chubby Granny Chaser
9290d94e2a ci: changing order of git hooks 2024-05-18 22:02:06 +01:00
Chubby Granny Chaser
756cf19c23 ci: changing order of git hooks 2024-05-18 22:01:18 +01:00
Chubby Granny Chaser
7a13ecd2b7 Merge branch 'main' into feature/steam-client-icon-cache 2024-05-18 22:00:08 +01:00
Chubby Granny Chaser
19f022e0f6 feat: adding steam client icon cache 2024-05-18 21:55:12 +01:00
Zamitto
026729e8c9 Merge branch 'main' into feat/replace-disable-hardware-acceleration-with-no-sandbox 2024-05-18 16:36:40 -03:00
Zamitto
7f918aaaca Merge pull request #440 from hydralauncher/revert-270-feature/better-repack-modal
Revert "More friendly experience when presenting repack options"
2024-05-18 16:29:53 -03:00
Zamitto
d98a01df2f creares release workflow and change build workflow to run on PR 2024-05-18 16:28:44 -03:00
Zamitto
2cb76a9ad4 Revert "More friendly experience when presenting repack options" 2024-05-18 16:26:16 -03:00
Zamitto
250c6901b7 feat: replace disableHardwareAcceleration with --no-sandbox 2024-05-18 15:04:54 -03:00
Zamitto
e5fec91062 Merge pull request #270 from ChristoferMendes/feature/better-repack-modal
More friendly experience when presenting repack options
2024-05-18 15:00:50 -03:00
Zamitto
6fd38df79e Merge branch 'main' into feature/better-repack-modal 2024-05-18 14:57:54 -03:00
Zamitto
d924c64710 Update web-torrent-data.ts
Small adjustment to webTorrentData logic
2024-05-18 14:55:56 -03:00
Zamitto
10943408e9 messing around and testing 2024-05-18 00:13:43 -03:00
JackEnx
cdad2f5554 Merge pull request #430 from hydralauncher/fix/game-play-time
fix: remove play time fraction
2024-05-17 22:45:07 -03:00
JackEnx
b0bf42f754 fix: remove play time fraction 2024-05-17 22:42:20 -03:00
Zamitto
7e321ea9d1 chore: update version to 1.2.2 2024-05-17 19:43:49 -03:00
Zamitto
01c3ddf167 Merge pull request #423 from hydralauncher/hotfix/repack-uploadDate
Hotfix/repack upload date
2024-05-17 19:33:22 -03:00
Zamitto
f8770a03f7 update migration to delete xatab repacks as well 2024-05-17 19:00:01 -03:00
Zamitto
3b7725d774 remove entris from game_shop_cache and migrations 2024-05-17 18:40:31 -03:00
Zamitto
2679b143ed add yarn.lock 2024-05-17 18:40:30 -03:00
JackEnx
2b0f57f967 fix: change migration to atomic 2024-05-17 18:35:56 -03:00
Zamitto
622107a6f1 check if table exists and has items before running migration 2024-05-17 17:12:03 -03:00
Zamitto
5908544602 improve xatab scrap performance and update seed with xatab repacks 2024-05-17 16:59:16 -03:00
Zamitto
b330c94dca update hydra.db after scrap 2024-05-17 16:21:43 -03:00
Zamitto
4b0f998830 fix: online fix totalPages becoming NaN 2024-05-17 16:19:59 -03:00
Zamitto
d3d9315102 ensure migrations are run before everything else 2024-05-17 14:02:41 -03:00
Zamitto
689fe5715e update migration so it updates xatab repacks 2024-05-17 13:47:17 -03:00
Zamitto
6a52c26874 fix: modal role 2024-05-17 13:46:35 -03:00
JackEnx
60907cdc4b fix: incomplete migration 2024-05-17 13:43:27 -03:00
JackEnx
1b00e2ed57 Merge branch 'hotfix/repack-uploadDate' of https://github.com/hydralauncher/hydra into hotfix/repack-uploadDate 2024-05-17 11:40:14 -03:00
Zamitto
6479049256 add missing await 2024-05-17 09:47:06 -03:00
Zamitto
e739f3a483 update migration to prevent fk error 2024-05-17 09:44:25 -03:00
ChristoferMendes
d8937b3672 Merge branch 'main' into feature/better-repack-modal 2024-05-17 08:27:47 -03:00
JackEnx
18f27e76d7 Merge branch 'hotfix/repack-uploadDate' of https://github.com/hydralauncher/hydra into hotfix/repack-uploadDate 2024-05-17 07:14:06 -03:00
JackEnx
47018ace60 Merge branch 'main' of https://github.com/hydralauncher/hydra into hotfix/repack-uploadDate 2024-05-17 07:10:42 -03:00
Zamitto
a8332c858e update migration to get onlinefix repacks from hydra.db 2024-05-16 23:54:27 -03:00
Zamitto
d93e580d0f Merge branch 'main' into hotfix/repack-uploadDate 2024-05-16 22:25:29 -03:00
Zamitto
0e7e62d596 Merge pull request #405 from userMacieG/patch-1
Update polish translation
2024-05-16 20:48:52 -03:00
Zamitto
1d05551f4e Merge branch 'main' into patch-1 2024-05-16 20:40:03 -03:00
Zamitto
4908d07ef2 change migration so it sets uploadDate = createdAt 2024-05-16 20:35:51 -03:00
Zamitto
be4d13533c fix: add migration 2024-05-16 20:30:08 -03:00
Zamitto
7231848bd8 fix: get date and name from torrent 2024-05-16 20:29:37 -03:00
Zamitto
fb5ed9aae3 Merge pull request #411 from itsOdell/feat/force-use-yarn
feat: force developer to use yarn
2024-05-16 12:50:08 -03:00
Abduladil Sunnat
e908cc6273 Merge branch 'main' into feat/force-use-yarn 2024-05-16 11:45:02 -04:00
Zamitto
5e670aab24 Merge pull request #373 from mag1yar/feature/recently-played-games-in-tray-context-menu
Adding recently played games to tray context menu
2024-05-16 12:24:39 -03:00
itsOdell
75a9d56624 feat: force developer to use yarn
This solves alot of issues in PR's that have package-lock.json becuase
they did npm install, this update forces an error and exits out when
developer runs npm install
2024-05-16 11:17:01 -04:00
mag1yar
28bd70e745 Removed update when clicking on a game and fixed sorting 2024-05-16 19:26:45 +05:00
ChristoferMendes
38d652c507 Merge branch 'main' into feature/better-repack-modal 2024-05-16 08:41:22 -03:00
ChristoferMendes
539f444ab5 feat(webTorrentHealth): update recursive function with a loop 2024-05-16 08:34:42 -03:00
mag1yar
3cbbb71768 Merge branch 'main' into feature/recently-played-games-in-tray-context-menu 2024-05-16 13:49:10 +05:00
Maciej Ratyński
2034e0a157 Update translation.json 2024-05-16 10:37:49 +02:00
Zamitto
a27a8644ea Merge pull request #400 from hydralauncher/fix/worker-null-error
fix/null-error
2024-05-15 23:26:28 -03:00
JackEnx
1a3e33cbc9 fix/null-error 2024-05-15 23:21:06 -03:00
Zamitto
4e8f260b33 Merge branch 'main' into feature/recently-played-games-in-tray-context-menu 2024-05-15 23:14:27 -03:00
Zamitto
29d9c43834 Merge pull request #397 from hydralauncher/add-prettier-check-on-pipeline
add prettier check on ci
2024-05-15 22:09:06 -03:00
Zamitto
d4be3ed4a0 add changes from prettier 2024-05-15 22:04:07 -03:00
Zamitto
16b9c9d340 add prettier check 2024-05-15 21:58:41 -03:00
Zamitto
f3f68e9009 fix: invalid json on spanish translation 2024-05-15 21:40:42 -03:00
Zamitto
2caf83b929 Merge pull request #395 from Lianela/main
Fixed and updated Spanish translation
2024-05-15 21:37:23 -03:00
ChristoferMendes
7a2b693397 refactor: Improve error handling and retry logic in getSeedersAndPeers function 2024-05-15 20:06:53 -03:00
Lianela
97467705b0 translation.json 2024-05-15 17:05:52 -06:00
Lianela
cdb15a0493 Update translation.json 2024-05-15 16:50:23 -06:00
Lianela
b9d42ca43f Update translation.json
Updated to new dialogs and cleaned some strings to match lines with english one
2024-05-15 16:27:08 -06:00
Zamitto
3d89fc659b Merge pull request #352 from ruth3n/feat/issues-forms
Using GitHub forms for Issues
2024-05-15 19:21:02 -03:00
Zamitto
e5bc60c13d Merge branch 'main' into feat/issues-forms 2024-05-15 19:16:46 -03:00
Zamitto
53e7053764 feat: disable hardware acceleration 2024-05-15 18:42:44 -03:00
Zamitto
04a5dbb71d Merge branch 'main' into feature/better-repack-modal 2024-05-15 17:48:42 -03:00
Zamitto
24c6a3ebe3 Merge pull request #383 from expload233/main
Fix typo in chinese Translation
2024-05-15 17:47:31 -03:00
Zamitto
3b2fe183b5 Merge branch 'main' into main 2024-05-15 17:45:07 -03:00
Zamitto
ba6a41d8e1 Merge pull request #384 from xmkgfm/main
Fixed some Korean translation
2024-05-15 07:57:54 -03:00
xmkgfm
4ef054175a Fixed some Korean translation 2024-05-15 15:19:49 +09:00
expload
642c2abfd6 fix steam language get wrong 2024-05-15 05:21:29 +00:00
expload
f90ad4c377 fix typo in chinese Translation 2024-05-15 05:09:46 +00:00
mag1yar
20dab9c4c1 Adding recently played games to tray context menu 2024-05-15 01:51:25 +05:00
Zamitto
be6c255bc1 Merge pull request #370 from xxDRV/patch-7
Fixed a typo in RU locale
2024-05-14 17:47:33 -03:00
Antecess
d5dfd7853f Fixed a typo in RU locale
Dunno how i oversaw it earlier, sorry
2024-05-15 01:43:55 +05:00
ChristoferMendes
7bdf7f8c2d Merge remote-tracking branch 'upstream/main' into feature/better-repack-modal 2024-05-14 15:36:26 -03:00
Matvey Natsevskiy
5882d3697c Merge branch 'main' into feat/issues-forms 2024-05-14 15:39:53 +03:00
ChristoferMendes
95e802372f Merge branch 'main' of github.com:ChristoferMendes/hydra into feature/better-repack-modal 2024-05-13 22:31:45 -03:00
ChristoferMendes
9c261551c3 feat: Add toCapitalize function for capitalizing strings 2024-05-13 22:28:34 -03:00
ChristoferMendes
4e9e9deec1 style: Remove unnecessary whitespace and newline in translation.json 2024-05-13 22:15:44 -03:00
ChristoferMendes
1c56227fa3 feat(searcher): Add repacker check to isMultiplayerRepack function 2024-05-13 22:14:38 -03:00
Zamitto
81ea790d73 Merge branch 'main' into feature/better-repack-modal 2024-05-13 19:04:20 -03:00
Matvey Natsevskiy
046d291585 Update and rename bug_report.md to bug_report.yml 2024-05-13 19:40:11 +03:00
Matvey Natsevskiy
819e8bc508 Update feature_request.yml 2024-05-13 19:38:55 +03:00
Matvey Natsevskiy
91fe56d810 Update feature_request.yml 2024-05-13 19:37:33 +03:00
ChristoferMendes
0d089bb5c4 Merge branch 'main' into feature/better-repack-modal 2024-05-13 08:27:31 -03:00
Christofer Luiz dos Santos Mendes
82edc6d438 Merge branch 'main' into feature/better-repack-modal 2024-05-12 22:40:08 -03:00
ChristoferMendes
26db88966f refactor: Update getRepackLanguageBasedOnRepacker function parameters and use user preferences 2024-05-12 21:54:03 -03:00
ChristoferMendes
f2af65d4cd style: Update formatting in various files 2024-05-12 21:40:30 -03:00
ChristoferMendes
e6b62399f7 fix: solve merge conflict markers 2024-05-12 21:35:10 -03:00
ChristoferMendes
713392ee29 style: Remove unnecessary code in translation.json 2024-05-12 21:34:23 -03:00
ChristoferMendes
c7da83cae1 Merge branch 'main' into feature/better-repack-modal 2024-05-12 21:33:12 -03:00
ChristoferMendes
f9343ca0c2 style: Remove lucide-react icons and replace them with SVG components 2024-05-12 21:29:06 -03:00
ChristoferMendes
6053b7cd67 refactor: Remove unused "repack_language_code" translations from multiple locale files 2024-05-12 21:20:56 -03:00
ChristoferMendes
0333282915 refactor: Update import paths and improve async function in get-magnet-health 2024-05-12 21:16:15 -03:00
ChristoferMendes
23ab98294a feat: Add webtorrent-health package to dependencies 2024-05-12 21:06:05 -03:00
ChristoferMendes
27bff9d2e6 fix: Replace getMagnetData with getMagnetHealth in references and implementations 2024-05-12 21:06:02 -03:00
ChristoferMendes
6b9f902b2c feat: Replace OpenWebTorrent service with WebTorrentData service 2024-05-12 21:05:46 -03:00
ChristoferMendes
4616f69a29 refactor: Update function names in repack tracker to use 'savePage' instead of 'saveRepacks' 2024-05-12 20:53:58 -03:00
ChristoferMendes
02417dda40 style: update tag component CSS formatting 2024-05-12 20:52:09 -03:00
ChristoferMendes
5f468d5b2e style: Update translation keys for "multi_player" to "multiplayer" in multiple language files 2024-05-12 20:50:55 -03:00
ChristoferMendes
0aa36c5a57 fix: update tag styles to match variables 2024-05-12 20:50:51 -03:00
ChristoferMendes
2f0cd24fb8 refactor: Improve the structure of useMagnetData function 2024-05-12 14:25:13 -03:00
ChristoferMendes
dce700b189 Merge branch 'main' into feature/better-repack-modal 2024-05-12 14:23:22 -03:00
ChristoferMendes
e55d41889d refactor: Simplify code by removing unnecessary try-catch block 2024-05-12 14:20:17 -03:00
ChristoferMendes
8f6922fc8a feat: Add multi-language and multiplayer tags in RepacksModal 2024-05-10 12:32:50 -03:00
ChristoferMendes
ff6a204686 feat: Add getMagnetData function to global declaration 2024-05-10 12:17:53 -03:00
ChristoferMendes
92f35bad9f refactor: Update function calls from savePage to saveRepacks in multiple files 2024-05-10 12:14:23 -03:00
ChristoferMendes
b84df28f39 feat: Add openWebTorrent service for fetching seeders and peers 2024-05-10 12:12:45 -03:00
ChristoferMendes
09bd7dcc36 feat: Add lucide-react package to dependencies 2024-05-10 12:11:30 -03:00
ChristoferMendes
06ed5e07bf feat: Add new functionality to display repack language and seeders/peers in RepacksModal 2024-05-10 12:10:43 -03:00
ChristoferMendes
ada218cea1 feat: Add functions for multiplayer repack, multi-language support, and repack language based on repacker 2024-05-10 12:10:28 -03:00
ChristoferMendes
2662ba3875 style: Add styling for tags container in repacks modal 2024-05-10 12:10:22 -03:00
ChristoferMendes
58693fdb00 feat: Add SeedersAndPeers component with skeleton loader 2024-05-10 12:10:08 -03:00
ChristoferMendes
1872ff1d24 feat: Add tooltip component with styles and visibility logic 2024-05-10 12:09:59 -03:00
ChristoferMendes
08c4906465 feat: Add new Tag component with styling for tags 2024-05-10 12:09:44 -03:00
ChristoferMendes
a0344ea491 feat(events): Add new event for getting magnet data 2024-05-10 11:43:36 -03:00
ChristoferMendes
02c4f0a0e6 feat: Add repack language codes to translation files 2024-05-10 11:42:53 -03:00
73 changed files with 7893 additions and 443 deletions

View File

@@ -1,29 +0,0 @@
---
name: Bug report
about: Create a report to help us improve. Write in English, please
title: "[BUG]"
labels: bug
assignees: ""
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
- OS: [Windows 11/Linux Distro/Steam Deck]
- Hydra Version:
- Additional information and context of your problem:

58
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: Bug Report
description: Create a report to help us improve. Write in English, please.
title: "[BUG] "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thank you for creating a bug report to help us improve!
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: bug-reproduce
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior. For example, "1. Go to '...', 2. Click on '...', 3. See error"
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
validations:
required: false
- type: input
id: OS
attributes:
label: Operating System
description: Which operating system are you using (e.g., Windows 11/Linux Distro/Steam Deck)?
validations:
required: true
- type: input
id: hydra-version
attributes:
label: Hydra Version
description: Please provide the version of Hydra you are using.
validations:
required: true
- type: textarea
id: additional-info
attributes:
label: Additional Information
description: Please provide any additional information and context about your problem.
validations:
required: false

View File

@@ -1,19 +0,0 @@
---
name: Feature request
about: Suggest an idea for Hydra. Write in English, please
title: "[REQUEST]"
labels: enhancement
assignees: ""
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,37 @@
name: Feature Request
description: Request a new feature.
title: "[REQUEST] "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to suggest a new feature!
- type: textarea
id: problem-related
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
validations:
required: false

View File

@@ -1,8 +1,6 @@
name: Build
on:
push:
branches: main
on: [pull_request]
jobs:
build:
@@ -39,7 +37,6 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: yarn build:linux
env:
MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }}
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -48,7 +45,6 @@ jobs:
if: matrix.os == 'windows-latest'
run: yarn build:win
env:
MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }}
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -58,7 +54,7 @@ jobs:
with:
name: Build-${{ matrix.os }}
path: |
dist/*.exe
dist/win-unpacked/**
dist/*.zip
dist/*.dmg
dist/*.deb
@@ -66,21 +62,3 @@ jobs:
dist/*.tar.gz
dist/*.yml
dist/*.blockmap
- name: Release
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
dist/*.exe
dist/*.zip
dist/*.dmg
dist/*.AppImage
dist/*.snap
dist/*.deb
dist/*.rpm
dist/*.tar.gz
dist/*.yml
dist/*.blockmap
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -26,3 +26,6 @@ jobs:
- name: Lint
run: yarn lint
- name: Format check
run: yarn format-check

70
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: Release
on:
push:
branches: main
jobs:
build:
strategy:
matrix:
os: [windows-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Check out Git repository
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20.11.1
- name: Install dependencies
run: yarn
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: 3.9
- name: Install dependencies
run: pip install -r requirements.txt
- name: Build with cx_Freeze
run: python torrent-client/setup.py build
- name: Build Linux
if: matrix.os == 'ubuntu-latest'
run: yarn build:linux
env:
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build Windows
if: matrix.os == 'windows-latest'
run: yarn build:win
env:
MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }}
MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
dist/*.exe
dist/*.zip
dist/*.dmg
dist/*.AppImage
dist/*.snap
dist/*.deb
dist/*.rpm
dist/*.tar.gz
dist/*.yml
dist/*.blockmap
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

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

View File

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

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
engine-strict = true

View File

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

View File

@@ -119,7 +119,7 @@ yarn
### Усталёўка Python 3.9
Упэўніцеся, што ў вас усталяваны Python 3.9 на вашым кампутары. Вы можаце загрузіць і ўсталяваць яго з [python.org](https://www.python.org/downloads/release/python-3919/).
Упэўніцеся, што ў вас усталяваны Python 3.9 на вашым кампутары. Вы можаце загрузіць і ўсталяваць яго з [python.org](https://www.python.org/downloads/release/python-3913/).
### Усталёўка залежнасцяў Python

182
README.es.md Normal file
View File

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

View File

@@ -13,11 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
![Hydra Catalogue](./docs/screenshot.png)
@@ -119,7 +119,7 @@ yarn
### Install Python 3.9
Ensure you have Python 3.9 installed on your machine. You can download and install it from [python.org](https://www.python.org/downloads/release/python-3919/).
Ensure you have Python 3.9 installed on your machine. You can download and install it from [python.org](https://www.python.org/downloads/release/python-3913/).
### Install Python Dependencies

185
README.pl.md Normal file
View File

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

View File

@@ -13,13 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
![Hydra Catalogue](./docs/screenshot.png)
</div>
@@ -120,7 +118,7 @@ yarn
### <a name="install-python-39"></a> Instale Python 3.9
Certifique-se de ter o Python 3.9 instalado em sua máquina. Você pode baixá-lo e instalá-lo em [python.org](https://www.python.org/downloads/release/python-3919/).
Certifique-se de ter o Python 3.9 instalado em sua máquina. Você pode baixá-lo e instalá-lo em [python.org](https://www.python.org/downloads/release/python-3913/).
### <a name="install-python-dependencies"></a> Instale Python Dependencies

View File

@@ -13,11 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
![Hydra Catalogue](./docs/screenshot.png)
@@ -119,7 +119,7 @@ yarn
### Установка Python 3.9
Убедитесь, что у вас установлен Python 3.9 на вашем компьютере. Вы можете загрузить и установить его с [python.org](https://www.python.org/downloads/release/python-3919/).
Убедитесь, что у вас установлен Python 3.9 на вашем компьютере. Вы можете загрузить и установить его с [python.org](https://www.python.org/downloads/release/python-3913/).
### Установка зависимостей Python

View File

@@ -13,11 +13,11 @@
[![build](https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml)](https://github.com/hydralauncher/hydra/actions)
[![release](https://img.shields.io/github/package-json/v/hydralauncher/hydra)](https://github.com/hydralauncher/hydra/releases)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
[![uk-UA](https://img.shields.io/badge/lang-uk--UA-blue)](README.uk-UA.md)
[![be](https://img.shields.io/badge/lang-be-orange)](README.be.md)
[![en](https://img.shields.io/badge/lang-en-red.svg)](README.md)
[![pl](https://img.shields.io/badge/lang-pl-white)](README.pl.md)
[![pt-BR](https://img.shields.io/badge/lang-pt--BR-green.svg)](README.pt-BR.md)
[![ru](https://img.shields.io/badge/lang-ru-yellow.svg)](README.ru.md)
![Hydra Catalogue](./docs/screenshot.png)
@@ -123,7 +123,7 @@ yarn
### Встановіть Python 3.9
Переконайтеся, що на вашому комп'ютері встановлено Python 3.9. Ви можете завантажити та встановити його з [python.org](https://www.python.org/downloads/release/python-3919/).
Переконайтеся, що на вашому комп'ютері встановлено Python 3.9. Ви можете завантажити та встановити його з [python.org](https://www.python.org/downloads/release/python-3913/).
### Встановіть Python залежності

View File

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

BIN
hydra.db

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{
"name": "hydra",
"version": "1.2.0",
"name": "hydralauncher",
"version": "1.2.4",
"description": "Hydra",
"main": "./out/main/index.js",
"author": "Los Broxas",
@@ -10,8 +10,13 @@
"url": "https://github.com/hydralauncher/hydra.git"
},
"type": "module",
"engines": {
"npm": "please-use-yarn",
"yarn": ">= 1.19.1"
},
"scripts": {
"format": "prettier --write .",
"format-check": "prettier --check .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false",
@@ -24,7 +29,8 @@
"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"
"prepare": "husky",
"typeorm:migration-create": "yarn typeorm migration:create"
},
"dependencies": {
"@electron-toolkit/preload": "^3.0.0",

1
seeds/steam-games.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -55,62 +55,62 @@
"remove_from_list": "إزالة",
"space_left_on_disk": "{{space}} متبقية على القرص",
"eta": "الوقت المتبقي {{eta}}",
"downloading_metadata": "جاري تنزيل البيانات الوصفية...",
"checking_files": "جاري التحقق من الملفات...",
"filter": "تصفية حزم إعادة التجميع",
"requirements": "متطلبات النظام",
"minimum": "الحد الأدنى",
"recommended": "موصى به",
"no_minimum_requirements": "{{title}} لا تتوفر معلومات عن الحد الأدنى للمتطلبات",
"no_recommended_requirements": "{{title}} لا تتوفر معلومات عن المتطلبات الموصى بها",
"paused_progress": "{{progress}} (متوقف)",
"release_date": "تم الإصدار في {{date}}",
"publisher": "نشر بواسطة {{publisher}}",
"copy_link_to_clipboard": "نسخ الرابط",
"copied_link_to_clipboard": "تم نسخ الرابط",
"hours": "ساعات",
"minutes": "دقائق",
"amount_hours": "{{amount}} ساعات",
"amount_minutes": "{{amount}} دقائق",
"accuracy": "دقة {{accuracy}}%",
"add_to_library": "إضافة إلى المكتبة",
"remove_from_library": "إزالة من المكتبة",
"no_downloads": "لا توجد تنزيلات متاحة",
"play_time": "تم اللعب لمدة {{amount}}",
"last_time_played": "آخر مرة لعبت {{period}}",
"not_played_yet": "لم تلعب {{title}} بعد",
"next_suggestion": "الاقتراح التالي",
"play": "لعب",
"deleting": "جاري حذف المثبت...",
"close": "إغلاق",
"playing_now": "قيد التشغيل الآن",
"change": "تغيير",
"repacks_modal_description": "اختر الحزمة التي تريد تنزيلها",
"select_folder_hint": "لتغيير المجلد الافتراضي، انتقل إلى الإعدادات",
"download_now": "تنزيل الآن",
"installation_instructions": "إرشادات التثبيت",
"installation_instructions_description": "هناك خطوات إضافية مطلوبة لتثبيت هذه اللعبة",
"online_fix_instruction": "تتطلب ألعاب OnlineFix كلمة مرور لاستخراجها. عند الحاجة، استخدم كلمة المرور التالية:",
"dodi_installation_instruction": "عند فتح مثبت DODI، اضغط على مفتاح التشغيل لأعلى <0 /> لبدء عملية التثبيت:",
"dont_show_it_again": "لا تعرضها مرة أخرى",
"copy_to_clipboard": "نسخ",
"copied_to_clipboard": "تم النسخ",
"got_it": "حسنأ",
"no_shop_details": "لم يتم استرداد تفاصيل المتجر.",
"download_options": "خيارات التنزيل",
"download_path": "مسار التنزيل",
"previous_screenshot": "لقطة الشاشة السابقة",
"next_screenshot": "لقطة الشاشة التالية",
"screenshot": "لقطة شاشة {{number}}",
"open_screenshot": "افتح لقطة الشاشة {{number}}"
"downloading_metadata": "جاري تنزيل البيانات الوصفية...",
"checking_files": "جاري التحقق من الملفات...",
"filter": "تصفية حزم إعادة التجميع",
"requirements": "متطلبات النظام",
"minimum": "الحد الأدنى",
"recommended": "موصى به",
"no_minimum_requirements": "{{title}} لا تتوفر معلومات عن الحد الأدنى للمتطلبات",
"no_recommended_requirements": "{{title}} لا تتوفر معلومات عن المتطلبات الموصى بها",
"paused_progress": "{{progress}} (متوقف)",
"release_date": "تم الإصدار في {{date}}",
"publisher": "نشر بواسطة {{publisher}}",
"copy_link_to_clipboard": "نسخ الرابط",
"copied_link_to_clipboard": "تم نسخ الرابط",
"hours": "ساعات",
"minutes": "دقائق",
"amount_hours": "{{amount}} ساعات",
"amount_minutes": "{{amount}} دقائق",
"accuracy": "دقة {{accuracy}}%",
"add_to_library": "إضافة إلى المكتبة",
"remove_from_library": "إزالة من المكتبة",
"no_downloads": "لا توجد تنزيلات متاحة",
"play_time": "تم اللعب لمدة {{amount}}",
"last_time_played": "آخر مرة لعبت {{period}}",
"not_played_yet": "لم تلعب {{title}} بعد",
"next_suggestion": "الاقتراح التالي",
"play": "لعب",
"deleting": "جاري حذف المثبت...",
"close": "إغلاق",
"playing_now": "قيد التشغيل الآن",
"change": "تغيير",
"repacks_modal_description": "اختر الحزمة التي تريد تنزيلها",
"select_folder_hint": "لتغيير المجلد الافتراضي، انتقل إلى الإعدادات",
"download_now": "تنزيل الآن",
"installation_instructions": "إرشادات التثبيت",
"installation_instructions_description": "هناك خطوات إضافية مطلوبة لتثبيت هذه اللعبة",
"online_fix_instruction": "تتطلب ألعاب OnlineFix كلمة مرور لاستخراجها. عند الحاجة، استخدم كلمة المرور التالية:",
"dodi_installation_instruction": "عند فتح مثبت DODI، اضغط على مفتاح التشغيل لأعلى <0 /> لبدء عملية التثبيت:",
"dont_show_it_again": "لا تعرضها مرة أخرى",
"copy_to_clipboard": "نسخ",
"copied_to_clipboard": "تم النسخ",
"got_it": "حسنأ",
"no_shop_details": "لم يتم استرداد تفاصيل المتجر.",
"download_options": "خيارات التنزيل",
"download_path": "مسار التنزيل",
"previous_screenshot": "لقطة الشاشة السابقة",
"next_screenshot": "لقطة الشاشة التالية",
"screenshot": "لقطة شاشة {{number}}",
"open_screenshot": "افتح لقطة الشاشة {{number}}"
},
"activation": {
"title": "تفعيل هايدرا",
"installation_id": "معرف التثبيت:",
"enter_activation_code": "أدخل رمز التفعيل الخاص بك",
"message": "إذا كنت لا تعرف أين تسأل عن هذا ، فلا يجب أن يكون لديك هذا.",
"title": "تفعيل هايدرا",
"installation_id": "معرف التثبيت:",
"enter_activation_code": "أدخل رمز التفعيل الخاص بك",
"message": "إذا كنت لا تعرف أين تسأل عن هذا ، فلا يجب أن يكون لديك هذا.",
"activate": "تفعيل",
"loading": "جار التحميل…"
"loading": "جار التحميل…"
},
"downloads": {
"resume": "استئناف",
@@ -146,7 +146,7 @@
"telemetry": "القياس عن بعد",
"telemetry_description": "تفعيل إحصائيات الاستخدام مجهولة المصدر",
"real_debrid_api_token_label": "رمز واجهة برمجة التطبيقات (API) لـReal Debrid ",
"quit_app_instead_hiding": "إنهاء هايدرا بدلاً من التصغير الى شريط الحالة",
"quit_app_instead_hiding": "إنهاء هايدرا بدلاً من التصغير الى شريط الحالة",
"launch_with_system": "تشغيل هايدرا عند بدء تشغيل النظام",
"general": "عام",
"behavior": "السلوك",
@@ -177,4 +177,4 @@
"modal": {
"close": "زر إغلاق"
}
}
}

View File

@@ -176,5 +176,11 @@
},
"modal": {
"close": "Close button"
},
"splash": {
"downloading_version": "Downloading version {{version}}",
"searching_updates": "Searching for updates",
"update_found": "Update {{version}} found",
"restarting_and_applying": "Restarting and applying update"
}
}

View File

@@ -24,12 +24,12 @@
"github": "Contribuye en GitHub"
},
"header": {
"search": "Buscar",
"search": "Buscar juegos",
"home": "Inicio",
"catalogue": "Catálogo",
"downloads": "Descargas",
"search_results": "Resultados de búsqueda",
"settings": "Ajustes",
"home": "Inicio"
"settings": "Ajustes"
},
"bottom_panel": {
"no_downloads_in_progress": "Sin descargas en progreso",
@@ -37,12 +37,17 @@
"checking_files": "Analizando archivos de {{title}} - ({{percentage}} completado)",
"downloading": "Descargando {{title}}… ({{percentage}} completado) - Finalizando {{eta}} - {{speed}}"
},
"catalogue": {
"next_page": "Siguiente página",
"previous_page": "Pagina anterior"
},
"game_details": {
"open_download_options": "Ver opciones de descargas",
"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}}",
"install": "Instalar",
"resume": "Continuar",
"pause": "Pausa",
"cancel": "Cancelar",
@@ -52,7 +57,7 @@
"eta": "Finalizando en {{eta}}",
"downloading_metadata": "Descargando metadatos…",
"checking_files": "Analizando archivos…",
"filter": "Filtrar repacks",
"filter": "Buscar repacks",
"requirements": "Requisitos del Sistema",
"minimum": "Mínimos",
"recommended": "Recomendados",
@@ -71,20 +76,17 @@
"add_to_library": "Agregar a la biblioteca",
"remove_from_library": "Eliminar de la biblioteca",
"no_downloads": "No hay descargas disponibles",
"next_suggestion": "Siguiente sugerencia",
"play_time": "Jugado por {{amount}}",
"install": "Instalar",
"play": "Jugar",
"not_played_yet": "Aún no has jugado a {{title}}",
"close": "Cerrar",
"deleting": "Eliminando instalador…",
"playing_now": "Jugando ahora",
"last_time_played": "Jugado por última vez {{period}}",
"got_it": "Entendido",
"not_played_yet": "Aún no has jugado a {{title}}",
"next_suggestion": "Siguiente sugerencia",
"play": "Jugar",
"deleting": "Eliminando instalador…",
"close": "Cerrar",
"playing_now": "Jugando ahora",
"change": "Cambiar",
"repacks_modal_description": "Selecciona el repack que quieres descargar",
"downloads_path": "Ruta de descarga",
"select_folder_hint": "Para cambiar la carpeta predeterminada, accede a",
"select_folder_hint": "Para cambiar la carpeta predeterminada, ve a <0>Ajustes</0>",
"download_now": "Descargar ahora",
"installation_instructions": "Instrucciones de instalación",
"installation_instructions_description": "Se requieren de pasos adicionales para instalar este juego",
@@ -92,7 +94,15 @@
"dodi_installation_instruction": "Cuando abras el instalador de DODI, presiona la tecla hacia arriba del teclado <0 /> para iniciar el proceso de instalación:",
"dont_show_it_again": "No mostrar de nuevo",
"copy_to_clipboard": "Copiar",
"copied_to_clipboard": "Copiado"
"copied_to_clipboard": "Copiado",
"got_it": "Entendido",
"no_shop_details": "No se pudieron obtener detalles de la tienda.",
"download_options": "Opciones de descarga",
"download_path": "Ruta de descarga",
"previous_screenshot": "Anterior captura",
"next_screenshot": "Siguiente captura",
"screenshot": "Captura {{number}}",
"open_screenshot": "Abrir captura {{number}}"
},
"activation": {
"title": "Activar Hydra",
@@ -118,12 +128,14 @@
"downloading_metadata": "Descargando metadatos…",
"checking_files": "Verificando archivos…",
"starting_download": "Iniciando descarga…",
"remove_from_list": "Eliminar",
"delete": "Eliminar instalador",
"delete_modal_description": "Esto eliminará todos los archivos de instalación de tu computadora.",
"delete_modal_title": "¿Estás seguro?",
"deleting": "Eliminando instalador…",
"install": "Instalar"
"delete": "Eliminar instalador",
"remove_from_list": "Eliminar",
"delete_modal_title": "¿Estás seguro?",
"delete_modal_description": "Esto eliminará todos los archivos de instalación de tu computadora.",
"install": "Instalar",
"real_debrid": "Real Debrid",
"torrent": "Torrent"
},
"settings": {
"downloads_path": "Ruta de descarga",
@@ -132,7 +144,16 @@
"enable_download_notifications": "Cuando se completa una descarga",
"enable_repack_list_notifications": "Cuando se añade un repack nuevo",
"telemetry": "Telemetría",
"telemetry_description": "Habilitar recopilación de datos de manera anónima"
"telemetry_description": "Habilitar recopilación de datos de manera anónima",
"real_debrid_api_token_label": "Token API de Real Debrid",
"quit_app_instead_hiding": "Salir de Hydra en vez de minimizar en la bandeja del sistema",
"launch_with_system": "Iniciar Hydra al inicio del sistema",
"general": "General",
"behavior": "Otros",
"enable_real_debrid": "Activar Real Debrid",
"real_debrid": "Real Debrid",
"real_debrid_api_token_hint": "Puedes obtener tu clave de API <0>aquí</0>.",
"save_changes": "Guardar cambios"
},
"notifications": {
"download_complete": "Descarga completada",
@@ -156,8 +177,10 @@
"modal": {
"close": "Botón de cierre"
},
"catalogue": {
"next_page": "Siguiente página",
"previous_page": "Pagina anterior"
"splash": {
"downloading_version": "Descargando versión {{version}}",
"searching_updates": "Buscando actualizaciones",
"update_found": "Actualización {{version}} encontrada",
"restarting_and_applying": "Reiniciando y aplicando actualización"
}
}

View File

@@ -15,7 +15,7 @@
"checking_files": "{{title}} ({{percentage}} - 파일 검사 중…)",
"paused": "{{title}} (일시 정지됨)",
"downloading": "{{title}} ({{percentage}} - 다운로드 중…)",
"filter": "필터 라이브러리",
"filter": "라이브러리 정렬",
"follow_us": "공식 SNS",
"home": "홈",
"discord": "공식 디스코드",
@@ -54,10 +54,10 @@
"remove": "제거",
"remove_from_list": "목록에서 제거",
"space_left_on_disk": "여유 저장 용량 {{space}} 남음",
"eta": "료까지 {{eta}}",
"eta": "료까지 {{eta}}",
"downloading_metadata": "메타데이터 다운로드 중…",
"checking_files": "파일 검사 중…",
"filter": "리팩들을 다음과 같이 걸러내기",
"filter": "리팩들을 다음과 같이 정렬하기",
"requirements": "시스템 사양",
"minimum": "최저 사양",
"recommended": "권장 사양",
@@ -91,8 +91,8 @@
"download_now": "지금 다운로드",
"installation_instructions": "설치 방법",
"installation_instructions_description": "이 게임을 설치하기 위해서는 추가적인 단계가 필요합니다",
"online_fix_instruction": "OnlineFix 게임들은 추출 시 암호가 필요합니다. 비밀번호를 물을 때 다음을 암호로 사용하기:",
"dodi_installation_instruction": "DODI 인스톨러를 열었다면 키보드의 위 방향키를 눌러 설치를 시작하세요:",
"online_fix_instruction": "OnlineFix 게임들은 압축 해제 시 암호가 필요합니다. 비밀번호를 물을 때 다음을 암호로 사용하기:",
"dodi_installation_instruction": "DODI 인스톨러를 실행했다면 키보드의 위 방향키를 눌러 설치를 시작하세요:",
"dont_show_it_again": "다시 보지 않기",
"copy_to_clipboard": "복사하기",
"copied_to_clipboard": "복사됨",

View File

@@ -17,7 +17,11 @@
"downloading": "{{title}} ({{percentage}} - Pobieranie…)",
"filter": "Filtruj biblioteke",
"follow_us": "Śledź nas",
"home": "Główna"
"home": "Główna",
"discord": "Dołącz nasz Discord",
"telegram": "Dołącz nasz Telegram",
"x": "Śledź na X",
"github": "Przyczyń się na GitHub"
},
"header": {
"search": "Szukaj",
@@ -66,6 +70,8 @@
"copied_link_to_clipboard": "Skopiowano łącze",
"hours": "godzin",
"minutes": "minut",
"amount_hours": "{{amount}} godzin",
"amount_minutes": "{{amount}} minut",
"accuracy": "{{accuracy}}% dokładność",
"add_to_library": "Dodaj do biblioteki",
"remove_from_library": "Usuń z biblioteki",
@@ -80,9 +86,23 @@
"playing_now": "Granie teraz",
"change": "Zmień",
"repacks_modal_description": "Wybierz repack, który chcesz pobrać",
"downloads_path": "Ścieżka pobierania",
"select_folder_hint": "Aby zmienić domyślny folder, przejdź do",
"download_now": "Pobierz teraz"
"download_now": "Pobierz teraz",
"installation_instructions": "Instrukcja instalacji",
"installation_instructions_description": "Do zainstalowania tej gry wymagane są dodatkowe kroki",
"online_fix_instruction": "Gry OnlineFix wymagają hasła do wyodrębnienia. W razie potrzeby użyj następującego hasła:",
"dodi_installation_instruction": "Po otwarciu instalatora DODI naciśnij klawisz <0 /> w górę, aby rozpocząć proces instalacji:",
"dont_show_it_again": "Nie pokazuj tego ponownie",
"copy_to_clipboard": "Skopiuj",
"copied_to_clipboard": "Skopiowano",
"got_it": "Rozumiem",
"no_shop_details": "Nie udało się pobrać danych sklepu.",
"download_options": "Opcje pobierania",
"download_path": "Ścieżka pobierania",
"previous_screenshot": "Poprzedni zrzut ekranu",
"next_screenshot": "Następny zrzut ekranu",
"screenshot": "Zrzut ekranu {{number}}",
"open_screenshot": "Otwórz zrzut ekranu {{number}}"
},
"activation": {
"title": "Aktywuj Hydra",
@@ -113,7 +133,9 @@
"remove_from_list": "Usuń",
"delete_modal_title": "Czy na pewno?",
"delete_modal_description": "Spowoduje to usunięcie wszystkich plików instalacyjnych z komputera",
"install": "Instaluj"
"install": "Instaluj",
"real_debrid": "Real Debrid",
"torrent": "Torrent"
},
"settings": {
"downloads_path": "Ścieżka pobierania",
@@ -122,7 +144,16 @@
"enable_download_notifications": "Gdy pobieranie zostanie zakończone",
"enable_repack_list_notifications": "Gdy dodawany jest nowy repack",
"telemetry": "Telemetria",
"telemetry_description": "Włącz anonimowe statystyki użycia"
"telemetry_description": "Włącz anonimowe statystyki użycia",
"real_debrid_api_token_label": "Real Debrid API token",
"quit_app_instead_hiding": "Zamknij Hydr zamiast minimalizować do zasobnika",
"launch_with_system": "Uruchom Hydra przy starcie systemu",
"general": "Ogólne",
"behavior": "Zachowania",
"enable_real_debrid": "Włącz Real Debrid",
"real_debrid": "Real Debrid",
"real_debrid_api_token_hint": "Możesz uzyskać swój klucz API <0>tutaj</0>.",
"save_changes": "Zapisz zmiany"
},
"notifications": {
"download_complete": "Pobieranie zakończone",
@@ -142,5 +173,8 @@
"title": "Programy nie są zainstalowane",
"description": "Pliki wykonywalne Wine lub Lutris nie zostały znalezione na twoim systemie",
"instructions": "Sprawdź prawidłowy sposób instalacji dowolnego z nich w swojej dystrybucji Linuksa, aby gra działała normalnie"
},
"modal": {
"close": "Zamknij"
}
}

View File

@@ -176,5 +176,11 @@
},
"modal": {
"close": "Botão de fechar"
},
"splash": {
"downloading_version": "Baixando versão {{version}}",
"searching_updates": "Buscando atualizações",
"update_found": "Versão {{version}} encontrada",
"restarting_and_applying": "Reiniciando e aplicando atualização"
}
}

View File

@@ -152,7 +152,7 @@
"behavior": "Поведение",
"enable_real_debrid": "Включить Real Debrid",
"real_debrid": "Real Debrid",
"real_debrid_api_token_hint": "API ключ можно получить <0>здесь/0>.",
"real_debrid_api_token_hint": "API ключ можно получить <0>здесь</0>.",
"save_changes": "Сохранить изменения"
},
"notifications": {

View File

@@ -150,7 +150,7 @@
"launch_with_system": "随系统启动时运行应用程序",
"enable_real_debrid": "启用 Real Debrid",
"real_debrid": "Real Debrid",
"real_debrid_api_token_hint": "您可以将API密钥填入<0>这里</0>.",
"real_debrid_api_token_hint": "您可以<0>这里</0>获取API密钥.",
"save_changes": "保存更改"
},
"notifications": {

View File

@@ -18,28 +18,14 @@ export const repackers = [
"onlinefix",
] as const;
export const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
export const defaultDownloadsPath = app.getPath("downloads");
export const databasePath = path.join(
app.getPath("appData"),
app.getName(),
"hydra",
"hydra.db"
);
export const INSTALLATION_ID_LENGTH = 6;
export const ACTIVATION_KEY_MULTIPLIER = 7;
export const seedsPath = app.isPackaged
? path.join(process.resourcesPath, "seeds")
: path.join(__dirname, "..", "..", "seeds");

View File

@@ -1,22 +1,21 @@
import { DataSource } from "typeorm";
import {
Game,
GameShopCache,
Repack,
UserPreferences,
SteamGame,
} from "@main/entity";
import type { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
import { Game, GameShopCache, Repack, UserPreferences } from "@main/entity";
import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";
import { databasePath } from "./constants";
import migrations from "./migrations";
export const createDataSource = (options: Partial<SqliteConnectionOptions>) =>
export const createDataSource = (
options: Partial<BetterSqlite3ConnectionOptions>
) =>
new DataSource({
type: "better-sqlite3",
database: databasePath,
entities: [Game, Repack, UserPreferences, GameShopCache, SteamGame],
entities: [Game, Repack, UserPreferences, GameShopCache],
synchronize: true,
database: databasePath,
...options,
});
export const dataSource = createDataSource({});
export const dataSource = createDataSource({
migrations,
});

View File

@@ -23,8 +23,8 @@ export class Game {
@Column("text")
title: string;
@Column("text")
iconUrl: string;
@Column("text", { nullable: true })
iconUrl: string | null;
@Column("text", { nullable: true })
folderName: string | null;

View File

@@ -2,4 +2,3 @@ export * from "./game.entity";
export * from "./repack.entity";
export * from "./user-preferences.entity";
export * from "./game-shop-cache.entity";
export * from "./steam-game.entity";

View File

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

View File

@@ -0,0 +1,48 @@
import { AppUpdaterEvents } from "@types";
import { registerEvent } from "../register-event";
import updater, { ProgressInfo, UpdateInfo } from "electron-updater";
import { WindowManager } from "@main/services";
import { app } from "electron";
const { autoUpdater } = updater;
const sendEvent = (event: AppUpdaterEvents) => {
WindowManager.splashWindow?.webContents.send("autoUpdaterEvent", event);
};
const mockValuesForDebug = async () => {
sendEvent({ type: "update-downloaded" });
};
const checkForUpdates = async (_event: Electron.IpcMainInvokeEvent) => {
autoUpdater
.addListener("error", () => {
sendEvent({ type: "error" });
})
.addListener("checking-for-update", () => {
sendEvent({ type: "checking-for-updates" });
})
.addListener("update-not-available", () => {
sendEvent({ type: "update-not-available" });
})
.addListener("update-available", (info: UpdateInfo) => {
sendEvent({ type: "update-available", info });
})
.addListener("update-downloaded", () => {
sendEvent({ type: "update-downloaded" });
})
.addListener("download-progress", (info: ProgressInfo) => {
sendEvent({ type: "download-progress", info });
})
.addListener("update-cancelled", () => {
sendEvent({ type: "update-cancelled" });
});
if (app.isPackaged) {
autoUpdater.checkForUpdates();
} else {
await mockValuesForDebug();
}
};
registerEvent("checkForUpdates", checkForUpdates);

View File

@@ -0,0 +1,12 @@
import { WindowManager } from "@main/services";
import { registerEvent } from "../register-event";
import updater from "electron-updater";
const { autoUpdater } = updater;
const continueToMainWindow = async (_event: Electron.IpcMainInvokeEvent) => {
autoUpdater.removeAllListeners();
WindowManager.prepareMainWindowAndCloseSplash();
};
registerEvent("continueToMainWindow", continueToMainWindow);

View File

@@ -0,0 +1,17 @@
import { app } from "electron";
import { registerEvent } from "../register-event";
import updater from "electron-updater";
import { WindowManager } from "@main/services";
const { autoUpdater } = updater;
const restartAndInstallUpdate = async (_event: Electron.IpcMainInvokeEvent) => {
if (app.isPackaged) {
autoUpdater.quitAndInstall(true, true);
} else {
autoUpdater.removeAllListeners();
WindowManager.prepareMainWindowAndCloseSplash();
}
};
registerEvent("restartAndInstallUpdate", restartAndInstallUpdate);

View File

@@ -1,9 +1,10 @@
import { gameShopCacheRepository, steamGameRepository } from "@main/repository";
import { gameShopCacheRepository } from "@main/repository";
import { getSteamAppDetails } from "@main/services";
import type { ShopDetails, GameShop, SteamAppDetails } from "@types";
import { registerEvent } from "../register-event";
import { stateManager } from "@main/state-manager";
const getLocalizedSteamAppDetails = (
objectID: string,
@@ -13,10 +14,11 @@ const getLocalizedSteamAppDetails = (
return getSteamAppDetails(objectID, language);
}
return Promise.all([
steamGameRepository.findOne({ where: { id: Number(objectID) } }),
getSteamAppDetails(objectID, language),
]).then(([steamGame, localizedAppDetails]) => {
return getSteamAppDetails(objectID, language).then((localizedAppDetails) => {
const steamGame = stateManager
.getValue("steamGames")
.find((game) => game.id === Number(objectID));
if (steamGame && localizedAppDetails) {
return {
...localizedAppDetails,

View File

@@ -27,6 +27,9 @@ import "./torrenting/start-game-download";
import "./user-preferences/get-user-preferences";
import "./user-preferences/update-user-preferences";
import "./user-preferences/auto-launch";
import "./autoupdater/check-for-updates";
import "./autoupdater/restart-and-install-update";
import "./autoupdater/continue-to-main-window";
ipcMain.handle("ping", () => "pong");
ipcMain.handle("getVersion", () => app.getVersion());

View File

@@ -3,8 +3,8 @@ import { gameRepository } from "@main/repository";
import { registerEvent } from "../register-event";
import type { GameShop } from "@types";
import { getFileBase64 } from "@main/helpers";
import { getSteamGameIconUrl } from "@main/services";
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
import { stateManager } from "@main/state-manager";
const addGameToLibrary = async (
_event: Electron.IpcMainInvokeEvent,
@@ -27,17 +27,29 @@ const addGameToLibrary = async (
)
.then(async ({ affected }) => {
if (!affected) {
const iconUrl = await getFileBase64(
await getSteamGameIconUrl(objectID)
);
const steamGame = stateManager
.getValue("steamGames")
.find((game) => game.id === Number(objectID));
await gameRepository.insert({
title,
iconUrl,
objectID,
shop: gameShop,
executablePath,
});
const iconUrl = steamGame?.clientIcon
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
: null;
await gameRepository
.insert({
title,
iconUrl,
objectID,
shop: gameShop,
executablePath,
})
.then(() => {
if (iconUrl) {
getFileBase64(iconUrl).then((base64) =>
gameRepository.update({ objectID }, { iconUrl: base64 })
);
}
});
}
});
};

View File

@@ -1,4 +1,3 @@
import { getSteamGameIconUrl } from "@main/services";
import {
gameRepository,
repackRepository,
@@ -8,10 +7,11 @@ import {
import { registerEvent } from "../register-event";
import type { GameShop } from "@types";
import { getFileBase64 } from "@main/helpers";
import { getFileBase64, getSteamAppAsset } from "@main/helpers";
import { In } from "typeorm";
import { DownloadManager } from "@main/services";
import { Downloader, GameStatus } from "@shared";
import { stateManager } from "@main/state-manager";
const startGameDownload = async (
_event: Electron.IpcMainInvokeEvent,
@@ -76,18 +76,34 @@ const startGameDownload = async (
return game;
} else {
const iconUrl = await getFileBase64(await getSteamGameIconUrl(objectID));
const steamGame = stateManager
.getValue("steamGames")
.find((game) => game.id === Number(objectID));
const createdGame = await gameRepository.save({
title,
iconUrl,
objectID,
downloader,
shop: gameShop,
status: GameStatus.Downloading,
downloadPath,
repack: { id: repackId },
});
const iconUrl = steamGame?.clientIcon
? getSteamAppAsset("icon", objectID, steamGame.clientIcon)
: null;
const createdGame = await gameRepository
.save({
title,
iconUrl,
objectID,
downloader,
shop: gameShop,
status: GameStatus.Downloading,
downloadPath,
repack: { id: repackId },
})
.then((result) => {
if (iconUrl) {
getFileBase64(iconUrl).then((base64) =>
gameRepository.update({ objectID }, { iconUrl: base64 })
);
}
return result;
});
DownloadManager.downloadGame(createdGame.id);

View File

@@ -13,7 +13,7 @@ import {
gogFormatter,
onlinefixFormatter,
} from "./formatters";
import { months, repackers } from "../constants";
import { repackers } from "../constants";
export const pipe =
<T>(...fns: ((arg: T) => any)[]) =>
@@ -44,19 +44,6 @@ export const repackerFormatter: Record<
onlinefix: onlinefixFormatter,
};
export const formatUploadDate = (str: string) => {
const date = new Date();
const [month, day, year] = str.split(" ");
date.setMonth(months.indexOf(month.replace(".", "")));
date.setDate(Number(day.substring(0, 2)));
date.setFullYear(Number("20" + year.replace("'", "")));
date.setHours(0, 0, 0, 0);
return date;
};
export const getSteamAppAsset = (
category: "library" | "hero" | "logo" | "icon",
objectID: string,

View File

@@ -3,11 +3,10 @@ import updater from "electron-updater";
import i18n from "i18next";
import path from "node:path";
import { electronApp, optimizer } from "@electron-toolkit/utils";
import { resolveDatabaseUpdates, WindowManager } from "@main/services";
import { logger, resolveDatabaseUpdates, WindowManager } from "@main/services";
import { dataSource } from "@main/data-source";
import * as resources from "@locales";
import { userPreferencesRepository } from "@main/repository";
const { autoUpdater } = updater;
autoUpdater.setFeedURL({
@@ -16,9 +15,13 @@ autoUpdater.setFeedURL({
repo: "hydra",
});
autoUpdater.logger = logger;
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) app.quit();
app.commandLine.appendSwitch("--no-sandbox");
i18n.init({
resources,
lng: "en",
@@ -51,6 +54,8 @@ app.whenReady().then(() => {
);
dataSource.initialize().then(async () => {
await dataSource.runMigrations();
await resolveDatabaseUpdates();
await import("./main");
@@ -59,12 +64,8 @@ app.whenReady().then(() => {
where: { id: 1 },
});
WindowManager.createMainWindow();
WindowManager.createSplashScreen();
WindowManager.createSystemTray(userPreferences?.language || "en");
WindowManager.mainWindow?.on("ready-to-show", () => {
autoUpdater.checkForUpdatesAndNotify();
});
});
});

View File

@@ -1,5 +1,5 @@
import { stateManager } from "./state-manager";
import { repackersOn1337x } from "./constants";
import { repackersOn1337x, seedsPath } from "./constants";
import {
getNewGOGGames,
getNewRepacksFromUser,
@@ -11,7 +11,6 @@ import {
import {
gameRepository,
repackRepository,
steamGameRepository,
userPreferencesRepository,
} from "./repository";
import { TorrentDownloader } from "./services";
@@ -20,7 +19,11 @@ import { Notification } from "electron";
import { t } from "i18next";
import { GameStatus } from "@shared";
import { In } from "typeorm";
import fs from "node:fs";
import path from "node:path";
import { RealDebridClient } from "./services/real-debrid";
import { orderBy } from "lodash-es";
import { SteamGame } from "@types";
startProcessWatcher();
@@ -69,21 +72,18 @@ const checkForNewRepacks = async (userPreferences: UserPreferences | null) => {
};
const loadState = async (userPreferences: UserPreferences | null) => {
const [repacks, steamGames] = await Promise.all([
repackRepository.find({
order: {
createdAt: "desc",
},
}),
steamGameRepository.find({
order: {
name: "asc",
},
}),
]);
const repacks = await repackRepository.find({
order: {
createdAt: "desc",
},
});
const steamGames = JSON.parse(
fs.readFileSync(path.join(seedsPath, "steam-games.json"), "utf-8")
) as SteamGame[];
stateManager.setValue("repacks", repacks);
stateManager.setValue("steamGames", steamGames);
stateManager.setValue("steamGames", orderBy(steamGames, ["name"], "asc"));
import("./events");

View File

@@ -0,0 +1,78 @@
import { createDataSource } from "@main/data-source";
import { Repack } from "@main/entity";
import { app } from "electron";
import { chunk } from "lodash-es";
import path from "path";
import { In, MigrationInterface, QueryRunner, Table } from "typeorm";
export class FixRepackUploadDate1715900413313 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: "repack_temp",
columns: [
{ name: "title", type: "varchar" },
{ name: "old_id", type: "int" },
],
}),
true
);
await queryRunner.query(
`INSERT INTO repack_temp (title, old_id) SELECT title, id FROM repack WHERE repacker IN ('onlinefix', 'Xatab');`
);
await queryRunner.query(
`DELETE FROM repack WHERE repacker IN ('onlinefix', 'Xatab');`
);
const updateDataSource = createDataSource({
database: app.isPackaged
? path.join(process.resourcesPath, "hydra.db")
: path.join(__dirname, "..", "..", "hydra.db"),
});
await updateDataSource.initialize();
const updateRepackRepository = updateDataSource.getRepository(Repack);
const updatedRepacks = await updateRepackRepository.find({
where: {
repacker: In(["onlinefix", "Xatab"]),
},
});
const chunks = chunk(
updatedRepacks.map((repack) => {
const { id: _, ...rest } = repack;
return rest;
}),
500
);
for (const chunk of chunks) {
await queryRunner.manager
.createQueryBuilder(Repack, "repack")
.insert()
.values(chunk)
.orIgnore()
.execute();
}
await queryRunner.query(
`UPDATE game
SET repackId = (
SELECT id
from repack LEFT JOIN repack_temp ON repack_temp.title = repack.title
WHERE repack_temp.old_id = game.repackId
)
WHERE EXISTS (select old_id from repack_temp WHERE old_id = game.repackId)`
);
await queryRunner.dropTable("repack_temp");
}
public async down(_: QueryRunner): Promise<void> {
return;
}
}

View File

@@ -0,0 +1,3 @@
import { FixRepackUploadDate1715900413313 } from "./1715900413313-fix_repack_uploadDate";
export default [FixRepackUploadDate1715900413313];

View File

@@ -1,11 +1,5 @@
import { dataSource } from "./data-source";
import {
Game,
GameShopCache,
Repack,
UserPreferences,
SteamGame,
} from "@main/entity";
import { Game, GameShopCache, Repack, UserPreferences } from "@main/entity";
export const gameRepository = dataSource.getRepository(Game);
@@ -15,5 +9,3 @@ export const userPreferencesRepository =
dataSource.getRepository(UserPreferences);
export const gameShopCacheRepository = dataSource.getRepository(GameShopCache);
export const steamGameRepository = dataSource.getRepository(SteamGame);

View File

@@ -0,0 +1,40 @@
import path from "node:path";
import fs from "node:fs";
import { getSteamGameClientIcon, logger } from "@main/services";
import { chunk } from "lodash-es";
import { seedsPath } from "@main/constants";
import type { SteamGame } from "@types";
const steamGamesPath = path.join(seedsPath, "steam-games.json");
const steamGames = JSON.parse(
fs.readFileSync(steamGamesPath, "utf-8")
) as SteamGame[];
const chunks = chunk(steamGames, 1500);
for (const chunk of chunks) {
await Promise.all(
chunk.map(async (steamGame) => {
if (steamGame.clientIcon) return;
const index = steamGames.findIndex((game) => game.id === steamGame.id);
try {
const clientIcon = await getSteamGameClientIcon(String(steamGame.id));
steamGames[index].clientIcon = clientIcon;
logger.log("info", `Set ${steamGame.name} client icon`);
} catch (err) {
steamGames[index].clientIcon = null;
logger.log("info", `Could not set icon for ${steamGame.name}`);
}
})
);
fs.writeFileSync(steamGamesPath, JSON.stringify(steamGames));
logger.log("info", "Updated steam games");
}

View File

@@ -1,13 +1,39 @@
import { JSDOM } from "jsdom";
import { formatUploadDate } from "@main/helpers";
import { Repack } from "@main/entity";
import { requestWebPage, savePage } from "./helpers";
const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
export const request1337x = async (path: string) =>
requestWebPage(`https://1337xx.to${path}`);
const formatUploadDate = (str: string) => {
const date = new Date();
const [month, day, year] = str.split(" ");
date.setMonth(months.indexOf(month.replace(".", "")));
date.setDate(Number(day.substring(0, 2)));
date.setFullYear(Number("20" + year.replace("'", "")));
date.setHours(0, 0, 0, 0);
return date;
};
/* TODO: $a will often be null */
const getTorrentDetails = async (path: string) => {
const response = await request1337x(path);

View File

@@ -3,21 +3,19 @@ import { decodeNonUtf8Response, savePage } from "./helpers";
import { logger } from "../logger";
import { JSDOM } from "jsdom";
import { format, parse, sub } from "date-fns";
import { ru } from "date-fns/locale";
import createWorker from "@main/workers/torrent-parser.worker?nodeWorker";
import { toMagnetURI } from "parse-torrent";
const worker = createWorker({});
import { onlinefixFormatter } from "@main/helpers";
import makeFetchCookie from "fetch-cookie";
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
import { formatBytes } from "@shared";
const ONLINE_FIX_URL = "https://online-fix.me/";
let totalPages = 1;
export const getNewRepacksFromOnlineFix = async (
existingRepacks: Repack[] = [],
page = 1,
@@ -74,18 +72,16 @@ export const getNewRepacksFromOnlineFix = async (
const repacks: QueryDeepPartialEntity<Repack>[] = [];
const articles = Array.from(document.querySelectorAll(".news"));
const totalPages = Number(
document.querySelector("nav > a:nth-child(13)")?.textContent
);
if (page == 1) {
totalPages = Number(
document.querySelector("nav > a:nth-child(13)")?.textContent
);
}
try {
await Promise.all(
articles.map(async (article) => {
const gameText = article.querySelector("h2.title")?.textContent?.trim();
if (!gameText) return;
const gameName = onlinefixFormatter(gameText);
const gameLink = article.querySelector("a")?.getAttribute("href");
if (!gameLink) return;
@@ -94,32 +90,6 @@ export const getNewRepacksFromOnlineFix = async (
);
const gameDocument = new JSDOM(gamePage).window.document;
const uploadDateText = gameDocument.querySelector("time")?.textContent;
if (!uploadDateText) return;
let decodedDateText = uploadDateText;
// "Вчера" means yesterday.
if (decodedDateText.includes("Вчера")) {
const yesterday = sub(new Date(), { days: 1 });
const formattedYesterday = format(yesterday, "d LLLL yyyy", {
locale: ru,
});
decodedDateText = decodedDateText.replace(
"Вчера", // "Change yesterday to the default expected date format"
formattedYesterday
);
}
const uploadDate = parse(
decodedDateText,
"d LLLL yyyy, HH:mm",
new Date(),
{
locale: ru,
}
);
const torrentButtons = Array.from(
gameDocument.querySelectorAll("a")
).filter((a) => a.textContent?.includes("Torrent"));
@@ -146,13 +116,17 @@ export const getNewRepacksFromOnlineFix = async (
);
worker.once("message", (torrent) => {
if (!torrent) return;
const { name, created } = torrent;
repacks.push({
fileSize: formatBytes(torrent.length ?? 0),
magnet: toMagnetURI(torrent),
page: 1,
repacker: "onlinefix",
title: gameName,
uploadDate: uploadDate,
title: name,
uploadDate: created,
});
});
@@ -174,9 +148,10 @@ export const getNewRepacksFromOnlineFix = async (
);
if (!newRepacks.length) return;
if (page === totalPages) return;
await savePage(newRepacks);
if (page === totalPages) return;
return getNewRepacksFromOnlineFix(existingRepacks, page + 1, cookieJar);
};

View File

@@ -12,6 +12,9 @@ import { formatBytes } from "@shared";
import { getFileBuffer } from "@main/helpers";
const worker = createWorker({});
worker.setMaxListeners(11);
let totalPages = 1;
const formatXatabDate = (str: string) => {
const date = new Date();
@@ -69,27 +72,37 @@ export const getNewRepacksFromXatab = async (
const repacks: QueryDeepPartialEntity<Repack>[] = [];
for (const $a of Array.from(
window.document.querySelectorAll(".entry__title a")
)) {
try {
const repack = await getXatabRepack(($a as HTMLAnchorElement).href);
if (repack) {
repacks.push({
title: $a.textContent!,
repacker: "Xatab",
...repack,
page,
});
}
} catch (err: unknown) {
logger.error((err as Error).message, {
method: "getNewRepacksFromXatab",
});
}
if (page === 1) {
totalPages = Number(
window.document.querySelector(
"#bottom-nav > div.pagination > a:nth-child(12)"
)?.textContent
);
}
const repacksFromPage = Array.from(
window.document.querySelectorAll(".entry__title a")
).map(($a) => {
return getXatabRepack(($a as HTMLAnchorElement).href)
.then((repack) => {
if (repack) {
repacks.push({
title: $a.textContent!,
repacker: "Xatab",
...repack,
page,
});
}
})
.catch((err: unknown) => {
logger.error((err as Error).message, {
method: "getNewRepacksFromXatab",
});
});
});
await Promise.all(repacksFromPage);
const newRepacks = repacks.filter(
(repack) =>
!existingRepacks.some(
@@ -101,5 +114,7 @@ export const getNewRepacksFromXatab = async (
await savePage(newRepacks);
if (page === totalPages) return;
return getNewRepacksFromXatab(existingRepacks, page + 1);
};

View File

@@ -1,5 +1,4 @@
import axios from "axios";
import { getSteamAppAsset } from "@main/helpers";
export interface SteamGridResponse {
success: boolean;
@@ -59,16 +58,11 @@ export const getSteamGridGameById = async (
return response.data;
};
export const getSteamGameIconUrl = async (objectID: string) => {
export const getSteamGameClientIcon = async (objectID: string) => {
const {
data: { id: steamGridGameId },
} = await getSteamGridData(objectID, "games", "steam");
const steamGridGame = await getSteamGridGameById(steamGridGameId);
return getSteamAppAsset(
"icon",
objectID,
steamGridGame.data.platforms.steam.metadata.clienticon
);
return steamGridGame.data.platforms.steam.metadata.clienticon;
};

View File

@@ -4,8 +4,8 @@ import { app } from "electron";
import { chunk } from "lodash-es";
import { createDataSource } from "@main/data-source";
import { Repack, SteamGame } from "@main/entity";
import { repackRepository, steamGameRepository } from "@main/repository";
import { Repack } from "@main/entity";
import { repackRepository } from "@main/repository";
export const resolveDatabaseUpdates = async () => {
const updateDataSource = createDataSource({
@@ -16,12 +16,8 @@ export const resolveDatabaseUpdates = async () => {
return updateDataSource.initialize().then(async () => {
const updateRepackRepository = updateDataSource.getRepository(Repack);
const updateSteamGameRepository = updateDataSource.getRepository(SteamGame);
const [updateRepacks, updateSteamGames] = await Promise.all([
updateRepackRepository.find(),
updateSteamGameRepository.find(),
]);
const updateRepacks = await updateRepackRepository.find();
const updateRepacksChunks = chunk(updateRepacks, 800);
@@ -33,16 +29,5 @@ export const resolveDatabaseUpdates = async () => {
.orIgnore()
.execute();
}
const steamGamesChunks = chunk(updateSteamGames, 800);
for (const chunk of steamGamesChunks) {
await steamGameRepository
.createQueryBuilder()
.insert()
.values(chunk)
.orIgnore()
.execute();
}
});
};

View File

@@ -1,13 +1,24 @@
import { BrowserWindow, Menu, Tray, app } from "electron";
import {
BrowserWindow,
Menu,
MenuItem,
MenuItemConstructorOptions,
Tray,
app,
shell,
} from "electron";
import { is } from "@electron-toolkit/utils";
import { t } from "i18next";
import path from "node:path";
import icon from "@resources/icon.png?asset";
import trayIcon from "@resources/tray-icon.png?asset";
import { userPreferencesRepository } from "@main/repository";
import { gameRepository, userPreferencesRepository } from "@main/repository";
import { IsNull, Not } from "typeorm";
export class WindowManager {
public static mainWindow: Electron.BrowserWindow | null = null;
public static splashWindow: Electron.BrowserWindow | null = null;
public static isReadyToShowMainWindow = false;
private static loadURL(hash = "") {
// HMR for renderer base on electron-vite cli.
@@ -26,13 +37,51 @@ export class WindowManager {
}
}
private static loadSplashURL() {
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
this.splashWindow?.loadURL(
`${process.env["ELECTRON_RENDERER_URL"]}#/splash`
);
} else {
this.splashWindow?.loadFile(
path.join(__dirname, "../renderer/index.html"),
{
hash: "splash",
}
);
}
}
public static createSplashScreen() {
if (this.splashWindow) return;
this.splashWindow = new BrowserWindow({
width: 380,
height: 380,
frame: false,
resizable: false,
backgroundColor: "#1c1c1c",
webPreferences: {
preload: path.join(__dirname, "../preload/index.mjs"),
sandbox: false,
},
});
this.loadSplashURL();
this.splashWindow.removeMenu();
}
public static createMainWindow() {
// Create the browser window.
if (this.mainWindow || !this.isReadyToShowMainWindow) return;
this.mainWindow = new BrowserWindow({
width: 1200,
height: 720,
minWidth: 1024,
minHeight: 540,
backgroundColor: "#1c1c1c",
titleBarStyle: "hidden",
...(process.platform === "linux" ? { icon } : {}),
trafficLightPosition: { x: 16, y: 16 },
@@ -66,6 +115,12 @@ export class WindowManager {
});
}
public static prepareMainWindowAndCloseSplash() {
this.isReadyToShowMainWindow = true;
this.splashWindow?.close();
this.createMainWindow();
}
public static redirect(hash: string) {
if (!this.mainWindow) this.createMainWindow();
this.loadURL(hash);
@@ -77,33 +132,66 @@ export class WindowManager {
public static createSystemTray(language: string) {
const tray = new Tray(trayIcon);
const contextMenu = Menu.buildFromTemplate([
{
label: t("open", {
ns: "system_tray",
lng: language,
}),
type: "normal",
click: () => {
if (this.mainWindow) {
this.mainWindow.show();
} else {
this.createMainWindow();
}
const updateSystemTray = async () => {
const games = await gameRepository.find({
where: {
isDeleted: false,
executablePath: Not(IsNull()),
lastTimePlayed: Not(IsNull()),
},
},
{
label: t("quit", {
ns: "system_tray",
lng: language,
}),
type: "normal",
click: () => app.quit(),
},
]);
take: 5,
order: {
updatedAt: "DESC",
},
});
const recentlyPlayedGames: Array<MenuItemConstructorOptions | MenuItem> =
games.map(({ title, executablePath }) => ({
label: title,
type: "normal",
click: async () => {
if (!executablePath) return;
shell.openPath(executablePath);
},
}));
const contextMenu = Menu.buildFromTemplate([
{
label: t("open", {
ns: "system_tray",
lng: language,
}),
type: "normal",
click: () => {
if (this.mainWindow) {
this.mainWindow.show();
} else {
this.createMainWindow();
}
},
},
{
type: "separator",
},
...recentlyPlayedGames,
{
type: "separator",
},
{
label: t("quit", {
ns: "system_tray",
lng: language,
}),
type: "normal",
click: () => app.quit(),
},
]);
return contextMenu;
};
tray.setToolTip("Hydra");
tray.setContextMenu(contextMenu);
if (process.platform === "win32" || process.platform === "linux") {
tray.addListener("click", () => {
@@ -117,6 +205,11 @@ export class WindowManager {
this.createMainWindow();
});
tray.addListener("right-click", async () => {
const contextMenu = await updateSystemTray();
tray.popUpContextMenu(contextMenu);
});
}
}
}

View File

@@ -1,4 +1,5 @@
import type { Repack, SteamGame } from "@main/entity";
import type { Repack } from "@main/entity";
import type { SteamGame } from "@types";
interface State {
repacks: Repack[];

View File

@@ -7,6 +7,7 @@ import type {
GameShop,
TorrentProgress,
UserPreferences,
AppUpdaterEvents,
} from "@types";
contextBridge.exposeInMainWorld("electron", {
@@ -112,4 +113,21 @@ contextBridge.exposeInMainWorld("electron", {
showOpenDialog: (options: Electron.OpenDialogOptions) =>
ipcRenderer.invoke("showOpenDialog", options),
platform: process.platform,
/* Splash */
onAutoUpdaterEvent: (cb: (value: AppUpdaterEvents) => void) => {
const listener = (
_event: Electron.IpcRendererEvent,
value: AppUpdaterEvents
) => cb(value);
ipcRenderer.on("autoUpdaterEvent", listener);
return () => {
ipcRenderer.removeListener("autoUpdaterEvent", listener);
};
},
checkForUpdates: () => ipcRenderer.invoke("checkForUpdates"),
restartAndInstallUpdate: () => ipcRenderer.invoke("restartAndInstallUpdate"),
continueToMainWindow: () => ipcRenderer.invoke("continueToMainWindow"),
});

View File

@@ -6,7 +6,7 @@
<title>Hydra</title>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com;"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://steamcdn-a.akamaihd.net https://shared.akamai.steamstatic.com https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com https://shared.akamai.steamstatic.com;"
/>
</head>
<body style="background-color: #1c1c1c">

View File

@@ -12,7 +12,7 @@ import {
import * as styles from "./app.css";
import { themeClass } from "./theme.css";
import { useLocation, useNavigate } from "react-router-dom";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import {
setSearch,
clearSearch,
@@ -27,7 +27,7 @@ export interface AppProps {
children: React.ReactNode;
}
export function App({ children }: AppProps) {
export function App() {
const contentRef = useRef<HTMLDivElement>(null);
const { updateLibrary } = useLibrary();
@@ -128,7 +128,7 @@ export function App({ children }: AppProps) {
/>
<section ref={contentRef} className={styles.content}>
{children}
<Outlet />
</section>
</article>
</main>

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@@ -42,7 +42,7 @@ export function Modal({
}, [onClose]);
const isTopMostModal = () => {
const openModals = document.querySelectorAll("[role=modal]");
const openModals = document.querySelectorAll("[role=dialog]");
return (
openModals.length &&

View File

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

View File

@@ -13,6 +13,8 @@ import * as styles from "./sidebar.css";
import { GameStatus, GameStatusHelper } from "@shared";
import { buildGameDetailsPath } from "@renderer/helpers";
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
const SIDEBAR_MIN_WIDTH = 200;
const SIDEBAR_INITIAL_WIDTH = 250;
const SIDEBAR_MAX_WIDTH = 450;
@@ -191,11 +193,16 @@ export function Sidebar() {
handleSidebarItemClick(buildGameDetailsPath(game))
}
>
<img
className={styles.gameIcon}
src={game.iconUrl}
alt={game.title}
/>
{game.iconUrl ? (
<img
className={styles.gameIcon}
src={game.iconUrl}
alt={game.title}
/>
) : (
<SteamLogo className={styles.gameIcon} />
)}
<span className={styles.menuItemButtonLabel}>
{getGameTitle(game)}
</span>

View File

@@ -1,4 +1,5 @@
import type {
AppUpdaterEvents,
CatalogueCategory,
CatalogueEntry,
Game,
@@ -90,6 +91,14 @@ declare global {
options: Electron.OpenDialogOptions
) => Promise<Electron.OpenDialogReturnValue>;
platform: NodeJS.Platform;
/* Splash */
onAutoUpdaterEvent: (
cb: (event: AppUpdaterEvents) => void
) => () => Electron.IpcRenderer;
checkForUpdates: () => Promise<void>;
restartAndInstallUpdate: () => Promise<void>;
continueToMainWindow: () => Promise<void>;
}
interface Window {

View File

@@ -27,7 +27,7 @@ export const getSteamLanguage = (language: string) => {
if (language.startsWith("it")) return "italian";
if (language.startsWith("hu")) return "hungarian";
if (language.startsWith("pl")) return "polish";
if (language.startsWith("zh")) return "chinese";
if (language.startsWith("zh")) return "schinese";
if (language.startsWith("da")) return "danish";
return "english";

View File

@@ -27,6 +27,7 @@ import {
import { store } from "./store";
import * as resources from "@locales";
import Splash from "./pages/splash/splash";
i18n
.use(LanguageDetector)
@@ -46,16 +47,17 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Provider store={store}>
<HashRouter>
<App>
<Routes>
<Routes>
<Route path="/splash" Component={Splash} />
<Route element={<App />}>
<Route path="/" Component={Home} />
<Route path="/catalogue" Component={Catalogue} />
<Route path="/downloads" Component={Downloads} />
<Route path="/game/:shop/:objectID" Component={GameDetails} />
<Route path="/search" Component={SearchResults} />
<Route path="/settings" Component={Settings} />
</Routes>
</App>
</Route>
</Routes>
</HashRouter>
</Provider>
</React.StrictMode>

View File

@@ -105,7 +105,7 @@ export function Downloads() {
if (GameStatusHelper.isReady(game?.status)) {
return (
<>
<p>{game?.repack.title}</p>
<p>{game?.repack?.title}</p>
<p>{t("completed")}</p>
</>
);

View File

@@ -58,9 +58,7 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
if (hasMovies && mediaContainerRef.current) {
mediaContainerRef.current.childNodes.forEach((node, index) => {
if (node instanceof HTMLVideoElement) {
if (index == mediaIndex) {
node.play();
} else {
if (index !== mediaIndex) {
node.pause();
}
}

View File

@@ -33,7 +33,7 @@ export function HeroPanelPlaytime({
const numberFormatter = useMemo(() => {
return new Intl.NumberFormat(i18n.language, {
maximumFractionDigits: 1,
maximumFractionDigits: 0,
});
}, [i18n.language]);

View File

@@ -0,0 +1,49 @@
import { style } from "@vanilla-extract/css";
import { SPACING_UNIT, vars } from "../../theme.css";
export const main = style({
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
padding: `${SPACING_UNIT * 3}px`,
flex: "1",
overflowY: "auto",
alignItems: "center",
});
export const splashIcon = style({
width: "75%",
});
export const updateInfoSection = style({
width: "100%",
display: "flex",
flexDirection: "column",
gap: `${SPACING_UNIT * 2}px`,
flex: "1",
overflowY: "auto",
alignItems: "center",
justifyContent: "center",
});
export const progressBar = style({
WebkitAppearance: "none",
appearance: "none",
borderRadius: "4px",
width: "100%",
border: `solid 1px ${vars.color.border}`,
overflow: "hidden",
height: "18px",
"::-webkit-progress-value": {
backgroundColor: vars.color.muted,
transition: "width 0.2s",
},
"::-webkit-progress-bar": {
backgroundColor: vars.color.darkBackground,
},
});
export const progressBarText = style({
zIndex: 2,
});

View File

@@ -0,0 +1,82 @@
import icon from "@renderer/assets/icon.png";
import * as styles from "./splash.css";
import { themeClass } from "../../theme.css";
import "../../app.css";
import { useEffect, useState } from "react";
import { AppUpdaterEvents } from "@types";
import { useTranslation } from "react-i18next";
document.body.classList.add(themeClass);
export default function Splash() {
const [status, setStatus] = useState<AppUpdaterEvents | null>(null);
const [newVersion, setNewVersion] = useState("");
const { t } = useTranslation("splash");
useEffect(() => {
const unsubscribe = window.electron.onAutoUpdaterEvent(
(event: AppUpdaterEvents) => {
setStatus(event);
switch (event.type) {
case "error":
window.electron.continueToMainWindow();
break;
case "update-available":
setNewVersion(event.info.version);
break;
case "update-cancelled":
window.electron.continueToMainWindow();
break;
case "update-downloaded":
window.electron.restartAndInstallUpdate();
break;
case "update-not-available":
window.electron.continueToMainWindow();
break;
}
}
);
window.electron.checkForUpdates();
return () => {
unsubscribe();
};
}, []);
const renderUpdateInfo = () => {
switch (status?.type) {
case "download-progress":
return (
<>
<p>{t("downloading_version", { version: newVersion })}</p>
<progress
className={styles.progressBar}
max="100"
value={status.info.percent}
/>
</>
);
case "checking-for-updates":
return <p>{t("searching_updates")}</p>;
case "update-available":
return <p>{t("update_found", { version: newVersion })}</p>;
case "update-downloaded":
return <p>{t("restarting_and_applying")}</p>;
default:
return <></>;
}
};
return (
<main className={styles.main}>
<img src={icon} className={styles.splashIcon} alt="Hydra Launcher Logo" />
<section className={styles.updateInfoSection}>
{renderUpdateInfo()}
</section>
</main>
);
}

View File

@@ -1,4 +1,5 @@
import type { Downloader, GameStatus } from "@shared";
import { ProgressInfo, UpdateInfo } from "electron-updater";
export type GameShop = "steam" | "epic";
export type CatalogueCategory = "recently_added" | "trending";
@@ -95,7 +96,7 @@ export interface Game extends Omit<CatalogueEntry, "cover"> {
folderName: string;
downloadPath: string | null;
repacks: GameRepack[];
repack: GameRepack;
repack: GameRepack | null;
progress: number;
fileVerificationProgress: number;
decompressionProgress: number;
@@ -137,3 +138,18 @@ export interface Steam250Game {
title: string;
objectID: string;
}
export interface SteamGame {
id: number;
name: string;
clientIcon: string | null;
}
export type AppUpdaterEvents =
| { type: "error" }
| { type: "checking-for-updates" }
| { type: "update-not-available" }
| { type: "update-available"; info: UpdateInfo }
| { type: "update-downloaded" }
| { type: "download-progress"; info: ProgressInfo }
| { type: "update-cancelled" };

6451
yarn.lock Normal file

File diff suppressed because it is too large Load Diff