mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-12 22:27:41 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a21f2b9614 | ||
|
|
c16cbfe04e | ||
|
|
4ff41da05a | ||
|
|
a12e5a15fa | ||
|
|
cc2311529b | ||
|
|
18b63d735d | ||
|
|
7379113dc8 | ||
|
|
ea85da259c | ||
|
|
b8084d6f67 | ||
|
|
97589e63fa | ||
|
|
2539f67e13 | ||
|
|
cc4aed2e17 | ||
|
|
9ea68e629a | ||
|
|
8c66b9a499 | ||
|
|
8fb183007a | ||
|
|
d0ac819da5 | ||
|
|
f4e428a574 | ||
|
|
69879a0303 |
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -33,9 +33,9 @@ body:
|
||||
attributes:
|
||||
label: Additional information and data
|
||||
description: |
|
||||
Add screenshots and upload your logs file here.
|
||||
Logs location on Windows: "%appdata%/hydra"
|
||||
Logs location on Linux: "~/.config/hydra/"
|
||||
Add screenshots and upload your all logs file here.
|
||||
Logs location on Windows: "%appdata%/hydralauncher/logs"
|
||||
Logs location on Linux: "~/.config/hydralauncher/logs"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -88,6 +88,18 @@ jobs:
|
||||
dist/*.blockmap
|
||||
dist/*.pacman
|
||||
|
||||
- name: Upload build
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
|
||||
S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
|
||||
S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
|
||||
S3_BUILDS_BUCKET_NAME: ${{ secrets.S3_BUILDS_BUCKET_NAME }}
|
||||
BUILDS_URL: ${{ secrets.BUILDS_URL }}
|
||||
BUILD_WEBHOOK_URL: ${{ secrets.BUILD_WEBHOOK_URL }}
|
||||
GITHUB_ACTOR: ${{ github.actor }}
|
||||
run: node scripts/upload-build.cjs
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydralauncher",
|
||||
"version": "3.4.3",
|
||||
"version": "3.4.4",
|
||||
"description": "Hydra",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "Los Broxas",
|
||||
@@ -48,7 +48,7 @@
|
||||
"classnames": "^2.5.1",
|
||||
"color": "^4.2.3",
|
||||
"color.js": "^1.2.0",
|
||||
"create-desktop-shortcuts": "^1.11.0",
|
||||
"create-desktop-shortcuts": "^1.11.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"dexie": "^4.0.10",
|
||||
"diskusage": "^1.2.0",
|
||||
@@ -59,7 +59,6 @@
|
||||
"i18next-browser-languagedetector": "^7.2.1",
|
||||
"jsdom": "^24.0.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"kill-port": "^2.0.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"parse-torrent": "^11.0.17",
|
||||
"piscina": "^4.7.0",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { default: axios } = require("axios");
|
||||
const tar = require("tar");
|
||||
const util = require("node:util");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
@@ -6,10 +7,12 @@ const { spawnSync } = require("node:child_process");
|
||||
|
||||
const exec = util.promisify(require("node:child_process").exec);
|
||||
|
||||
const ludusaviVersion = "0.29.0";
|
||||
|
||||
const fileName = {
|
||||
win32: "ludusavi-v0.25.0-win64.zip",
|
||||
linux: "ludusavi-v0.25.0-linux.zip",
|
||||
darwin: "ludusavi-v0.25.0-mac.zip",
|
||||
win32: `ludusavi-v${ludusaviVersion}-win64.zip`,
|
||||
linux: `ludusavi-v${ludusaviVersion}-linux.tar.gz`,
|
||||
darwin: `ludusavi-v${ludusaviVersion}-mac.tar.gz`,
|
||||
};
|
||||
|
||||
const downloadLudusavi = async () => {
|
||||
@@ -19,7 +22,7 @@ const downloadLudusavi = async () => {
|
||||
}
|
||||
|
||||
const file = fileName[process.platform];
|
||||
const downloadUrl = `https://github.com/mtkennerly/ludusavi/releases/download/v0.25.0/${file}`;
|
||||
const downloadUrl = `https://github.com/mtkennerly/ludusavi/releases/download/v${ludusaviVersion}/${file}`;
|
||||
|
||||
console.log(`Downloading ${file}...`);
|
||||
|
||||
@@ -31,10 +34,18 @@ const downloadLudusavi = async () => {
|
||||
console.log(`Downloaded ${file}, extracting...`);
|
||||
|
||||
const pwd = process.cwd();
|
||||
|
||||
const targetPath = path.join(pwd, "ludusavi");
|
||||
|
||||
await exec(`npx extract-zip ${file} ${targetPath}`);
|
||||
await fs.promises.mkdir(targetPath, { recursive: true });
|
||||
|
||||
if (process.platform === "win32") {
|
||||
await exec(`npx extract-zip ${file} ${targetPath}`);
|
||||
} else {
|
||||
await tar.x({
|
||||
file: file,
|
||||
cwd: targetPath,
|
||||
});
|
||||
}
|
||||
|
||||
if (process.platform !== "win32") {
|
||||
fs.chmodSync(path.join(targetPath, "ludusavi"), 0o755);
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
"downloading_metadata": "Descargando metadatos de {{title}}…",
|
||||
"downloading": "Descargando {{title}}… ({{percentage}} completado) - Finalizando {{eta}} - {{speed}}",
|
||||
"calculating_eta": "Descargando {{title}}… ({{percentage}} completado) - Calculando tiempo restante…",
|
||||
"installation_complete": "Instalación completada",
|
||||
"installation_complete_message": "Common redistributables instalados exitosamente",
|
||||
"installing_common_redist": "{{log}}…",
|
||||
"checking_files": "Verificando archivos de {{title}}… ({{percentage}} completado)"
|
||||
},
|
||||
"catalogue": {
|
||||
@@ -59,6 +62,8 @@
|
||||
},
|
||||
"game_details": {
|
||||
"open_download_options": "Ver opciones de descargas",
|
||||
"automatically_extract_downloaded_files": "Extraer automáticamente archivos descargados",
|
||||
"download_error_not_cached_on_hydra": "Esta descarga no está disponible en Nimbus.",
|
||||
"download_options_zero": "No hay opciones de descargas disponibles",
|
||||
"download_options_one": "{{count}} opción de descarga",
|
||||
"download_options_other": "{{count}} opciones de descargas",
|
||||
@@ -230,10 +235,19 @@
|
||||
"seeding": "Seeding",
|
||||
"stop_seeding": "Detener seeding",
|
||||
"resume_seeding": "Continuar seeding",
|
||||
"extract": "Extraer archivos",
|
||||
"extracting": "Extrayendo archivos…",
|
||||
"options": "Gestionar"
|
||||
},
|
||||
"settings": {
|
||||
"downloads_path": "Ruta de descarga",
|
||||
"common_redist": "Common redistributables",
|
||||
"common_redist_description": "Las Common redistributables son requeridos para ejecutar algunos juegos. Es recomendado instalarlos para evitar problemas.",
|
||||
"create_real_debrid_account": "Presiona acá si no tienes una cuenta de Real-Debrid aún",
|
||||
"create_torbox_account": "Presiona acá si no tienes una cuenta de TorBox aún",
|
||||
"install_common_redist": "Instalar",
|
||||
"installing_common_redist": "Instalando…",
|
||||
"show_download_speed_in_megabytes": "Mostrar velocidad de descargar en megabytes por segundo",
|
||||
"change": "Cambiar",
|
||||
"notifications": "Notificaciones",
|
||||
"enable_download_notifications": "Cuando se completa una descarga",
|
||||
@@ -346,6 +360,8 @@
|
||||
},
|
||||
"notifications": {
|
||||
"download_complete": "Descarga completada",
|
||||
"extraction_complete": "Extracción completada",
|
||||
"game_extracted": "{{title}} extraído exitosamente",
|
||||
"game_ready_to_install": "{{title}} está listo para instalarse",
|
||||
"repack_list_updated": "Lista de repacks actualizadas",
|
||||
"repack_count_one": "{{count}} repack ha sido añadido",
|
||||
@@ -475,6 +491,7 @@
|
||||
},
|
||||
"hydra_cloud": {
|
||||
"subscription_tour_title": "Suscripción Hydra Cloud",
|
||||
"debrid_description": "Descargas hasta x4 más rápidas con Nimbus",
|
||||
"subscribe_now": "Suscribirse ahora",
|
||||
"cloud_saving": "Guardado en la nube",
|
||||
"cloud_achievements": "Guarda tus logros en la nube",
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { CloudSync } from "@main/services";
|
||||
import { registerEvent } from "../register-event";
|
||||
import type { GameShop } from "@types";
|
||||
import i18next, { t } from "i18next";
|
||||
import { formatDate } from "date-fns";
|
||||
|
||||
const uploadSaveGame = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -10,16 +8,11 @@ const uploadSaveGame = async (
|
||||
shop: GameShop,
|
||||
downloadOptionTitle: string | null
|
||||
) => {
|
||||
const { language } = i18next;
|
||||
|
||||
return CloudSync.uploadSaveGame(
|
||||
objectId,
|
||||
shop,
|
||||
downloadOptionTitle,
|
||||
t("backup_from", {
|
||||
ns: "game_details",
|
||||
date: formatDate(new Date(), language),
|
||||
})
|
||||
CloudSync.getBackupLabel(false)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import updater from "electron-updater";
|
||||
import i18n from "i18next";
|
||||
import path from "node:path";
|
||||
import url from "node:url";
|
||||
import kill from "kill-port";
|
||||
import { electronApp, optimizer } from "@electron-toolkit/utils";
|
||||
import { logger, WindowManager } from "@main/services";
|
||||
import resources from "@locales";
|
||||
@@ -58,7 +57,7 @@ app.whenReady().then(async () => {
|
||||
return net.fetch(url.pathToFileURL(decodeURI(filePath)).toString());
|
||||
});
|
||||
|
||||
await kill(PythonRPC.RPC_PORT).finally(() => loadState());
|
||||
await loadState();
|
||||
|
||||
const language = await db.get<string, string>(levelKeys.language, {
|
||||
valueEncoding: "utf-8",
|
||||
|
||||
@@ -32,7 +32,7 @@ export const loadState = async () => {
|
||||
|
||||
Ludusavi.addManifestToLudusaviConfig();
|
||||
|
||||
HydraApi.setupApi().then(() => {
|
||||
await HydraApi.setupApi().then(() => {
|
||||
uploadGamesBatch();
|
||||
});
|
||||
|
||||
|
||||
@@ -13,9 +13,28 @@ import { logger } from "./logger";
|
||||
import { WindowManager } from "./window-manager";
|
||||
import axios from "axios";
|
||||
import { Ludusavi } from "./ludusavi";
|
||||
import { SubscriptionRequiredError } from "@shared";
|
||||
import { formatDate, SubscriptionRequiredError } from "@shared";
|
||||
import i18next, { t } from "i18next";
|
||||
|
||||
export class CloudSync {
|
||||
public static getBackupLabel(automatic: boolean) {
|
||||
const language = i18next.language;
|
||||
|
||||
const date = formatDate(new Date(), language);
|
||||
|
||||
if (automatic) {
|
||||
return t("automatic_backup_from", {
|
||||
ns: "game_details",
|
||||
date,
|
||||
});
|
||||
}
|
||||
|
||||
return t("backup_from", {
|
||||
ns: "game_details",
|
||||
date,
|
||||
});
|
||||
}
|
||||
|
||||
private static async bundleBackup(
|
||||
shop: GameShop,
|
||||
objectId: string,
|
||||
@@ -25,7 +44,11 @@ export class CloudSync {
|
||||
|
||||
// Remove existing backup
|
||||
if (fs.existsSync(backupPath)) {
|
||||
fs.rmSync(backupPath, { recursive: true });
|
||||
try {
|
||||
await fs.promises.rm(backupPath, { recursive: true });
|
||||
} catch (error) {
|
||||
logger.error("Failed to remove backup path", error);
|
||||
}
|
||||
}
|
||||
|
||||
await Ludusavi.backupGame(shop, objectId, backupPath, winePrefix);
|
||||
@@ -101,11 +124,10 @@ export class CloudSync {
|
||||
true
|
||||
);
|
||||
|
||||
fs.rm(bundleLocation, (err) => {
|
||||
if (err) {
|
||||
logger.error("Failed to remove tar file", err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
try {
|
||||
await fs.promises.unlink(bundleLocation);
|
||||
} catch (error) {
|
||||
logger.error("Failed to remove tar file", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ import axios from "axios";
|
||||
import { exec } from "child_process";
|
||||
import { ProcessPayload } from "./download/types";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
import i18next, { t } from "i18next";
|
||||
import { CloudSync } from "./cloud-sync";
|
||||
import { formatDate } from "date-fns";
|
||||
|
||||
const commands = {
|
||||
findWineDir: `lsof -c wine 2>/dev/null | grep '/drive_c/windows$' | head -n 1 | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}'`,
|
||||
@@ -229,17 +227,12 @@ function onOpenGame(game: Game) {
|
||||
if (game.remoteId) {
|
||||
updateGamePlaytime(game, 0, new Date()).catch(() => {});
|
||||
|
||||
const { language } = i18next;
|
||||
|
||||
if (game.automaticCloudSync) {
|
||||
CloudSync.uploadSaveGame(
|
||||
game.objectId,
|
||||
game.shop,
|
||||
null,
|
||||
t("automatic_backup_from", {
|
||||
ns: "game_details",
|
||||
date: formatDate(new Date(), language),
|
||||
})
|
||||
CloudSync.getBackupLabel(true)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -298,8 +291,6 @@ const onCloseGame = (game: Game) => {
|
||||
)!;
|
||||
gamesPlaytime.delete(levelKeys.game(game.shop, game.objectId));
|
||||
|
||||
const { language } = i18next;
|
||||
|
||||
if (game.remoteId) {
|
||||
updateGamePlaytime(
|
||||
game,
|
||||
@@ -312,10 +303,7 @@ const onCloseGame = (game: Game) => {
|
||||
game.objectId,
|
||||
game.shop,
|
||||
null,
|
||||
t("automatic_backup_from", {
|
||||
ns: "game_details",
|
||||
date: formatDate(new Date(), language),
|
||||
})
|
||||
CloudSync.getBackupLabel(true)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { formatDate, getDateLocale } from "@shared";
|
||||
import { format, formatDistance, subMilliseconds } from "date-fns";
|
||||
import type { FormatDistanceOptions } from "date-fns";
|
||||
import { enUS } from "date-fns/locale";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export function useDate() {
|
||||
@@ -41,10 +40,10 @@ export function useDate() {
|
||||
},
|
||||
|
||||
formatDateTime: (date: number | Date | string): string => {
|
||||
const locale = getDateLocale(language);
|
||||
return format(
|
||||
date,
|
||||
locale == enUS ? "MM/dd/yyyy - HH:mm" : "dd/MM/yyyy HH:mm"
|
||||
language == "en" ? "MM-dd-yyyy - hh:mm a" : "dd/MM/yyyy HH:mm",
|
||||
{ locale: getDateLocale(language) }
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -173,7 +173,5 @@ export const formatDate = (
|
||||
language: string
|
||||
): string => {
|
||||
if (isNaN(new Date(date).getDate())) return "N/A";
|
||||
|
||||
const locale = getDateLocale(language);
|
||||
return format(date, locale == enUS ? "MM/dd/yyyy" : "dd/MM/yyyy");
|
||||
return format(date, language == "en" ? "MM-dd-yyyy" : "dd/MM/yyyy");
|
||||
};
|
||||
|
||||
30
yarn.lock
30
yarn.lock
@@ -1460,9 +1460,9 @@
|
||||
optionalDependencies:
|
||||
global-agent "^3.0.0"
|
||||
|
||||
"@electron/node-gyp@git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2":
|
||||
"@electron/node-gyp@https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2":
|
||||
version "10.2.0-electron.1"
|
||||
resolved "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
||||
resolved "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
exponential-backoff "^3.1.1"
|
||||
@@ -4501,10 +4501,10 @@ crc@^3.8.0:
|
||||
dependencies:
|
||||
buffer "^5.1.0"
|
||||
|
||||
create-desktop-shortcuts@^1.11.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/create-desktop-shortcuts/-/create-desktop-shortcuts-1.11.0.tgz#8eed89329e9bce70dece46d02a80573fe1f2536d"
|
||||
integrity sha512-nmVtPVqNyMuAyMpDnd7l++hb2laqCWZXnHQaFhqGT1YEi2Ve3unu6QyuyIpGxAwIscNHcG1Ehnl+lFw6ygB2nQ==
|
||||
create-desktop-shortcuts@^1.11.1:
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/create-desktop-shortcuts/-/create-desktop-shortcuts-1.11.1.tgz#59f9dced7931bda551c0717791a909419472c809"
|
||||
integrity sha512-EiHvxrMXXEp4xDD3Nvu1FKLueL9+aBWFYtuTlstYZLIg9H45SoYciizteNB+hvQAls3cRSpoXCM7c4q+lcJpyw==
|
||||
dependencies:
|
||||
which "2.0.2"
|
||||
|
||||
@@ -5814,11 +5814,6 @@ get-symbol-description@^1.1.0:
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.6"
|
||||
|
||||
get-them-args@1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/get-them-args/-/get-them-args-1.3.2.tgz#74a20ba8a4abece5ae199ad03f2bcc68fdfc9ba5"
|
||||
integrity sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==
|
||||
|
||||
git-raw-commits@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285"
|
||||
@@ -6826,14 +6821,6 @@ keyv@^4.0.0, keyv@^4.5.3:
|
||||
dependencies:
|
||||
json-buffer "3.0.1"
|
||||
|
||||
kill-port@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/kill-port/-/kill-port-2.0.1.tgz#e5e18e2706b13d54320938be42cb7d40609b15cf"
|
||||
integrity sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==
|
||||
dependencies:
|
||||
get-them-args "1.3.2"
|
||||
shell-exec "1.0.2"
|
||||
|
||||
language-subtag-registry@^0.3.20:
|
||||
version "0.3.23"
|
||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7"
|
||||
@@ -8459,11 +8446,6 @@ shebang-regex@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
shell-exec@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/shell-exec/-/shell-exec-1.0.2.tgz#2e9361b0fde1d73f476c4b6671fa17785f696756"
|
||||
integrity sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==
|
||||
|
||||
side-channel-list@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
|
||||
|
||||
Reference in New Issue
Block a user