mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: removing sentry
This commit is contained in:
parent
59b1f2d5a5
commit
dc7591ee28
77 changed files with 161 additions and 7545 deletions
|
|
@ -12,8 +12,8 @@ export const repackersOn1337x = [
|
|||
export const repackers = [
|
||||
...repackersOn1337x,
|
||||
"Xatab",
|
||||
"CPG",
|
||||
"TinyRepacks",
|
||||
"CPG",
|
||||
"GOG",
|
||||
"onlinefix",
|
||||
] as const;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ import {
|
|||
Game,
|
||||
GameShopCache,
|
||||
Repack,
|
||||
RepackerFriendlyName,
|
||||
UserPreferences,
|
||||
MigrationScript,
|
||||
SteamGame,
|
||||
} from "@main/entity";
|
||||
import type { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
|
||||
|
|
@ -16,15 +14,7 @@ export const createDataSource = (options: Partial<SqliteConnectionOptions>) =>
|
|||
new DataSource({
|
||||
type: "better-sqlite3",
|
||||
database: databasePath,
|
||||
entities: [
|
||||
Game,
|
||||
Repack,
|
||||
RepackerFriendlyName,
|
||||
UserPreferences,
|
||||
GameShopCache,
|
||||
MigrationScript,
|
||||
SteamGame,
|
||||
],
|
||||
entities: [Game, Repack, UserPreferences, GameShopCache, SteamGame],
|
||||
...options,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
export * from "./game.entity";
|
||||
export * from "./repack.entity";
|
||||
export * from "./repacker-friendly-name.entity";
|
||||
export * from "./user-preferences.entity";
|
||||
export * from "./game-shop-cache.entity";
|
||||
export * from "./migration-script.entity";
|
||||
export * from "./steam-game.entity";
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from "typeorm";
|
||||
|
||||
@Entity("migration_script")
|
||||
export class MigrationScript {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column("text", { unique: true })
|
||||
version: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from "typeorm";
|
||||
|
||||
@Entity("repacker_friendly_name")
|
||||
export class RepackerFriendlyName {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column("text", { unique: true })
|
||||
name: string;
|
||||
|
||||
@Column("text")
|
||||
friendlyName: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
|
@ -26,9 +26,6 @@ export class UserPreferences {
|
|||
@Column("boolean", { default: false })
|
||||
repackUpdatesNotificationsEnabled: boolean;
|
||||
|
||||
@Column("boolean", { default: true })
|
||||
telemetryEnabled: boolean;
|
||||
|
||||
@Column("boolean", { default: false })
|
||||
preferQuitInsteadOfHiding: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,4 @@ const getRecentlyAddedCatalogue = async (
|
|||
return results.slice(0, resultSize);
|
||||
};
|
||||
|
||||
registerEvent(getCatalogue, {
|
||||
name: "getCatalogue",
|
||||
memoize: true,
|
||||
});
|
||||
registerEvent("getCatalogue", getCatalogue);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,4 @@ const getGameShopDetails = async (
|
|||
throw new Error("Not implemented");
|
||||
};
|
||||
|
||||
registerEvent(getGameShopDetails, {
|
||||
name: "getGameShopDetails",
|
||||
memoize: true,
|
||||
});
|
||||
registerEvent("getGameShopDetails", getGameShopDetails);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,4 @@ const getGames = async (
|
|||
return { results, cursor: i };
|
||||
};
|
||||
|
||||
registerEvent(getGames, {
|
||||
name: "getGames",
|
||||
memoize: true,
|
||||
});
|
||||
registerEvent("getGames", getGames);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,4 @@ const getHowLongToBeat = async (
|
|||
});
|
||||
};
|
||||
|
||||
registerEvent(getHowLongToBeat, {
|
||||
name: "getHowLongToBeat",
|
||||
memoize: true,
|
||||
});
|
||||
registerEvent("getHowLongToBeat", getHowLongToBeat);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,4 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => {
|
|||
return state.games[state.index];
|
||||
};
|
||||
|
||||
registerEvent(getRandomGame, {
|
||||
name: "getRandomGame",
|
||||
});
|
||||
registerEvent("getRandomGame", getRandomGame);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,4 @@ const searchGameRepacks = (
|
|||
return searchRepacks(query);
|
||||
};
|
||||
|
||||
registerEvent(searchGameRepacks, {
|
||||
name: "searchGameRepacks",
|
||||
memoize: true,
|
||||
});
|
||||
registerEvent("searchGameRepacks", searchGameRepacks);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,4 @@ const searchGamesEvent = async (
|
|||
return searchGames({ query, take: 12 });
|
||||
};
|
||||
|
||||
registerEvent(searchGamesEvent, {
|
||||
name: "searchGames",
|
||||
memoize: true,
|
||||
});
|
||||
registerEvent("searchGames", searchGamesEvent);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,4 @@ const getDiskFreeSpace = async (
|
|||
path: string
|
||||
) => checkDiskSpace(path);
|
||||
|
||||
registerEvent(getDiskFreeSpace, {
|
||||
name: "getDiskFreeSpace",
|
||||
});
|
||||
registerEvent("getDiskFreeSpace", getDiskFreeSpace);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import "./library/close-game";
|
|||
import "./library/delete-game-folder";
|
||||
import "./library/get-game-by-object-id";
|
||||
import "./library/get-library";
|
||||
import "./library/get-repackers-friendly-names";
|
||||
import "./library/open-game";
|
||||
import "./library/open-game-installer";
|
||||
import "./library/remove-game";
|
||||
|
|
|
|||
|
|
@ -42,6 +42,4 @@ const addGameToLibrary = async (
|
|||
});
|
||||
};
|
||||
|
||||
registerEvent(addGameToLibrary, {
|
||||
name: "addGameToLibrary",
|
||||
});
|
||||
registerEvent("addGameToLibrary", addGameToLibrary);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,4 @@ const closeGame = async (
|
|||
return false;
|
||||
};
|
||||
|
||||
registerEvent(closeGame, {
|
||||
name: "closeGame",
|
||||
});
|
||||
registerEvent("closeGame", closeGame);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,4 @@ const deleteGameFolder = async (
|
|||
}
|
||||
};
|
||||
|
||||
registerEvent(deleteGameFolder, {
|
||||
name: "deleteGameFolder",
|
||||
});
|
||||
registerEvent("deleteGameFolder", deleteGameFolder);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,4 @@ const getGameByObjectID = async (
|
|||
},
|
||||
});
|
||||
|
||||
registerEvent(getGameByObjectID, {
|
||||
name: "getGameByObjectID",
|
||||
});
|
||||
registerEvent("getGameByObjectID", getGameByObjectID);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,4 @@ const getLibrary = async () =>
|
|||
)
|
||||
);
|
||||
|
||||
registerEvent(getLibrary, {
|
||||
name: "getLibrary",
|
||||
});
|
||||
registerEvent("getLibrary", getLibrary);
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
import { registerEvent } from "../register-event";
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
const getRepackersFriendlyNames = async () =>
|
||||
stateManager.getValue("repackersFriendlyNames").reduce((prev, next) => {
|
||||
return { ...prev, [next.name]: next.friendlyName };
|
||||
}, {});
|
||||
|
||||
registerEvent(getRepackersFriendlyNames, {
|
||||
name: "getRepackersFriendlyNames",
|
||||
memoize: true,
|
||||
});
|
||||
|
|
@ -55,6 +55,4 @@ const openGameInstaller = async (
|
|||
return false;
|
||||
};
|
||||
|
||||
registerEvent(openGameInstaller, {
|
||||
name: "openGameInstaller",
|
||||
});
|
||||
registerEvent("openGameInstaller", openGameInstaller);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,4 @@ const openGame = async (
|
|||
shell.openPath(executablePath);
|
||||
};
|
||||
|
||||
registerEvent(openGame, {
|
||||
name: "openGame",
|
||||
});
|
||||
registerEvent("openGame", openGame);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,4 @@ const removeGameFromLibrary = async (
|
|||
gameRepository.update({ id: gameId }, { isDeleted: true });
|
||||
};
|
||||
|
||||
registerEvent(removeGameFromLibrary, {
|
||||
name: "removeGameFromLibrary",
|
||||
});
|
||||
registerEvent("removeGameFromLibrary", removeGameFromLibrary);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,4 @@ const removeGame = async (
|
|||
);
|
||||
};
|
||||
|
||||
registerEvent(removeGame, {
|
||||
name: "removeGame",
|
||||
});
|
||||
registerEvent("removeGame", removeGame);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,4 @@ import { registerEvent } from "../register-event";
|
|||
const openExternal = async (_event: Electron.IpcMainInvokeEvent, src: string) =>
|
||||
shell.openExternal(src);
|
||||
|
||||
registerEvent(openExternal, {
|
||||
name: "openExternal",
|
||||
});
|
||||
registerEvent("openExternal", openExternal);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,4 @@ const showOpenDialog = async (
|
|||
throw new Error("Main window is not available");
|
||||
};
|
||||
|
||||
registerEvent(showOpenDialog, {
|
||||
name: "showOpenDialog",
|
||||
});
|
||||
registerEvent("showOpenDialog", showOpenDialog);
|
||||
|
|
|
|||
|
|
@ -1,37 +1,11 @@
|
|||
import { ipcMain } from "electron";
|
||||
|
||||
import { stateManager } from "@main/state-manager";
|
||||
|
||||
interface EventArgs {
|
||||
name: string;
|
||||
memoize?: boolean;
|
||||
}
|
||||
|
||||
export const registerEvent = (
|
||||
listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any,
|
||||
{ name, memoize = false }: EventArgs
|
||||
name: string,
|
||||
listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any
|
||||
) => {
|
||||
ipcMain.handle(name, (event: Electron.IpcMainInvokeEvent, ...args) => {
|
||||
const eventResults = stateManager.getValue("eventResults");
|
||||
const keys = Array.from(eventResults.keys());
|
||||
|
||||
const key = [name, args] as [string, any[]];
|
||||
|
||||
const memoizationKey = keys.find(([memoizedEvent, memoizedArgs]) => {
|
||||
const sameEvent = name === memoizedEvent;
|
||||
const sameArgs = memoizedArgs.every((arg, index) => arg === args[index]);
|
||||
|
||||
return sameEvent && sameArgs;
|
||||
});
|
||||
|
||||
if (memoizationKey) return eventResults.get(memoizationKey);
|
||||
|
||||
ipcMain.handle(name, async (event: Electron.IpcMainInvokeEvent, ...args) => {
|
||||
return Promise.resolve(listener(event, ...args)).then((result) => {
|
||||
if (memoize) {
|
||||
eventResults.set(key, JSON.parse(JSON.stringify(result)));
|
||||
stateManager.setValue("eventResults", eventResults);
|
||||
}
|
||||
|
||||
if (!result) return result;
|
||||
return JSON.parse(JSON.stringify(result));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -50,6 +50,4 @@ const cancelGameDownload = async (
|
|||
});
|
||||
};
|
||||
|
||||
registerEvent(cancelGameDownload, {
|
||||
name: "cancelGameDownload",
|
||||
});
|
||||
registerEvent("cancelGameDownload", cancelGameDownload);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,4 @@ const pauseGameDownload = async (
|
|||
});
|
||||
};
|
||||
|
||||
registerEvent(pauseGameDownload, {
|
||||
name: "pauseGameDownload",
|
||||
});
|
||||
registerEvent("pauseGameDownload", pauseGameDownload);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,4 @@ const resumeGameDownload = async (
|
|||
}
|
||||
};
|
||||
|
||||
registerEvent(resumeGameDownload, {
|
||||
name: "resumeGameDownload",
|
||||
});
|
||||
registerEvent("resumeGameDownload", resumeGameDownload);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,4 @@ const startGameDownload = async (
|
|||
}
|
||||
};
|
||||
|
||||
registerEvent(startGameDownload, {
|
||||
name: "startGameDownload",
|
||||
});
|
||||
registerEvent("startGameDownload", startGameDownload);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,4 @@ const autoLaunch = async (
|
|||
}
|
||||
};
|
||||
|
||||
registerEvent(autoLaunch, {
|
||||
name: "autoLaunch",
|
||||
});
|
||||
registerEvent("autoLaunch", autoLaunch);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,4 @@ const getUserPreferences = async () =>
|
|||
where: { id: 1 },
|
||||
});
|
||||
|
||||
registerEvent(getUserPreferences, {
|
||||
name: "getUserPreferences",
|
||||
});
|
||||
registerEvent("getUserPreferences", getUserPreferences);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,4 @@ const updateUserPreferences = async (
|
|||
);
|
||||
};
|
||||
|
||||
registerEvent(updateUserPreferences, {
|
||||
name: "updateUserPreferences",
|
||||
});
|
||||
registerEvent("updateUserPreferences", updateUserPreferences);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { app, BrowserWindow, net, protocol } from "electron";
|
||||
import { init } from "@sentry/electron/main";
|
||||
import i18n from "i18next";
|
||||
import path from "node:path";
|
||||
import { electronApp, optimizer } from "@electron-toolkit/utils";
|
||||
|
|
@ -11,20 +10,6 @@ import { userPreferencesRepository } from "@main/repository";
|
|||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
if (!gotTheLock) app.quit();
|
||||
|
||||
if (import.meta.env.MAIN_VITE_SENTRY_DSN) {
|
||||
init({
|
||||
dsn: import.meta.env.MAIN_VITE_SENTRY_DSN,
|
||||
beforeSend: async (event) => {
|
||||
const userPreferences = await userPreferencesRepository.findOne({
|
||||
where: { id: 1 },
|
||||
});
|
||||
|
||||
if (userPreferences?.telemetryEnabled) return event;
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
i18n.init({
|
||||
resources,
|
||||
lng: "en",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { stateManager } from "./state-manager";
|
||||
import { repackers } from "./constants";
|
||||
import { repackersOn1337x } from "./constants";
|
||||
import {
|
||||
getNewGOGGames,
|
||||
getNewRepacksFromCPG,
|
||||
getNewRepacksFromUser,
|
||||
getNewRepacksFromXatab,
|
||||
getNewRepacksFromOnlineFix,
|
||||
|
|
@ -12,7 +11,6 @@ import {
|
|||
import {
|
||||
gameRepository,
|
||||
repackRepository,
|
||||
repackerFriendlyNameRepository,
|
||||
steamGameRepository,
|
||||
userPreferencesRepository,
|
||||
} from "./repository";
|
||||
|
|
@ -27,7 +25,7 @@ import { RealDebridClient } from "./services/real-debrid";
|
|||
startProcessWatcher();
|
||||
|
||||
const track1337xUsers = async (existingRepacks: Repack[]) => {
|
||||
for (const repacker of repackers) {
|
||||
for (const repacker of repackersOn1337x) {
|
||||
await getNewRepacksFromUser(
|
||||
repacker,
|
||||
existingRepacks.filter((repack) => repack.repacker === repacker)
|
||||
|
|
@ -39,19 +37,16 @@ const checkForNewRepacks = async (userPreferences: UserPreferences | null) => {
|
|||
const existingRepacks = stateManager.getValue("repacks");
|
||||
|
||||
Promise.allSettled([
|
||||
getNewGOGGames(
|
||||
existingRepacks.filter((repack) => repack.repacker === "GOG")
|
||||
),
|
||||
track1337xUsers(existingRepacks),
|
||||
getNewRepacksFromXatab(
|
||||
existingRepacks.filter((repack) => repack.repacker === "Xatab")
|
||||
),
|
||||
getNewRepacksFromCPG(
|
||||
existingRepacks.filter((repack) => repack.repacker === "CPG")
|
||||
getNewGOGGames(
|
||||
existingRepacks.filter((repack) => repack.repacker === "GOG")
|
||||
),
|
||||
getNewRepacksFromOnlineFix(
|
||||
existingRepacks.filter((repack) => repack.repacker === "onlinefix")
|
||||
),
|
||||
track1337xUsers(existingRepacks),
|
||||
]).then(() => {
|
||||
repackRepository.count().then((count) => {
|
||||
const total = count - stateManager.getValue("repacks").length;
|
||||
|
|
@ -74,8 +69,7 @@ const checkForNewRepacks = async (userPreferences: UserPreferences | null) => {
|
|||
};
|
||||
|
||||
const loadState = async (userPreferences: UserPreferences | null) => {
|
||||
const [friendlyNames, repacks, steamGames] = await Promise.all([
|
||||
repackerFriendlyNameRepository.find(),
|
||||
const [repacks, steamGames] = await Promise.all([
|
||||
repackRepository.find({
|
||||
order: {
|
||||
createdAt: "desc",
|
||||
|
|
@ -88,7 +82,6 @@ const loadState = async (userPreferences: UserPreferences | null) => {
|
|||
}),
|
||||
]);
|
||||
|
||||
stateManager.setValue("repackersFriendlyNames", friendlyNames);
|
||||
stateManager.setValue("repacks", repacks);
|
||||
stateManager.setValue("steamGames", steamGames);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ import {
|
|||
Game,
|
||||
GameShopCache,
|
||||
Repack,
|
||||
RepackerFriendlyName,
|
||||
UserPreferences,
|
||||
MigrationScript,
|
||||
SteamGame,
|
||||
} from "@main/entity";
|
||||
|
||||
|
|
@ -13,15 +11,9 @@ export const gameRepository = dataSource.getRepository(Game);
|
|||
|
||||
export const repackRepository = dataSource.getRepository(Repack);
|
||||
|
||||
export const repackerFriendlyNameRepository =
|
||||
dataSource.getRepository(RepackerFriendlyName);
|
||||
|
||||
export const userPreferencesRepository =
|
||||
dataSource.getRepository(UserPreferences);
|
||||
|
||||
export const gameShopCacheRepository = dataSource.getRepository(GameShopCache);
|
||||
|
||||
export const migrationScriptRepository =
|
||||
dataSource.getRepository(MigrationScript);
|
||||
|
||||
export const steamGameRepository = dataSource.getRepository(SteamGame);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import path from "node:path";
|
||||
import cp from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import * as Sentry from "@sentry/electron/main";
|
||||
import { app, dialog } from "electron";
|
||||
import type { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||
|
||||
|
|
@ -87,8 +86,6 @@ export class TorrentDownloader extends Downloader {
|
|||
downloadSpeed: payload.downloadSpeed,
|
||||
timeRemaining: payload.timeRemaining,
|
||||
});
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
} finally {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
import { JSDOM } from "jsdom";
|
||||
|
||||
import { Repack } from "@main/entity";
|
||||
|
||||
import { requestWebPage, savePage } from "./helpers";
|
||||
import { logger } from "../logger";
|
||||
import type { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||
|
||||
export const getNewRepacksFromCPG = async (
|
||||
existingRepacks: Repack[] = [],
|
||||
page = 1
|
||||
): Promise<void> => {
|
||||
const data = await requestWebPage(`https://cpgrepacks.site/page/${page}`);
|
||||
|
||||
const { window } = new JSDOM(data);
|
||||
|
||||
const repacks: QueryDeepPartialEntity<Repack>[] = [];
|
||||
|
||||
try {
|
||||
Array.from(window.document.querySelectorAll(".post")).forEach(($post) => {
|
||||
const $title = $post.querySelector(".entry-title")!;
|
||||
const uploadDate = $post.querySelector("time")?.getAttribute("datetime");
|
||||
|
||||
const $downloadInfo = Array.from(
|
||||
$post.querySelectorAll(".wp-block-heading")
|
||||
).find(($heading) => $heading.textContent?.startsWith("Download"));
|
||||
|
||||
/* Side note: CPG often misspells "Magnet" as "Magent" */
|
||||
const $magnet = Array.from($post.querySelectorAll("a")).find(
|
||||
($a) =>
|
||||
$a.textContent?.startsWith("Magnet") ||
|
||||
$a.textContent?.startsWith("Magent")
|
||||
);
|
||||
|
||||
const fileSize = ($downloadInfo?.textContent ?? "")
|
||||
.split("Download link => ")
|
||||
.at(1);
|
||||
|
||||
repacks.push({
|
||||
title: $title.textContent!,
|
||||
fileSize: fileSize ?? "N/A",
|
||||
magnet: $magnet!.href,
|
||||
repacker: "CPG",
|
||||
page,
|
||||
uploadDate: uploadDate ? new Date(uploadDate) : new Date(),
|
||||
});
|
||||
});
|
||||
} catch (err: unknown) {
|
||||
logger.error((err as Error).message, { method: "getNewRepacksFromCPG" });
|
||||
}
|
||||
|
||||
const newRepacks = repacks.filter(
|
||||
(repack) =>
|
||||
!existingRepacks.some(
|
||||
(existingRepack) => existingRepack.title === repack.title
|
||||
)
|
||||
);
|
||||
|
||||
if (!newRepacks.length) return;
|
||||
|
||||
await savePage(newRepacks);
|
||||
|
||||
return getNewRepacksFromCPG(existingRepacks, page + 1);
|
||||
};
|
||||
|
|
@ -6,32 +6,57 @@ import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity
|
|||
|
||||
const virtualConsole = new VirtualConsole();
|
||||
|
||||
const getUploadDate = (document: Document) => {
|
||||
const $modifiedTime = document.querySelector(
|
||||
'[property="article:modified_time"]'
|
||||
) as HTMLMetaElement;
|
||||
if ($modifiedTime) return $modifiedTime.content;
|
||||
|
||||
const $publishedTime = document.querySelector(
|
||||
'[property="article:published_time"]'
|
||||
) as HTMLMetaElement;
|
||||
return $publishedTime.content;
|
||||
};
|
||||
|
||||
const getDownloadLink = (document: Document) => {
|
||||
const $latestDownloadButton = document.querySelector(
|
||||
".download-btn:not(.lightweight-accordion *)"
|
||||
) as HTMLAnchorElement;
|
||||
if ($latestDownloadButton) return $latestDownloadButton.href;
|
||||
|
||||
const $downloadButton = document.querySelector(
|
||||
".download-btn"
|
||||
) as HTMLAnchorElement;
|
||||
if (!$downloadButton) return null;
|
||||
|
||||
return $downloadButton.href;
|
||||
};
|
||||
|
||||
const getMagnet = (downloadLink: string) => {
|
||||
if (downloadLink.startsWith("http")) {
|
||||
const { searchParams } = new URL(downloadLink);
|
||||
return Buffer.from(searchParams.get("url")!, "base64").toString("utf-8");
|
||||
}
|
||||
|
||||
return downloadLink;
|
||||
};
|
||||
|
||||
const getGOGGame = async (url: string) => {
|
||||
const data = await requestWebPage(url);
|
||||
const { window } = new JSDOM(data, { virtualConsole });
|
||||
|
||||
const $modifiedTime = window.document.querySelector(
|
||||
'[property="article:modified_time"]'
|
||||
) as HTMLMetaElement;
|
||||
const downloadLink = getDownloadLink(window.document);
|
||||
if (!downloadLink) return null;
|
||||
|
||||
const $em = window.document.querySelector(
|
||||
"p:not(.lightweight-accordion *) em"
|
||||
)!;
|
||||
const $em = window.document.querySelector("p em");
|
||||
if (!$em) return null;
|
||||
const fileSize = $em.textContent!.split("Size: ").at(1);
|
||||
const $downloadButton = window.document.querySelector(
|
||||
".download-btn:not(.lightweight-accordion *)"
|
||||
) as HTMLAnchorElement;
|
||||
|
||||
const { searchParams } = new URL($downloadButton.href);
|
||||
const magnet = Buffer.from(searchParams.get("url")!, "base64").toString(
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
return {
|
||||
fileSize: fileSize ?? "N/A",
|
||||
uploadDate: new Date($modifiedTime.content),
|
||||
uploadDate: new Date(getUploadDate(window.document)),
|
||||
repacker: "GOG",
|
||||
magnet,
|
||||
magnet: getMagnet(downloadLink),
|
||||
page: 1,
|
||||
};
|
||||
};
|
||||
|
|
@ -62,7 +87,7 @@ export const getNewGOGGames = async (existingRepacks: Repack[] = []) => {
|
|||
if (!gameExists) {
|
||||
const game = await getGOGGame(href);
|
||||
|
||||
repacks.push({ ...game, title });
|
||||
if (game) repacks.push({ ...game, title });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import axios from "axios";
|
||||
import UserAgent from "user-agents";
|
||||
|
||||
import type { Repack } from "@main/entity";
|
||||
|
|
@ -13,12 +14,13 @@ export const savePage = async (repacks: QueryDeepPartialEntity<Repack>[]) =>
|
|||
export const requestWebPage = async (url: string) => {
|
||||
const userAgent = new UserAgent();
|
||||
|
||||
return fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"User-Agent": userAgent.toString(),
|
||||
},
|
||||
}).then((response) => response.text());
|
||||
return axios
|
||||
.get(url, {
|
||||
headers: {
|
||||
"User-Agent": userAgent.toString(),
|
||||
},
|
||||
})
|
||||
.then((response) => response.data);
|
||||
};
|
||||
|
||||
export const decodeNonUtf8Response = async (res: Response) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
export * from "./1337x";
|
||||
export * from "./xatab";
|
||||
export * from "./cpg-repacks";
|
||||
export * from "./gog";
|
||||
export * from "./online-fix";
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import { Repack } from "@main/entity";
|
||||
import { decodeNonUtf8Response, savePage } from "./helpers";
|
||||
import { logger } from "../logger";
|
||||
import parseTorrent, {
|
||||
toMagnetURI,
|
||||
Instance as TorrentInstance,
|
||||
} from "parse-torrent";
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
import { format, parse, sub } from "date-fns";
|
||||
import { ru } from "date-fns/locale";
|
||||
|
||||
import createWorker from "@main/workers/torrent-parser.worker?nodeWorker";
|
||||
import { toMagnetURI } from "parse-torrent";
|
||||
|
||||
const worker = createWorker({});
|
||||
|
||||
import { onlinefixFormatter } from "@main/helpers";
|
||||
import makeFetchCookie from "fetch-cookie";
|
||||
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||
|
|
@ -139,27 +140,23 @@ export const getNewRepacksFromOnlineFix = async (
|
|||
?.getAttribute("href");
|
||||
|
||||
const torrentFile = Buffer.from(
|
||||
await http(`${torrentPrePage}/${torrentLink}`).then((res) =>
|
||||
await http(`${torrentPrePage}${torrentLink}`).then((res) =>
|
||||
res.arrayBuffer()
|
||||
)
|
||||
);
|
||||
|
||||
const torrent = parseTorrent(torrentFile) as TorrentInstance;
|
||||
const magnetLink = toMagnetURI({
|
||||
infoHash: torrent.infoHash,
|
||||
worker.once("message", (torrent) => {
|
||||
repacks.push({
|
||||
fileSize: formatBytes(torrent.length ?? 0),
|
||||
magnet: toMagnetURI(torrent),
|
||||
page: 1,
|
||||
repacker: "onlinefix",
|
||||
title: gameName,
|
||||
uploadDate: uploadDate,
|
||||
});
|
||||
});
|
||||
|
||||
const torrentSizeInBytes = torrent.length;
|
||||
if (!torrentSizeInBytes) return;
|
||||
|
||||
repacks.push({
|
||||
fileSize: formatBytes(torrentSizeInBytes),
|
||||
magnet: magnetLink,
|
||||
page: 1,
|
||||
repacker: "onlinefix",
|
||||
title: gameName,
|
||||
uploadDate: uploadDate,
|
||||
});
|
||||
worker.postMessage(torrentFile);
|
||||
})
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { toMagnetURI } from "parse-torrent";
|
|||
import type { Instance } from "parse-torrent";
|
||||
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||
import { formatBytes } from "@shared";
|
||||
import { getFileBuffer } from "@main/helpers";
|
||||
|
||||
const worker = createWorker({});
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ const formatXatabDate = (str: string) => {
|
|||
|
||||
const getXatabRepack = (
|
||||
url: string
|
||||
): Promise<{ fileSize: string; magnet: string; uploadDate: Date }> => {
|
||||
): Promise<{ fileSize: string; magnet: string; uploadDate: Date } | null> => {
|
||||
return new Promise((resolve) => {
|
||||
(async () => {
|
||||
const data = await requestWebPage(url);
|
||||
|
|
@ -40,15 +41,20 @@ const getXatabRepack = (
|
|||
".download-torrent"
|
||||
) as HTMLAnchorElement;
|
||||
|
||||
if (!$downloadButton) throw new Error("Download button not found");
|
||||
if (!$downloadButton) return resolve(null);
|
||||
|
||||
worker.once("message", (torrent: Instance | null) => {
|
||||
if (!torrent) return resolve(null);
|
||||
|
||||
worker.once("message", (torrent: Instance) => {
|
||||
resolve({
|
||||
fileSize: formatBytes(torrent.length ?? 0),
|
||||
magnet: toMagnetURI(torrent),
|
||||
uploadDate: formatXatabDate($uploadDate!.textContent!),
|
||||
});
|
||||
});
|
||||
|
||||
const buffer = await getFileBuffer($downloadButton.href);
|
||||
worker.postMessage(buffer);
|
||||
})();
|
||||
});
|
||||
};
|
||||
|
|
@ -69,12 +75,14 @@ export const getNewRepacksFromXatab = async (
|
|||
try {
|
||||
const repack = await getXatabRepack(($a as HTMLAnchorElement).href);
|
||||
|
||||
repacks.push({
|
||||
title: $a.textContent!,
|
||||
repacker: "Xatab",
|
||||
...repack,
|
||||
page,
|
||||
});
|
||||
if (repack) {
|
||||
repacks.push({
|
||||
title: $a.textContent!,
|
||||
repacker: "Xatab",
|
||||
...repack,
|
||||
page,
|
||||
});
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
logger.error((err as Error).message, {
|
||||
method: "getNewRepacksFromXatab",
|
||||
|
|
|
|||
|
|
@ -3,107 +3,9 @@ import { app } from "electron";
|
|||
|
||||
import { chunk } from "lodash-es";
|
||||
|
||||
import { createDataSource, dataSource } from "@main/data-source";
|
||||
import { Repack, RepackerFriendlyName, SteamGame } from "@main/entity";
|
||||
import {
|
||||
migrationScriptRepository,
|
||||
repackRepository,
|
||||
repackerFriendlyNameRepository,
|
||||
steamGameRepository,
|
||||
} from "@main/repository";
|
||||
import { MigrationScript } from "@main/entity/migration-script.entity";
|
||||
import { Like } from "typeorm";
|
||||
|
||||
const migrationScripts = {
|
||||
/*
|
||||
0.0.6 -> 0.0.7
|
||||
Xatab repacks were previously created with an incorrect upload date.
|
||||
This migration script will update the upload date of all Xatab repacks.
|
||||
*/
|
||||
"0.0.7": async (updateRepacks: Repack[]) => {
|
||||
const VERSION = "0.0.7";
|
||||
|
||||
const migrationScript = await migrationScriptRepository.findOne({
|
||||
where: {
|
||||
version: VERSION,
|
||||
},
|
||||
});
|
||||
|
||||
if (!migrationScript) {
|
||||
const xatabRepacks = updateRepacks.filter(
|
||||
(repack) => repack.repacker === "Xatab"
|
||||
);
|
||||
|
||||
await dataSource.transaction(async (transactionalEntityManager) => {
|
||||
await Promise.all(
|
||||
xatabRepacks.map((repack) =>
|
||||
transactionalEntityManager.getRepository(Repack).update(
|
||||
{
|
||||
title: repack.title,
|
||||
repacker: repack.repacker,
|
||||
},
|
||||
{
|
||||
uploadDate: repack.uploadDate,
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
await transactionalEntityManager.getRepository(MigrationScript).insert({
|
||||
version: VERSION,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
/*
|
||||
1.0.1 -> 1.1.0
|
||||
A few torrents scraped from 1337x were previously created with an incorrect upload date.
|
||||
*/
|
||||
"1.1.0": async () => {
|
||||
const VERSION = "1.1.0";
|
||||
|
||||
const migrationScript = await migrationScriptRepository.findOne({
|
||||
where: {
|
||||
version: VERSION,
|
||||
},
|
||||
});
|
||||
|
||||
if (!migrationScript) {
|
||||
await dataSource.transaction(async (transactionalEntityManager) => {
|
||||
const repacks = await transactionalEntityManager
|
||||
.getRepository(Repack)
|
||||
.find({
|
||||
where: {
|
||||
uploadDate: Like("1%"),
|
||||
},
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
repacks.map(async (repack) => {
|
||||
return transactionalEntityManager
|
||||
.getRepository(Repack)
|
||||
.update(
|
||||
{ id: repack.id },
|
||||
{ uploadDate: new Date(repack.uploadDate) }
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
await transactionalEntityManager.getRepository(MigrationScript).insert({
|
||||
version: VERSION,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const runMigrationScripts = async (updateRepacks: Repack[]) => {
|
||||
return Promise.all(
|
||||
Object.values(migrationScripts).map((migrationScript) => {
|
||||
return migrationScript(updateRepacks);
|
||||
})
|
||||
);
|
||||
};
|
||||
import { createDataSource } from "@main/data-source";
|
||||
import { Repack, SteamGame } from "@main/entity";
|
||||
import { repackRepository, steamGameRepository } from "@main/repository";
|
||||
|
||||
export const resolveDatabaseUpdates = async () => {
|
||||
const updateDataSource = createDataSource({
|
||||
|
|
@ -114,25 +16,12 @@ export const resolveDatabaseUpdates = async () => {
|
|||
|
||||
return updateDataSource.initialize().then(async () => {
|
||||
const updateRepackRepository = updateDataSource.getRepository(Repack);
|
||||
const updateRepackerFriendlyNameRepository =
|
||||
updateDataSource.getRepository(RepackerFriendlyName);
|
||||
const updateSteamGameRepository = updateDataSource.getRepository(SteamGame);
|
||||
|
||||
const [updateRepacks, updateSteamGames, updateRepackerFriendlyNames] =
|
||||
await Promise.all([
|
||||
updateRepackRepository.find(),
|
||||
updateSteamGameRepository.find(),
|
||||
updateRepackerFriendlyNameRepository.find(),
|
||||
]);
|
||||
|
||||
await runMigrationScripts(updateRepacks);
|
||||
|
||||
await repackerFriendlyNameRepository
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.values(updateRepackerFriendlyNames)
|
||||
.orIgnore()
|
||||
.execute();
|
||||
const [updateRepacks, updateSteamGames] = await Promise.all([
|
||||
updateRepackRepository.find(),
|
||||
updateSteamGameRepository.find(),
|
||||
]);
|
||||
|
||||
const updateRepacksChunks = chunk(updateRepacks, 800);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
import type { Repack, RepackerFriendlyName, SteamGame } from "@main/entity";
|
||||
import type { Repack, SteamGame } from "@main/entity";
|
||||
|
||||
interface State {
|
||||
repacks: Repack[];
|
||||
repackersFriendlyNames: RepackerFriendlyName[];
|
||||
steamGames: SteamGame[];
|
||||
eventResults: Map<[string, any[]], any>;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
repacks: [],
|
||||
repackersFriendlyNames: [],
|
||||
steamGames: [],
|
||||
eventResults: new Map(),
|
||||
};
|
||||
|
||||
export class StateManager {
|
||||
|
|
|
|||
1
src/main/vite-env.d.ts
vendored
1
src/main/vite-env.d.ts
vendored
|
|
@ -4,7 +4,6 @@ interface ImportMetaEnv {
|
|||
readonly MAIN_VITE_STEAMGRIDDB_API_KEY: string;
|
||||
readonly MAIN_VITE_ONLINEFIX_USERNAME: string;
|
||||
readonly MAIN_VITE_ONLINEFIX_PASSWORD: string;
|
||||
readonly MAIN_VITE_SENTRY_DSN: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,11 @@ import parseTorrent from "parse-torrent";
|
|||
const port = parentPort;
|
||||
if (!port) throw new Error("IllegalState");
|
||||
|
||||
export const getFileBuffer = async (url: string) =>
|
||||
fetch(url, { method: "GET" }).then((response) =>
|
||||
response.arrayBuffer().then((buffer) => Buffer.from(buffer))
|
||||
);
|
||||
|
||||
port.on("message", async (url: string) => {
|
||||
const buffer = await getFileBuffer(url);
|
||||
const torrent = await parseTorrent(buffer);
|
||||
port.postMessage(torrent);
|
||||
port.on("message", async (buffer: Buffer) => {
|
||||
try {
|
||||
const torrent = await parseTorrent(buffer);
|
||||
port.postMessage(torrent);
|
||||
} catch (err) {
|
||||
port.postMessage(null);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue