mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-24 11:21:02 +00:00
feat: removing crypto from level
This commit is contained in:
@@ -141,7 +141,7 @@ const processAchievementFileDiff = async (
|
||||
export class AchievementWatcherManager {
|
||||
private static hasFinishedMergingWithRemote = false;
|
||||
|
||||
public static watchAchievements = () => {
|
||||
public static watchAchievements() {
|
||||
if (!this.hasFinishedMergingWithRemote) return;
|
||||
|
||||
if (process.platform === "win32") {
|
||||
@@ -149,12 +149,12 @@ export class AchievementWatcherManager {
|
||||
}
|
||||
|
||||
return watchAchievementsWithWine();
|
||||
};
|
||||
}
|
||||
|
||||
private static preProcessGameAchievementFiles = (
|
||||
private static preProcessGameAchievementFiles(
|
||||
game: Game,
|
||||
gameAchievementFiles: AchievementFile[]
|
||||
) => {
|
||||
) {
|
||||
const unlockedAchievements: UnlockedAchievement[] = [];
|
||||
for (const achievementFile of gameAchievementFiles) {
|
||||
const parsedAchievements = parseAchievementFile(
|
||||
@@ -182,7 +182,7 @@ export class AchievementWatcherManager {
|
||||
}
|
||||
|
||||
return mergeAchievements(game, unlockedAchievements, false);
|
||||
};
|
||||
}
|
||||
|
||||
private static preSearchAchievementsWindows = async () => {
|
||||
const games = await gamesSublevel
|
||||
@@ -230,7 +230,7 @@ export class AchievementWatcherManager {
|
||||
);
|
||||
};
|
||||
|
||||
public static preSearchAchievements = async () => {
|
||||
public static async preSearchAchievements() {
|
||||
try {
|
||||
const newAchievementsCount =
|
||||
process.platform === "win32"
|
||||
@@ -256,5 +256,5 @@ export class AchievementWatcherManager {
|
||||
}
|
||||
|
||||
this.hasFinishedMergingWithRemote = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export const getGameAchievementData = async (
|
||||
throw err;
|
||||
}
|
||||
|
||||
logger.error("Failed to get game achievements", err);
|
||||
logger.error("Failed to get game achievements for", objectId, err);
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ export const mergeAchievements = async (
|
||||
const unlockedAchievements = localGameAchievement?.unlockedAchievements ?? [];
|
||||
|
||||
const newAchievementsMap = new Map(
|
||||
achievements.reverse().map((achievement) => {
|
||||
achievements.toReversed().map((achievement) => {
|
||||
return [achievement.name.toUpperCase(), achievement];
|
||||
})
|
||||
);
|
||||
@@ -87,7 +87,7 @@ export const mergeAchievements = async (
|
||||
userPreferences?.achievementNotificationsEnabled
|
||||
) {
|
||||
const achievementsInfo = newAchievements
|
||||
.sort((a, b) => {
|
||||
.toSorted((a, b) => {
|
||||
return a.unlockTime - b.unlockTime;
|
||||
})
|
||||
.map((achievement) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Downloader } from "@shared";
|
||||
import { Downloader, DownloadError } from "@shared";
|
||||
import { WindowManager } from "../window-manager";
|
||||
import { publishDownloadCompleteNotification } from "../notifications";
|
||||
import type { Download, DownloadProgress, UserPreferences } from "@types";
|
||||
import { GofileApi, QiwiApi, DatanodesApi } from "../hosters";
|
||||
import { GofileApi, QiwiApi, DatanodesApi, MediafireApi } from "../hosters";
|
||||
import { PythonRPC } from "../python-rpc";
|
||||
import {
|
||||
LibtorrentPayload,
|
||||
@@ -15,6 +15,7 @@ import path from "path";
|
||||
import { logger } from "../logger";
|
||||
import { db, downloadsSublevel, gamesSublevel, levelKeys } from "@main/level";
|
||||
import { sortBy } from "lodash-es";
|
||||
import { TorBoxClient } from "./torbox";
|
||||
|
||||
export class DownloadManager {
|
||||
private static downloadingGameId: string | null = null;
|
||||
@@ -25,17 +26,20 @@ export class DownloadManager {
|
||||
) {
|
||||
PythonRPC.spawn(
|
||||
download?.status === "active"
|
||||
? await this.getDownloadPayload(download).catch(() => undefined)
|
||||
? await this.getDownloadPayload(download).catch((err) => {
|
||||
logger.error("Error getting download payload", err);
|
||||
return undefined;
|
||||
})
|
||||
: undefined,
|
||||
downloadsToSeed?.map((download) => ({
|
||||
game_id: `${download.shop}-${download.objectId}`,
|
||||
game_id: levelKeys.game(download.shop, download.objectId),
|
||||
url: download.uri,
|
||||
save_path: download.downloadPath,
|
||||
}))
|
||||
);
|
||||
|
||||
if (download) {
|
||||
this.downloadingGameId = `${download.shop}-${download.objectId}`;
|
||||
this.downloadingGameId = levelKeys.game(download.shop, download.objectId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +110,7 @@ export class DownloadManager {
|
||||
|
||||
if (!download || !game) return;
|
||||
|
||||
const userPreferences = await db.get<string, UserPreferences>(
|
||||
const userPreferences = await db.get<string, UserPreferences | null>(
|
||||
levelKeys.userPreferences,
|
||||
{
|
||||
valueEncoding: "json",
|
||||
@@ -230,7 +234,9 @@ export class DownloadManager {
|
||||
});
|
||||
|
||||
WindowManager.mainWindow?.setProgressBar(-1);
|
||||
|
||||
if (downloadKey === this.downloadingGameId) {
|
||||
WindowManager.mainWindow?.webContents.send("on-download-progress", null);
|
||||
this.downloadingGameId = null;
|
||||
}
|
||||
}
|
||||
@@ -260,6 +266,8 @@ export class DownloadManager {
|
||||
const token = await GofileApi.authorize();
|
||||
const downloadLink = await GofileApi.getDownloadLink(id!);
|
||||
|
||||
await GofileApi.checkDownloadUrl(downloadLink);
|
||||
|
||||
return {
|
||||
action: "start",
|
||||
game_id: downloadId,
|
||||
@@ -270,10 +278,11 @@ export class DownloadManager {
|
||||
}
|
||||
case Downloader.PixelDrain: {
|
||||
const id = download.uri.split("/").pop();
|
||||
|
||||
return {
|
||||
action: "start",
|
||||
game_id: downloadId,
|
||||
url: `https://pixeldrain.com/api/file/${id}?download`,
|
||||
url: `https://cdn.pd5-gamedriveorg.workers.dev/api/file/${id}`,
|
||||
save_path: download.downloadPath,
|
||||
};
|
||||
}
|
||||
@@ -295,6 +304,16 @@ export class DownloadManager {
|
||||
save_path: download.downloadPath,
|
||||
};
|
||||
}
|
||||
case Downloader.Mediafire: {
|
||||
const downloadUrl = await MediafireApi.getDownloadUrl(download.uri);
|
||||
|
||||
return {
|
||||
action: "start",
|
||||
game_id: downloadId,
|
||||
url: downloadUrl,
|
||||
save_path: download.downloadPath,
|
||||
};
|
||||
}
|
||||
case Downloader.Torrent:
|
||||
return {
|
||||
action: "start",
|
||||
@@ -305,10 +324,7 @@ export class DownloadManager {
|
||||
case Downloader.RealDebrid: {
|
||||
const downloadUrl = await RealDebridClient.getDownloadUrl(download.uri);
|
||||
|
||||
if (!downloadUrl)
|
||||
throw new Error(
|
||||
"This download is not available on Real-Debrid and polling download status from Real-Debrid is not yet available."
|
||||
);
|
||||
if (!downloadUrl) throw new Error(DownloadError.NotCachedInRealDebrid);
|
||||
|
||||
return {
|
||||
action: "start",
|
||||
@@ -317,6 +333,18 @@ export class DownloadManager {
|
||||
save_path: download.downloadPath,
|
||||
};
|
||||
}
|
||||
case Downloader.TorBox: {
|
||||
const { name, url } = await TorBoxClient.getDownloadInfo(download.uri);
|
||||
|
||||
if (!url) return;
|
||||
return {
|
||||
action: "start",
|
||||
game_id: downloadId,
|
||||
url,
|
||||
save_path: download.downloadPath,
|
||||
out: name,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,24 +6,23 @@ import type {
|
||||
TorBoxAddTorrentRequest,
|
||||
TorBoxRequestLinkRequest,
|
||||
} from "@types";
|
||||
import { logger } from "../logger";
|
||||
|
||||
export class TorBoxClient {
|
||||
private static instance: AxiosInstance;
|
||||
private static readonly baseURL = "https://api.torbox.app/v1/api";
|
||||
public static apiToken: string;
|
||||
private static apiToken: string;
|
||||
|
||||
static authorize(apiToken: string) {
|
||||
this.apiToken = apiToken;
|
||||
this.instance = axios.create({
|
||||
baseURL: this.baseURL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiToken}`,
|
||||
},
|
||||
});
|
||||
this.apiToken = apiToken;
|
||||
}
|
||||
|
||||
static async addMagnet(magnet: string) {
|
||||
private static async addMagnet(magnet: string) {
|
||||
const form = new FormData();
|
||||
form.append("magnet", magnet);
|
||||
|
||||
@@ -32,6 +31,10 @@ export class TorBoxClient {
|
||||
form
|
||||
);
|
||||
|
||||
if (!response.data.success) {
|
||||
throw new Error(response.data.detail);
|
||||
}
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
@@ -55,22 +58,16 @@ export class TorBoxClient {
|
||||
}
|
||||
|
||||
static async requestLink(id: number) {
|
||||
const searchParams = new URLSearchParams({});
|
||||
|
||||
searchParams.set("token", this.apiToken);
|
||||
searchParams.set("torrent_id", id.toString());
|
||||
searchParams.set("zip_link", "true");
|
||||
const searchParams = new URLSearchParams({
|
||||
token: this.apiToken,
|
||||
torrent_id: id.toString(),
|
||||
zip_link: "true",
|
||||
});
|
||||
|
||||
const response = await this.instance.get<TorBoxRequestLinkRequest>(
|
||||
"/torrents/requestdl?" + searchParams.toString()
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
logger.error(response.data.error);
|
||||
logger.error(response.data.detail);
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
@@ -81,7 +78,7 @@ export class TorBoxClient {
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
static async getTorrentId(magnetUri: string) {
|
||||
private static async getTorrentIdAndName(magnetUri: string) {
|
||||
const userTorrents = await this.getAllTorrentsFromUser();
|
||||
|
||||
const { infoHash } = await parseTorrent(magnetUri);
|
||||
@@ -89,9 +86,18 @@ export class TorBoxClient {
|
||||
(userTorrent) => userTorrent.hash === infoHash
|
||||
);
|
||||
|
||||
if (userTorrent) return userTorrent.id;
|
||||
if (userTorrent) return { id: userTorrent.id, name: userTorrent.name };
|
||||
|
||||
const torrent = await this.addMagnet(magnetUri);
|
||||
return torrent.torrent_id;
|
||||
return { id: torrent.torrent_id, name: torrent.name };
|
||||
}
|
||||
|
||||
static async getDownloadInfo(uri: string) {
|
||||
const torrentData = await this.getTorrentIdAndName(uri);
|
||||
const url = await this.requestLink(torrentData.id);
|
||||
|
||||
const name = torrentData.name ? `${torrentData.name}.zip` : undefined;
|
||||
|
||||
return { url, name };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +60,12 @@ export class GofileApi {
|
||||
|
||||
throw new Error("Failed to get download link");
|
||||
}
|
||||
|
||||
public static async checkDownloadUrl(url: string) {
|
||||
return axios.head(url, {
|
||||
headers: {
|
||||
Cookie: `accountToken=${this.token}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./gofile";
|
||||
export * from "./qiwi";
|
||||
export * from "./datanodes";
|
||||
export * from "./mediafire";
|
||||
|
||||
54
src/main/services/hosters/mediafire.ts
Normal file
54
src/main/services/hosters/mediafire.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import fetch from "node-fetch";
|
||||
|
||||
export class MediafireApi {
|
||||
private static readonly validMediafireIdentifierDL = /^[a-zA-Z0-9]+$/m;
|
||||
private static readonly validMediafirePreDL =
|
||||
/(?<=['"])(https?:)?(\/\/)?(www\.)?mediafire\.com\/(file|view|download)\/[^'"?]+\?dkey=[^'"]+(?=['"])/;
|
||||
private static readonly validDynamicDL =
|
||||
/(?<=['"])https?:\/\/download\d+\.mediafire\.com\/[^'"]+(?=['"])/;
|
||||
private static readonly checkHTTP = /^https?:\/\//m;
|
||||
|
||||
public static async getDownloadUrl(mediafireUrl: string): Promise<string> {
|
||||
try {
|
||||
const processedUrl = this.processUrl(mediafireUrl);
|
||||
const response = await fetch(processedUrl);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to fetch Mediafire page");
|
||||
|
||||
const html = await response.text();
|
||||
return this.extractDirectUrl(html);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to get download URL`);
|
||||
}
|
||||
}
|
||||
|
||||
private static processUrl(url: string): string {
|
||||
let processed = url.replace("http://", "https://");
|
||||
|
||||
if (this.validMediafireIdentifierDL.test(processed)) {
|
||||
processed = `https://mediafire.com/?${processed}`;
|
||||
}
|
||||
|
||||
if (!this.checkHTTP.test(processed)) {
|
||||
processed = processed.startsWith("//")
|
||||
? `https:${processed}`
|
||||
: `https://${processed}`;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
private static extractDirectUrl(html: string): string {
|
||||
const preMatch = this.validMediafirePreDL.exec(html);
|
||||
if (preMatch?.[0]) {
|
||||
return preMatch[0];
|
||||
}
|
||||
|
||||
const dlMatch = this.validDynamicDL.exec(html);
|
||||
if (dlMatch?.[0]) {
|
||||
return dlMatch[0];
|
||||
}
|
||||
|
||||
throw new Error("No valid download links found");
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { WindowManager } from "./window-manager";
|
||||
import url from "url";
|
||||
import { uploadGamesBatch } from "./library-sync";
|
||||
import { clearGamesRemoteIds } from "./library-sync/clear-games-remote-id";
|
||||
import { logger } from "./logger";
|
||||
import { networkLogger as logger } from "./logger";
|
||||
import { UserNotLoggedInError, SubscriptionRequiredError } from "@shared";
|
||||
import { omit } from "lodash-es";
|
||||
import { appVersion } from "@main/constants";
|
||||
@@ -154,7 +154,8 @@ export class HydraApi {
|
||||
(error) => {
|
||||
logger.error(" ---- RESPONSE ERROR -----");
|
||||
const { config } = error;
|
||||
const data = JSON.parse(config.data);
|
||||
|
||||
const data = JSON.parse(config.data ?? null);
|
||||
|
||||
logger.error(
|
||||
config.method,
|
||||
@@ -175,14 +176,22 @@ export class HydraApi {
|
||||
error.response.status,
|
||||
error.response.data
|
||||
);
|
||||
} else if (error.request) {
|
||||
const errorData = error.toJSON();
|
||||
logger.error("Request error:", errorData.message);
|
||||
} else {
|
||||
logger.error("Error", error.message);
|
||||
|
||||
return Promise.reject(error as Error);
|
||||
}
|
||||
logger.error(" ----- END RESPONSE ERROR -------");
|
||||
return Promise.reject(error);
|
||||
|
||||
if (error.request) {
|
||||
const errorData = error.toJSON();
|
||||
logger.error("Request error:", errorData.code, errorData.message);
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
`Request failed with ${errorData.code} ${errorData.message}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
logger.error("Error", error.message);
|
||||
return Promise.reject(error as Error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from "./crypto";
|
||||
export * from "./logger";
|
||||
export * from "./steam";
|
||||
export * from "./steam-250";
|
||||
|
||||
@@ -35,22 +35,20 @@ export const mergeWithRemoteGames = async () => {
|
||||
name: "getById",
|
||||
});
|
||||
|
||||
if (steamGame) {
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? steamUrlBuilder.icon(game.objectId, steamGame.clientIcon)
|
||||
: null;
|
||||
const iconUrl = steamGame?.clientIcon
|
||||
? steamUrlBuilder.icon(game.objectId, steamGame.clientIcon)
|
||||
: null;
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@ export const uploadGamesBatch = async () => {
|
||||
);
|
||||
});
|
||||
|
||||
const gamesChunks = chunk(games, 200);
|
||||
const gamesChunks = chunk(games, 50);
|
||||
|
||||
for (const chunk of gamesChunks) {
|
||||
await HydraApi.post(
|
||||
|
||||
@@ -6,8 +6,12 @@ log.transports.file.resolvePathFn = (
|
||||
_: log.PathVariables,
|
||||
message?: log.LogMessage | undefined
|
||||
) => {
|
||||
if (message?.scope === "python-instance") {
|
||||
return path.join(logsPath, "pythoninstance.txt");
|
||||
if (message?.scope === "python-rpc") {
|
||||
return path.join(logsPath, "pythonrpc.txt");
|
||||
}
|
||||
|
||||
if (message?.scope === "network") {
|
||||
return path.join(logsPath, "network.txt");
|
||||
}
|
||||
|
||||
if (message?.scope == "achievements") {
|
||||
@@ -34,3 +38,4 @@ log.initialize();
|
||||
export const pythonRpcLogger = log.scope("python-rpc");
|
||||
export const logger = log.scope("main");
|
||||
export const achievementsLogger = log.scope("achievements");
|
||||
export const networkLogger = log.scope("network");
|
||||
|
||||
@@ -2,6 +2,7 @@ import { sleep } from "@main/helpers";
|
||||
import { DownloadManager } from "./download";
|
||||
import { watchProcesses } from "./process-watcher";
|
||||
import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager";
|
||||
import { UpdateManager } from "./update-manager";
|
||||
|
||||
export const startMainLoop = async () => {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
@@ -11,6 +12,7 @@ export const startMainLoop = async () => {
|
||||
DownloadManager.watchDownloads(),
|
||||
AchievementWatcherManager.watchAchievements(),
|
||||
DownloadManager.getSeedStatus(),
|
||||
UpdateManager.checkForUpdatePeriodically(),
|
||||
]);
|
||||
|
||||
await sleep(1500);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { achievementSoundPath } from "@main/constants";
|
||||
import icon from "@resources/icon.png?asset";
|
||||
import { NotificationOptions, toXmlString } from "./xml";
|
||||
import { logger } from "../logger";
|
||||
import { WindowManager } from "../window-manager";
|
||||
import type { Game, UserPreferences } from "@types";
|
||||
import { db, levelKeys } from "@main/level";
|
||||
|
||||
@@ -96,7 +97,9 @@ export const publishCombinedNewAchievementNotification = async (
|
||||
toastXml: toXmlString(options),
|
||||
}).show();
|
||||
|
||||
if (process.platform !== "linux") {
|
||||
if (WindowManager.mainWindow) {
|
||||
WindowManager.mainWindow.webContents.send("on-achievement-unlocked");
|
||||
} else if (process.platform !== "linux") {
|
||||
sound.play(achievementSoundPath);
|
||||
}
|
||||
};
|
||||
@@ -143,7 +146,9 @@ export const publishNewAchievementNotification = async (info: {
|
||||
toastXml: toXmlString(options),
|
||||
}).show();
|
||||
|
||||
if (process.platform !== "linux") {
|
||||
if (WindowManager.mainWindow) {
|
||||
WindowManager.mainWindow.webContents.send("on-achievement-unlocked");
|
||||
} else if (process.platform !== "linux") {
|
||||
sound.play(achievementSoundPath);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,11 +21,18 @@ export const getSteamAppDetails = async (
|
||||
});
|
||||
|
||||
return axios
|
||||
.get(
|
||||
.get<SteamAppDetailsResponse>(
|
||||
`http://store.steampowered.com/api/appdetails?${searchParams.toString()}`
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.data[objectId].success) return response.data[objectId].data;
|
||||
if (response.data[objectId].success) {
|
||||
const data = response.data[objectId].data;
|
||||
return {
|
||||
...data,
|
||||
objectId,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
60
src/main/services/update-manager.ts
Normal file
60
src/main/services/update-manager.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import updater, { UpdateInfo } from "electron-updater";
|
||||
import { logger, WindowManager } from "@main/services";
|
||||
import { AppUpdaterEvent } from "@types";
|
||||
import { app } from "electron";
|
||||
import { publishNotificationUpdateReadyToInstall } from "@main/services/notifications";
|
||||
|
||||
const isAutoInstallAvailable =
|
||||
process.platform !== "darwin" && process.env.PORTABLE_EXECUTABLE_FILE == null;
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
const sendEventsForDebug = false;
|
||||
|
||||
export class UpdateManager {
|
||||
private static hasNotified = false;
|
||||
private static newVersion = "";
|
||||
private static checkTick = 0;
|
||||
|
||||
private static mockValuesForDebug() {
|
||||
this.sendEvent({ type: "update-available", info: { version: "1.3.0" } });
|
||||
this.sendEvent({ type: "update-downloaded" });
|
||||
}
|
||||
|
||||
private static sendEvent(event: AppUpdaterEvent) {
|
||||
WindowManager.mainWindow?.webContents.send("autoUpdaterEvent", event);
|
||||
}
|
||||
|
||||
public static checkForUpdates() {
|
||||
autoUpdater
|
||||
.once("update-available", (info: UpdateInfo) => {
|
||||
this.sendEvent({ type: "update-available", info });
|
||||
this.newVersion = info.version;
|
||||
})
|
||||
.once("update-downloaded", () => {
|
||||
this.sendEvent({ type: "update-downloaded" });
|
||||
|
||||
if (!this.hasNotified) {
|
||||
this.hasNotified = true;
|
||||
publishNotificationUpdateReadyToInstall(this.newVersion);
|
||||
}
|
||||
});
|
||||
|
||||
if (app.isPackaged) {
|
||||
autoUpdater.autoDownload = isAutoInstallAvailable;
|
||||
autoUpdater.checkForUpdates().then((result) => {
|
||||
logger.log(`Check for updates result: ${result}`);
|
||||
});
|
||||
} else if (sendEventsForDebug) {
|
||||
this.mockValuesForDebug();
|
||||
}
|
||||
|
||||
return isAutoInstallAvailable;
|
||||
}
|
||||
|
||||
public static checkForUpdatePeriodically() {
|
||||
if (this.checkTick % 2000 == 0) {
|
||||
this.checkForUpdates();
|
||||
}
|
||||
this.checkTick++;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ export const getUserData = async () => {
|
||||
})
|
||||
.catch(async (err) => {
|
||||
if (err instanceof UserNotLoggedInError) {
|
||||
logger.info("User is not logged in", err);
|
||||
return null;
|
||||
}
|
||||
logger.error("Failed to get logged user");
|
||||
@@ -59,6 +58,7 @@ export const getUserData = async () => {
|
||||
expiresAt: loggedUser.subscription.expiresAt,
|
||||
}
|
||||
: null,
|
||||
featurebaseJwt: "",
|
||||
} as UserDetails;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { db, gamesSublevel, levelKeys } from "@main/level";
|
||||
import { slice, sortBy } from "lodash-es";
|
||||
import type { UserPreferences } from "@types";
|
||||
import { AuthPage } from "@shared";
|
||||
import { isStaging } from "@main/constants";
|
||||
|
||||
export class WindowManager {
|
||||
public static mainWindow: Electron.BrowserWindow | null = null;
|
||||
@@ -52,7 +53,7 @@ export class WindowManager {
|
||||
minHeight: 540,
|
||||
backgroundColor: "#1c1c1c",
|
||||
titleBarStyle: process.platform === "linux" ? "default" : "hidden",
|
||||
...(process.platform === "linux" ? { icon } : {}),
|
||||
icon,
|
||||
trafficLightPosition: { x: 16, y: 16 },
|
||||
titleBarOverlay: {
|
||||
symbolColor: "#DADBE1",
|
||||
@@ -129,7 +130,8 @@ export class WindowManager {
|
||||
this.mainWindow.removeMenu();
|
||||
|
||||
this.mainWindow.on("ready-to-show", () => {
|
||||
if (!app.isPackaged) WindowManager.mainWindow?.webContents.openDevTools();
|
||||
if (!app.isPackaged || isStaging)
|
||||
WindowManager.mainWindow?.webContents.openDevTools();
|
||||
WindowManager.mainWindow?.show();
|
||||
});
|
||||
|
||||
@@ -147,6 +149,11 @@ export class WindowManager {
|
||||
WindowManager.mainWindow?.setProgressBar(-1);
|
||||
WindowManager.mainWindow = null;
|
||||
});
|
||||
|
||||
this.mainWindow.webContents.setWindowOpenHandler((handler) => {
|
||||
shell.openExternal(handler.url);
|
||||
return { action: "deny" };
|
||||
});
|
||||
}
|
||||
|
||||
public static openAuthWindow(page: AuthPage, searchParams: URLSearchParams) {
|
||||
|
||||
Reference in New Issue
Block a user