mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-27 12:51:03 +00:00
fix: fixing seeding on level
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { DownloadManager, HydraApi, gamesPlaytime } from "@main/services";
|
||||
import { PythonRPC } from "@main/services/python-rpc";
|
||||
import { db, downloadsSublevel, gamesSublevel, levelKeys } from "@main/level";
|
||||
|
||||
const signOut = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
@@ -25,9 +24,6 @@ const signOut = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
/* Cancels any ongoing downloads */
|
||||
DownloadManager.cancelDownload();
|
||||
|
||||
/* Disconnects libtorrent */
|
||||
PythonRPC.kill();
|
||||
|
||||
HydraApi.handleSignOut();
|
||||
|
||||
await Promise.all([
|
||||
|
||||
@@ -46,6 +46,7 @@ import "./user-preferences/auto-launch";
|
||||
import "./autoupdater/check-for-updates";
|
||||
import "./autoupdater/restart-and-install-update";
|
||||
import "./user-preferences/authenticate-real-debrid";
|
||||
import "./user-preferences/authenticate-torbox";
|
||||
import "./download-sources/put-download-source";
|
||||
import "./auth/sign-out";
|
||||
import "./auth/open-auth-window";
|
||||
|
||||
@@ -46,9 +46,9 @@ const addGameToLibrary = async (
|
||||
|
||||
await gamesSublevel.put(levelKeys.game(shop, objectId), game);
|
||||
|
||||
updateLocalUnlockedAchivements(game!);
|
||||
updateLocalUnlockedAchivements(game);
|
||||
|
||||
createGame(game!).catch(() => {});
|
||||
createGame(game).catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -76,10 +76,10 @@ const startGameDownload = async (
|
||||
queued: true,
|
||||
};
|
||||
|
||||
await downloadsSublevel.put(gameKey, download);
|
||||
|
||||
try {
|
||||
await DownloadManager.startDownload(download);
|
||||
await DownloadManager.startDownload(download).then(() => {
|
||||
return downloadsSublevel.put(gameKey, download);
|
||||
});
|
||||
|
||||
const updatedGame = await gamesSublevel.get(gameKey);
|
||||
|
||||
@@ -113,6 +113,10 @@ const startGameDownload = async (
|
||||
error: DownloadError.RealDebridAccountNotAuthorized,
|
||||
};
|
||||
}
|
||||
|
||||
if (downloader === Downloader.TorBox) {
|
||||
return { ok: false, error: err.response?.data?.detail };
|
||||
}
|
||||
}
|
||||
|
||||
if (err instanceof Error) {
|
||||
|
||||
14
src/main/events/user-preferences/authenticate-torbox.ts
Normal file
14
src/main/events/user-preferences/authenticate-torbox.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { TorBoxClient } from "@main/services/download/torbox";
|
||||
|
||||
const authenticateTorBox = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
apiToken: string
|
||||
) => {
|
||||
TorBoxClient.authorize(apiToken);
|
||||
|
||||
const user = await TorBoxClient.getUser();
|
||||
return user;
|
||||
};
|
||||
|
||||
registerEvent("authenticateTorBox", authenticateTorBox);
|
||||
@@ -15,6 +15,12 @@ const getUserPreferences = async () =>
|
||||
);
|
||||
}
|
||||
|
||||
if (userPreferences?.torBoxApiToken) {
|
||||
userPreferences.torBoxApiToken = Crypto.decrypt(
|
||||
userPreferences.torBoxApiToken
|
||||
);
|
||||
}
|
||||
|
||||
return userPreferences;
|
||||
});
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ const updateUserPreferences = async (
|
||||
);
|
||||
}
|
||||
|
||||
if (preferences.torBoxApiToken) {
|
||||
preferences.torBoxApiToken = Crypto.encrypt(preferences.torBoxApiToken);
|
||||
}
|
||||
|
||||
if (!preferences.downloadsPath) {
|
||||
preferences.downloadsPath = null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { db } from "./level";
|
||||
|
||||
export * from "./sublevels";
|
||||
|
||||
@@ -2,5 +2,4 @@ export * from "./downloads";
|
||||
export * from "./games";
|
||||
export * from "./game-shop-cache";
|
||||
export * from "./game-achievements";
|
||||
|
||||
export * from "./keys";
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from "./level";
|
||||
import { Auth, User, type UserPreferences } from "@types";
|
||||
import { knexClient } from "./knex-client";
|
||||
import { TorBoxClient } from "./services/download/torbox";
|
||||
|
||||
export const loadState = async () => {
|
||||
const userPreferences = await migrateFromSqlite().then(async () => {
|
||||
@@ -42,6 +43,10 @@ export const loadState = async () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (userPreferences?.torBoxApiToken) {
|
||||
TorBoxClient.authorize(Crypto.decrypt(userPreferences.torBoxApiToken));
|
||||
}
|
||||
|
||||
Ludusavi.addManifestToLudusaviConfig();
|
||||
|
||||
HydraApi.setupApi().then(() => {
|
||||
|
||||
@@ -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;
|
||||
@@ -233,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;
|
||||
}
|
||||
}
|
||||
@@ -275,6 +278,7 @@ export class DownloadManager {
|
||||
}
|
||||
case Downloader.PixelDrain: {
|
||||
const id = download.uri.split("/").pop();
|
||||
|
||||
return {
|
||||
action: "start",
|
||||
game_id: downloadId,
|
||||
@@ -329,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 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user