mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 00:33:49 +03:00
Merge pull request #423 from hydralauncher/hotfix/repack-uploadDate
Hotfix/repack upload date
This commit is contained in:
commit
01c3ddf167
@ -29,7 +29,8 @@
|
|||||||
"build:win": "electron-vite build && electron-builder --win",
|
"build:win": "electron-vite build && electron-builder --win",
|
||||||
"build:mac": "electron-vite build && electron-builder --mac",
|
"build:mac": "electron-vite build && electron-builder --mac",
|
||||||
"build:linux": "electron-vite build && electron-builder --linux",
|
"build:linux": "electron-vite build && electron-builder --linux",
|
||||||
"prepare": "husky"
|
"prepare": "husky",
|
||||||
|
"typeorm:migration-create": "yarn typeorm migration:create"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron-toolkit/preload": "^3.0.0",
|
"@electron-toolkit/preload": "^3.0.0",
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
import type { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
|
import type { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
|
||||||
|
|
||||||
import { databasePath } from "./constants";
|
import { databasePath } from "./constants";
|
||||||
|
import migrations from "./migrations";
|
||||||
|
|
||||||
export const createDataSource = (options: Partial<SqliteConnectionOptions>) =>
|
export const createDataSource = (options: Partial<SqliteConnectionOptions>) =>
|
||||||
new DataSource({
|
new DataSource({
|
||||||
@ -19,4 +20,6 @@ export const createDataSource = (options: Partial<SqliteConnectionOptions>) =>
|
|||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const dataSource = createDataSource({});
|
export const dataSource = createDataSource({
|
||||||
|
migrations: migrations,
|
||||||
|
});
|
||||||
|
@ -53,6 +53,8 @@ app.whenReady().then(() => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
dataSource.initialize().then(async () => {
|
dataSource.initialize().then(async () => {
|
||||||
|
await dataSource.runMigrations();
|
||||||
|
|
||||||
await resolveDatabaseUpdates();
|
await resolveDatabaseUpdates();
|
||||||
|
|
||||||
await import("./main");
|
await import("./main");
|
||||||
|
78
src/main/migrations/1715900413313-fix_repack_uploadDate.ts
Normal file
78
src/main/migrations/1715900413313-fix_repack_uploadDate.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { createDataSource } from "@main/data-source";
|
||||||
|
import { Repack } from "@main/entity";
|
||||||
|
import { app } from "electron";
|
||||||
|
import { chunk } from "lodash-es";
|
||||||
|
import path from "path";
|
||||||
|
import { In, MigrationInterface, QueryRunner, Table } from "typeorm";
|
||||||
|
|
||||||
|
export class FixRepackUploadDate1715900413313 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "repack_temp",
|
||||||
|
columns: [
|
||||||
|
{ name: "title", type: "varchar" },
|
||||||
|
{ name: "old_id", type: "int" },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO repack_temp (title, old_id) SELECT title, id FROM repack WHERE repacker IN ('onlinefix', 'Xatab');`
|
||||||
|
);
|
||||||
|
|
||||||
|
await queryRunner.query(
|
||||||
|
`DELETE FROM repack WHERE repacker IN ('onlinefix', 'Xatab');`
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateDataSource = createDataSource({
|
||||||
|
database: app.isPackaged
|
||||||
|
? path.join(process.resourcesPath, "hydra.db")
|
||||||
|
: path.join(__dirname, "..", "..", "hydra.db"),
|
||||||
|
});
|
||||||
|
|
||||||
|
await updateDataSource.initialize();
|
||||||
|
|
||||||
|
const updateRepackRepository = updateDataSource.getRepository(Repack);
|
||||||
|
|
||||||
|
const updatedRepacks = await updateRepackRepository.find({
|
||||||
|
where: {
|
||||||
|
repacker: In(["onlinefix", "Xatab"]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const chunks = chunk(
|
||||||
|
updatedRepacks.map((repack) => {
|
||||||
|
const { id: _, ...rest } = repack;
|
||||||
|
return rest;
|
||||||
|
}),
|
||||||
|
500
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
await queryRunner.manager
|
||||||
|
.createQueryBuilder(Repack, "repack")
|
||||||
|
.insert()
|
||||||
|
.values(chunk)
|
||||||
|
.orIgnore()
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE game
|
||||||
|
SET repackId = (
|
||||||
|
SELECT id
|
||||||
|
from repack LEFT JOIN repack_temp ON repack_temp.title = repack.title
|
||||||
|
WHERE repack_temp.old_id = game.repackId
|
||||||
|
)
|
||||||
|
WHERE EXISTS (select old_id from repack_temp WHERE old_id = game.repackId)`
|
||||||
|
);
|
||||||
|
|
||||||
|
await queryRunner.dropTable("repack_temp");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(_: QueryRunner): Promise<void> {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
3
src/main/migrations/index.ts
Normal file
3
src/main/migrations/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { FixRepackUploadDate1715900413313 } from "./1715900413313-fix_repack_uploadDate";
|
||||||
|
|
||||||
|
export default [FixRepackUploadDate1715900413313];
|
@ -3,21 +3,19 @@ import { decodeNonUtf8Response, savePage } from "./helpers";
|
|||||||
import { logger } from "../logger";
|
import { logger } from "../logger";
|
||||||
import { JSDOM } from "jsdom";
|
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 createWorker from "@main/workers/torrent-parser.worker?nodeWorker";
|
||||||
import { toMagnetURI } from "parse-torrent";
|
import { toMagnetURI } from "parse-torrent";
|
||||||
|
|
||||||
const worker = createWorker({});
|
const worker = createWorker({});
|
||||||
|
|
||||||
import { onlinefixFormatter } from "@main/helpers";
|
|
||||||
import makeFetchCookie from "fetch-cookie";
|
import makeFetchCookie from "fetch-cookie";
|
||||||
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||||
import { formatBytes } from "@shared";
|
import { formatBytes } from "@shared";
|
||||||
|
|
||||||
const ONLINE_FIX_URL = "https://online-fix.me/";
|
const ONLINE_FIX_URL = "https://online-fix.me/";
|
||||||
|
|
||||||
|
let totalPages = 1;
|
||||||
|
|
||||||
export const getNewRepacksFromOnlineFix = async (
|
export const getNewRepacksFromOnlineFix = async (
|
||||||
existingRepacks: Repack[] = [],
|
existingRepacks: Repack[] = [],
|
||||||
page = 1,
|
page = 1,
|
||||||
@ -74,18 +72,16 @@ export const getNewRepacksFromOnlineFix = async (
|
|||||||
|
|
||||||
const repacks: QueryDeepPartialEntity<Repack>[] = [];
|
const repacks: QueryDeepPartialEntity<Repack>[] = [];
|
||||||
const articles = Array.from(document.querySelectorAll(".news"));
|
const articles = Array.from(document.querySelectorAll(".news"));
|
||||||
const totalPages = Number(
|
|
||||||
document.querySelector("nav > a:nth-child(13)")?.textContent
|
if (page == 1) {
|
||||||
);
|
totalPages = Number(
|
||||||
|
document.querySelector("nav > a:nth-child(13)")?.textContent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
articles.map(async (article) => {
|
articles.map(async (article) => {
|
||||||
const gameText = article.querySelector("h2.title")?.textContent?.trim();
|
|
||||||
if (!gameText) return;
|
|
||||||
|
|
||||||
const gameName = onlinefixFormatter(gameText);
|
|
||||||
|
|
||||||
const gameLink = article.querySelector("a")?.getAttribute("href");
|
const gameLink = article.querySelector("a")?.getAttribute("href");
|
||||||
if (!gameLink) return;
|
if (!gameLink) return;
|
||||||
|
|
||||||
@ -94,32 +90,6 @@ export const getNewRepacksFromOnlineFix = async (
|
|||||||
);
|
);
|
||||||
const gameDocument = new JSDOM(gamePage).window.document;
|
const gameDocument = new JSDOM(gamePage).window.document;
|
||||||
|
|
||||||
const uploadDateText = gameDocument.querySelector("time")?.textContent;
|
|
||||||
if (!uploadDateText) return;
|
|
||||||
|
|
||||||
let decodedDateText = uploadDateText;
|
|
||||||
|
|
||||||
// "Вчера" means yesterday.
|
|
||||||
if (decodedDateText.includes("Вчера")) {
|
|
||||||
const yesterday = sub(new Date(), { days: 1 });
|
|
||||||
const formattedYesterday = format(yesterday, "d LLLL yyyy", {
|
|
||||||
locale: ru,
|
|
||||||
});
|
|
||||||
decodedDateText = decodedDateText.replace(
|
|
||||||
"Вчера", // "Change yesterday to the default expected date format"
|
|
||||||
formattedYesterday
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadDate = parse(
|
|
||||||
decodedDateText,
|
|
||||||
"d LLLL yyyy, HH:mm",
|
|
||||||
new Date(),
|
|
||||||
{
|
|
||||||
locale: ru,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const torrentButtons = Array.from(
|
const torrentButtons = Array.from(
|
||||||
gameDocument.querySelectorAll("a")
|
gameDocument.querySelectorAll("a")
|
||||||
).filter((a) => a.textContent?.includes("Torrent"));
|
).filter((a) => a.textContent?.includes("Torrent"));
|
||||||
@ -148,13 +118,15 @@ export const getNewRepacksFromOnlineFix = async (
|
|||||||
worker.once("message", (torrent) => {
|
worker.once("message", (torrent) => {
|
||||||
if (!torrent) return;
|
if (!torrent) return;
|
||||||
|
|
||||||
|
const { name, created } = torrent;
|
||||||
|
|
||||||
repacks.push({
|
repacks.push({
|
||||||
fileSize: formatBytes(torrent.length ?? 0),
|
fileSize: formatBytes(torrent.length ?? 0),
|
||||||
magnet: toMagnetURI(torrent),
|
magnet: toMagnetURI(torrent),
|
||||||
page: 1,
|
page: 1,
|
||||||
repacker: "onlinefix",
|
repacker: "onlinefix",
|
||||||
title: gameName,
|
title: name,
|
||||||
uploadDate: uploadDate,
|
uploadDate: created,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ import { formatBytes } from "@shared";
|
|||||||
import { getFileBuffer } from "@main/helpers";
|
import { getFileBuffer } from "@main/helpers";
|
||||||
|
|
||||||
const worker = createWorker({});
|
const worker = createWorker({});
|
||||||
|
worker.setMaxListeners(11);
|
||||||
|
|
||||||
|
let totalPages = 1;
|
||||||
|
|
||||||
const formatXatabDate = (str: string) => {
|
const formatXatabDate = (str: string) => {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
@ -69,27 +72,37 @@ export const getNewRepacksFromXatab = async (
|
|||||||
|
|
||||||
const repacks: QueryDeepPartialEntity<Repack>[] = [];
|
const repacks: QueryDeepPartialEntity<Repack>[] = [];
|
||||||
|
|
||||||
for (const $a of Array.from(
|
if (page === 1) {
|
||||||
window.document.querySelectorAll(".entry__title a")
|
totalPages = Number(
|
||||||
)) {
|
window.document.querySelector(
|
||||||
try {
|
"#bottom-nav > div.pagination > a:nth-child(12)"
|
||||||
const repack = await getXatabRepack(($a as HTMLAnchorElement).href);
|
)?.textContent
|
||||||
|
);
|
||||||
if (repack) {
|
|
||||||
repacks.push({
|
|
||||||
title: $a.textContent!,
|
|
||||||
repacker: "Xatab",
|
|
||||||
...repack,
|
|
||||||
page,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err: unknown) {
|
|
||||||
logger.error((err as Error).message, {
|
|
||||||
method: "getNewRepacksFromXatab",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const repacksFromPage = Array.from(
|
||||||
|
window.document.querySelectorAll(".entry__title a")
|
||||||
|
).map(($a) => {
|
||||||
|
return getXatabRepack(($a as HTMLAnchorElement).href)
|
||||||
|
.then((repack) => {
|
||||||
|
if (repack) {
|
||||||
|
repacks.push({
|
||||||
|
title: $a.textContent!,
|
||||||
|
repacker: "Xatab",
|
||||||
|
...repack,
|
||||||
|
page,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: unknown) => {
|
||||||
|
logger.error((err as Error).message, {
|
||||||
|
method: "getNewRepacksFromXatab",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(repacksFromPage);
|
||||||
|
|
||||||
const newRepacks = repacks.filter(
|
const newRepacks = repacks.filter(
|
||||||
(repack) =>
|
(repack) =>
|
||||||
!existingRepacks.some(
|
!existingRepacks.some(
|
||||||
@ -98,6 +111,7 @@ export const getNewRepacksFromXatab = async (
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!newRepacks.length) return;
|
if (!newRepacks.length) return;
|
||||||
|
if (page === totalPages) return;
|
||||||
|
|
||||||
await savePage(newRepacks);
|
await savePage(newRepacks);
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export function Modal({
|
|||||||
}, [onClose]);
|
}, [onClose]);
|
||||||
|
|
||||||
const isTopMostModal = () => {
|
const isTopMostModal = () => {
|
||||||
const openModals = document.querySelectorAll("[role=modal]");
|
const openModals = document.querySelectorAll("[role=dialog]");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
openModals.length &&
|
openModals.length &&
|
||||||
|
Loading…
Reference in New Issue
Block a user