mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-19 17:23:57 +00:00
feat: migrating games to level
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
import { gameRepository } from "@main/repository";
|
||||
import { parseAchievementFile } from "./parse-achievement-file";
|
||||
import { Game } from "@main/entity";
|
||||
import { mergeAchievements } from "./merge-achievements";
|
||||
import fs, { readdirSync } from "node:fs";
|
||||
import {
|
||||
@@ -9,10 +7,9 @@ import {
|
||||
findAllAchievementFiles,
|
||||
getAlternativeObjectIds,
|
||||
} from "./find-achivement-files";
|
||||
import type { AchievementFile, UnlockedAchievement } from "@types";
|
||||
import type { AchievementFile, Game, UnlockedAchievement } from "@types";
|
||||
import { achievementsLogger } from "../logger";
|
||||
import { Cracker } from "@shared";
|
||||
import { IsNull, Not } from "typeorm";
|
||||
import { publishCombinedNewAchievementNotification } from "../notifications";
|
||||
import { gamesSublevel } from "@main/level";
|
||||
|
||||
@@ -47,12 +44,12 @@ const watchAchievementsWindows = async () => {
|
||||
};
|
||||
|
||||
const watchAchievementsWithWine = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
winePrefixPath: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
const games = await gamesSublevel
|
||||
.values()
|
||||
.all()
|
||||
.then((games) =>
|
||||
games.filter((game) => !game.isDeleted && game.winePrefixPath)
|
||||
);
|
||||
|
||||
for (const game of games) {
|
||||
const gameAchievementFiles = findAchievementFiles(game);
|
||||
@@ -188,11 +185,10 @@ export class AchievementWatcherManager {
|
||||
};
|
||||
|
||||
private static preSearchAchievementsWindows = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
},
|
||||
});
|
||||
const games = await gamesSublevel
|
||||
.values()
|
||||
.all()
|
||||
.then((games) => games.filter((game) => !game.isDeleted));
|
||||
|
||||
const gameAchievementFilesMap = findAllAchievementFiles();
|
||||
|
||||
@@ -200,7 +196,7 @@ export class AchievementWatcherManager {
|
||||
games.map((game) => {
|
||||
const gameAchievementFiles: AchievementFile[] = [];
|
||||
|
||||
for (const objectId of getAlternativeObjectIds(game.objectID)) {
|
||||
for (const objectId of getAlternativeObjectIds(game.objectId)) {
|
||||
gameAchievementFiles.push(
|
||||
...(gameAchievementFilesMap.get(objectId) || [])
|
||||
);
|
||||
@@ -216,11 +212,10 @@ export class AchievementWatcherManager {
|
||||
};
|
||||
|
||||
private static preSearchAchievementsWithWine = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
},
|
||||
});
|
||||
const games = await gamesSublevel
|
||||
.values()
|
||||
.all()
|
||||
.then((games) => games.filter((game) => !game.isDeleted));
|
||||
|
||||
return Promise.all(
|
||||
games.map((game) => {
|
||||
|
||||
@@ -254,7 +254,7 @@ export const findAchievementFiles = (game: Game) => {
|
||||
|
||||
for (const cracker of crackers) {
|
||||
for (const { folderPath, fileLocation } of getPathFromCracker(cracker)) {
|
||||
for (const objectId of getAlternativeObjectIds(game.objectID)) {
|
||||
for (const objectId of getAlternativeObjectIds(game.objectId)) {
|
||||
const filePath = path.join(
|
||||
game.winePrefixPath ?? "",
|
||||
folderPath,
|
||||
|
||||
@@ -4,8 +4,7 @@ import {
|
||||
} from "./find-achivement-files";
|
||||
import { parseAchievementFile } from "./parse-achievement-file";
|
||||
import { mergeAchievements } from "./merge-achievements";
|
||||
import type { UnlockedAchievement } from "@types";
|
||||
import { Game } from "@main/entity";
|
||||
import type { Game, UnlockedAchievement } from "@types";
|
||||
|
||||
export const updateLocalUnlockedAchivements = async (game: Game) => {
|
||||
const gameAchievementFiles = findAchievementFiles(game);
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { Game } from "@main/entity";
|
||||
import { Downloader } from "@shared";
|
||||
import { WindowManager } from "../window-manager";
|
||||
import {
|
||||
downloadQueueRepository,
|
||||
gameRepository,
|
||||
userPreferencesRepository,
|
||||
} from "@main/repository";
|
||||
import { userPreferencesRepository } from "@main/repository";
|
||||
import { publishDownloadCompleteNotification } from "../notifications";
|
||||
import type { Download, DownloadProgress } from "@types";
|
||||
import { GofileApi, QiwiApi, DatanodesApi } from "../hosters";
|
||||
@@ -23,7 +18,7 @@ import { logger } from "../logger";
|
||||
import { downloadsSublevel, levelKeys } from "@main/level";
|
||||
|
||||
export class DownloadManager {
|
||||
private static downloadingGameId: number | null = null;
|
||||
private static downloadingGameId: string | null = null;
|
||||
|
||||
public static async startRPC(
|
||||
download?: Download,
|
||||
@@ -34,13 +29,15 @@ export class DownloadManager {
|
||||
? await this.getDownloadPayload(download).catch(() => undefined)
|
||||
: undefined,
|
||||
downloadsToSeed?.map((download) => ({
|
||||
game_id: game.id,
|
||||
url: game.uri!,
|
||||
save_path: game.downloadPath!,
|
||||
game_id: `${download.shop}-${download.objectId}`,
|
||||
url: download.uri!,
|
||||
save_path: download.downloadPath!,
|
||||
}))
|
||||
);
|
||||
|
||||
this.downloadingGameId = game?.id ?? null;
|
||||
if (download) {
|
||||
this.downloadingGameId = `${download.shop}-${download.objectId}`;
|
||||
}
|
||||
}
|
||||
|
||||
private static async getDownloadStatus() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export interface PauseDownloadPayload {
|
||||
game_id: number;
|
||||
game_id: string;
|
||||
}
|
||||
|
||||
export interface CancelDownloadPayload {
|
||||
game_id: number;
|
||||
game_id: string;
|
||||
}
|
||||
|
||||
export enum LibtorrentStatus {
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import { gameRepository } from "@main/repository";
|
||||
import { HydraApi } from "../hydra-api";
|
||||
import { steamGamesWorker } from "@main/workers";
|
||||
import { steamUrlBuilder } from "@shared";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
|
||||
export const mergeWithRemoteGames = async () => {
|
||||
return HydraApi.get("/profile/games")
|
||||
.then(async (response) => {
|
||||
for (const game of response) {
|
||||
const localGame = await gameRepository.findOne({
|
||||
where: {
|
||||
objectID: game.objectId,
|
||||
},
|
||||
});
|
||||
const localGame = await gamesSublevel.get(
|
||||
levelKeys.game(game.shop, game.objectId)
|
||||
);
|
||||
|
||||
if (localGame) {
|
||||
const updatedLastTimePlayed =
|
||||
@@ -26,17 +24,12 @@ export const mergeWithRemoteGames = async () => {
|
||||
? game.playTimeInMilliseconds
|
||||
: localGame.playTimeInMilliseconds;
|
||||
|
||||
gameRepository.update(
|
||||
{
|
||||
objectID: game.objectId,
|
||||
shop: "steam",
|
||||
},
|
||||
{
|
||||
remoteId: game.id,
|
||||
lastTimePlayed: updatedLastTimePlayed,
|
||||
playTimeInMilliseconds: updatedPlayTime,
|
||||
}
|
||||
);
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
...localGame,
|
||||
remoteId: game.id,
|
||||
lastTimePlayed: updatedLastTimePlayed,
|
||||
playTimeInMilliseconds: updatedPlayTime,
|
||||
});
|
||||
} else {
|
||||
const steamGame = await steamGamesWorker.run(Number(game.objectId), {
|
||||
name: "getById",
|
||||
@@ -47,14 +40,15 @@ export const mergeWithRemoteGames = async () => {
|
||||
? steamUrlBuilder.icon(game.objectId, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
gameRepository.insert({
|
||||
objectID: game.objectId,
|
||||
gamesSublevel.put(levelKeys.game(game.shop, game.objectId), {
|
||||
objectId: game.objectId,
|
||||
title: steamGame?.name,
|
||||
remoteId: game.id,
|
||||
shop: game.shop,
|
||||
iconUrl,
|
||||
lastTimePlayed: game.lastTimePlayed,
|
||||
playTimeInMilliseconds: game.playTimeInMilliseconds,
|
||||
isDeleted: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Notification, app } from "electron";
|
||||
import { t } from "i18next";
|
||||
import trayIcon from "@resources/tray-icon.png?asset";
|
||||
import { Game } from "@main/entity";
|
||||
import { userPreferencesRepository } from "@main/repository";
|
||||
import fs from "node:fs";
|
||||
import axios from "axios";
|
||||
@@ -11,6 +10,7 @@ import { achievementSoundPath } from "@main/constants";
|
||||
import icon from "@resources/icon.png?asset";
|
||||
import { NotificationOptions, toXmlString } from "./xml";
|
||||
import { logger } from "../logger";
|
||||
import type { Game } from "@types";
|
||||
|
||||
async function downloadImage(url: string | null) {
|
||||
if (!url) return undefined;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Readable } from "node:stream";
|
||||
import { app, dialog } from "electron";
|
||||
|
||||
interface GamePayload {
|
||||
game_id: number;
|
||||
game_id: string;
|
||||
url: string;
|
||||
save_path: string;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,11 @@ import i18next, { t } from "i18next";
|
||||
import path from "node:path";
|
||||
import icon from "@resources/icon.png?asset";
|
||||
import trayIcon from "@resources/tray-icon.png?asset";
|
||||
import { gameRepository, userPreferencesRepository } from "@main/repository";
|
||||
import { IsNull, Not } from "typeorm";
|
||||
import { userPreferencesRepository } from "@main/repository";
|
||||
import { HydraApi } from "./hydra-api";
|
||||
import UserAgent from "user-agents";
|
||||
import { gamesSublevel } from "@main/level";
|
||||
import { slice, sortBy } from "lodash-es";
|
||||
|
||||
export class WindowManager {
|
||||
public static mainWindow: Electron.BrowserWindow | null = null;
|
||||
@@ -207,17 +208,22 @@ export class WindowManager {
|
||||
}
|
||||
|
||||
const updateSystemTray = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
executablePath: Not(IsNull()),
|
||||
lastTimePlayed: Not(IsNull()),
|
||||
},
|
||||
take: 5,
|
||||
order: {
|
||||
lastTimePlayed: "DESC",
|
||||
},
|
||||
});
|
||||
const games = await gamesSublevel
|
||||
.values()
|
||||
.all()
|
||||
.then((games) =>
|
||||
slice(
|
||||
sortBy(
|
||||
games.filter(
|
||||
(game) =>
|
||||
!game.isDeleted && game.executablePath && game.lastTimePlayed
|
||||
),
|
||||
"lastTimePlayed",
|
||||
"DESC"
|
||||
),
|
||||
5
|
||||
)
|
||||
);
|
||||
|
||||
const recentlyPlayedGames: Array<MenuItemConstructorOptions | MenuItem> =
|
||||
games.map(({ title, executablePath }) => ({
|
||||
|
||||
Reference in New Issue
Block a user