mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 00:33:49 +03:00
fix: showing multiple download options
This commit is contained in:
parent
c218070463
commit
42ea35441c
@ -174,12 +174,9 @@
|
|||||||
"validate_download_source": "Validate",
|
"validate_download_source": "Validate",
|
||||||
"remove_download_source": "Remove",
|
"remove_download_source": "Remove",
|
||||||
"add_download_source": "Add source",
|
"add_download_source": "Add source",
|
||||||
"download_count_zero": "No downloads in list",
|
"download_count_zero": "No download options",
|
||||||
"download_count_one": "{{countFormatted}} download in list",
|
"download_count_one": "{{countFormatted}} download option",
|
||||||
"download_count_other": "{{countFormatted}} downloads in list",
|
"download_count_other": "{{countFormatted}} download options",
|
||||||
"download_options_zero": "No download available",
|
|
||||||
"download_options_one": "{{countFormatted}} download available",
|
|
||||||
"download_options_other": "{{countFormatted}} downloads available",
|
|
||||||
"download_source_url": "Download source URL",
|
"download_source_url": "Download source URL",
|
||||||
"add_download_source_description": "Insert the URL containing the .json file",
|
"add_download_source_description": "Insert the URL containing the .json file",
|
||||||
"download_source_up_to_date": "Up-to-date",
|
"download_source_up_to_date": "Up-to-date",
|
||||||
|
@ -6,12 +6,12 @@ import {
|
|||||||
GameShopCache,
|
GameShopCache,
|
||||||
Repack,
|
Repack,
|
||||||
UserPreferences,
|
UserPreferences,
|
||||||
|
UserAuth,
|
||||||
} from "@main/entity";
|
} from "@main/entity";
|
||||||
import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";
|
import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";
|
||||||
|
|
||||||
import { databasePath } from "./constants";
|
import { databasePath } from "./constants";
|
||||||
import migrations from "./migrations";
|
import migrations from "./migrations";
|
||||||
import { UserAuth } from "./entity/user-auth";
|
|
||||||
|
|
||||||
export const createDataSource = (
|
export const createDataSource = (
|
||||||
options: Partial<BetterSqlite3ConnectionOptions>
|
options: Partial<BetterSqlite3ConnectionOptions>
|
||||||
|
@ -16,11 +16,14 @@ export class Repack {
|
|||||||
@Column("text", { unique: true })
|
@Column("text", { unique: true })
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
@Column("text", { unique: true })
|
/**
|
||||||
|
* @deprecated Use uris instead
|
||||||
|
*/
|
||||||
|
@Column("text", { unique: true, nullable: true })
|
||||||
magnet: string;
|
magnet: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated Direct scraping capability has been removed
|
||||||
*/
|
*/
|
||||||
@Column("int", { nullable: true })
|
@Column("int", { nullable: true })
|
||||||
page: number;
|
page: number;
|
||||||
@ -37,6 +40,9 @@ export class Repack {
|
|||||||
@ManyToOne(() => DownloadSource, { nullable: true, onDelete: "CASCADE" })
|
@ManyToOne(() => DownloadSource, { nullable: true, onDelete: "CASCADE" })
|
||||||
downloadSource: DownloadSource;
|
downloadSource: DownloadSource;
|
||||||
|
|
||||||
|
@Column("text")
|
||||||
|
uris: string;
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
import { downloadSourceRepository } from "@main/repository";
|
import { downloadSourceRepository } from "@main/repository";
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
|
|
||||||
const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) => {
|
const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) =>
|
||||||
return downloadSourceRepository
|
downloadSourceRepository.find({
|
||||||
.createQueryBuilder("downloadSource")
|
order: {
|
||||||
.leftJoin("downloadSource.repacks", "repacks")
|
createdAt: "DESC",
|
||||||
.orderBy("downloadSource.createdAt", "DESC")
|
},
|
||||||
.loadRelationCountAndMap(
|
});
|
||||||
"downloadSource.repackCount",
|
|
||||||
"downloadSource.repacks"
|
|
||||||
)
|
|
||||||
.getMany();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerEvent("getDownloadSources", getDownloadSources);
|
registerEvent("getDownloadSources", getDownloadSources);
|
||||||
|
@ -18,7 +18,8 @@ const startGameDownload = async (
|
|||||||
_event: Electron.IpcMainInvokeEvent,
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
payload: StartGameDownloadPayload
|
payload: StartGameDownloadPayload
|
||||||
) => {
|
) => {
|
||||||
const { repackId, objectID, title, shop, downloadPath, downloader } = payload;
|
const { repackId, objectID, title, shop, downloadPath, downloader, uri } =
|
||||||
|
payload;
|
||||||
|
|
||||||
const [game, repack] = await Promise.all([
|
const [game, repack] = await Promise.all([
|
||||||
gameRepository.findOne({
|
gameRepository.findOne({
|
||||||
@ -54,7 +55,7 @@ const startGameDownload = async (
|
|||||||
bytesDownloaded: 0,
|
bytesDownloaded: 0,
|
||||||
downloadPath,
|
downloadPath,
|
||||||
downloader,
|
downloader,
|
||||||
uri: repack.magnet,
|
uri,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -76,7 +77,7 @@ const startGameDownload = async (
|
|||||||
shop,
|
shop,
|
||||||
status: "active",
|
status: "active",
|
||||||
downloadPath,
|
downloadPath,
|
||||||
uri: repack.magnet,
|
uri,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (iconUrl) {
|
if (iconUrl) {
|
||||||
|
@ -17,7 +17,7 @@ export const insertDownloadsFromSource = async (
|
|||||||
const repacks: QueryDeepPartialEntity<Repack>[] = downloads.map(
|
const repacks: QueryDeepPartialEntity<Repack>[] = downloads.map(
|
||||||
(download) => ({
|
(download) => ({
|
||||||
title: download.title,
|
title: download.title,
|
||||||
magnet: download.uris[0],
|
uris: JSON.stringify(download.uris),
|
||||||
fileSize: download.fileSize,
|
fileSize: download.fileSize,
|
||||||
repacker: downloadSource.name,
|
repacker: downloadSource.name,
|
||||||
uploadDate: download.uploadDate,
|
uploadDate: download.uploadDate,
|
||||||
|
@ -77,54 +77,54 @@ export class HydraApi {
|
|||||||
baseURL: import.meta.env.MAIN_VITE_API_URL,
|
baseURL: import.meta.env.MAIN_VITE_API_URL,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.instance.interceptors.request.use(
|
// this.instance.interceptors.request.use(
|
||||||
(request) => {
|
// (request) => {
|
||||||
logger.log(" ---- REQUEST -----");
|
// logger.log(" ---- REQUEST -----");
|
||||||
logger.log(request.method, request.url, request.params, request.data);
|
// logger.log(request.method, request.url, request.params, request.data);
|
||||||
return request;
|
// return request;
|
||||||
},
|
// },
|
||||||
(error) => {
|
// (error) => {
|
||||||
logger.error("request error", error);
|
// logger.error("request error", error);
|
||||||
return Promise.reject(error);
|
// return Promise.reject(error);
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
|
|
||||||
this.instance.interceptors.response.use(
|
// this.instance.interceptors.response.use(
|
||||||
(response) => {
|
// (response) => {
|
||||||
logger.log(" ---- RESPONSE -----");
|
// logger.log(" ---- RESPONSE -----");
|
||||||
logger.log(
|
// logger.log(
|
||||||
response.status,
|
// response.status,
|
||||||
response.config.method,
|
// response.config.method,
|
||||||
response.config.url,
|
// response.config.url,
|
||||||
response.data
|
// response.data
|
||||||
);
|
// );
|
||||||
return response;
|
// return response;
|
||||||
},
|
// },
|
||||||
(error) => {
|
// (error) => {
|
||||||
logger.error(" ---- RESPONSE ERROR -----");
|
// logger.error(" ---- RESPONSE ERROR -----");
|
||||||
|
|
||||||
const { config } = error;
|
// const { config } = error;
|
||||||
|
|
||||||
logger.error(
|
// logger.error(
|
||||||
config.method,
|
// config.method,
|
||||||
config.baseURL,
|
// config.baseURL,
|
||||||
config.url,
|
// config.url,
|
||||||
config.headers,
|
// config.headers,
|
||||||
config.data
|
// config.data
|
||||||
);
|
// );
|
||||||
|
|
||||||
if (error.response) {
|
// if (error.response) {
|
||||||
logger.error("Response", error.response.status, error.response.data);
|
// logger.error("Response", error.response.status, error.response.data);
|
||||||
} else if (error.request) {
|
// } else if (error.request) {
|
||||||
logger.error("Request", error.request);
|
// logger.error("Request", error.request);
|
||||||
} else {
|
// } else {
|
||||||
logger.error("Error", error.message);
|
// logger.error("Error", error.message);
|
||||||
}
|
// }
|
||||||
|
|
||||||
logger.error(" ----- END RESPONSE ERROR -------");
|
// logger.error(" ----- END RESPONSE ERROR -------");
|
||||||
return Promise.reject(error);
|
// return Promise.reject(error);
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
|
|
||||||
const userAuth = await userAuthRepository.findOne({
|
const userAuth = await userAuthRepository.findOne({
|
||||||
where: { id: 1 },
|
where: { id: 1 },
|
||||||
|
@ -8,11 +8,18 @@ export class RepacksManager {
|
|||||||
private static repacksIndex = new flexSearch.Index();
|
private static repacksIndex = new flexSearch.Index();
|
||||||
|
|
||||||
public static async updateRepacks() {
|
public static async updateRepacks() {
|
||||||
this.repacks = await repackRepository.find({
|
this.repacks = await repackRepository
|
||||||
|
.find({
|
||||||
order: {
|
order: {
|
||||||
createdAt: "DESC",
|
createdAt: "DESC",
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
.then((repacks) =>
|
||||||
|
repacks.map((repack) => ({
|
||||||
|
...repack,
|
||||||
|
uris: JSON.parse(repack.uris),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
for (let i = 0; i < this.repacks.length; i++) {
|
for (let i = 0; i < this.repacks.length; i++) {
|
||||||
this.repacksIndex.remove(i);
|
this.repacksIndex.remove(i);
|
||||||
|
@ -64,6 +64,8 @@ export class WindowManager {
|
|||||||
this.loadURL();
|
this.loadURL();
|
||||||
this.mainWindow.removeMenu();
|
this.mainWindow.removeMenu();
|
||||||
|
|
||||||
|
WindowManager.mainWindow?.webContents.openDevTools();
|
||||||
|
|
||||||
this.mainWindow.on("ready-to-show", () => {
|
this.mainWindow.on("ready-to-show", () => {
|
||||||
if (!app.isPackaged) WindowManager.mainWindow?.webContents.openDevTools();
|
if (!app.isPackaged) WindowManager.mainWindow?.webContents.openDevTools();
|
||||||
WindowManager.mainWindow?.show();
|
WindowManager.mainWindow?.show();
|
||||||
|
@ -22,9 +22,10 @@ export function useDownload() {
|
|||||||
);
|
);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const startDownload = (payload: StartGameDownloadPayload) => {
|
const startDownload = async (payload: StartGameDownloadPayload) => {
|
||||||
dispatch(clearDownload());
|
dispatch(clearDownload());
|
||||||
window.electron.startGameDownload(payload).then((game) => {
|
|
||||||
|
return window.electron.startGameDownload(payload).then((game) => {
|
||||||
updateLibrary();
|
updateLibrary();
|
||||||
|
|
||||||
return game;
|
return game;
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
} from "@renderer/context";
|
} from "@renderer/context";
|
||||||
import { useDownload } from "@renderer/hooks";
|
import { useDownload } from "@renderer/hooks";
|
||||||
import { GameOptionsModal, RepacksModal } from "./modals";
|
import { GameOptionsModal, RepacksModal } from "./modals";
|
||||||
import { Downloader } from "@shared";
|
import { Downloader, getDownloadersForUri } from "@shared";
|
||||||
|
|
||||||
export function GameDetails() {
|
export function GameDetails() {
|
||||||
const [randomGame, setRandomGame] = useState<Steam250Game | null>(null);
|
const [randomGame, setRandomGame] = useState<Steam250Game | null>(null);
|
||||||
@ -70,6 +70,9 @@ export function GameDetails() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectRepackUri = (repack: GameRepack, downloader: Downloader) =>
|
||||||
|
repack.uris.find((uri) => getDownloadersForUri(uri).includes(downloader))!;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GameDetailsContextProvider>
|
<GameDetailsContextProvider>
|
||||||
<GameDetailsContextConsumer>
|
<GameDetailsContextConsumer>
|
||||||
@ -96,6 +99,7 @@ export function GameDetails() {
|
|||||||
downloader,
|
downloader,
|
||||||
shop: shop as GameShop,
|
shop: shop as GameShop,
|
||||||
downloadPath,
|
downloadPath,
|
||||||
|
uri: selectRepackUri(repack, downloader),
|
||||||
});
|
});
|
||||||
|
|
||||||
await updateGame();
|
await updateGame();
|
||||||
|
@ -5,7 +5,7 @@ import { DiskSpace } from "check-disk-space";
|
|||||||
import * as styles from "./download-settings-modal.css";
|
import * as styles from "./download-settings-modal.css";
|
||||||
import { Button, Link, Modal, TextField } from "@renderer/components";
|
import { Button, Link, Modal, TextField } from "@renderer/components";
|
||||||
import { CheckCircleFillIcon, DownloadIcon } from "@primer/octicons-react";
|
import { CheckCircleFillIcon, DownloadIcon } from "@primer/octicons-react";
|
||||||
import { Downloader, formatBytes, getDownloadersForUri } from "@shared";
|
import { Downloader, formatBytes, getDownloadersForUris } from "@shared";
|
||||||
|
|
||||||
import type { GameRepack } from "@types";
|
import type { GameRepack } from "@types";
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||||
@ -48,8 +48,8 @@ export function DownloadSettingsModal({
|
|||||||
}, [visible, selectedPath]);
|
}, [visible, selectedPath]);
|
||||||
|
|
||||||
const downloaders = useMemo(() => {
|
const downloaders = useMemo(() => {
|
||||||
return getDownloadersForUri(repack?.magnet ?? "");
|
return getDownloadersForUris(repack?.uris ?? []);
|
||||||
}, [repack?.magnet]);
|
}, [repack?.uris]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userPreferences?.downloadsPath) {
|
if (userPreferences?.downloadsPath) {
|
||||||
|
@ -76,6 +76,13 @@ export function RepacksModal({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkIfLastDownloadedOption = (repack: GameRepack) => {
|
||||||
|
if (infoHash) return repack.uris.some((uri) => uri.includes(infoHash));
|
||||||
|
if (!game?.uri) return false;
|
||||||
|
|
||||||
|
return repack.uris.some((uri) => uri.includes(game?.uri ?? ""));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DownloadSettingsModal
|
<DownloadSettingsModal
|
||||||
@ -97,9 +104,7 @@ export function RepacksModal({
|
|||||||
|
|
||||||
<div className={styles.repacks}>
|
<div className={styles.repacks}>
|
||||||
{filteredRepacks.map((repack) => {
|
{filteredRepacks.map((repack) => {
|
||||||
const isLastDownloadedOption =
|
const isLastDownloadedOption = checkIfLastDownloadedOption(repack);
|
||||||
infoHash !== null &&
|
|
||||||
repack.magnet.toLowerCase().includes(infoHash);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -42,10 +42,3 @@ export const downloadSourcesHeader = style({
|
|||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const separator = style({
|
|
||||||
height: "100%",
|
|
||||||
width: "1px",
|
|
||||||
backgroundColor: vars.color.border,
|
|
||||||
margin: `${SPACING_UNIT}px 0`,
|
|
||||||
});
|
|
||||||
|
@ -134,15 +134,6 @@ export function SettingsDownloadSources() {
|
|||||||
downloadSource.downloadCount.toLocaleString(),
|
downloadSource.downloadCount.toLocaleString(),
|
||||||
})}
|
})}
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
<div className={styles.separator} />
|
|
||||||
|
|
||||||
<small>
|
|
||||||
{t("download_options", {
|
|
||||||
count: downloadSource.repackCount,
|
|
||||||
countFormatted: downloadSource.repackCount.toLocaleString(),
|
|
||||||
})}
|
|
||||||
</small>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -73,13 +73,26 @@ const realDebridHosts = ["https://1fichier.com", "https://mediafire.com"];
|
|||||||
|
|
||||||
export const getDownloadersForUri = (uri: string) => {
|
export const getDownloadersForUri = (uri: string) => {
|
||||||
if (uri.startsWith("https://gofile.io")) return [Downloader.Gofile];
|
if (uri.startsWith("https://gofile.io")) return [Downloader.Gofile];
|
||||||
|
|
||||||
if (uri.startsWith("https://pixeldrain.com")) return [Downloader.PixelDrain];
|
if (uri.startsWith("https://pixeldrain.com")) return [Downloader.PixelDrain];
|
||||||
|
|
||||||
if (realDebridHosts.some((host) => uri.startsWith(host)))
|
if (realDebridHosts.some((host) => uri.startsWith(host)))
|
||||||
return [Downloader.RealDebrid];
|
return [Downloader.RealDebrid];
|
||||||
|
|
||||||
if (uri.startsWith("magnet:"))
|
if (uri.startsWith("magnet:")) {
|
||||||
return [Downloader.Torrent, Downloader.RealDebrid];
|
return [Downloader.Torrent, Downloader.RealDebrid];
|
||||||
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDownloadersForUris = (uris: string[]) => {
|
||||||
|
const downloadersSet = uris.reduce<Set<Downloader>>((prev, next) => {
|
||||||
|
const downloaders = getDownloadersForUri(next);
|
||||||
|
downloaders.forEach((downloader) => prev.add(downloader));
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
}, new Set());
|
||||||
|
|
||||||
|
return Array.from(downloadersSet);
|
||||||
|
};
|
||||||
|
@ -67,7 +67,11 @@ export interface SteamAppDetails {
|
|||||||
export interface GameRepack {
|
export interface GameRepack {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
/**
|
||||||
|
* @deprecated Use uris instead
|
||||||
|
*/
|
||||||
magnet: string;
|
magnet: string;
|
||||||
|
uris: string[];
|
||||||
repacker: string;
|
repacker: string;
|
||||||
fileSize: string | null;
|
fileSize: string | null;
|
||||||
uploadDate: Date | string | null;
|
uploadDate: Date | string | null;
|
||||||
@ -194,6 +198,7 @@ export interface StartGameDownloadPayload {
|
|||||||
objectID: string;
|
objectID: string;
|
||||||
title: string;
|
title: string;
|
||||||
shop: GameShop;
|
shop: GameShop;
|
||||||
|
uri: string;
|
||||||
downloadPath: string;
|
downloadPath: string;
|
||||||
downloader: Downloader;
|
downloader: Downloader;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user