Skip to content

Commit

Permalink
Merge pull request #901 from hydralauncher/fix/http-downloads-duplicate
Browse files Browse the repository at this point in the history
feat: reducing http downloads duplicate
  • Loading branch information
thegrannychaseroperation authored Aug 20, 2024
2 parents 3a3b7b9 + c1bd1d3 commit aaf20b2
Show file tree
Hide file tree
Showing 28 changed files with 252 additions and 292 deletions.
9 changes: 3 additions & 6 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,9 @@
"validate_download_source": "Validate",
"remove_download_source": "Remove",
"add_download_source": "Add source",
"download_count_zero": "No downloads in list",
"download_count_one": "{{countFormatted}} download in list",
"download_count_other": "{{countFormatted}} downloads in list",
"download_options_zero": "No download available",
"download_options_one": "{{countFormatted}} download available",
"download_options_other": "{{countFormatted}} downloads available",
"download_count_zero": "No download options",
"download_count_one": "{{countFormatted}} download option",
"download_count_other": "{{countFormatted}} download options",
"download_source_url": "Download source URL",
"add_download_source_description": "Insert the URL containing the .json file",
"download_source_up_to_date": "Up-to-date",
Expand Down
2 changes: 1 addition & 1 deletion src/main/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import {
GameShopCache,
Repack,
UserPreferences,
UserAuth,
} from "@main/entity";
import type { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";

import { databasePath } from "./constants";
import migrations from "./migrations";
import { UserAuth } from "./entity/user-auth";

export const createDataSource = (
options: Partial<BetterSqlite3ConnectionOptions>
Expand Down
8 changes: 7 additions & 1 deletion src/main/entity/repack.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ export class Repack {
@Column("text", { unique: true })
title: string;

/**
* @deprecated Use uris instead
*/
@Column("text", { unique: true })
magnet: string;

/**
* @deprecated
* @deprecated Direct scraping capability has been removed
*/
@Column("int", { nullable: true })
page: number;
Expand All @@ -37,6 +40,9 @@ export class Repack {
@ManyToOne(() => DownloadSource, { nullable: true, onDelete: "CASCADE" })
downloadSource: DownloadSource;

@Column("text", { default: "[]" })
uris: string;

@CreateDateColumn()
createdAt: Date;

Expand Down
17 changes: 6 additions & 11 deletions src/main/events/download-sources/get-download-sources.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { downloadSourceRepository } from "@main/repository";
import { registerEvent } from "../register-event";

const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) => {
return downloadSourceRepository
.createQueryBuilder("downloadSource")
.leftJoin("downloadSource.repacks", "repacks")
.orderBy("downloadSource.createdAt", "DESC")
.loadRelationCountAndMap(
"downloadSource.repackCount",
"downloadSource.repacks"
)
.getMany();
};
const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) =>
downloadSourceRepository.find({
order: {
createdAt: "DESC",
},
});

registerEvent("getDownloadSources", getDownloadSources);
8 changes: 5 additions & 3 deletions src/main/events/torrenting/start-game-download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ const startGameDownload = async (
_event: Electron.IpcMainInvokeEvent,
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([
gameRepository.findOne({
Expand Down Expand Up @@ -54,7 +55,7 @@ const startGameDownload = async (
bytesDownloaded: 0,
downloadPath,
downloader,
uri: repack.magnet,
uri,
isDeleted: false,
}
);
Expand All @@ -76,7 +77,7 @@ const startGameDownload = async (
shop,
status: "active",
downloadPath,
uri: repack.magnet,
uri,
})
.then((result) => {
if (iconUrl) {
Expand All @@ -100,6 +101,7 @@ const startGameDownload = async (
await downloadQueueRepository.delete({ game: { id: updatedGame!.id } });
await downloadQueueRepository.insert({ game: { id: updatedGame!.id } });

await DownloadManager.cancelDownload(updatedGame!.id);
await DownloadManager.startDownload(updatedGame!);
};

Expand Down
3 changes: 2 additions & 1 deletion src/main/helpers/download-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export const insertDownloadsFromSource = async (
const repacks: QueryDeepPartialEntity<Repack>[] = downloads.map(
(download) => ({
title: download.title,
magnet: download.uris[0],
uris: JSON.stringify(download.uris),
magnet: download.uris[0]!,
fileSize: download.fileSize,
repacker: downloadSource.name,
uploadDate: download.uploadDate,
Expand Down
6 changes: 5 additions & 1 deletion src/main/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from "axios";
import { JSDOM } from "jsdom";
import UserAgent from "user-agents";

export const getSteamAppAsset = (
Expand Down Expand Up @@ -48,13 +49,16 @@ export const sleep = (ms: number) =>
export const requestWebPage = async (url: string) => {
const userAgent = new UserAgent();

return axios
const data = await axios
.get(url, {
headers: {
"User-Agent": userAgent.toString(),
},
})
.then((response) => response.data);

const { window } = new JSDOM(data);
return window.document;
};

export const isPortableVersion = () =>
Expand Down
3 changes: 0 additions & 3 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ autoUpdater.setFeedURL({

autoUpdater.logger = logger;

logger.log("Init Hydra");

const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) app.quit();

Expand Down Expand Up @@ -123,7 +121,6 @@ app.on("window-all-closed", () => {
app.on("before-quit", () => {
/* Disconnects libtorrent */
PythonInstance.kill();
logger.log("Quit Hydra");
});

app.on("activate", () => {
Expand Down
58 changes: 35 additions & 23 deletions src/main/services/download/download-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { downloadQueueRepository, gameRepository } from "@main/repository";
import { publishDownloadCompleteNotification } from "../notifications";
import { RealDebridDownloader } from "./real-debrid-downloader";
import type { DownloadProgress } from "@types";
import { GofileApi } from "../hosters";
import { GenericHTTPDownloader } from "./generic-http-downloader";
import { GofileApi, QiwiApi } from "../hosters";
import { GenericHttpDownloader } from "./generic-http-downloader";

export class DownloadManager {
private static currentDownloader: Downloader | null = null;
Expand All @@ -20,7 +20,7 @@ export class DownloadManager {
} else if (this.currentDownloader === Downloader.RealDebrid) {
status = await RealDebridDownloader.getStatus();
} else {
status = await GenericHTTPDownloader.getStatus();
status = await GenericHttpDownloader.getStatus();
}

if (status) {
Expand Down Expand Up @@ -71,7 +71,7 @@ export class DownloadManager {
} else if (this.currentDownloader === Downloader.RealDebrid) {
await RealDebridDownloader.pauseDownload();
} else {
await GenericHTTPDownloader.pauseDownload();
await GenericHttpDownloader.pauseDownload();
}

WindowManager.mainWindow?.setProgressBar(-1);
Expand All @@ -88,34 +88,46 @@ export class DownloadManager {
} else if (this.currentDownloader === Downloader.RealDebrid) {
RealDebridDownloader.cancelDownload(gameId);
} else {
GenericHTTPDownloader.cancelDownload(gameId);
GenericHttpDownloader.cancelDownload(gameId);
}

WindowManager.mainWindow?.setProgressBar(-1);
this.currentDownloader = null;
}

static async startDownload(game: Game) {
if (game.downloader === Downloader.Gofile) {
const id = game!.uri!.split("/").pop();
switch (game.downloader) {
case Downloader.Gofile: {
const id = game!.uri!.split("/").pop();

const token = await GofileApi.authorize();
const downloadLink = await GofileApi.getDownloadLink(id!);
const token = await GofileApi.authorize();
const downloadLink = await GofileApi.getDownloadLink(id!);

GenericHTTPDownloader.startDownload(game, downloadLink, {
Cookie: `accountToken=${token}`,
});
} else if (game.downloader === Downloader.PixelDrain) {
const id = game!.uri!.split("/").pop();

await GenericHTTPDownloader.startDownload(
game,
`https://pixeldrain.com/api/file/${id}?download`
);
} else if (game.downloader === Downloader.Torrent) {
PythonInstance.startDownload(game);
} else if (game.downloader === Downloader.RealDebrid) {
RealDebridDownloader.startDownload(game);
GenericHttpDownloader.startDownload(game, downloadLink, {
Cookie: `accountToken=${token}`,
});
break;
}
case Downloader.PixelDrain: {
const id = game!.uri!.split("/").pop();

await GenericHttpDownloader.startDownload(
game,
`https://pixeldrain.com/api/file/${id}?download`
);
break;
}
case Downloader.Qiwi: {
const downloadUrl = await QiwiApi.getDownloadUrl(game.uri!);

await GenericHttpDownloader.startDownload(game, downloadUrl);
break;
}
case Downloader.Torrent:
PythonInstance.startDownload(game);
break;
case Downloader.RealDebrid:
RealDebridDownloader.startDownload(game);
}

this.currentDownloader = game.downloader;
Expand Down
34 changes: 18 additions & 16 deletions src/main/services/download/generic-http-downloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { calculateETA } from "./helpers";
import { DownloadProgress } from "@types";
import { HttpDownload } from "./http-download";

export class GenericHTTPDownloader {
private static downloads = new Map<number, string>();
private static downloadingGame: Game | null = null;
export class GenericHttpDownloader {
public static downloads = new Map<number, HttpDownload>();
public static downloadingGame: Game | null = null;

public static async getStatus() {
if (this.downloadingGame) {
const gid = this.downloads.get(this.downloadingGame.id)!;
const status = HttpDownload.getStatus(gid);
const download = this.downloads.get(this.downloadingGame.id)!;
const status = download.getStatus();

if (status) {
const progress =
Expand Down Expand Up @@ -57,10 +57,10 @@ export class GenericHTTPDownloader {

static async pauseDownload() {
if (this.downloadingGame) {
const gid = this.downloads.get(this.downloadingGame!.id!);
const httpDownload = this.downloads.get(this.downloadingGame!.id!);

if (gid) {
await HttpDownload.pauseDownload(gid);
if (httpDownload) {
await httpDownload.pauseDownload();
}

this.downloadingGame = null;
Expand All @@ -79,29 +79,31 @@ export class GenericHTTPDownloader {
return;
}

const gid = await HttpDownload.startDownload(
const httpDownload = new HttpDownload(
game.downloadPath!,
downloadUrl,
headers
);

this.downloads.set(game.id!, gid);
httpDownload.startDownload();

this.downloads.set(game.id!, httpDownload);
}

static async cancelDownload(gameId: number) {
const gid = this.downloads.get(gameId);
const httpDownload = this.downloads.get(gameId);

if (gid) {
await HttpDownload.cancelDownload(gid);
if (httpDownload) {
await httpDownload.cancelDownload();
this.downloads.delete(gameId);
}
}

static async resumeDownload(gameId: number) {
const gid = this.downloads.get(gameId);
const httpDownload = this.downloads.get(gameId);

if (gid) {
await HttpDownload.resumeDownload(gid);
if (httpDownload) {
await httpDownload.resumeDownload();
}
}
}
Loading

0 comments on commit aaf20b2

Please sign in to comment.