From a2ef0f304daa827d29aeaca4a13e92a4fe87b5fb Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Thu, 30 Oct 2025 07:35:49 -0300 Subject: [PATCH 01/13] fix: playtime count and custom games request on process watcher --- .../achievement-watcher-manager.ts | 2 + src/main/services/library-sync/create-game.ts | 4 ++ .../library-sync/update-game-playtime.ts | 4 ++ src/main/services/process-watcher.ts | 44 +++++++++++++------ 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/main/services/achievements/achievement-watcher-manager.ts b/src/main/services/achievements/achievement-watcher-manager.ts index b862abbe..dd65165a 100644 --- a/src/main/services/achievements/achievement-watcher-manager.ts +++ b/src/main/services/achievements/achievement-watcher-manager.ts @@ -167,6 +167,8 @@ export class AchievementWatcherManager { shop: GameShop, objectId: string ) { + if (shop === "custom") return; + const gameKey = levelKeys.game(shop, objectId); if (this.alreadySyncedGames.get(gameKey)) return; diff --git a/src/main/services/library-sync/create-game.ts b/src/main/services/library-sync/create-game.ts index a346d3b4..e9ec9612 100644 --- a/src/main/services/library-sync/create-game.ts +++ b/src/main/services/library-sync/create-game.ts @@ -3,6 +3,10 @@ import { HydraApi } from "../hydra-api"; import { gamesSublevel, levelKeys } from "@main/level"; export const createGame = async (game: Game) => { + if (game.shop === "custom") { + return; + } + return HydraApi.post(`/profile/games`, { objectId: game.objectId, playTimeInMilliseconds: Math.trunc(game.playTimeInMilliseconds ?? 0), diff --git a/src/main/services/library-sync/update-game-playtime.ts b/src/main/services/library-sync/update-game-playtime.ts index 3689b302..b53ebebc 100644 --- a/src/main/services/library-sync/update-game-playtime.ts +++ b/src/main/services/library-sync/update-game-playtime.ts @@ -6,6 +6,10 @@ export const updateGamePlaytime = async ( deltaInMillis: number, lastTimePlayed: Date ) => { + if (game.shop === "custom") { + return; + } + return HydraApi.put(`/profile/games/${game.remoteId}`, { playTimeDeltaInSeconds: Math.trunc(deltaInMillis / 1000), lastTimePlayed, diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 6408c30d..a1449255 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -198,11 +198,6 @@ export const watchProcesses = async () => { function onOpenGame(game: Game) { const now = performance.now(); - AchievementWatcherManager.firstSyncWithRemoteIfNeeded( - game.shop, - game.objectId - ); - gamesPlaytime.set(levelKeys.game(game.shop, game.objectId), { lastTick: now, firstTick: now, @@ -220,6 +215,13 @@ function onOpenGame(game: Game) { }) .catch(() => {}); + if (game.shop === "custom") return; + + AchievementWatcherManager.firstSyncWithRemoteIfNeeded( + game.shop, + game.objectId + ); + if (game.remoteId) { updateGamePlaytime( game, @@ -255,18 +257,20 @@ function onTickGame(game: Game) { const delta = now - gamePlaytime.lastTick; - gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { + const updatedGame: Game = { ...game, playTimeInMilliseconds: (game.playTimeInMilliseconds ?? 0) + delta, lastTimePlayed: new Date(), - }); + }; + + gamesSublevel.put(levelKeys.game(game.shop, game.objectId), updatedGame); gamesPlaytime.set(levelKeys.game(game.shop, game.objectId), { ...gamePlaytime, lastTick: now, }); - if (currentTick % TICKS_TO_UPDATE_API === 0) { + if (currentTick % TICKS_TO_UPDATE_API === 0 && game.shop !== "custom") { const deltaToSync = now - gamePlaytime.lastSyncTick + @@ -279,19 +283,20 @@ function onTickGame(game: Game) { gamePromise .then(() => { gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { - ...game, + ...updatedGame, unsyncedDeltaPlayTimeInMilliseconds: 0, }); }) .catch(() => { gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { - ...game, + ...updatedGame, unsyncedDeltaPlayTimeInMilliseconds: deltaToSync, }); }) .finally(() => { gamesPlaytime.set(levelKeys.game(game.shop, game.objectId), { ...gamePlaytime, + lastTick: now, lastSyncTick: now, }); }); @@ -299,11 +304,24 @@ function onTickGame(game: Game) { } const onCloseGame = (game: Game) => { + const now = performance.now(); const gamePlaytime = gamesPlaytime.get( levelKeys.game(game.shop, game.objectId) )!; gamesPlaytime.delete(levelKeys.game(game.shop, game.objectId)); + const delta = now - gamePlaytime.lastTick; + + const updatedGame: Game = { + ...game, + playTimeInMilliseconds: (game.playTimeInMilliseconds ?? 0) + delta, + lastTimePlayed: new Date(), + }; + + gamesSublevel.put(levelKeys.game(game.shop, game.objectId), updatedGame); + + if (game.shop === "custom") return; + if (game.remoteId) { if (game.automaticCloudSync) { CloudSync.uploadSaveGame( @@ -315,20 +333,20 @@ const onCloseGame = (game: Game) => { } const deltaToSync = - performance.now() - + now - gamePlaytime.lastSyncTick + (game.unsyncedDeltaPlayTimeInMilliseconds ?? 0); return updateGamePlaytime(game, deltaToSync, game.lastTimePlayed!) .then(() => { return gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { - ...game, + ...updatedGame, unsyncedDeltaPlayTimeInMilliseconds: 0, }); }) .catch(() => { return gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { - ...game, + ...updatedGame, unsyncedDeltaPlayTimeInMilliseconds: deltaToSync, }); }); From 459bf731217ace778a9ff9e7c6dc18288d2a17bd Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Thu, 30 Oct 2025 07:36:23 -0300 Subject: [PATCH 02/13] fix: request download-sources on custom game --- src/renderer/src/context/game-details/game-details.context.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/renderer/src/context/game-details/game-details.context.tsx b/src/renderer/src/context/game-details/game-details.context.tsx index c5b88607..bc1a6351 100644 --- a/src/renderer/src/context/game-details/game-details.context.tsx +++ b/src/renderer/src/context/game-details/game-details.context.tsx @@ -293,6 +293,8 @@ export function GameDetailsContextProvider({ }, [objectId, shop, userDetails]); useEffect(() => { + if (shop === "custom") return; + const fetchDownloadSources = async () => { try { const sources = await window.electron.getDownloadSources(); From aadf648a2bfe7a52db7036d90ec7b418663f68c6 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Thu, 30 Oct 2025 07:58:43 -0300 Subject: [PATCH 03/13] chore: unnecessary casting --- .../src/pages/settings/settings-download-sources.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/pages/settings/settings-download-sources.tsx b/src/renderer/src/pages/settings/settings-download-sources.tsx index 75f0cc73..675919e3 100644 --- a/src/renderer/src/pages/settings/settings-download-sources.tsx +++ b/src/renderer/src/pages/settings/settings-download-sources.tsx @@ -89,7 +89,7 @@ export function SettingsDownloadSources() { try { await window.electron.removeDownloadSource(false, downloadSource.id); const sources = await window.electron.getDownloadSources(); - setDownloadSources(sources as DownloadSource[]); + setDownloadSources(sources); showSuccessToast(t("removed_download_source")); } catch (error) { logger.error("Failed to remove download source:", error); @@ -104,7 +104,7 @@ export function SettingsDownloadSources() { try { await window.electron.removeDownloadSource(true); const sources = await window.electron.getDownloadSources(); - setDownloadSources(sources as DownloadSource[]); + setDownloadSources(sources); showSuccessToast(t("removed_all_download_sources")); } catch (error) { logger.error("Failed to remove all download sources:", error); @@ -117,7 +117,7 @@ export function SettingsDownloadSources() { const handleAddDownloadSource = async () => { try { const sources = await window.electron.getDownloadSources(); - setDownloadSources(sources as DownloadSource[]); + setDownloadSources(sources); } catch (error) { logger.error("Failed to refresh download sources:", error); } @@ -128,7 +128,7 @@ export function SettingsDownloadSources() { try { await window.electron.syncDownloadSources(); const sources = await window.electron.getDownloadSources(); - setDownloadSources(sources as DownloadSource[]); + setDownloadSources(sources); showSuccessToast(t("download_sources_synced_successfully")); } finally { From 4bfe6d7f86f864c8989339d7ee6a6bc6ea483f64 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:32:08 -0300 Subject: [PATCH 04/13] feat: limit game text search to 255 chars --- src/renderer/src/components/header/header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/header/header.tsx b/src/renderer/src/components/header/header.tsx index e61f3954..8166658d 100644 --- a/src/renderer/src/components/header/header.tsx +++ b/src/renderer/src/components/header/header.tsx @@ -60,7 +60,7 @@ export function Header() { }; const handleSearch = (value: string) => { - dispatch(setFilters({ title: value })); + dispatch(setFilters({ title: value.trim().slice(0, 255) })); if (!location.pathname.startsWith("/catalogue")) { navigate("/catalogue"); From 2aa31c0db0556b1a674d6cd49d08e2ce1fecbf67 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:34:49 -0300 Subject: [PATCH 05/13] feat: limit game text search to 255 chars --- src/renderer/src/pages/catalogue/catalogue.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/renderer/src/pages/catalogue/catalogue.tsx b/src/renderer/src/pages/catalogue/catalogue.tsx index bbeda906..b9eb3c24 100644 --- a/src/renderer/src/pages/catalogue/catalogue.tsx +++ b/src/renderer/src/pages/catalogue/catalogue.tsx @@ -35,7 +35,7 @@ export default function Catalogue() { const { steamDevelopers, steamPublishers, downloadSources } = useCatalogue(); - const { steamGenres, steamUserTags } = useAppSelector( + const { steamGenres, steamUserTags, filters, page } = useAppSelector( (state) => state.catalogueSearch ); @@ -47,8 +47,6 @@ export default function Catalogue() { const { formatNumber } = useFormat(); - const { filters, page } = useAppSelector((state) => state.catalogueSearch); - const dispatch = useAppDispatch(); const { t, i18n } = useTranslation("catalogue"); From aa148c0b70234013c2137b64afc7530faf1ea48f Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:01:47 -0300 Subject: [PATCH 06/13] fix: trim --- src/renderer/src/components/header/header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/header/header.tsx b/src/renderer/src/components/header/header.tsx index 8166658d..6f97729f 100644 --- a/src/renderer/src/components/header/header.tsx +++ b/src/renderer/src/components/header/header.tsx @@ -60,7 +60,7 @@ export function Header() { }; const handleSearch = (value: string) => { - dispatch(setFilters({ title: value.trim().slice(0, 255) })); + dispatch(setFilters({ title: value.slice(0, 255) })); if (!location.pathname.startsWith("/catalogue")) { navigate("/catalogue"); From b8af69b0fbc52533b9c144b23ad22c107de53cd7 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 31 Oct 2025 12:01:42 +0000 Subject: [PATCH 07/13] fix: fixing review partial --- src/locales/en/translation.json | 4 +++- src/locales/es/translation.json | 4 +++- src/locales/pt-BR/translation.json | 4 +++- src/locales/pt-PT/translation.json | 4 +++- src/locales/ru/translation.json | 4 +++- .../src/pages/game-details/game-reviews.tsx | 1 - .../src/pages/game-details/review-item.tsx | 21 ++++++------------- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 668f1547..b48c6ece 100755 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -361,7 +361,9 @@ "show_original": "Show original", "show_translation": "Show translation", "show_original_translated_from": "Show original (translated from {{language}})", - "hide_original": "Hide original" + "hide_original": "Hide original", + "show": "Show", + "hide": "Hide" }, "activation": { "title": "Activate Hydra", diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json index 863b8332..75a9adce 100644 --- a/src/locales/es/translation.json +++ b/src/locales/es/translation.json @@ -361,7 +361,9 @@ "you_seemed_to_enjoy_this_game": "Parece que has disfrutado de este juego", "language": "Idioma", "caption": "Subtítulo", - "audio": "Audio" + "audio": "Audio", + "show": "Mostrar", + "hide": "Ocultar" }, "activation": { "title": "Activar Hydra", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index 5bfc2af3..98946d51 100755 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -349,7 +349,9 @@ "show_translation": "Mostrar tradução", "show_original_translated_from": "Mostrar original (traduzido do {{language}})", "hide_original": "Ocultar original", - "rating_count": "Avaliação" + "rating_count": "Avaliação", + "show": "Mostrar", + "hide": "Ocultar" }, "activation": { "title": "Ativação", diff --git a/src/locales/pt-PT/translation.json b/src/locales/pt-PT/translation.json index 2894cf65..a99bb93d 100644 --- a/src/locales/pt-PT/translation.json +++ b/src/locales/pt-PT/translation.json @@ -180,7 +180,9 @@ "download_error_not_cached_on_torbox": "Este download não está disponível no TorBox e a verificação do status do download não está disponível.", "game_removed_from_favorites": "Jogo removido dos favoritos", "game_added_to_favorites": "Jogo adicionado aos favoritos", - "create_start_menu_shortcut": "Criar atalho no Menu Iniciar" + "create_start_menu_shortcut": "Criar atalho no Menu Iniciar", + "show": "Mostrar", + "hide": "Ocultar" }, "activation": { "title": "Ativação", diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json index 886c7d07..388763bd 100644 --- a/src/locales/ru/translation.json +++ b/src/locales/ru/translation.json @@ -360,7 +360,9 @@ "caption": "Субтитры", "audio": "Аудио", "filter_by_source": "Фильтр по источнику", - "no_repacks_found": "Источники для этой игры не найдены" + "no_repacks_found": "Источники для этой игры не найдены", + "show": "Показать", + "hide": "Скрыть" }, "activation": { "title": "Активировать Hydra", diff --git a/src/renderer/src/pages/game-details/game-reviews.tsx b/src/renderer/src/pages/game-details/game-reviews.tsx index 1a6fc675..2dfd8864 100644 --- a/src/renderer/src/pages/game-details/game-reviews.tsx +++ b/src/renderer/src/pages/game-details/game-reviews.tsx @@ -163,7 +163,6 @@ export function GameReviews({ take: "20", skip: skip.toString(), sortBy: reviewsSortBy, - language: i18n.language, }); const response = await window.electron.hydraApi.get( diff --git a/src/renderer/src/pages/game-details/review-item.tsx b/src/renderer/src/pages/game-details/review-item.tsx index f5e3528a..7e407e20 100644 --- a/src/renderer/src/pages/game-details/review-item.tsx +++ b/src/renderer/src/pages/game-details/review-item.tsx @@ -71,24 +71,16 @@ export function ReviewItem({ const [showOriginal, setShowOriginal] = useState(false); - // Check if this is the user's own review const isOwnReview = userDetailsId === review.user.id; - // Helper to get base language code (e.g., "pt" from "pt-BR") - const getBaseLanguage = (lang: string) => lang.split("-")[0]; + const getBaseLanguage = (lang: string | null) => lang?.split("-")[0] || ""; - // Check if the review is in a different language (comparing base language codes) const isDifferentLanguage = getBaseLanguage(review.detectedLanguage) !== getBaseLanguage(i18n.language); - // Check if translation is available and needed (but not for own reviews) const needsTranslation = - !isOwnReview && - isDifferentLanguage && - review.translations && - review.translations[i18n.language]; + !isOwnReview && isDifferentLanguage && review.translations[i18n.language]; - // Get the full language name using Intl.DisplayNames const getLanguageName = (languageCode: string) => { try { const displayNames = new Intl.DisplayNames([i18n.language], { @@ -100,7 +92,6 @@ export function ReviewItem({ } }; - // Determine which content to show - always show original for own reviews const displayContent = needsTranslation ? review.translations[i18n.language] : review.reviewHtml; @@ -109,12 +100,12 @@ export function ReviewItem({ return (
- Review from blocked user —{" "} + {t("review_from_blocked_user")}
@@ -191,7 +182,7 @@ export function ReviewItem({ {showOriginal ? t("hide_original") : t("show_original_translated_from", { - language: getLanguageName(review.detectedLanguage), + language: getLanguageName(review.detectedLanguage!), })} {showOriginal && ( @@ -323,7 +314,7 @@ export function ReviewItem({ className="game-details__blocked-review-hide-link" onClick={() => onToggleVisibility(review.id)} > - Hide + {t("hide")} )} From ff8a61ff7a83394e08609a48770cfe1323c8d8ce Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 31 Oct 2025 12:05:24 +0000 Subject: [PATCH 08/13] fix: fixing review partial --- src/locales/en/translation.json | 1 + src/locales/es/translation.json | 1 + src/locales/pt-BR/translation.json | 1 + src/locales/pt-PT/translation.json | 1 + src/locales/ru/translation.json | 3 ++- 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index b48c6ece..8b9ff73e 100755 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -362,6 +362,7 @@ "show_translation": "Show translation", "show_original_translated_from": "Show original (translated from {{language}})", "hide_original": "Hide original", + "review_from_blocked_user": "Review from blocked user", "show": "Show", "hide": "Hide" }, diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json index 75a9adce..adf25e33 100644 --- a/src/locales/es/translation.json +++ b/src/locales/es/translation.json @@ -362,6 +362,7 @@ "language": "Idioma", "caption": "Subtítulo", "audio": "Audio", + "review_from_blocked_user": "Reseña de usuario bloqueado", "show": "Mostrar", "hide": "Ocultar" }, diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index 98946d51..42743a64 100755 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -350,6 +350,7 @@ "show_original_translated_from": "Mostrar original (traduzido do {{language}})", "hide_original": "Ocultar original", "rating_count": "Avaliação", + "review_from_blocked_user": "Avaliação de usuário bloqueado", "show": "Mostrar", "hide": "Ocultar" }, diff --git a/src/locales/pt-PT/translation.json b/src/locales/pt-PT/translation.json index a99bb93d..6c1963cc 100644 --- a/src/locales/pt-PT/translation.json +++ b/src/locales/pt-PT/translation.json @@ -181,6 +181,7 @@ "game_removed_from_favorites": "Jogo removido dos favoritos", "game_added_to_favorites": "Jogo adicionado aos favoritos", "create_start_menu_shortcut": "Criar atalho no Menu Iniciar", + "review_from_blocked_user": "Avaliação de utilizador bloqueado", "show": "Mostrar", "hide": "Ocultar" }, diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json index 682b1322..6f4d4b92 100644 --- a/src/locales/ru/translation.json +++ b/src/locales/ru/translation.json @@ -363,7 +363,8 @@ "show_original": "Показать оригинал", "show_translation": "Показать перевод", "show_original_translated_from": "Показать оригинал (переведено с {{language}})", - "hide_original": "Скрыть оригинал" + "hide_original": "Скрыть оригинал", + "review_from_blocked_user": "Отзыв от заблокированного пользователя" }, "activation": { "title": "Активировать Hydra", From c71f5947ba8dfb7856625477289bb9b2f44346f2 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Fri, 31 Oct 2025 10:20:11 -0300 Subject: [PATCH 09/13] feat: use new ep to track game playtime --- src/main/services/library-sync/update-game-playtime.ts | 4 ++-- src/main/services/process-watcher.ts | 8 ++++---- src/main/services/window-manager.ts | 8 +------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/services/library-sync/update-game-playtime.ts b/src/main/services/library-sync/update-game-playtime.ts index b53ebebc..a669a363 100644 --- a/src/main/services/library-sync/update-game-playtime.ts +++ b/src/main/services/library-sync/update-game-playtime.ts @@ -1,7 +1,7 @@ import type { Game } from "@types"; import { HydraApi } from "../hydra-api"; -export const updateGamePlaytime = async ( +export const trackGamePlaytime = async ( game: Game, deltaInMillis: number, lastTimePlayed: Date @@ -10,7 +10,7 @@ export const updateGamePlaytime = async ( return; } - return HydraApi.put(`/profile/games/${game.remoteId}`, { + return HydraApi.put(`/profile/games/${game.shop}/${game.objectId}`, { playTimeDeltaInSeconds: Math.trunc(deltaInMillis / 1000), lastTimePlayed, }); diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index a1449255..db5bbee1 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -1,5 +1,5 @@ import { WindowManager } from "./window-manager"; -import { createGame, updateGamePlaytime } from "./library-sync"; +import { createGame, trackGamePlaytime } from "./library-sync"; import type { Game, GameRunning, UserPreferences } from "@types"; import { PythonRPC } from "./python-rpc"; import axios from "axios"; @@ -223,7 +223,7 @@ function onOpenGame(game: Game) { ); if (game.remoteId) { - updateGamePlaytime( + trackGamePlaytime( game, game.unsyncedDeltaPlayTimeInMilliseconds ?? 0, new Date() @@ -277,7 +277,7 @@ function onTickGame(game: Game) { (game.unsyncedDeltaPlayTimeInMilliseconds ?? 0); const gamePromise = game.remoteId - ? updateGamePlaytime(game, deltaToSync, game.lastTimePlayed!) + ? trackGamePlaytime(game, deltaToSync, game.lastTimePlayed!) : createGame(game); gamePromise @@ -337,7 +337,7 @@ const onCloseGame = (game: Game) => { gamePlaytime.lastSyncTick + (game.unsyncedDeltaPlayTimeInMilliseconds ?? 0); - return updateGamePlaytime(game, deltaToSync, game.lastTimePlayed!) + return trackGamePlaytime(game, deltaToSync, game.lastTimePlayed!) .then(() => { return gamesSublevel.put(levelKeys.game(game.shop, game.objectId), { ...updatedGame, diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 673bf1a0..2484e8e7 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -289,12 +289,6 @@ export class WindowManager { } } - private static loadNotificationWindowURL() { - if (this.notificationWindow) { - this.loadWindowURL(this.notificationWindow, "achievement-notification"); - } - } - private static readonly NOTIFICATION_WINDOW_WIDTH = 360; private static readonly NOTIFICATION_WINDOW_HEIGHT = 140; @@ -387,7 +381,7 @@ export class WindowManager { this.notificationWindow.setIgnoreMouseEvents(true); this.notificationWindow.setAlwaysOnTop(true, "screen-saver", 1); - this.loadNotificationWindowURL(); + this.loadWindowURL(this.notificationWindow, "achievement-notification"); if (!app.isPackaged || isStaging) { this.notificationWindow.webContents.openDevTools(); From 138120460cf0957eaf584162172f8791c2c318e1 Mon Sep 17 00:00:00 2001 From: jarexe Date: Fri, 31 Oct 2025 10:57:44 -0300 Subject: [PATCH 10/13] fix: correct achievement notification positioning on multi-monitor setups --- src/main/services/window-manager.ts | 38 +++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 673bf1a0..834bf7ab 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -302,46 +302,58 @@ export class WindowManager { position: AchievementCustomNotificationPosition | undefined ) { const display = screen.getPrimaryDisplay(); - const { width, height } = display.workAreaSize; + const { + x: displayX, + y: displayY, + width: displayWidth, + height: displayHeight, + } = display.bounds; if (position === "bottom-left") { return { - x: 0, - y: height - this.NOTIFICATION_WINDOW_HEIGHT, + x: displayX, + y: displayY + displayHeight - this.NOTIFICATION_WINDOW_HEIGHT, }; } if (position === "bottom-center") { return { - x: (width - this.NOTIFICATION_WINDOW_WIDTH) / 2, - y: height - this.NOTIFICATION_WINDOW_HEIGHT, + x: displayX + (displayWidth - this.NOTIFICATION_WINDOW_WIDTH) / 2, + y: displayY + displayHeight - this.NOTIFICATION_WINDOW_HEIGHT, }; } if (position === "bottom-right") { return { - x: width - this.NOTIFICATION_WINDOW_WIDTH, - y: height - this.NOTIFICATION_WINDOW_HEIGHT, + x: displayX + displayWidth - this.NOTIFICATION_WINDOW_WIDTH, + y: displayY + displayHeight - this.NOTIFICATION_WINDOW_HEIGHT, + }; + } + + if (position === "top-left") { + return { + x: displayX, + y: displayY, }; } if (position === "top-center") { return { - x: (width - this.NOTIFICATION_WINDOW_WIDTH) / 2, - y: 0, + x: displayX + (displayWidth - this.NOTIFICATION_WINDOW_WIDTH) / 2, + y: displayY, }; } if (position === "top-right") { return { - x: width - this.NOTIFICATION_WINDOW_WIDTH, - y: 0, + x: displayX + displayWidth - this.NOTIFICATION_WINDOW_WIDTH, + y: displayY, }; } return { - x: 0, - y: 0, + x: displayX, + y: displayY, }; } From 51c4e4f5b38b411f0ac92d13a1b15d8b676ceecc Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:07:06 -0300 Subject: [PATCH 11/13] chore: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5d84e763..ee039574 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydralauncher", - "version": "3.7.2", + "version": "3.7.3", "description": "Hydra", "main": "./out/main/index.js", "author": "Los Broxas", From d167628ed44e22c6090f352ee57cdb5710b32811 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:57:15 -0300 Subject: [PATCH 12/13] fix: prevent crash when detectedLanguage is null --- src/renderer/src/pages/game-details/review-item.tsx | 5 +++-- src/types/index.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/pages/game-details/review-item.tsx b/src/renderer/src/pages/game-details/review-item.tsx index 7e407e20..c411e0cb 100644 --- a/src/renderer/src/pages/game-details/review-item.tsx +++ b/src/renderer/src/pages/game-details/review-item.tsx @@ -81,7 +81,8 @@ export function ReviewItem({ const needsTranslation = !isOwnReview && isDifferentLanguage && review.translations[i18n.language]; - const getLanguageName = (languageCode: string) => { + const getLanguageName = (languageCode: string | null) => { + if (!languageCode) return ""; try { const displayNames = new Intl.DisplayNames([i18n.language], { type: "language", @@ -182,7 +183,7 @@ export function ReviewItem({ {showOriginal ? t("hide_original") : t("show_original_translated_from", { - language: getLanguageName(review.detectedLanguage!), + language: getLanguageName(review.detectedLanguage), })} {showOriginal && ( diff --git a/src/types/index.ts b/src/types/index.ts index 4b13c496..c04b6232 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -252,7 +252,7 @@ export interface GameReview { translations: { [key: string]: string; }; - detectedLanguage: string; + detectedLanguage: string | null; } export interface TrendingGame extends ShopAssets { From 19bf99ff119f65394bcdaed84d0a1423472b1d88 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:16:03 -0300 Subject: [PATCH 13/13] chore: add sleep to aur script --- .github/workflows/update-aur.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/update-aur.yml b/.github/workflows/update-aur.yml index 52fe907e..fa12b500 100644 --- a/.github/workflows/update-aur.yml +++ b/.github/workflows/update-aur.yml @@ -95,6 +95,8 @@ jobs: - name: Update PKGBUILD and .SRCINFO if: steps.check-update.outputs.update_needed == 'true' run: | + # sleeps for 1 minute to be sure GH updated the release info + sleep 60 # Update pkgver in PKGBUILD cd hydra-launcher-bin NEW_VERSION="${{ steps.get-version.outputs.version }}"