diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc03a2db..8325cd5c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,7 +77,7 @@ jobs: dist/*.pacman - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: draft: true files: | diff --git a/resources/achievement-sound.mp3 b/resources/achievement-sound.mp3 deleted file mode 100644 index e942cb6b..00000000 Binary files a/resources/achievement-sound.mp3 and /dev/null differ diff --git a/resources/achievement.wav b/resources/achievement.wav new file mode 100644 index 00000000..adf40d74 Binary files /dev/null and b/resources/achievement.wav differ diff --git a/src/main/main.ts b/src/main/main.ts index 69bc62e0..ae96ca37 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -12,6 +12,8 @@ import { UserPreferences } from "./entity"; import { RealDebridClient } from "./services/real-debrid"; import { HydraApi } from "./services/hydra-api"; import { uploadGamesBatch } from "./services/library-sync"; +import { Toast } from "powertoast"; +import { publishNewAchievementNotification } from "./services/notifications"; const loadState = async (userPreferences: UserPreferences | null) => { import("./events"); @@ -49,5 +51,10 @@ userPreferencesRepository where: { id: 1 }, }) .then((userPreferences) => { + publishNewAchievementNotification({ + icon: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/72850/c3a604f698d247b53d20f212e9f31a9ec707a180.jpg", + displayName: "Hydra has started", + }); + loadState(userPreferences); }); diff --git a/src/main/services/notifications.ts b/src/main/services/notifications.ts index 81d9e582..70e8a71f 100644 --- a/src/main/services/notifications.ts +++ b/src/main/services/notifications.ts @@ -1,9 +1,13 @@ -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 { Toast } from "powertoast"; +import fs from "node:fs"; +import axios from "axios"; +import path from "node:path"; const getGameIconNativeImage = async (gameId: number) => { try { @@ -65,3 +69,42 @@ export const publishNotificationUpdateReadyToInstall = async ( }; export const publishNewFriendRequestNotification = async () => {}; + +async function downloadImage(url: string) { + const fileName = url.split("/").pop()!; + const outputPath = path.join(app.getPath("temp"), fileName); + const writer = fs.createWriteStream(outputPath); + + const response = await axios.get(url, { + responseType: "stream", + }); + + response.data.pipe(writer); + + return new Promise((resolve, reject) => { + writer.on("finish", () => { + resolve(outputPath); + }); + writer.on("error", reject); + }); +} + +export const publishNewAchievementNotification = async (achievement: { + displayName: string; + icon: string; +}) => { + const iconPath = await downloadImage(achievement.icon); + + new Toast({ + aumid: "gg.hydralauncher.hydra", + title: "New achievement unlocked", + message: achievement.displayName, + icon: iconPath, + sound: true, + audio: "ms-appx:///resources/achievement.wav", + progress: { + value: 30, + valueOverride: "30/100 achievements", + }, + }).show(); +}; diff --git a/src/types/index.ts b/src/types/index.ts index 7f970d63..80a910e6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -94,8 +94,6 @@ export interface UserGame { cover: string; playTimeInSeconds: number; lastTimePlayed: Date | null; - unlockedAchievementCount: number; - achievementCount: number; } export interface DownloadQueue { @@ -258,7 +256,10 @@ export interface UserProfile { profileImageUrl: string | null; backgroundImageUrl: string | null; profileVisibility: ProfileVisibility; - libraryGames: UserGame[]; + libraryGames: (UserGame & { + unlockedAchievementCount: number; + achievementCount: number; + })[]; recentGames: UserGame[]; friends: UserFriend[]; totalFriends: number; diff --git a/yarn.lock b/yarn.lock index 51391923..fdc60588 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2828,6 +2828,26 @@ "@types/babel__core" "^7.20.5" react-refresh "^0.14.0" +"@xan105/error@^1.6.2", "@xan105/error@^1.7.0": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@xan105/error/-/error-1.7.1.tgz#d417e839cef7d79df4594943553d3d5b14f26bfa" + integrity sha512-FYIUYijbmg62L9QQ5BsR14DuZatAJJvwo10yzuEDEsu8L0FAa4DZivWFAf66nYjEiSz50SFGtMxWSyG+y/ZGGw== + +"@xan105/fs@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@xan105/fs/-/fs-2.2.1.tgz#46ca0f943443f5fa5daebd0af6bee289637be098" + integrity sha512-jYvheYkJ1F6XfUYSfCIgdfgx/yWiW5uitXhydEceirICNMRubboNQM1LUB5+ZDmKq4hCNyjqxv4TPeARMcOepQ== + dependencies: + "@xan105/error" "^1.6.2" + "@xan105/is" "^2.9.3" + +"@xan105/is@^2.9.3": + version "2.9.3" + resolved "https://registry.yarnpkg.com/@xan105/is/-/is-2.9.3.tgz#81c2152202e450c0aad8927fdc6eea30649f30d6" + integrity sha512-1Ivr52VENqksdcvhar+rv+kTSsDWFBPyScpMIJibZJMzSOyiGmu25bJOwiSVl0x2hFJcQW2FFUURUqYyxe9X1g== + dependencies: + "@xan105/error" "^1.6.2" + "@xmldom/xmldom@^0.8.8": version "0.8.10" resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz" @@ -7081,6 +7101,15 @@ postgres-range@^1.1.1: resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== +powertoast@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/powertoast/-/powertoast-3.0.0.tgz#38cbcfde8cb15867ef14d89d0c890c76a445f828" + integrity sha512-nlGnBkMchJS6P4uQgjROpzHs72WqgB6cYP7hDFACXOZUSu2lXgDqJ5fKt2B/53jO+UynVlbhAQHHQvSOLUAUmQ== + dependencies: + "@xan105/error" "^1.7.0" + "@xan105/fs" "^2.2.1" + "@xan105/is" "^2.9.3" + prebuild-install@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056"