mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-21 01:53:57 +00:00
Merge branch 'feature/rpc' of https://github.com/hydralauncher/hydra into feature/rpc
This commit is contained in:
@@ -236,24 +236,28 @@ export class AchievementWatcherManager {
|
||||
};
|
||||
|
||||
public static preSearchAchievements = async () => {
|
||||
const newAchievementsCount =
|
||||
process.platform === "win32"
|
||||
? await this.preSearchAchievementsWindows()
|
||||
: await this.preSearchAchievementsWithWine();
|
||||
try {
|
||||
const newAchievementsCount =
|
||||
process.platform === "win32"
|
||||
? await this.preSearchAchievementsWindows()
|
||||
: await this.preSearchAchievementsWithWine();
|
||||
|
||||
const totalNewGamesWithAchievements = newAchievementsCount.filter(
|
||||
(achievements) => achievements
|
||||
).length;
|
||||
const totalNewAchievements = newAchievementsCount.reduce(
|
||||
(acc, val) => acc + val,
|
||||
0
|
||||
);
|
||||
|
||||
if (totalNewAchievements > 0) {
|
||||
publishCombinedNewAchievementNotification(
|
||||
totalNewAchievements,
|
||||
totalNewGamesWithAchievements
|
||||
const totalNewGamesWithAchievements = newAchievementsCount.filter(
|
||||
(achievements) => achievements
|
||||
).length;
|
||||
const totalNewAchievements = newAchievementsCount.reduce(
|
||||
(acc, val) => acc + val,
|
||||
0
|
||||
);
|
||||
|
||||
if (totalNewAchievements > 0) {
|
||||
publishCombinedNewAchievementNotification(
|
||||
totalNewAchievements,
|
||||
totalNewGamesWithAchievements
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
achievementsLogger.error("Error on preSearchAchievements", err);
|
||||
}
|
||||
|
||||
this.hasFinishedMergingWithRemote = true;
|
||||
|
||||
@@ -6,20 +6,15 @@ import { HydraApi } from "../hydra-api";
|
||||
import type { AchievementData, GameShop } from "@types";
|
||||
import { UserNotLoggedInError } from "@shared";
|
||||
import { logger } from "../logger";
|
||||
import { GameAchievement } from "@main/entity";
|
||||
|
||||
export const getGameAchievementData = async (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
useCachedData: boolean
|
||||
cachedAchievements: GameAchievement | null
|
||||
) => {
|
||||
if (useCachedData) {
|
||||
const cachedAchievements = await gameAchievementRepository.findOne({
|
||||
where: { objectId, shop },
|
||||
});
|
||||
|
||||
if (cachedAchievements && cachedAchievements.achievements) {
|
||||
return JSON.parse(cachedAchievements.achievements) as AchievementData[];
|
||||
}
|
||||
if (cachedAchievements && cachedAchievements.achievements) {
|
||||
return JSON.parse(cachedAchievements.achievements) as AchievementData[];
|
||||
}
|
||||
|
||||
const userPreferences = await userPreferencesRepository.findOne({
|
||||
|
||||
@@ -9,144 +9,134 @@ export const parseAchievementFile = (
|
||||
): UnlockedAchievement[] => {
|
||||
if (!existsSync(filePath)) return [];
|
||||
|
||||
if (type == Cracker.codex) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processDefault(parsed);
|
||||
try {
|
||||
if (type == Cracker.codex) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processDefault(parsed);
|
||||
}
|
||||
|
||||
if (type == Cracker.rune) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processDefault(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.onlineFix) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processOnlineFix(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.goldberg) {
|
||||
const parsed = jsonParse(filePath);
|
||||
return processGoldberg(parsed);
|
||||
}
|
||||
|
||||
if (type == Cracker.userstats) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processUserStats(parsed);
|
||||
}
|
||||
|
||||
if (type == Cracker.rld) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processRld(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.skidrow) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processSkidrow(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker._3dm) {
|
||||
const parsed = iniParse(filePath);
|
||||
return process3DM(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.flt) {
|
||||
const achievements = readdirSync(filePath);
|
||||
|
||||
return achievements.map((achievement) => {
|
||||
return {
|
||||
name: achievement,
|
||||
unlockTime: Date.now(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (type === Cracker.creamAPI) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processCreamAPI(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.empress) {
|
||||
const parsed = jsonParse(filePath);
|
||||
return processGoldberg(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.razor1911) {
|
||||
return processRazor1911(filePath);
|
||||
}
|
||||
|
||||
achievementsLogger.log(
|
||||
`Unprocessed ${type} achievements found on ${filePath}`
|
||||
);
|
||||
return [];
|
||||
} catch (err) {
|
||||
achievementsLogger.error(`Error parsing ${type} - ${filePath}`, err);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (type == Cracker.rune) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processDefault(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.onlineFix) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processOnlineFix(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.goldberg) {
|
||||
const parsed = jsonParse(filePath);
|
||||
return processGoldberg(parsed);
|
||||
}
|
||||
|
||||
if (type == Cracker.userstats) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processUserStats(parsed);
|
||||
}
|
||||
|
||||
if (type == Cracker.rld) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processRld(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.skidrow) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processSkidrow(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker._3dm) {
|
||||
const parsed = iniParse(filePath);
|
||||
return process3DM(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.flt) {
|
||||
const achievements = readdirSync(filePath);
|
||||
|
||||
return achievements.map((achievement) => {
|
||||
return {
|
||||
name: achievement,
|
||||
unlockTime: Date.now(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (type === Cracker.creamAPI) {
|
||||
const parsed = iniParse(filePath);
|
||||
return processCreamAPI(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.empress) {
|
||||
const parsed = jsonParse(filePath);
|
||||
return processGoldberg(parsed);
|
||||
}
|
||||
|
||||
if (type === Cracker.razor1911) {
|
||||
return processRazor1911(filePath);
|
||||
}
|
||||
|
||||
achievementsLogger.log(
|
||||
`Unprocessed ${type} achievements found on ${filePath}`
|
||||
);
|
||||
return [];
|
||||
};
|
||||
|
||||
const iniParse = (filePath: string) => {
|
||||
try {
|
||||
const fileContent = readFileSync(filePath, "utf-8");
|
||||
const fileContent = readFileSync(filePath, "utf-8");
|
||||
|
||||
const lines =
|
||||
fileContent.charCodeAt(0) === 0xfeff
|
||||
? fileContent.slice(1).split(/[\r\n]+/)
|
||||
: fileContent.split(/[\r\n]+/);
|
||||
const lines =
|
||||
fileContent.charCodeAt(0) === 0xfeff
|
||||
? fileContent.slice(1).split(/[\r\n]+/)
|
||||
: fileContent.split(/[\r\n]+/);
|
||||
|
||||
let objectName = "";
|
||||
const object: Record<string, Record<string, string | number>> = {};
|
||||
let objectName = "";
|
||||
const object: Record<string, Record<string, string | number>> = {};
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("###") || !line.length) continue;
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("###") || !line.length) continue;
|
||||
|
||||
if (line.startsWith("[") && line.endsWith("]")) {
|
||||
objectName = line.slice(1, -1);
|
||||
object[objectName] = {};
|
||||
} else {
|
||||
const [name, ...value] = line.split("=");
|
||||
object[objectName][name.trim()] = value.join("=").trim();
|
||||
}
|
||||
if (line.startsWith("[") && line.endsWith("]")) {
|
||||
objectName = line.slice(1, -1);
|
||||
object[objectName] = {};
|
||||
} else {
|
||||
const [name, ...value] = line.split("=");
|
||||
object[objectName][name.trim()] = value.join("=").trim();
|
||||
}
|
||||
|
||||
return object;
|
||||
} catch (err) {
|
||||
achievementsLogger.error(`Error parsing ${filePath}`, err);
|
||||
return {};
|
||||
}
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
const jsonParse = (filePath: string) => {
|
||||
try {
|
||||
return JSON.parse(readFileSync(filePath, "utf-8"));
|
||||
} catch (err) {
|
||||
achievementsLogger.error(`Error parsing ${filePath}`, err);
|
||||
return {};
|
||||
}
|
||||
return JSON.parse(readFileSync(filePath, "utf-8"));
|
||||
};
|
||||
|
||||
const processRazor1911 = (filePath: string): UnlockedAchievement[] => {
|
||||
try {
|
||||
const fileContent = readFileSync(filePath, "utf-8");
|
||||
const fileContent = readFileSync(filePath, "utf-8");
|
||||
|
||||
const lines =
|
||||
fileContent.charCodeAt(0) === 0xfeff
|
||||
? fileContent.slice(1).split(/[\r\n]+/)
|
||||
: fileContent.split(/[\r\n]+/);
|
||||
const lines =
|
||||
fileContent.charCodeAt(0) === 0xfeff
|
||||
? fileContent.slice(1).split(/[\r\n]+/)
|
||||
: fileContent.split(/[\r\n]+/);
|
||||
|
||||
const achievements: UnlockedAchievement[] = [];
|
||||
for (const line of lines) {
|
||||
if (!line.length) continue;
|
||||
const achievements: UnlockedAchievement[] = [];
|
||||
for (const line of lines) {
|
||||
if (!line.length) continue;
|
||||
|
||||
const [name, unlocked, unlockTime] = line.split(" ");
|
||||
if (unlocked === "1") {
|
||||
achievements.push({
|
||||
name,
|
||||
unlockTime: Number(unlockTime) * 1000,
|
||||
});
|
||||
}
|
||||
const [name, unlocked, unlockTime] = line.split(" ");
|
||||
if (unlocked === "1") {
|
||||
achievements.push({
|
||||
name,
|
||||
unlockTime: Number(unlockTime) * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
return achievements;
|
||||
} catch (err) {
|
||||
achievementsLogger.error(`Error processing ${filePath}`, err);
|
||||
return [];
|
||||
}
|
||||
|
||||
return achievements;
|
||||
};
|
||||
|
||||
const processOnlineFix = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
export * from "./logger";
|
||||
export * from "./steam";
|
||||
export * from "./steam-250";
|
||||
export * from "./steam-grid";
|
||||
export * from "./window-manager";
|
||||
export * from "./download";
|
||||
export * from "./process-watcher";
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import type { GameShop } from "@types";
|
||||
import axios from "axios";
|
||||
|
||||
export interface SteamGridResponse {
|
||||
success: boolean;
|
||||
data: {
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SteamGridGameResponse {
|
||||
data: {
|
||||
platforms: {
|
||||
steam: {
|
||||
metadata: {
|
||||
clienticon: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const getSteamGridData = async (
|
||||
objectId: string,
|
||||
path: string,
|
||||
shop: GameShop,
|
||||
params: Record<string, string> = {}
|
||||
): Promise<SteamGridResponse> => {
|
||||
const searchParams = new URLSearchParams(params);
|
||||
|
||||
if (!import.meta.env.MAIN_VITE_STEAMGRIDDB_API_KEY) {
|
||||
throw new Error("MAIN_VITE_STEAMGRIDDB_API_KEY is not set");
|
||||
}
|
||||
|
||||
const response = await axios.get(
|
||||
`https://www.steamgriddb.com/api/v2/${path}/${shop}/${objectId}?${searchParams.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${import.meta.env.MAIN_VITE_STEAMGRIDDB_API_KEY}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getSteamGridGameById = async (
|
||||
id: number
|
||||
): Promise<SteamGridGameResponse> => {
|
||||
const response = await axios.get(
|
||||
`https://www.steamgriddb.com/api/public/game/${id}`,
|
||||
{
|
||||
headers: {
|
||||
Referer: "https://www.steamgriddb.com/",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getSteamGameClientIcon = async (objectId: string) => {
|
||||
const {
|
||||
data: { id: steamGridGameId },
|
||||
} = await getSteamGridData(objectId, "games", "steam");
|
||||
|
||||
const steamGridGame = await getSteamGridGameById(steamGridGameId);
|
||||
return steamGridGame.data.platforms.steam.metadata.clienticon;
|
||||
};
|
||||
Reference in New Issue
Block a user