diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 784da11e..c8700663 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -226,7 +226,8 @@ "repack_count_one": "{{count}} repack added", "repack_count_other": "{{count}} repacks added", "new_update_available": "Version {{version}} available", - "restart_to_install_update": "Restart Hydra to install the update" + "restart_to_install_update": "Restart Hydra to install the update", + "game_achievement_unlocked": "{{game}} achievement unlocked" }, "system_tray": { "open": "Open Hydra", diff --git a/src/main/events/catalogue/get-game-achievements.ts b/src/main/events/catalogue/get-game-achievements.ts index fff05248..0d3a40cf 100644 --- a/src/main/events/catalogue/get-game-achievements.ts +++ b/src/main/events/catalogue/get-game-achievements.ts @@ -1,23 +1,30 @@ import type { GameAchievement, GameShop } from "@types"; import { registerEvent } from "../register-event"; import { HydraApi } from "@main/services"; -import { gameAchievementRepository, gameRepository } from "@main/repository"; +import { + gameAchievementRepository, + gameRepository, + userPreferencesRepository, +} from "@main/repository"; const getGameAchievements = async ( _event: Electron.IpcMainInvokeEvent, objectId: string, shop: GameShop ): Promise => { - const [game, cachedAchievements] = await Promise.all([ + const [game, cachedAchievements, userPreferences] = await Promise.all([ gameRepository.findOne({ where: { objectID: objectId, shop }, }), gameAchievementRepository.findOne({ where: { objectId, shop } }), + userPreferencesRepository.findOne({ + where: { id: 1 }, + }), ]); const apiAchievement = HydraApi.get( "/games/achievements", - { objectId, shop }, + { objectId, shop, language: userPreferences?.language || "en" }, { needsAuth: false } ) .then((achievements) => { diff --git a/src/main/main.ts b/src/main/main.ts index 459e20d2..af594e20 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -16,7 +16,6 @@ import { publishNewRepacksNotifications } from "./services/notifications"; import { MoreThan } from "typeorm"; import { HydraApi } from "./services/hydra-api"; import { uploadGamesBatch } from "./services/library-sync"; -import { saveAllLocalSteamAchivements } from "./services/achievements/save-all-local-steam-achivements"; const loadState = async (userPreferences: UserPreferences | null) => { RepacksManager.updateRepacks(); diff --git a/src/main/services/achievements/merge-achievements.ts b/src/main/services/achievements/merge-achievements.ts index dc360e6e..adf05092 100644 --- a/src/main/services/achievements/merge-achievements.ts +++ b/src/main/services/achievements/merge-achievements.ts @@ -1,11 +1,17 @@ -import { gameAchievementRepository } from "@main/repository"; +import { gameAchievementRepository, gameRepository } from "@main/repository"; import { UnlockedAchievement } from "./types"; +import { publishNewAchievementNotification } from "../notifications"; +import { GameShop } from "@types"; export const mergeAchievements = async ( objectId: string, shop: string, achievements: UnlockedAchievement[] ) => { + const game = await gameRepository.findOne({ + where: { objectID: objectId, shop: shop as GameShop }, + }); + const localGameAchievement = await gameAchievementRepository.findOne({ where: { objectId, @@ -17,16 +23,30 @@ export const mergeAchievements = async ( localGameAchievement?.unlockedAchievements || "[]" ); - console.log("file achievemets:", achievements); const newAchievements = achievements.filter((achievement) => { return !unlockedAchievements.some((localAchievement) => { return localAchievement.name === achievement.name; }); }); + for (const achievement of newAchievements) { + const completeAchievement = JSON.parse( + localGameAchievement?.achievements || "[]" + ).find((steamAchievement) => { + return achievement.name === steamAchievement.name; + }); + + if (completeAchievement) { + publishNewAchievementNotification( + game?.title || " ", + completeAchievement.displayName, + completeAchievement.icon + ); + } + } + const mergedAchievements = unlockedAchievements.concat(newAchievements); - console.log("merged achievemetns", mergedAchievements); gameAchievementRepository.upsert( { objectId, diff --git a/src/main/services/achievements/save-all-local-steam-achivements.ts b/src/main/services/achievements/save-all-local-steam-achivements.ts index b76db6b6..4f4bd0b0 100644 --- a/src/main/services/achievements/save-all-local-steam-achivements.ts +++ b/src/main/services/achievements/save-all-local-steam-achivements.ts @@ -1,4 +1,8 @@ -import { gameAchievementRepository, gameRepository } from "@main/repository"; +import { + gameAchievementRepository, + gameRepository, + userPreferencesRepository, +} from "@main/repository"; import { steamFindGameAchievementFiles } from "./steam/steam-find-game-achivement-files"; import { parseAchievementFile } from "./util/parseAchievementFile"; import { HydraApi } from "@main/services"; @@ -7,6 +11,10 @@ import { mergeAchievements } from "./merge-achievements"; import { UnlockedAchievement } from "./types"; export const saveAllLocalSteamAchivements = async () => { + const userPreferences = await userPreferencesRepository.findOne({ + where: { id: 1 }, + }); + const gameAchievementFiles = steamFindGameAchievementFiles(); for (const objectId of Object.keys(gameAchievementFiles)) { @@ -22,11 +30,12 @@ export const saveAllLocalSteamAchivements = async () => { if (!game) continue; if (!localAchievements || !localAchievements.achievements) { - HydraApi.get( + await HydraApi.get( "/games/achievements", { shop: "steam", objectId, + language: userPreferences?.language || "en", }, { needsAuth: false } ) @@ -50,11 +59,14 @@ export const saveAllLocalSteamAchivements = async () => { achievementFile.filePath ); - console.log(achievementFile.filePath); - - unlockedAchievements.push( - ...checkUnlockedAchievements(achievementFile.type, localAchievementFile) - ); + if (localAchievementFile) { + unlockedAchievements.push( + ...checkUnlockedAchievements( + achievementFile.type, + localAchievementFile + ) + ); + } } mergeAchievements(objectId, "steam", unlockedAchievements); diff --git a/src/main/services/notifications.ts b/src/main/services/notifications.ts index aa43571d..114fb5a2 100644 --- a/src/main/services/notifications.ts +++ b/src/main/services/notifications.ts @@ -1,9 +1,12 @@ -import { Notification, nativeImage } from "electron"; +import { Notification, app, nativeImage } from "electron"; import { t } from "i18next"; import { parseICO } from "icojs"; import trayIcon from "@resources/tray-icon.png?asset"; import { Game } from "@main/entity"; import { gameRepository, userPreferencesRepository } from "@main/repository"; +import axios from "axios"; +import fs from "node:fs"; +import path from "node:path"; const getGameIconNativeImage = async (gameId: number) => { try { @@ -82,4 +85,26 @@ export const publishNotificationUpdateReadyToInstall = async ( }).show(); }; +export const publishNewAchievementNotification = async ( + game: string, + name: string, + icon: string +) => { + const iconName = icon.split("/").pop() || "icon.png"; + await axios.get(icon, { responseType: "stream" }).then((response) => { + return response.data.pipe( + fs.createWriteStream(path.join(app.getPath("temp"), iconName)) + ); + }); + + new Notification({ + title: t("game_achievement_unlocked", { + ns: "notifications", + game, + }), + body: name, + icon: path.join(app.getPath("temp"), iconName), + }).show(); +}; + export const publishNewFriendRequestNotification = async () => {}; diff --git a/src/preload/index.ts b/src/preload/index.ts index 223d2201..878f396d 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -13,7 +13,6 @@ import type { UpdateProfileRequest, } from "@types"; import type { CatalogueCategory } from "@shared"; -import { Game } from "@main/entity"; contextBridge.exposeInMainWorld("electron", { /* Torrenting */ diff --git a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx index 0ef16194..74092719 100644 --- a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx +++ b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx @@ -75,6 +75,7 @@ export function Sidebar() { src={ achievement.unlocked ? achievement.icon : achievement.icongray } + alt={achievement.displayName} />

{achievement.displayName}