mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
97ef496703
43 changed files with 858 additions and 219 deletions
175
README.md
175
README.md
|
@ -1,16 +1,112 @@
|
|||
# Hydra
|
||||
<br>
|
||||
|
||||
<a href="https://discord.gg/hydralauncher" target="_blank"></a>
|
||||

|
||||

|
||||
|
||||
Hydra is a game launcher with its own embedded bittorrent client and a self-managed repack scraper.
|
||||
The launcher is written in TypeScript (Electron) and Python, which handles the torrenting system by using [libtorrent](https://www.libtorrent.org/).
|
||||
<div align="center">
|
||||
<a href="https://hydralauncher.site">
|
||||
<img src="./resources/icon.png" width="144"/>
|
||||
</a>
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
<p align="center">
|
||||
<strong>Hydra is a game launcher with its own embedded bittorrent client and a self-managed repack scraper.</strong>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://discord.gg/hydralauncher">
|
||||
<img src ="https://img.shields.io/discord/1220692017311645737?style=flat&logo=discord&label=Hydra&labelColor=%231c1c1c"/>
|
||||
</a>
|
||||
<a href="https://github.com/hydralauncher/hydra">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml" />
|
||||
</a>
|
||||
<a href="https://github.com/hydralauncher/hydra">
|
||||
<img src="https://img.shields.io/github/package-json/v/hydralauncher/hydra" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [About](#about)
|
||||
- [Features](#features)
|
||||
- [Installation](#installation)
|
||||
- [Contributing](#contributing)
|
||||
- [Join our Discord](#join-our-discord)
|
||||
- [Fork and clone your repository](#fork-and-clone-your-repository)
|
||||
- [Ways you can contribute](#ways-you-can-contribute)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Build from source](#build-from-source)
|
||||
- [Install Node.js](#install-nodejs)
|
||||
- [Install Yarn](#install-yarn)
|
||||
- [Install Node Dependencies](#install-node-dependencies)
|
||||
- [Install Python 3.9](#install-python-39)
|
||||
- [Install Python Dependencies](#install-python-dependencies)
|
||||
- [Environment variables](#environment-variables)
|
||||
- [Running](#running)
|
||||
- [Build](#build)
|
||||
- [Build the bittorrent client](#build-the-bittorrent-client)
|
||||
- [Build the Electron application](#build-the-electron-application)
|
||||
- [Contributors](#contributors)
|
||||
|
||||
## About
|
||||
|
||||
**Hydra** is a **Game Launcher** with its own embedded **BitTorrent Client** and a **self-managed repack scraper**.
|
||||
<br>
|
||||
The launcher is written in TypeScript (Electron) and Python, which handles the torrenting system by using libtorrent.
|
||||
|
||||
## Features
|
||||
|
||||
- Self-Managed repack scraper among all the most reliable websites on the [Megathread]("https://www.reddit.com/r/Piracy/wiki/megathread/")
|
||||
- Own embedded bittorrent client
|
||||
- How Long To Beat (HLTB) integration on game page
|
||||
- Downloads path customization
|
||||
- Repack list update notifications
|
||||
- Windows and Linux support
|
||||
- Constantly updated
|
||||
- And more ...
|
||||
|
||||
## Installation
|
||||
|
||||
Follow the steps below to install:
|
||||
|
||||
1. Download the latest version of Hydra from the [Releases](https://github.com/hydralauncher/hydra/releases/latest) page.
|
||||
- Download only .exe if you want to install Hydra on Windows.
|
||||
- Download .deb or .rpm or .zip if you want to install Hydra on Linux. (depends on your Linux distro)
|
||||
2. Run the downloaded file.
|
||||
3. Enjoy Hydra!
|
||||
|
||||
## Contributing
|
||||
|
||||
### Join our Discord
|
||||
|
||||
We concentrate our discussions on our [Discord](https://discord.gg/hydralauncher) server.
|
||||
|
||||
1. Join our server
|
||||
2. Go to the roles channel and grab the Collaborator role
|
||||
3. Go to the dev channel, talk to us and share your ideas.
|
||||
|
||||
### Fork and clone your repository
|
||||
|
||||
1. Fork the repository [(click here to fork now)](https://github.com/hydralauncher/hydra/fork)
|
||||
2. Clone your forked code `git clone https://github.com/your_username/hydra`
|
||||
3. Create a new branch
|
||||
4. Push your commits
|
||||
5. Submit a new Pull Request
|
||||
|
||||
### Ways you can contribute
|
||||
|
||||
- Translation: We want Hydra to be available to as many people as possible. Feel free to help translate to new languages or update and improve the ones that are already available on Hydra.
|
||||
- Code: Hydra is built with Typescript, Electron and a little bit of Python. If you want to contribute, join our Discord server!
|
||||
|
||||
### Project Structure
|
||||
|
||||
- torrent-client: We use libtorrent, a Python library, to manage torrent downloads
|
||||
- src/renderer: the UI of the application
|
||||
- src/main: all the logic rests here.
|
||||
|
||||
## Build from source
|
||||
|
||||
### Install Node.js
|
||||
|
||||
Ensure you have Node.js installed on your machine. If not, download and install it from [nodejs.org](https://nodejs.org/).
|
||||
|
@ -19,12 +115,6 @@ Ensure you have Node.js installed on your machine. If not, download and install
|
|||
|
||||
Yarn is a package manager for Node.js. If you haven't installed Yarn yet, you can do so by following the instructions on [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
|
||||
|
||||
### Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/hydralauncher/hydra.git
|
||||
```
|
||||
|
||||
### Install Node Dependencies
|
||||
|
||||
Navigate to the project directory and install the Node dependencies using Yarn:
|
||||
|
@ -36,7 +126,7 @@ yarn
|
|||
|
||||
### Install Python 3.9
|
||||
|
||||
Ensure you have Python 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-3919/).
|
||||
|
||||
### Install Python Dependencies
|
||||
|
||||
|
@ -48,17 +138,17 @@ pip install -r requirements.txt
|
|||
|
||||
## Environment variables
|
||||
|
||||
You'll need a SteamGridDB API Key in order to fetch the game icons on installation.
|
||||
You'll need an SteamGridDB API Key in order to fetch the game icons on installation.
|
||||
If you want to have onlinefix as a repacker you'll need to add your credentials to the .env
|
||||
|
||||
Once you have it, you can paste the `.env.example` file and put it on `STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
|
||||
Once you have it, you can copy or rename the `.env.example` file to `.env`and put it on`STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
|
||||
|
||||
## Running
|
||||
|
||||
Once you've got all things set up, you can run the following command to start both the Electron process and the bittorrent client:
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Build
|
||||
|
@ -75,8 +165,16 @@ python torrent-client/setup.py build
|
|||
|
||||
Build the Electron application by using this command:
|
||||
|
||||
On Windows:
|
||||
|
||||
```bash
|
||||
yarn make
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
On Linux:
|
||||
|
||||
```bash
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## Contributors
|
||||
|
@ -141,6 +239,13 @@ yarn make
|
|||
<sub><b>Null</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Hachi-R">
|
||||
<img src="https://avatars.githubusercontent.com/u/58823742?v=4" width="100;" alt="Hachi-R"/>
|
||||
<br />
|
||||
<sub><b>Hachi</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/pmenta">
|
||||
<img src="https://avatars.githubusercontent.com/u/71457671?v=4" width="100;" alt="pmenta"/>
|
||||
|
@ -161,15 +266,15 @@ yarn make
|
|||
<br />
|
||||
<sub><b>Guilherme Viana</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/eltociear">
|
||||
<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="100;" alt="eltociear"/>
|
||||
<br />
|
||||
<sub><b>Ikko Eltociear Ashimine</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Netflixyapp">
|
||||
<img src="https://avatars.githubusercontent.com/u/91623880?v=4" width="100;" alt="Netflixyapp"/>
|
||||
|
@ -177,19 +282,33 @@ yarn make
|
|||
<sub><b>Netflixy</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Hachi-R">
|
||||
<img src="https://avatars.githubusercontent.com/u/58823742?v=4" width="100;" alt="Hachi-R"/>
|
||||
<br />
|
||||
<sub><b>Hachi</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/FerNikoMF">
|
||||
<img src="https://avatars.githubusercontent.com/u/76095334?v=4" width="100;" alt="FerNikoMF"/>
|
||||
<br />
|
||||
<sub><b>Firdavs</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Chr1s0Blood">
|
||||
<img src="https://avatars.githubusercontent.com/u/166660500?v=4" width="100;" alt="Chr1s0Blood"/>
|
||||
<br />
|
||||
<sub><b>Cristian S.</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/userMacieG">
|
||||
<img src="https://avatars.githubusercontent.com/u/24211405?v=4" width="100;" alt="userMacieG"/>
|
||||
<br />
|
||||
<sub><b>Maciej Ratyński</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Tunchichi">
|
||||
<img src="https://avatars.githubusercontent.com/u/118926729?v=4" width="100;" alt="Tunchichi"/>
|
||||
<br />
|
||||
<sub><b>Ruslan</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
</table>
|
||||
<!-- readme: contributors -end -->
|
||||
|
|
314
README.ru.md
Normal file
314
README.ru.md
Normal file
|
@ -0,0 +1,314 @@
|
|||
<br>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://hydralauncher.site">
|
||||
<img src="./resources/icon.png" width="144"/>
|
||||
</a>
|
||||
<h1 align="center">Hydra Launcher</h1>
|
||||
<p align="center">
|
||||
<strong>Hydra-это игровой лаунчер со своим собственным встроенным клиентом BitTorrent и самоуправляемым скребком репаков.</strong>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://discord.gg/hydralauncher">
|
||||
<img src ="https://img.shields.io/discord/1220692017311645737?style=flat&logo=discord&label=Hydra&labelColor=%231c1c1c"/>
|
||||
</a>
|
||||
<a href="https://github.com/hydralauncher/hydra">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/hydralauncher/hydra/build.yml" />
|
||||
</a>
|
||||
<a href="https://github.com/hydralauncher/hydra">
|
||||
<img src="https://img.shields.io/github/package-json/v/hydralauncher/hydra" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### Язык
|
||||
[](https://github.com/hydralauncher/hydra/blob/main/README.ru.md)
|
||||
|
||||
## Содержание
|
||||
|
||||
- [О нас](#о-нас)
|
||||
- [Функции](#функции)
|
||||
- [Установка](#установка)
|
||||
- [Сотрудничество](#сотрудничество)
|
||||
- [Присоединяйтесь к нашему Discord](#присоединяйтесь-к-нашему-discord)
|
||||
- [Ответвлить и клонировать свой репозиторий](#ответвлить-и-клонировать-свой-репозиторий)
|
||||
- [Способы внести свой вклад](#способы-внести-свой-вклад)
|
||||
- [Структура проекта](#структура-проекта)
|
||||
- [Создать из источника](#создать-из-источника)
|
||||
- [Установите Node.js](#установите-nodejs)
|
||||
- [Установите Yarn](#установите-yarn)
|
||||
- [Установите зависимости Node](#установите-зависимости-node)
|
||||
- [Установите Python 3.9](#установите-python-39)
|
||||
- [Установите зависимости Python](#установите-зависимости-python)
|
||||
- [Переменные среды](#переменные-среды)
|
||||
- [Запуск](#запуск)
|
||||
- [Создание](#создание)
|
||||
- [Создайте клиент BitTorrent](#создайте-клиент-bittorrent)
|
||||
- [Создайте приложение Electron](#создайте-приложение-electron)
|
||||
- [Участники](#участники)
|
||||
|
||||
## О нас
|
||||
|
||||
**Hydra**-это **Игровой Лаунчер** со своим собственным встроенным **BitTorrent Client** и **самоуправляемым скребком репаков**.
|
||||
<br>
|
||||
Лаунчер написан на TypeScript (Electron) и Python, который обрабатывает систему торрента с использованием LibTorrent.
|
||||
|
||||
## Функции
|
||||
|
||||
- Самоуправляемый скребок репаков среди всех самых надежных веб-сайтов на [Megathread]("https://www.reddit.com/r/Piracy/wiki/megathread/")
|
||||
- Собственный встроенный клиент BitTorrent
|
||||
- Как долго пробиться (HLTB) интеграция на странице игры
|
||||
- Загрузка настройки пути
|
||||
- Уведомления об обновлении списка репаков
|
||||
- Поддержка Windows и Linux
|
||||
- Постоянно обновляется
|
||||
- И более ...
|
||||
|
||||
## Установка
|
||||
|
||||
Следуйте приведенным ниже шагам, чтобы установить:
|
||||
|
||||
1. Загрузите последнюю версию Hydra из [Выпуски](https://github.com/hydralauncher/hydra/releases/latest).
|
||||
- Загрузите только .exe, если вы хотите установить Hydra в Windows.
|
||||
- Скачать .deb или .rpm или .zip, если вы хотите установить Hydra на Linux.(Зависит от вашего дистрибутива Linux)
|
||||
2. Запустите загруженный файл.
|
||||
3. Наслаждаться Hydra!
|
||||
|
||||
## Сотрудничество
|
||||
|
||||
### Присоединяйтесь к нашему Discord
|
||||
|
||||
Мы концентрируем наши обсуждения на нашем [Discord](https://discord.gg/hydralauncher) сервере.
|
||||
|
||||
1. Присоединяйтесь к нашему серверу
|
||||
2. Перейдите на роли канала и возьмите роль сотрудничества
|
||||
3. Зайдите на канал Dev, поговорите с нами и поделитесь своими идеями.
|
||||
|
||||
### Ответвлить и клонировать свой репозиторий
|
||||
|
||||
1. Ответвление репозитория [(Нажмите здесь, чтобы сейчас ответвлить)](https://github.com/hydralauncher/hydra/fork)
|
||||
2. Клонировать свой ответвленный код `git clone https://github.com/your_username/hydra`
|
||||
3. Создать новую ветку
|
||||
4. Подтолкнуть свои коммиты
|
||||
5. Отправить новый запрос на привлечение
|
||||
|
||||
### Способы внести свой вклад
|
||||
|
||||
- Перевод: Мы хотим, чтобы Hydra была доступна как можно большему количеству людей. Не стесняйтесь переводить на новые языки или обновить и улучшить те, которые уже доступны на Hydra.
|
||||
- Код: Hydra построена на TypeScript, Electron и немного Python.Если вы хотите внести свой вклад, присоединяйтесь к нашему серверу Discord!
|
||||
|
||||
### Структура проекта
|
||||
|
||||
- torrent-client: Мы используем LibTorrent, библиотеку Python, чтобы управлять загрузками торрента
|
||||
- src/renderer: пользовательский интерфейс приложения
|
||||
- src/main: Вся логика отдыхает здесь.
|
||||
|
||||
## Создать из источника
|
||||
|
||||
### Установите Node.js
|
||||
|
||||
Убедитесь, что у вас установлен Node.js на вашем компьютере.Если нет, загрузите и установите из [nodejs.org](https://nodejs.org/).
|
||||
|
||||
### Установите Yarn
|
||||
|
||||
Yarn является менеджером пакетов для node.js. Если вы еще не установили Yarn, вы можете сделать это, следуя инструкциям на [yarnpkg.com](https://classic.yarnpkg.com/lang/en/docs/install/).
|
||||
|
||||
### Установите зависимости Node
|
||||
|
||||
Перейдите к каталогу проекта и установите Node зависимости с использованием Yarn:
|
||||
|
||||
```bash
|
||||
cd hydra
|
||||
yarn
|
||||
```
|
||||
|
||||
### Установите Python 3.9
|
||||
|
||||
Убедитесь, что на вашем компьютере установлен Python 3.9. Вы можете скачать и установить его из [python.org](https://www.python.org/downloads/release/python-3919/).
|
||||
|
||||
### Установите зависимости Python
|
||||
|
||||
Установите необходимые зависимости Python, используя pip:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Переменные среды
|
||||
|
||||
Вам понадобится ключ API SteamGridDB, чтобы принести значки игры при установке.
|
||||
Если вы хотите получить онлайн -фикс в качестве репака, вам нужно добавить свои учетные данные в .env
|
||||
|
||||
Как только он у вас есть, вы можете скопировать или переименовать `.env.example` файл в `.env`и заполнить это`STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`.
|
||||
|
||||
## Запуск
|
||||
|
||||
После того, как у вас все настроено, вы можете запустить следующую команду, чтобы запустить приложение Electron и клиент BitTorrent:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Создание
|
||||
|
||||
### Создайте клиент BitTorrent
|
||||
|
||||
Создайте клиент BitTorrent, используя эту команду:
|
||||
|
||||
```bash
|
||||
python torrent-client/setup.py build
|
||||
```
|
||||
|
||||
### Создайте приложение Electron
|
||||
|
||||
Создайте приложение Electron с помощью этой команды:
|
||||
|
||||
В Windows:
|
||||
|
||||
```bash
|
||||
yarn build:win
|
||||
```
|
||||
|
||||
В Linux:
|
||||
|
||||
```bash
|
||||
yarn build:linux
|
||||
```
|
||||
|
||||
## Участники
|
||||
|
||||
<!-- readme: contributors -start -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/hydralauncher">
|
||||
<img src="https://avatars.githubusercontent.com/u/164102380?v=4" width="100;" alt="hydralauncher"/>
|
||||
<br />
|
||||
<sub><b>Hydra</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/zamitto">
|
||||
<img src="https://avatars.githubusercontent.com/u/167933696?v=4" width="100;" alt="zamitto"/>
|
||||
<br />
|
||||
<sub><b>Null</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/fzanutto">
|
||||
<img src="https://avatars.githubusercontent.com/u/15229294?v=4" width="100;" alt="fzanutto"/>
|
||||
<br />
|
||||
<sub><b>Null</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/JackEnx">
|
||||
<img src="https://avatars.githubusercontent.com/u/167036558?v=4" width="100;" alt="JackEnx"/>
|
||||
<br />
|
||||
<sub><b>Null</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Magrid0">
|
||||
<img src="https://avatars.githubusercontent.com/u/73496008?v=4" width="100;" alt="Magrid0"/>
|
||||
<br />
|
||||
<sub><b>Magrid</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/fhilipecrash">
|
||||
<img src="https://avatars.githubusercontent.com/u/36455575?v=4" width="100;" alt="fhilipecrash"/>
|
||||
<br />
|
||||
<sub><b>Fhilipe Coelho</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/jps14">
|
||||
<img src="https://avatars.githubusercontent.com/u/168477146?v=4" width="100;" alt="jps14"/>
|
||||
<br />
|
||||
<sub><b>José Luís</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/shadowtosser">
|
||||
<img src="https://avatars.githubusercontent.com/u/168544958?v=4" width="100;" alt="shadowtosser"/>
|
||||
<br />
|
||||
<sub><b>Null</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/pmenta">
|
||||
<img src="https://avatars.githubusercontent.com/u/71457671?v=4" width="100;" alt="pmenta"/>
|
||||
<br />
|
||||
<sub><b>João Martins</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/ferivoq">
|
||||
<img src="https://avatars.githubusercontent.com/u/36544651?v=4" width="100;" alt="ferivoq"/>
|
||||
<br />
|
||||
<sub><b>FeriVOQ</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/xbozo">
|
||||
<img src="https://avatars.githubusercontent.com/u/119091492?v=4" width="100;" alt="xbozo"/>
|
||||
<br />
|
||||
<sub><b>Guilherme Viana</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/eltociear">
|
||||
<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="100;" alt="eltociear"/>
|
||||
<br />
|
||||
<sub><b>Ikko Eltociear Ashimine</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Netflixyapp">
|
||||
<img src="https://avatars.githubusercontent.com/u/91623880?v=4" width="100;" alt="Netflixyapp"/>
|
||||
<br />
|
||||
<sub><b>Netflixy</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Hachi-R">
|
||||
<img src="https://avatars.githubusercontent.com/u/58823742?v=4" width="100;" alt="Hachi-R"/>
|
||||
<br />
|
||||
<sub><b>Hachi</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/FerNikoMF">
|
||||
<img src="https://avatars.githubusercontent.com/u/76095334?v=4" width="100;" alt="FerNikoMF"/>
|
||||
<br />
|
||||
<sub><b>Firdavs</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/userMacieG">
|
||||
<img src="https://avatars.githubusercontent.com/u/24211405?v=4" width="100;" alt="userMacieG"/>
|
||||
<br />
|
||||
<sub><b>Maciej Ratyński</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Tunchichi">
|
||||
<img src="https://avatars.githubusercontent.com/u/118926729?v=4" width="100;" alt="Tunchichi"/>
|
||||
<br />
|
||||
<sub><b>Ruslan</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
</table>
|
||||
<!-- readme: contributors -end -->
|
||||
|
||||
## License
|
||||
|
||||
Hydra лицензирована в соответствии с лицензией [MIT License](LICENSE).
|
Binary file not shown.
Before Width: | Height: | Size: 390 KiB After Width: | Height: | Size: 830 KiB |
|
@ -37,6 +37,7 @@
|
|||
"@sentry/vite-plugin": "^2.16.1",
|
||||
"@vanilla-extract/css": "^1.14.2",
|
||||
"@vanilla-extract/recipes": "^0.5.2",
|
||||
"auto-launch": "^5.0.6",
|
||||
"axios": "^1.6.8",
|
||||
"better-sqlite3": "^9.5.0",
|
||||
"check-disk-space": "^3.4.0",
|
||||
|
@ -66,6 +67,7 @@
|
|||
"@electron-toolkit/eslint-config-ts": "^1.0.1",
|
||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||
"@swc/core": "^1.4.16",
|
||||
"@types/auto-launch": "^5.0.5",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.12.7",
|
||||
|
|
|
@ -138,7 +138,8 @@
|
|||
"telemetry": "Telemetry",
|
||||
"telemetry_description": "Enable anonymous usage statistics",
|
||||
"behavior": "Behavior",
|
||||
"quit_app_instead_hiding": "Close app instead of minimizing to tray"
|
||||
"quit_app_instead_hiding": "Close app instead of minimizing to tray",
|
||||
"launch_with_system": "Launch app on system start-up"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download complete",
|
||||
|
|
|
@ -15,9 +15,12 @@
|
|||
"checking_files": "{{title}} ({{percentage}} - Analizando archivos…)",
|
||||
"paused": "{{title}} (Pausado)",
|
||||
"downloading": "{{title}} ({{percentage}} - Descargando…)",
|
||||
"filter": "Filtrar biblioteca",
|
||||
"filter": "Buscar en la biblioteca",
|
||||
"follow_us": "Síguenos",
|
||||
"home": "Inicio",
|
||||
"follow_us": "Síguenos"
|
||||
"discord": "Únete a nuestro Discord",
|
||||
"x": "Síguenos en X",
|
||||
"github": "Contribuye en GitHub"
|
||||
},
|
||||
"header": {
|
||||
"search": "Buscar",
|
||||
|
@ -45,7 +48,7 @@
|
|||
"remove": "Eliminar",
|
||||
"remove_from_list": "Quitar",
|
||||
"space_left_on_disk": "{{space}} restantes en el disco",
|
||||
"eta": "Finalizando {{eta}}",
|
||||
"eta": "Finalizando en {{eta}}",
|
||||
"downloading_metadata": "Descargando metadatos…",
|
||||
"checking_files": "Analizando archivos…",
|
||||
"filter": "Filtrar repacks",
|
||||
|
@ -55,14 +58,12 @@
|
|||
"no_minimum_requirements": "Sin requisitos mínimos para {{title}}",
|
||||
"no_recommended_requirements": "{{title}} no tiene requisitos recomendados",
|
||||
"paused_progress": "{{progress}} (Pausado)",
|
||||
"release_date": "Fecha de lanzamiento {{date}}",
|
||||
"publisher": "Publicado por {{publisher}}",
|
||||
"release_date": "Fecha de lanzamiento: {{date}}",
|
||||
"publisher": "Publicado por: {{publisher}}",
|
||||
"copy_link_to_clipboard": "Copiar enlace",
|
||||
"copied_link_to_clipboard": "Enlace copiado",
|
||||
"hours": "horas",
|
||||
"minutes": "minutos",
|
||||
"amount_hours": "{{amount}} horas",
|
||||
"amount_minutes": "{{amount}} minutos",
|
||||
"accuracy": "{{accuracy}}% precisión",
|
||||
"add_to_library": "Agregar a la biblioteca",
|
||||
"remove_from_library": "Eliminar de la biblioteca",
|
||||
|
@ -75,7 +76,21 @@
|
|||
"close": "Cerrar",
|
||||
"deleting": "Eliminando instalador…",
|
||||
"playing_now": "Jugando ahora",
|
||||
"last_time_played": "Jugado por última vez {{period}}"
|
||||
"last_time_played": "Jugado por última vez {{period}}",
|
||||
"got_it": "Entendido",
|
||||
"change": "Cambiar",
|
||||
"repacks_modal_description": "Selecciona el repack que quieres descargar",
|
||||
"downloads_path": "Ruta de descarga",
|
||||
"select_folder_hint": "Para cambiar la carpeta predeterminada, accede a",
|
||||
"settings": "Ajustes",
|
||||
"download_now": "Descargar ahora",
|
||||
"installation_instructions": "Instrucciones de instalación",
|
||||
"installation_instructions_description": "Se requieren de pasos adicionales para instalar este juego",
|
||||
"online_fix_instruction": "Los juegos de OnlineFix requieren una contraseña para ser extraídos. Cuando se requiera, usa la siguiente contraseña:",
|
||||
"dodi_installation_instruction": "Cuando abras el instalador de DODI, presiona la tecla hacia arriba del teclado <0 /> para iniciar el proceso de instalación:",
|
||||
"dont_show_it_again": "No mostrar de nuevo",
|
||||
"copy_to_clipboard": "Copiar",
|
||||
"copied_to_clipboard": "Copiado"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activar Hydra",
|
||||
|
@ -88,7 +103,7 @@
|
|||
"downloads": {
|
||||
"resume": "Resumir",
|
||||
"pause": "Pausa",
|
||||
"eta": "Finalizando {{eta}}",
|
||||
"eta": "Finalizando en {{eta}}",
|
||||
"paused": "En Pausa",
|
||||
"verifying": "Verificando…",
|
||||
"completed_at": "Completado el {{date}}",
|
||||
|
@ -103,8 +118,8 @@
|
|||
"starting_download": "Iniciando descarga…",
|
||||
"remove_from_list": "Eliminar",
|
||||
"delete": "Eliminar instalador",
|
||||
"delete_modal_description": "Esto eliminará todos los archivos de instalación de su computadora.",
|
||||
"delete_modal_title": "¿Está seguro?",
|
||||
"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"
|
||||
},
|
||||
|
@ -136,6 +151,9 @@
|
|||
"description": "Los ejecutables de Wine o Lutris no se encontraron en su sistema",
|
||||
"instructions": "Comprueba como instalar de forma correcta uno de los dos en tu distro de Linux para ejecutar el juego con normalidad"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Botón de cierre"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Siguiente página",
|
||||
"previous_page": "Pagina anterior"
|
||||
|
|
|
@ -4,4 +4,5 @@ export { default as es } from "./es/translation.json";
|
|||
export { default as fr } from "./fr/translation.json";
|
||||
export { default as hu } from "./hu/translation.json";
|
||||
export { default as it } from "./it/translation.json";
|
||||
export { default as pl } from "./pl/translation.json";
|
||||
export { default as ru } from "./ru/translation.json";
|
||||
|
|
147
src/locales/pl/translation.json
Normal file
147
src/locales/pl/translation.json
Normal file
|
@ -0,0 +1,147 @@
|
|||
{
|
||||
"home": {
|
||||
"featured": "Wyróżnione",
|
||||
"recently_added": "Ostatnio dodane",
|
||||
"trending": "Trendujące",
|
||||
"surprise_me": "Zaskocz mnie",
|
||||
"no_results": "Nie znaleziono wyników"
|
||||
},
|
||||
"sidebar": {
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Pobrane",
|
||||
"settings": "Ustawienia",
|
||||
"my_library": "Moja biblioteka",
|
||||
"downloading_metadata": "{{title}} (Pobieranie metadata…)",
|
||||
"checking_files": "{{title}} ({{percentage}} - Sprawdzanie plików…)",
|
||||
"paused": "{{title}} (Zatrzymano)",
|
||||
"downloading": "{{title}} ({{percentage}} - Pobieranie…)",
|
||||
"filter": "Filtruj biblioteke",
|
||||
"follow_us": "Śledź nas",
|
||||
"home": "Główna"
|
||||
},
|
||||
"header": {
|
||||
"search": "Szukaj",
|
||||
"home": "Główna",
|
||||
"catalogue": "Katalog",
|
||||
"downloads": "Pobrane",
|
||||
"search_results": "Wyniki wyszukiwania",
|
||||
"settings": "Ustawienia"
|
||||
},
|
||||
"bottom_panel": {
|
||||
"no_downloads_in_progress": "Brak pobierań w toku",
|
||||
"downloading_metadata": "Pobieranie {{title}} metadata…",
|
||||
"checking_files": "Sprawdzanie {{title}} plików… (ukończone w {{percentage}})",
|
||||
"downloading": "Pobieranie {{title}}… (ukończone w {{percentage}}) - Podsumowanie {{eta}} - {{speed}}"
|
||||
},
|
||||
"catalogue": {
|
||||
"next_page": "Następna strona",
|
||||
"previous_page": "Poprzednia strona"
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Otwórz opcje pobierania",
|
||||
"download_options_zero": "Brak opcji pobierania",
|
||||
"download_options_one": "{{count}} opcja pobierania",
|
||||
"download_options_other": "{{count}} opcji pobierania",
|
||||
"updated_at": "Zaktualizowano {{updated_at}}",
|
||||
"install": "Instaluj",
|
||||
"resume": "Wznów",
|
||||
"pause": "Zatrzymaj",
|
||||
"cancel": "Anuluj",
|
||||
"remove": "Usuń",
|
||||
"remove_from_list": "Usuń",
|
||||
"space_left_on_disk": "{{space}} wolnego na dysku",
|
||||
"eta": "Podsumowanie {{eta}}",
|
||||
"downloading_metadata": "Pobieranie metadata…",
|
||||
"checking_files": "Sprawdzanie plików…",
|
||||
"filter": "Filtruj repacki",
|
||||
"requirements": "Wymagania systemowe",
|
||||
"minimum": "Minimalne",
|
||||
"recommended": "Zalecane",
|
||||
"no_minimum_requirements": "{{title}} nie zawiera informacji o minimalnych wymaganiach",
|
||||
"no_recommended_requirements": "{{title}} nie zawiera informacji o zalecanych wymaganiach",
|
||||
"paused_progress": "{{progress}} (Zatrzymano)",
|
||||
"release_date": "Wydano w {{date}}",
|
||||
"publisher": "Opublikowany przez {{publisher}}",
|
||||
"copy_link_to_clipboard": "Kopiuj łącze",
|
||||
"copied_link_to_clipboard": "Skopiowano łącze",
|
||||
"hours": "godzin",
|
||||
"minutes": "minut",
|
||||
"accuracy": "{{accuracy}}% dokładność",
|
||||
"add_to_library": "Dodaj do biblioteki",
|
||||
"remove_from_library": "Usuń z biblioteki",
|
||||
"no_downloads": "Brak dostępnych plików do pobrania",
|
||||
"play_time": "Grano przez {{amount}}",
|
||||
"last_time_played": "Ostatnio grano {{period}}",
|
||||
"not_played_yet": "Nie grano {{title}}",
|
||||
"next_suggestion": "Następna sugestia",
|
||||
"play": "Graj",
|
||||
"deleting": "Usuwanie instalatora…",
|
||||
"close": "Zamknij",
|
||||
"playing_now": "Granie teraz",
|
||||
"change": "Zmień",
|
||||
"repacks_modal_description": "Wybierz repack, który chcesz pobrać",
|
||||
"downloads_path": "Ścieżka pobierania",
|
||||
"select_folder_hint": "Aby zmienić domyślny folder, przejdź do",
|
||||
"settings": "Ustawienia Hydra",
|
||||
"download_now": "Pobierz teraz"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Aktywuj Hydra",
|
||||
"installation_id": "Identyfikator instalacji:",
|
||||
"enter_activation_code": "Enter your activation code",
|
||||
"message": "Jeśli nie wiesz, gdzie o to poprosić, to nie powinieneś/aś tego mieć.",
|
||||
"activate": "Aktywuj",
|
||||
"loading": "Ładowanie…"
|
||||
},
|
||||
"downloads": {
|
||||
"resume": "Wznów",
|
||||
"pause": "Zatrzymaj",
|
||||
"eta": "Podsumowanie {{eta}}",
|
||||
"paused": "Zatrzymano",
|
||||
"verifying": "Weryfikowanie…",
|
||||
"completed_at": "Zakończono w {{date}}",
|
||||
"completed": "Zakończono",
|
||||
"cancelled": "Anulowano",
|
||||
"download_again": "Pobierz ponownie",
|
||||
"cancel": "Anuluj",
|
||||
"filter": "Filtruj pobrane gry",
|
||||
"remove": "Usuń",
|
||||
"downloading_metadata": "Pobieranie metadata…",
|
||||
"checking_files": "Sprawdzanie plików…",
|
||||
"starting_download": "Rozpoczęto pobieranie…",
|
||||
"deleting": "Usuwanie instalatora…",
|
||||
"delete": "Usuń instalator",
|
||||
"remove_from_list": "Usuń",
|
||||
"delete_modal_title": "Czy na pewno?",
|
||||
"delete_modal_description": "Spowoduje to usunięcie wszystkich plików instalacyjnych z komputera",
|
||||
"install": "Instaluj"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Ścieżka pobierania",
|
||||
"change": "Aktualizuj",
|
||||
"notifications": "Powiadomienia",
|
||||
"enable_download_notifications": "Gdy pobieranie zostanie zakończone",
|
||||
"enable_repack_list_notifications": "Gdy dodawany jest nowy repack",
|
||||
"telemetry": "Telemetria",
|
||||
"telemetry_description": "Włącz anonimowe statystyki użycia"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Pobieranie zakończone",
|
||||
"game_ready_to_install": "{{title}} jest gotowe do zainstalowania",
|
||||
"repack_list_updated": "Lista repacków zaktualizowana",
|
||||
"repack_count_one": "{{count}} repack dodany",
|
||||
"repack_count_other": "{{count}} repacki dodane"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Otwórz Hydra",
|
||||
"quit": "Wyjdź"
|
||||
},
|
||||
"game_card": {
|
||||
"no_downloads": "Brak dostępnych plików do pobrania"
|
||||
},
|
||||
"binary_not_found_modal": {
|
||||
"title": "Programy nie są zainstalowane",
|
||||
"description": "Pliki wykonywalne Wine lub Lutris nie zostały znalezione na twoim systemie",
|
||||
"instructions": "Sprawdź prawidłowy sposób instalacji dowolnego z nich w swojej dystrybucji Linuksa, aby gra działała normalnie"
|
||||
}
|
||||
}
|
|
@ -134,7 +134,8 @@
|
|||
"telemetry": "Telemetria",
|
||||
"telemetry_description": "Habilitar estatísticas de uso anônimas",
|
||||
"behavior": "Comportamento",
|
||||
"quit_app_instead_hiding": "Fechar o aplicativo em vez de minimizá-lo"
|
||||
"quit_app_instead_hiding": "Fechar o aplicativo em vez de minimizá-lo",
|
||||
"launch_with_system": "Iniciar aplicativo na inicialização do sistema"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Download concluído",
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
"downloading": "{{title}} ({{percentage}} - Загрузка…)",
|
||||
"filter": "Фильтровать библиотеку",
|
||||
"follow_us": "Подписывайтесь на нас",
|
||||
"home": "Главная"
|
||||
"home": "Главная",
|
||||
"discord": "Присоединяйся к Discord",
|
||||
"x": "Подписывайтесь на X",
|
||||
"github": "Внести свой вклад в GitHub"
|
||||
},
|
||||
"header": {
|
||||
"search": "Поиск",
|
||||
|
@ -66,6 +69,8 @@
|
|||
"copied_link_to_clipboard": "Ссылка скопирована",
|
||||
"hours": "часов",
|
||||
"minutes": "минут",
|
||||
"amount_hours": "{{amount}} часов",
|
||||
"amount_minutes": "{{amount}} минут",
|
||||
"accuracy": "{{accuracy}}% точность",
|
||||
"add_to_library": "Добавить в библиотеку",
|
||||
"remove_from_library": "Удалить из библиотеки",
|
||||
|
@ -83,7 +88,15 @@
|
|||
"downloads_path": "Путь загрузок",
|
||||
"select_folder_hint": "Чтобы изменить папку по умолчанию, откройте",
|
||||
"settings": "Настройки Hydra",
|
||||
"download_now": "Загрузить сейчас"
|
||||
"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": "Понятно"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Активировать Hydra",
|
||||
|
@ -123,7 +136,10 @@
|
|||
"enable_download_notifications": "По завершении загрузки",
|
||||
"enable_repack_list_notifications": "При добавлении нового репака",
|
||||
"telemetry": "Телеметрия",
|
||||
"telemetry_description": "Включить анонимную статистику использования"
|
||||
"telemetry_description": "Включить анонимную статистику использования",
|
||||
"behavior": "Поведение",
|
||||
"quit_app_instead_hiding": "Закрывать приложение вместо того, чтобы сворачивать его в трей"
|
||||
"launch_with_system": "Запуск приложения при запуске системы"
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Загрузка завершена",
|
||||
|
@ -143,5 +159,8 @@
|
|||
"title": "Программы не установлены",
|
||||
"description": "Исполняемые файлы Wine или Lutris не найдены на вашей системе",
|
||||
"instructions": "Узнайте правильный способ установить любой из них на вашем дистрибутиве Linux, чтобы игра могла нормально работать"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Кнопка закрытия"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ export class UserPreferences {
|
|||
@Column("boolean", { default: false })
|
||||
preferQuitInsteadOfHiding: boolean;
|
||||
|
||||
@Column("boolean", { default: false })
|
||||
runAtStartup: boolean;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import "./library/open-game";
|
|||
import "./library/open-game-installer";
|
||||
import "./library/remove-game";
|
||||
import "./library/remove-game-from-library";
|
||||
import "./misc/get-or-cache-image";
|
||||
import "./misc/open-external";
|
||||
import "./misc/show-open-dialog";
|
||||
import "./torrenting/cancel-game-download";
|
||||
|
@ -27,6 +26,7 @@ import "./torrenting/resume-game-download";
|
|||
import "./torrenting/start-game-download";
|
||||
import "./user-preferences/get-user-preferences";
|
||||
import "./user-preferences/update-user-preferences";
|
||||
import "./user-preferences/auto-launch";
|
||||
|
||||
ipcMain.handle("ping", () => "pong");
|
||||
ipcMain.handle("getVersion", () => app.getVersion());
|
||||
|
|
|
@ -3,7 +3,7 @@ import { gameRepository } from "@main/repository";
|
|||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import { getImageBase64 } from "@main/helpers";
|
||||
import { getFileBase64 } from "@main/helpers";
|
||||
import { getSteamGameIconUrl } from "@main/services";
|
||||
|
||||
const addGameToLibrary = async (
|
||||
|
@ -11,7 +11,7 @@ const addGameToLibrary = async (
|
|||
objectID: string,
|
||||
title: string,
|
||||
gameShop: GameShop,
|
||||
executablePath: string
|
||||
executablePath: string | null
|
||||
) => {
|
||||
const game = await gameRepository.findOne({
|
||||
where: {
|
||||
|
@ -31,7 +31,7 @@ const addGameToLibrary = async (
|
|||
}
|
||||
);
|
||||
} else {
|
||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
||||
const iconUrl = await getFileBase64(await getSteamGameIconUrl(objectID));
|
||||
|
||||
return gameRepository.insert({
|
||||
title,
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { registerEvent } from "../register-event";
|
||||
import { getFileBuffer } from "@main/helpers";
|
||||
import { logger } from "@main/services";
|
||||
import { imageCachePath } from "@main/constants";
|
||||
|
||||
const getOrCacheImage = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
url: string
|
||||
) => {
|
||||
if (!fs.existsSync(imageCachePath)) fs.mkdirSync(imageCachePath);
|
||||
|
||||
const extname = path.extname(url);
|
||||
|
||||
const checksum = crypto.createHash("sha256").update(url).digest("hex");
|
||||
const cachePath = path.join(imageCachePath, `${checksum}${extname}`);
|
||||
|
||||
const cache = fs.existsSync(cachePath);
|
||||
|
||||
if (cache) return `hydra://${cachePath}`;
|
||||
|
||||
getFileBuffer(url).then((buffer) =>
|
||||
fs.writeFile(cachePath, buffer, (err) => {
|
||||
if (err) {
|
||||
logger.error(`Failed to cache image`, err, {
|
||||
method: "getOrCacheImage",
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
registerEvent(getOrCacheImage, {
|
||||
name: "getOrCacheImage",
|
||||
});
|
|
@ -5,7 +5,11 @@ import { registerEvent } from "../register-event";
|
|||
const showOpenDialog = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
options: Electron.OpenDialogOptions
|
||||
) => dialog.showOpenDialog(WindowManager.mainWindow, options);
|
||||
) => {
|
||||
if (WindowManager.mainWindow) {
|
||||
dialog.showOpenDialog(WindowManager.mainWindow, options);
|
||||
}
|
||||
};
|
||||
|
||||
registerEvent(showOpenDialog, {
|
||||
name: "showOpenDialog",
|
||||
|
|
|
@ -5,7 +5,7 @@ import { GameStatus } from "@main/constants";
|
|||
import { registerEvent } from "../register-event";
|
||||
|
||||
import type { GameShop } from "@types";
|
||||
import { getImageBase64 } from "@main/helpers";
|
||||
import { getFileBase64 } from "@main/helpers";
|
||||
import { In } from "typeorm";
|
||||
|
||||
const startGameDownload = async (
|
||||
|
@ -72,7 +72,7 @@ const startGameDownload = async (
|
|||
|
||||
return game;
|
||||
} else {
|
||||
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));
|
||||
const iconUrl = await getFileBase64(await getSteamGameIconUrl(objectID));
|
||||
|
||||
const createdGame = await gameRepository.save({
|
||||
title,
|
||||
|
|
21
src/main/events/user-preferences/auto-launch.ts
Normal file
21
src/main/events/user-preferences/auto-launch.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { registerEvent } from "../register-event";
|
||||
import AutoLaunch from "auto-launch";
|
||||
import { app } from "electron";
|
||||
|
||||
const autoLaunch = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
enabled: boolean
|
||||
) => {
|
||||
const appLauncher = new AutoLaunch({
|
||||
name: app.getName(),
|
||||
});
|
||||
if (enabled) {
|
||||
appLauncher.enable().catch();
|
||||
} else {
|
||||
appLauncher.disable().catch();
|
||||
}
|
||||
};
|
||||
|
||||
registerEvent(autoLaunch, {
|
||||
name: "autoLaunch",
|
||||
});
|
|
@ -79,10 +79,24 @@ export const getFileBuffer = async (url: string) =>
|
|||
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
||||
);
|
||||
|
||||
export const getImageBase64 = async (url: string) =>
|
||||
getFileBuffer(url).then((buffer) => {
|
||||
return `data:image/jpeg;base64,${Buffer.from(buffer).toString("base64")}`;
|
||||
});
|
||||
export const getFileBase64 = async (url: string) =>
|
||||
fetch(url, { method: "GET" }).then((response) =>
|
||||
response.arrayBuffer().then((buffer) => {
|
||||
const base64 = Buffer.from(buffer).toString("base64");
|
||||
const contentType = response.headers.get("content-type");
|
||||
|
||||
return `data:${contentType};base64,${base64}`;
|
||||
})
|
||||
);
|
||||
|
||||
export const steamUrlBuilder = {
|
||||
library: (objectID: string) =>
|
||||
`https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/header.jpg`,
|
||||
libraryHero: (objectID: string) =>
|
||||
`https://steamcdn-a.akamaihd.net/steam/apps/${objectID}/library_hero.jpg`,
|
||||
logo: (objectID: string) =>
|
||||
`https://cdn.cloudflare.steamstatic.com/steam/apps/${objectID}/logo.png`,
|
||||
};
|
||||
|
||||
export * from "./formatters";
|
||||
export * from "./ps";
|
||||
|
|
|
@ -85,7 +85,7 @@ app.on("second-instance", (_event, commandLine) => {
|
|||
WindowManager.createMainWindow();
|
||||
}
|
||||
|
||||
const [, path] = commandLine.pop().split("://");
|
||||
const [, path] = commandLine.pop()?.split("://") ?? [];
|
||||
if (path) WindowManager.redirect(path);
|
||||
});
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ export const getSteam250List = async () => {
|
|||
).flat();
|
||||
|
||||
const gamesMap: Map<string, Steam250Game> = gamesList.reduce((map, item) => {
|
||||
map.set(item.objectID, item);
|
||||
if (item) map.set(item.objectID, item);
|
||||
|
||||
return map;
|
||||
}, new Map());
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import path from "node:path";
|
||||
import cp from "node:child_process";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import * as Sentry from "@sentry/electron/main";
|
||||
import { Notification, app, dialog } from "electron";
|
||||
|
@ -99,25 +98,6 @@ export class TorrentClient {
|
|||
return game.progress;
|
||||
}
|
||||
|
||||
private static createTempIcon(encodedIcon: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const hash = crypto.randomBytes(16).toString("hex");
|
||||
const iconPath = path.join(app.getPath("temp"), `${hash}.png`);
|
||||
|
||||
fs.writeFile(
|
||||
iconPath,
|
||||
Buffer.from(
|
||||
encodedIcon.replace("data:image/jpeg;base64,", ""),
|
||||
"base64"
|
||||
),
|
||||
(err) => {
|
||||
if (err) reject(err);
|
||||
resolve(iconPath);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public static async onSocketData(data: Buffer) {
|
||||
const message = Buffer.from(data).toString("utf-8");
|
||||
|
||||
|
@ -159,10 +139,7 @@ export class TorrentClient {
|
|||
});
|
||||
|
||||
if (userPreferences?.downloadNotificationsEnabled) {
|
||||
const iconPath = await this.createTempIcon(game.iconUrl);
|
||||
|
||||
new Notification({
|
||||
icon: iconPath,
|
||||
title: t("download_complete", {
|
||||
ns: "notifications",
|
||||
lng: userPreferences.language,
|
||||
|
|
|
@ -26,7 +26,7 @@ export class WindowManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static async createMainWindow() {
|
||||
public static createMainWindow() {
|
||||
// Create the browser window.
|
||||
this.mainWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
|
@ -50,11 +50,15 @@ export class WindowManager {
|
|||
this.loadURL();
|
||||
this.mainWindow.removeMenu();
|
||||
|
||||
const userPreferences = await userPreferencesRepository.findOne({
|
||||
where: { id: 1 },
|
||||
this.mainWindow.on("ready-to-show", () => {
|
||||
if (!app.isPackaged) WindowManager.mainWindow?.webContents.openDevTools();
|
||||
});
|
||||
|
||||
this.mainWindow.on("close", () => {
|
||||
this.mainWindow.on("close", async () => {
|
||||
const userPreferences = await userPreferencesRepository.findOne({
|
||||
where: { id: 1 },
|
||||
});
|
||||
|
||||
if (userPreferences?.preferQuitInsteadOfHiding) {
|
||||
app.quit();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { parentPort } from "worker_threads";
|
||||
import parseTorrent from "parse-torrent";
|
||||
import { getFileBuffer } from "@main/helpers";
|
||||
|
||||
const port = parentPort;
|
||||
if (!port) throw new Error("IllegalState");
|
||||
|
||||
export const getFileBuffer = async (url: string) =>
|
||||
fetch(url, { method: "GET" }).then((response) =>
|
||||
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
||||
);
|
||||
|
||||
port.on("message", async (url: string) => {
|
||||
const buffer = await getFileBuffer(url);
|
||||
const torrent = await parseTorrent(buffer);
|
||||
|
||||
port.postMessage(torrent);
|
||||
});
|
||||
|
|
2
src/preload/index.d.ts
vendored
2
src/preload/index.d.ts
vendored
|
@ -48,6 +48,7 @@ contextBridge.exposeInMainWorld("electron", {
|
|||
getUserPreferences: () => ipcRenderer.invoke("getUserPreferences"),
|
||||
updateUserPreferences: (preferences: UserPreferences) =>
|
||||
ipcRenderer.invoke("updateUserPreferences", preferences),
|
||||
autoLaunch: (enabled: boolean) => ipcRenderer.invoke("autoLaunch", enabled),
|
||||
|
||||
/* Library */
|
||||
addGameToLibrary: (
|
||||
|
@ -94,7 +95,6 @@ contextBridge.exposeInMainWorld("electron", {
|
|||
getDiskFreeSpace: () => ipcRenderer.invoke("getDiskFreeSpace"),
|
||||
|
||||
/* Misc */
|
||||
getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url),
|
||||
ping: () => ipcRenderer.invoke("ping"),
|
||||
getVersion: () => ipcRenderer.invoke("getVersion"),
|
||||
getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"),
|
||||
|
|
|
@ -57,6 +57,7 @@ contextBridge.exposeInMainWorld("electron", {
|
|||
getUserPreferences: () => ipcRenderer.invoke("getUserPreferences"),
|
||||
updateUserPreferences: (preferences: UserPreferences) =>
|
||||
ipcRenderer.invoke("updateUserPreferences", preferences),
|
||||
autoLaunch: (enabled: boolean) => ipcRenderer.invoke("autoLaunch", enabled),
|
||||
|
||||
/* Library */
|
||||
addGameToLibrary: (
|
||||
|
@ -104,7 +105,6 @@ contextBridge.exposeInMainWorld("electron", {
|
|||
ipcRenderer.invoke("getDiskFreeSpace", path),
|
||||
|
||||
/* Misc */
|
||||
getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url),
|
||||
ping: () => ipcRenderer.invoke("ping"),
|
||||
getVersion: () => ipcRenderer.invoke("getVersion"),
|
||||
getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"),
|
||||
|
|
|
@ -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: hydra: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' data: hydra: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com;"
|
||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com; media-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com;"
|
||||
/>
|
||||
</head>
|
||||
<body style="background-color: #1c1c1c">
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import { forwardRef, useEffect, useState } from "react";
|
||||
|
||||
export interface AsyncImageProps
|
||||
extends React.DetailedHTMLProps<
|
||||
React.ImgHTMLAttributes<HTMLImageElement>,
|
||||
HTMLImageElement
|
||||
> {
|
||||
onSettled?: (url: string) => void;
|
||||
}
|
||||
|
||||
export const AsyncImage = forwardRef<HTMLImageElement, AsyncImageProps>(
|
||||
({ onSettled, ...props }, ref) => {
|
||||
const [source, setSource] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.src && props.src.startsWith("http")) {
|
||||
window.electron.getOrCacheImage(props.src).then((url) => {
|
||||
setSource(url);
|
||||
|
||||
if (onSettled) onSettled(url);
|
||||
});
|
||||
}
|
||||
}, [props.src, onSettled]);
|
||||
|
||||
return <img ref={ref} {...props} src={source ?? props.src} />;
|
||||
}
|
||||
);
|
||||
|
||||
AsyncImage.displayName = "AsyncImage";
|
|
@ -4,8 +4,6 @@ import type { CatalogueEntry } from "@types";
|
|||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||
import EpicGamesLogo from "@renderer/assets/epic-games-logo.svg?react";
|
||||
|
||||
import { AsyncImage } from "../async-image/async-image";
|
||||
|
||||
import * as styles from "./game-card.css";
|
||||
import { useAppSelector } from "@renderer/hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -43,11 +41,7 @@ export function GameCard({ game, disabled, ...props }: GameCardProps) {
|
|||
disabled={disabled}
|
||||
>
|
||||
<div className={styles.backdrop}>
|
||||
<AsyncImage
|
||||
src={game.cover}
|
||||
alt={game.title}
|
||||
className={styles.cover}
|
||||
/>
|
||||
<img src={game.cover} alt={game.title} className={styles.cover} />
|
||||
|
||||
<div className={styles.content}>
|
||||
<div className={styles.titleContainer}>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useNavigate } from "react-router-dom";
|
||||
import { AsyncImage } from "@renderer/components";
|
||||
import * as styles from "./hero.css";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ShopDetails } from "@types";
|
||||
|
@ -35,14 +34,14 @@ export function Hero() {
|
|||
className={styles.hero}
|
||||
>
|
||||
<div className={styles.backdrop}>
|
||||
<AsyncImage
|
||||
<img
|
||||
src="https://cdn2.steamgriddb.com/hero/4ef10445b952a8b3c93a9379d581146a.jpg"
|
||||
alt={featuredGameDetails?.name}
|
||||
className={styles.heroMedia}
|
||||
/>
|
||||
|
||||
<div className={styles.content}>
|
||||
<AsyncImage
|
||||
<img
|
||||
src={steamUrlBuilder.logo(FEATURED_GAME_ID)}
|
||||
width="250px"
|
||||
alt={featuredGameDetails?.name}
|
||||
|
|
|
@ -5,6 +5,5 @@ export * from "./header/header";
|
|||
export * from "./hero/hero";
|
||||
export * from "./modal/modal";
|
||||
export * from "./sidebar/sidebar";
|
||||
export * from "./async-image/async-image";
|
||||
export * from "./text-field/text-field";
|
||||
export * from "./checkbox-field/checkbox-field";
|
||||
|
|
|
@ -74,7 +74,6 @@ export const menuItem = recipe({
|
|||
active: {
|
||||
true: {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
muted: {
|
||||
|
@ -97,11 +96,6 @@ export const menuItemButton = style({
|
|||
overflow: "hidden",
|
||||
width: "100%",
|
||||
padding: `9px ${SPACING_UNIT}px`,
|
||||
selectors: {
|
||||
[`${menuItem({ active: true }).split(" ")[1]} &`]: {
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const menuItemButtonLabel = style({
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useLocation, useNavigate } from "react-router-dom";
|
|||
|
||||
import type { Game } from "@types";
|
||||
|
||||
import { AsyncImage, TextField } from "@renderer/components";
|
||||
import { TextField } from "@renderer/components";
|
||||
import { useDownload, useLibrary } from "@renderer/hooks";
|
||||
|
||||
import { routes } from "./routes";
|
||||
|
@ -14,7 +14,6 @@ import DiscordLogo from "@renderer/assets/discord-icon.svg?react";
|
|||
import XLogo from "@renderer/assets/x-icon.svg?react";
|
||||
|
||||
import * as styles from "./sidebar.css";
|
||||
import { vars } from "@renderer/theme.css";
|
||||
|
||||
const SIDEBAR_MIN_WIDTH = 200;
|
||||
const SIDEBAR_INITIAL_WIDTH = 250;
|
||||
|
@ -217,7 +216,11 @@ export function Sidebar() {
|
|||
)
|
||||
}
|
||||
>
|
||||
<AsyncImage className={styles.gameIcon} src={game.iconUrl} />
|
||||
<img
|
||||
className={styles.gameIcon}
|
||||
src={game.iconUrl}
|
||||
alt={game.title}
|
||||
/>
|
||||
<span className={styles.menuItemButtonLabel}>
|
||||
{getGameTitle(game)}
|
||||
</span>
|
||||
|
|
4
src/renderer/src/declaration.d.ts
vendored
4
src/renderer/src/declaration.d.ts
vendored
|
@ -56,7 +56,7 @@ declare global {
|
|||
objectID: string,
|
||||
title: string,
|
||||
shop: GameShop,
|
||||
executablePath: string
|
||||
executablePath: string | null
|
||||
) => Promise<void>;
|
||||
getLibrary: () => Promise<Game[]>;
|
||||
getRepackersFriendlyNames: () => Promise<Record<string, string>>;
|
||||
|
@ -74,12 +74,12 @@ declare global {
|
|||
updateUserPreferences: (
|
||||
preferences: Partial<UserPreferences>
|
||||
) => Promise<void>;
|
||||
autoLaunch: (enabled: boolean) => Promise<void>;
|
||||
|
||||
/* Hardware */
|
||||
getDiskFreeSpace: (path: string) => Promise<DiskSpace>;
|
||||
|
||||
/* Misc */
|
||||
getOrCacheImage: (url: string) => Promise<string>;
|
||||
openExternal: (src: string) => Promise<void>;
|
||||
getVersion: () => Promise<string>;
|
||||
ping: () => string;
|
||||
|
|
|
@ -24,5 +24,7 @@ export const getSteamLanguage = (language: string) => {
|
|||
if (language.startsWith("ru")) return "russian";
|
||||
if (language.startsWith("it")) return "italian";
|
||||
if (language.startsWith("hu")) return "hungarian";
|
||||
if (language.startsWith("pl")) return "polish";
|
||||
|
||||
return "english";
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { AsyncImage, Button, TextField } from "@renderer/components";
|
||||
import { Button, TextField } from "@renderer/components";
|
||||
import { formatDownloadProgress, steamUrlBuilder } from "@renderer/helpers";
|
||||
import { useDownload, useLibrary } from "@renderer/hooks";
|
||||
import type { Game } from "@types";
|
||||
|
@ -103,6 +103,7 @@ export function Downloads() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (game?.status === "cancelled") return <p>{t("cancelled")}</p>;
|
||||
if (game?.status === "downloading_metadata")
|
||||
return <p>{t("starting_download")}</p>;
|
||||
|
@ -115,6 +116,8 @@ export function Downloads() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const openDeleteModal = (gameId: number) => {
|
||||
|
@ -210,6 +213,12 @@ export function Downloads() {
|
|||
);
|
||||
};
|
||||
|
||||
const handleDeleteGame = () => {
|
||||
if (gameToBeDeleted.current) {
|
||||
deleteGame(gameToBeDeleted.current).then(updateLibrary);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.downloadsContainer}>
|
||||
<BinaryNotFoundModal
|
||||
|
@ -219,9 +228,7 @@ export function Downloads() {
|
|||
<DeleteModal
|
||||
visible={showDeleteModal}
|
||||
onClose={() => setShowDeleteModal(false)}
|
||||
deleteGame={() =>
|
||||
deleteGame(gameToBeDeleted.current).then(updateLibrary)
|
||||
}
|
||||
deleteGame={handleDeleteGame}
|
||||
/>
|
||||
|
||||
<TextField placeholder={t("filter")} onChange={handleFilter} />
|
||||
|
@ -235,7 +242,7 @@ export function Downloads() {
|
|||
cancelled: game.status === "cancelled",
|
||||
})}
|
||||
>
|
||||
<AsyncImage
|
||||
<img
|
||||
src={steamUrlBuilder.library(game.objectID)}
|
||||
className={styles.downloadCover}
|
||||
alt={game.title}
|
||||
|
|
|
@ -12,7 +12,7 @@ import type {
|
|||
SteamAppDetails,
|
||||
} from "@types";
|
||||
|
||||
import { AsyncImage, Button } from "@renderer/components";
|
||||
import { Button } from "@renderer/components";
|
||||
import { setHeaderTitle } from "@renderer/features";
|
||||
import { getSteamLanguage, steamUrlBuilder } from "@renderer/helpers";
|
||||
import { useAppDispatch, useDownload } from "@renderer/hooks";
|
||||
|
@ -70,14 +70,16 @@ export function GameDetails() {
|
|||
|
||||
const { game: gameDownloading, startDownload, isDownloading } = useDownload();
|
||||
|
||||
const handleImageSettled = useCallback((url: string) => {
|
||||
average(url, { amount: 1, format: "hex" })
|
||||
const heroImage = steamUrlBuilder.libraryHero(objectID!);
|
||||
|
||||
const handleHeroLoad = () => {
|
||||
average(heroImage, { amount: 1, format: "hex" })
|
||||
.then((color) => {
|
||||
const darkColor = new Color(color).darken(0.6).toString() as string;
|
||||
setColor({ light: color as string, dark: darkColor });
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
};
|
||||
|
||||
const getGame = useCallback(() => {
|
||||
window.electron
|
||||
|
@ -218,15 +220,15 @@ export function GameDetails() {
|
|||
) : (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.hero}>
|
||||
<AsyncImage
|
||||
src={steamUrlBuilder.libraryHero(objectID!)}
|
||||
<img
|
||||
src={heroImage}
|
||||
className={styles.heroImage}
|
||||
alt={game?.title}
|
||||
onSettled={handleImageSettled}
|
||||
onLoad={handleHeroLoad}
|
||||
/>
|
||||
<div className={styles.heroBackdrop}>
|
||||
<div className={styles.heroContent}>
|
||||
<AsyncImage
|
||||
<img
|
||||
src={steamUrlBuilder.logo(objectID!)}
|
||||
style={{ width: 300, alignSelf: "flex-end" }}
|
||||
/>
|
||||
|
|
|
@ -68,7 +68,7 @@ export function HeroPanelActions({
|
|||
try {
|
||||
if (game) {
|
||||
await removeGameFromLibrary(game.id);
|
||||
} else {
|
||||
} else if (gameDetails) {
|
||||
const gameExecutablePath = await selectGameExecutable();
|
||||
|
||||
await window.electron.addGameToLibrary(
|
||||
|
@ -87,30 +87,37 @@ export function HeroPanelActions({
|
|||
};
|
||||
|
||||
const openGameInstaller = () => {
|
||||
window.electron.openGameInstaller(game.id).then((isBinaryInPath) => {
|
||||
if (!isBinaryInPath) openBinaryNotFoundModal();
|
||||
updateLibrary();
|
||||
});
|
||||
if (game) {
|
||||
window.electron.openGameInstaller(game.id).then((isBinaryInPath) => {
|
||||
if (!isBinaryInPath) openBinaryNotFoundModal();
|
||||
updateLibrary();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const openGame = async () => {
|
||||
if (game.executablePath) {
|
||||
window.electron.openGame(game.id, game.executablePath);
|
||||
return;
|
||||
}
|
||||
if (game) {
|
||||
if (game.executablePath) {
|
||||
window.electron.openGame(game.id, game.executablePath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (game?.executablePath) {
|
||||
window.electron.openGame(game.id, game.executablePath);
|
||||
return;
|
||||
}
|
||||
if (game?.executablePath) {
|
||||
window.electron.openGame(game.id, game.executablePath);
|
||||
return;
|
||||
}
|
||||
|
||||
const gameExecutablePath = await selectGameExecutable();
|
||||
window.electron.openGame(game.id, gameExecutablePath);
|
||||
const gameExecutablePath = await selectGameExecutable();
|
||||
if (gameExecutablePath)
|
||||
window.electron.openGame(game.id, gameExecutablePath);
|
||||
}
|
||||
};
|
||||
|
||||
const closeGame = () => window.electron.closeGame(game.id);
|
||||
const closeGame = () => {
|
||||
if (game) window.electron.closeGame(game.id);
|
||||
};
|
||||
|
||||
const deleting = isGameDeleting(game?.id);
|
||||
const deleting = game ? isGameDeleting(game?.id) : false;
|
||||
|
||||
const toggleGameOnLibraryButton = (
|
||||
<Button
|
||||
|
@ -124,7 +131,7 @@ export function HeroPanelActions({
|
|||
</Button>
|
||||
);
|
||||
|
||||
if (isGameDownloading) {
|
||||
if (game && isGameDownloading) {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
|
|
|
@ -98,7 +98,7 @@ export function HeroPanel({
|
|||
return <p>{t("deleting")}</p>;
|
||||
}
|
||||
|
||||
if (isGameDownloading) {
|
||||
if (isGameDownloading && gameDownloading?.status) {
|
||||
return (
|
||||
<>
|
||||
<p className={styles.downloadDetailsRow}>
|
||||
|
@ -106,14 +106,14 @@ export function HeroPanel({
|
|||
{eta && <small>{t("eta", { eta })}</small>}
|
||||
</p>
|
||||
|
||||
{gameDownloading?.status !== "downloading" ? (
|
||||
{gameDownloading.status !== "downloading" ? (
|
||||
<>
|
||||
<p>{t(gameDownloading?.status)}</p>
|
||||
<p>{t(gameDownloading.status)}</p>
|
||||
{eta && <small>{t("eta", { eta })}</small>}
|
||||
</>
|
||||
) : (
|
||||
<p className={styles.downloadDetailsRow}>
|
||||
{formatBytes(gameDownloading?.bytesDownloaded)} /{" "}
|
||||
{formatBytes(gameDownloading.bytesDownloaded)} /{" "}
|
||||
{finalDownloadSize}
|
||||
<small>
|
||||
{numPeers} peers / {numSeeds} seeds
|
||||
|
@ -148,7 +148,7 @@ export function HeroPanel({
|
|||
<>
|
||||
<p>
|
||||
{t("play_time", {
|
||||
amount: formatPlayTime(game.playTimeInMilliseconds),
|
||||
amount: formatPlayTime(),
|
||||
})}
|
||||
</p>
|
||||
|
||||
|
|
|
@ -89,7 +89,9 @@ export function RepacksModal({
|
|||
<p style={{ color: "#DADBE1" }}>{repack.title}</p>
|
||||
<p style={{ fontSize: "12px" }}>
|
||||
{repack.fileSize} - {repackersFriendlyNames[repack.repacker]} -{" "}
|
||||
{format(repack.uploadDate, "dd/MM/yyyy")}
|
||||
{repack.uploadDate
|
||||
? format(repack.uploadDate, "dd/MM/yyyy")
|
||||
: ""}
|
||||
</p>
|
||||
</Button>
|
||||
))}
|
||||
|
|
|
@ -12,6 +12,7 @@ export function Settings() {
|
|||
repackUpdatesNotificationsEnabled: false,
|
||||
telemetryEnabled: false,
|
||||
preferQuitInsteadOfHiding: false,
|
||||
runAtStartup: false,
|
||||
});
|
||||
|
||||
const { t } = useTranslation("settings");
|
||||
|
@ -30,6 +31,7 @@ export function Settings() {
|
|||
telemetryEnabled: userPreferences?.telemetryEnabled ?? false,
|
||||
preferQuitInsteadOfHiding:
|
||||
userPreferences?.preferQuitInsteadOfHiding ?? false,
|
||||
runAtStartup: userPreferences?.runAtStartup ?? false,
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
@ -123,6 +125,15 @@ export function Settings() {
|
|||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<CheckboxField
|
||||
label={t("launch_with_system")}
|
||||
onChange={() => {
|
||||
updateUserPreferences("runAtStartup", !form.runAtStartup);
|
||||
window.electron.autoLaunch(!form.runAtStartup);
|
||||
}}
|
||||
checked={form.runAtStartup}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
|
|
@ -43,7 +43,7 @@ export interface SteamAppDetails {
|
|||
minimum: string;
|
||||
recommended: string;
|
||||
};
|
||||
linux_requirmenets: {
|
||||
linux_requirements: {
|
||||
minimum: string;
|
||||
recommended: string;
|
||||
};
|
||||
|
@ -121,6 +121,7 @@ export interface UserPreferences {
|
|||
repackUpdatesNotificationsEnabled: boolean;
|
||||
telemetryEnabled: boolean;
|
||||
preferQuitInsteadOfHiding: boolean;
|
||||
runAtStartup: boolean;
|
||||
}
|
||||
|
||||
export interface HowLongToBeatCategory {
|
||||
|
|
|
@ -15,6 +15,6 @@ setup(
|
|||
executables=[Executable(
|
||||
"torrent-client/main.py",
|
||||
target_name="hydra-download-manager",
|
||||
icon="images/icon.ico"
|
||||
icon="build/icon.ico"
|
||||
)]
|
||||
)
|
||||
|
|
38
yarn.lock
38
yarn.lock
|
@ -1316,6 +1316,11 @@
|
|||
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz"
|
||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||
|
||||
"@types/auto-launch@^5.0.5":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/auto-launch/-/auto-launch-5.0.5.tgz#439ed36aaaea501e2e2cfbddd8a20c366c34863b"
|
||||
integrity sha512-/nGvQZSzM/pvCMCh4Gt2kIeiUmOP/cKGJbjlInI+A+5MoV/7XmT56DJ6EU8bqc3+ItxEe4UC2GVspmPzcCc8cg==
|
||||
|
||||
"@types/babel__core@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
|
||||
|
@ -1822,6 +1827,11 @@ app-root-path@^3.1.0:
|
|||
resolved "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz"
|
||||
integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==
|
||||
|
||||
applescript@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/applescript/-/applescript-1.0.0.tgz#bb87af568cad034a4e48c4bdaf6067a3a2701317"
|
||||
integrity sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ==
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
|
||||
|
@ -1949,6 +1959,17 @@ at-least-node@^1.0.0:
|
|||
resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz"
|
||||
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
||||
|
||||
auto-launch@^5.0.6:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/auto-launch/-/auto-launch-5.0.6.tgz#ccc238ddc07b2fa84e96a1bc2fd11b581a20cb2d"
|
||||
integrity sha512-OgxiAm4q9EBf9EeXdPBiVNENaWE3jUZofwrhAkWjHDYGezu1k3FRZHU8V2FBxGuSJOHzKmTJEd0G7L7/0xDGFA==
|
||||
dependencies:
|
||||
applescript "^1.0.0"
|
||||
mkdirp "^0.5.1"
|
||||
path-is-absolute "^1.0.0"
|
||||
untildify "^3.0.2"
|
||||
winreg "1.2.4"
|
||||
|
||||
available-typed-arrays@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz"
|
||||
|
@ -4381,6 +4402,13 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
|
|||
resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz"
|
||||
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.6"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
|
||||
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
|
||||
dependencies:
|
||||
minimist "^1.2.6"
|
||||
|
||||
mkdirp@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
|
||||
|
@ -5763,6 +5791,11 @@ unplugin@1.0.1:
|
|||
webpack-sources "^3.2.3"
|
||||
webpack-virtual-modules "^0.5.0"
|
||||
|
||||
untildify@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9"
|
||||
integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==
|
||||
|
||||
update-browserslist-db@^1.0.13:
|
||||
version "1.0.14"
|
||||
resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.14.tgz"
|
||||
|
@ -5975,6 +6008,11 @@ which@^2.0.1, which@^2.0.2:
|
|||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
winreg@1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
|
||||
integrity sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==
|
||||
|
||||
winston-transport@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue