diff --git a/src/globals.ts b/src/globals.ts index 2625e7f7..3ce216a8 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -21,6 +21,5 @@ export namespace GameStatus { GameStatus.Decompressing == status; export const isReady = (status: GameStatus | null) => - status === GameStatus.Finished || - status === GameStatus.Seeding; -} \ No newline at end of file + status === GameStatus.Finished || status === GameStatus.Seeding; +} diff --git a/src/main/entity/game.entity.ts b/src/main/entity/game.entity.ts index c3621d5d..51e976fa 100644 --- a/src/main/entity/game.entity.ts +++ b/src/main/entity/game.entity.ts @@ -46,9 +46,9 @@ export class Game { @Column("text", { nullable: true }) status: GameStatus | null; - /** + /** * Progress is a float between 0 and 1 - */ + */ @Column("float", { default: 0 }) progress: number; diff --git a/src/main/entity/user-preferences.entity.ts b/src/main/entity/user-preferences.entity.ts index 8cb06aa5..eb220468 100644 --- a/src/main/entity/user-preferences.entity.ts +++ b/src/main/entity/user-preferences.entity.ts @@ -35,4 +35,3 @@ export class UserPreferences { @UpdateDateColumn() updatedAt: Date; } - diff --git a/src/main/events/torrenting/cancel-game-download.ts b/src/main/events/torrenting/cancel-game-download.ts index af8ae89f..39772e21 100644 --- a/src/main/events/torrenting/cancel-game-download.ts +++ b/src/main/events/torrenting/cancel-game-download.ts @@ -45,7 +45,7 @@ const cancelGameDownload = async ( game.status !== GameStatus.Seeding ) { Downloader.cancelDownload(); - if (result.affected) WindowManager.mainWindow.setProgressBar(-1); + if (result.affected) WindowManager.mainWindow?.setProgressBar(-1); } }); }; diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index f6125c8a..8ae520d5 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -1,4 +1,4 @@ -import { getSteamGameIconUrl, writePipe } from "@main/services"; +import { getSteamGameIconUrl } from "@main/services"; import { gameRepository, repackRepository } from "@main/repository"; import { registerEvent } from "../register-event"; diff --git a/src/main/index.ts b/src/main/index.ts index b2a1b227..a146b6f7 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -106,4 +106,4 @@ app.on("activate", () => { }); // In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and import them here. \ No newline at end of file +// code. You can also put them in separate files and import them here. diff --git a/src/main/main.ts b/src/main/main.ts index be5a82b5..309d6272 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -123,4 +123,4 @@ const loadState = async () => { import("./events"); }; -loadState().then(() => checkForNewRepacks()); \ No newline at end of file +loadState().then(() => checkForNewRepacks()); diff --git a/src/main/services/donwloaders/downloader.ts b/src/main/services/donwloaders/downloader.ts index c5f29fae..c13d4d01 100644 --- a/src/main/services/donwloaders/downloader.ts +++ b/src/main/services/donwloaders/downloader.ts @@ -10,139 +10,168 @@ import { TorrentUpdate } from "./torrent-client"; import { HTTPDownloader } from "./http-downloader"; import { Unrar } from "../unrar"; import { GameStatus } from "@globals"; -import path from 'node:path'; +import path from "node:path"; interface DownloadStatus { - numPeers: number; - numSeeds: number; - downloadSpeed: number; - timeRemaining: number; + numPeers: number; + numSeeds: number; + downloadSpeed: number; + timeRemaining: number; } export class Downloader { - private static lastHttpDownloader: HTTPDownloader | null = null; + private static lastHttpDownloader: HTTPDownloader | null = null; - static async usesRealDebrid() { - const userPreferences = await userPreferencesRepository.findOne({ where: { id: 1 } }); - return userPreferences!.realDebridApiToken !== null; + static async usesRealDebrid() { + const userPreferences = await userPreferencesRepository.findOne({ + where: { id: 1 }, + }); + return userPreferences!.realDebridApiToken !== null; + } + + static async cancelDownload() { + if (!(await this.usesRealDebrid())) { + writePipe.write({ action: "cancel" }); + } else { + if (this.lastHttpDownloader) { + this.lastHttpDownloader.cancel(); + } + } + } + + static async pauseDownload() { + if (!(await this.usesRealDebrid())) { + writePipe.write({ action: "pause" }); + } else { + if (this.lastHttpDownloader) { + this.lastHttpDownloader.pause(); + } + } + } + + static async resumeDownload() { + if (!(await this.usesRealDebrid())) { + writePipe.write({ action: "pause" }); + } else { + if (this.lastHttpDownloader) { + this.lastHttpDownloader.resume(); + } + } + } + + static async downloadGame(game: Game, repack: Repack) { + if (!(await this.usesRealDebrid())) { + writePipe.write({ + action: "start", + game_id: game.id, + magnet: repack.magnet, + save_path: game.downloadPath, + }); + } else { + try { + const torrent = await RealDebridClient.addMagnet(repack.magnet); + if (torrent && torrent.id) { + await RealDebridClient.selectAllFiles(torrent.id); + const { links } = await RealDebridClient.getInfo(torrent.id); + const { download } = await RealDebridClient.unrestrictLink(links[0]); + this.lastHttpDownloader = new HTTPDownloader(); + this.lastHttpDownloader.download( + download, + game.downloadPath!, + game.id + ); + } + } catch (e) { + console.error(e); + } + } + } + + static async updateGameProgress( + gameId: number, + gameUpdate: QueryDeepPartialEntity, + downloadStatus: DownloadStatus + ) { + await gameRepository.update({ id: gameId }, gameUpdate); + + const game = await gameRepository.findOne({ + where: { id: gameId }, + relations: { repack: true }, + }); + + if ( + gameUpdate.progress === 1 && + gameUpdate.status !== GameStatus.Decompressing + ) { + const userPreferences = await userPreferencesRepository.findOne({ + where: { id: 1 }, + }); + + if (userPreferences?.downloadNotificationsEnabled) { + new Notification({ + title: t("download_complete", { + ns: "notifications", + lng: userPreferences.language, + }), + body: t("game_ready_to_install", { + ns: "notifications", + lng: userPreferences.language, + title: game?.title, + }), + }).show(); + } } - static async cancelDownload() { - if (!await this.usesRealDebrid()) { - writePipe.write({ action: "cancel" }); - } else { - if (this.lastHttpDownloader) { - this.lastHttpDownloader.cancel(); - } - } + if ( + game && + gameUpdate.decompressionProgress === 0 && + gameUpdate.status === GameStatus.Decompressing + ) { + const unrar = await Unrar.fromFilePath( + game.rarPath!, + path.join(game.downloadPath!, game.folderName!) + ); + unrar.extract(); + this.updateGameProgress( + gameId, + { + decompressionProgress: 1, + status: GameStatus.Finished, + }, + downloadStatus + ); } - static async pauseDownload() { - if (!await this.usesRealDebrid()) { - writePipe.write({ action: "pause" }); - } else { - if (this.lastHttpDownloader) { - this.lastHttpDownloader.pause(); - } - } + if (WindowManager.mainWindow && game) { + const progress = this.getGameProgress(game); + WindowManager.mainWindow.setProgressBar(progress === 1 ? -1 : progress); + + WindowManager.mainWindow.webContents.send( + "on-download-progress", + JSON.parse( + JSON.stringify({ + ...({ + progress: gameUpdate.progress, + bytesDownloaded: gameUpdate.bytesDownloaded, + fileSize: gameUpdate.fileSize, + gameId, + numPeers: downloadStatus.numPeers, + numSeeds: downloadStatus.numSeeds, + downloadSpeed: downloadStatus.downloadSpeed, + timeRemaining: downloadStatus.timeRemaining, + } as TorrentUpdate), + game, + }) + ) + ); } + } - static async resumeDownload() { - if (!await this.usesRealDebrid()) { - writePipe.write({ action: "pause" }); - } else { - if (this.lastHttpDownloader) { - this.lastHttpDownloader.resume(); - } - } - } - - static async downloadGame(game: Game, repack: Repack) { - if (!await this.usesRealDebrid()) { - writePipe.write({ - action: "start", - game_id: game.id, - magnet: repack.magnet, - save_path: game.downloadPath, - }); - } else { - try { - const torrent = await RealDebridClient.addMagnet(repack.magnet); - if (torrent && torrent.id) { - await RealDebridClient.selectAllFiles(torrent.id); - const { links } = await RealDebridClient.getInfo(torrent.id); - const { download } = await RealDebridClient.unrestrictLink(links[0]); - this.lastHttpDownloader = new HTTPDownloader(); - this.lastHttpDownloader.download(download, game.downloadPath!, game.id); - } - } catch (e) { - console.error(e); - } - } - } - - static async updateGameProgress(gameId: number, gameUpdate: QueryDeepPartialEntity, downloadStatus: DownloadStatus) { - await gameRepository.update({ id: gameId }, gameUpdate); - - const game = await gameRepository.findOne({ - where: { id: gameId }, - relations: { repack: true }, - }); - - if (gameUpdate.progress === 1 && gameUpdate.status !== GameStatus.Decompressing) { - const userPreferences = await userPreferencesRepository.findOne({ - where: { id: 1 }, - }); - - if (userPreferences?.downloadNotificationsEnabled) { - new Notification({ - title: t("download_complete", { - ns: "notifications", - lng: userPreferences.language, - }), - body: t("game_ready_to_install", { - ns: "notifications", - lng: userPreferences.language, - title: game?.title, - }), - }).show(); - } - } - - if (game && gameUpdate.decompressionProgress === 0 && gameUpdate.status === GameStatus.Decompressing) { - const unrar = await Unrar.fromFilePath(game.rarPath!, path.join(game.downloadPath!, game.folderName!)); - unrar.extract(); - this.updateGameProgress(gameId, { - decompressionProgress: 1, - status: GameStatus.Finished, - }, downloadStatus); - } - - if (WindowManager.mainWindow && game) { - const progress = this.getGameProgress(game); - WindowManager.mainWindow.setProgressBar(progress === 1 ? -1 : progress); - - WindowManager.mainWindow.webContents.send( - "on-download-progress", - JSON.parse(JSON.stringify({ - ...{ - progress: gameUpdate.progress, - bytesDownloaded: gameUpdate.bytesDownloaded, - fileSize: gameUpdate.fileSize, - gameId, - numPeers: downloadStatus.numPeers, - numSeeds: downloadStatus.numSeeds, - downloadSpeed: downloadStatus.downloadSpeed, - timeRemaining: downloadStatus.timeRemaining, - } as TorrentUpdate, game - })) - ); - } - } - - static getGameProgress(game: Game) { - if (game.status === GameStatus.CheckingFiles) return game.fileVerificationProgress; - if (game.status === GameStatus.Decompressing) return game.decompressionProgress; - return game.progress; - } -} \ No newline at end of file + static getGameProgress(game: Game) { + if (game.status === GameStatus.CheckingFiles) + return game.fileVerificationProgress; + if (game.status === GameStatus.Decompressing) + return game.decompressionProgress; + return game.progress; + } +} diff --git a/src/main/services/donwloaders/http-downloader.ts b/src/main/services/donwloaders/http-downloader.ts index 01c3218f..c94a5755 100644 --- a/src/main/services/donwloaders/http-downloader.ts +++ b/src/main/services/donwloaders/http-downloader.ts @@ -1,94 +1,106 @@ -import { Game } from '@main/entity'; -import { ElectronDownloadManager } from 'electron-dl-manager'; -import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import { WindowManager } from '../window-manager'; -import { Downloader } from './downloader'; -import { GameStatus } from '@globals'; +import { Game } from "@main/entity"; +import { ElectronDownloadManager } from "electron-dl-manager"; +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; +import { WindowManager } from "../window-manager"; +import { Downloader } from "./downloader"; +import { GameStatus } from "@globals"; function dropExtension(fileName: string) { - return fileName.split('.').slice(0, -1).join('.'); + return fileName.split(".").slice(0, -1).join("."); } export class HTTPDownloader { - private downloadManager: ElectronDownloadManager; - private downloadId: string | null = null; - - constructor() { - this.downloadManager = new ElectronDownloadManager(); - } - - async download(url: string, destination: string, gameId: number) { - const window = WindowManager.mainWindow; + private downloadManager: ElectronDownloadManager; + private downloadId: string | null = null; - this.downloadId = await this.downloadManager.download({ - url, - window: window!, - callbacks: { - onDownloadStarted: async (ev) => { - const updatePayload: QueryDeepPartialEntity = { - status: GameStatus.Downloading, - progress: 0, - bytesDownloaded: 0, - fileSize: ev.item.getTotalBytes(), - rarPath: `${destination}/.rd/${ev.resolvedFilename}`, - folderName: dropExtension(ev.resolvedFilename) - }; - const downloadStatus = { - numPeers: 0, - numSeeds: 0, - downloadSpeed: 0, - timeRemaining: Number.POSITIVE_INFINITY, - }; - await Downloader.updateGameProgress(gameId, updatePayload, downloadStatus); - }, - onDownloadCompleted: async (ev) => { - const updatePayload: QueryDeepPartialEntity = { - progress: 1, - decompressionProgress: 0, - bytesDownloaded: ev.item.getReceivedBytes(), - status: GameStatus.Decompressing, - }; - const downloadStatus = { - numPeers: 1, - numSeeds: 1, - downloadSpeed: 0, - timeRemaining: 0, - }; - await Downloader.updateGameProgress(gameId, updatePayload, downloadStatus); - }, - onDownloadProgress: async (ev) => { - const updatePayload: QueryDeepPartialEntity = { - progress: ev.percentCompleted / 100, - bytesDownloaded: ev.item.getReceivedBytes(), - }; - const downloadStatus = { - numPeers: 1, - numSeeds: 1, - downloadSpeed: ev.downloadRateBytesPerSecond, - timeRemaining: ev.estimatedTimeRemainingSeconds, - }; - await Downloader.updateGameProgress(gameId, updatePayload, downloadStatus); - } - }, - directory: `${destination}/.rd/`, - }); - } + constructor() { + this.downloadManager = new ElectronDownloadManager(); + } - pause() { - if (this.downloadId) { - this.downloadManager.pauseDownload(this.downloadId); - } - } + async download(url: string, destination: string, gameId: number) { + const window = WindowManager.mainWindow; - cancel() { - if (this.downloadId) { - this.downloadManager.cancelDownload(this.downloadId); - } - } + this.downloadId = await this.downloadManager.download({ + url, + window: window!, + callbacks: { + onDownloadStarted: async (ev) => { + const updatePayload: QueryDeepPartialEntity = { + status: GameStatus.Downloading, + progress: 0, + bytesDownloaded: 0, + fileSize: ev.item.getTotalBytes(), + rarPath: `${destination}/.rd/${ev.resolvedFilename}`, + folderName: dropExtension(ev.resolvedFilename), + }; + const downloadStatus = { + numPeers: 0, + numSeeds: 0, + downloadSpeed: 0, + timeRemaining: Number.POSITIVE_INFINITY, + }; + await Downloader.updateGameProgress( + gameId, + updatePayload, + downloadStatus + ); + }, + onDownloadCompleted: async (ev) => { + const updatePayload: QueryDeepPartialEntity = { + progress: 1, + decompressionProgress: 0, + bytesDownloaded: ev.item.getReceivedBytes(), + status: GameStatus.Decompressing, + }; + const downloadStatus = { + numPeers: 1, + numSeeds: 1, + downloadSpeed: 0, + timeRemaining: 0, + }; + await Downloader.updateGameProgress( + gameId, + updatePayload, + downloadStatus + ); + }, + onDownloadProgress: async (ev) => { + const updatePayload: QueryDeepPartialEntity = { + progress: ev.percentCompleted / 100, + bytesDownloaded: ev.item.getReceivedBytes(), + }; + const downloadStatus = { + numPeers: 1, + numSeeds: 1, + downloadSpeed: ev.downloadRateBytesPerSecond, + timeRemaining: ev.estimatedTimeRemainingSeconds, + }; + await Downloader.updateGameProgress( + gameId, + updatePayload, + downloadStatus + ); + }, + }, + directory: `${destination}/.rd/`, + }); + } - resume() { - if (this.downloadId) { - this.downloadManager.resumeDownload(this.downloadId); - } + pause() { + if (this.downloadId) { + this.downloadManager.pauseDownload(this.downloadId); } -} \ No newline at end of file + } + + cancel() { + if (this.downloadId) { + this.downloadManager.cancelDownload(this.downloadId); + } + } + + resume() { + if (this.downloadId) { + this.downloadManager.resumeDownload(this.downloadId); + } + } +} diff --git a/src/main/services/donwloaders/real-debrid-types.ts b/src/main/services/donwloaders/real-debrid-types.ts index 10a87e60..6a3e7304 100644 --- a/src/main/services/donwloaders/real-debrid-types.ts +++ b/src/main/services/donwloaders/real-debrid-types.ts @@ -1,53 +1,53 @@ export interface RealDebridUnrestrictLink { - id: string; - filename: string; - mimeType: string; - filesize: number; - link: string; - host: string; - host_icon: string; - chunks: number; - crc: number; - download: string; - streamable: number; + id: string; + filename: string; + mimeType: string; + filesize: number; + link: string; + host: string; + host_icon: string; + chunks: number; + crc: number; + download: string; + streamable: number; } export interface RealDebridAddMagnet { - "id": string, - // URL of the created ressource - "uri": string + id: string; + // URL of the created ressource + uri: string; } export interface RealDebridTorrentInfo { - "id": string, - "filename": string, - "original_filename": string, // Original name of the torrent - "hash": string, // SHA1 Hash of the torrent - "bytes": number, // Size of selected files only - "original_bytes": number, // Total size of the torrent - "host": string, // Host main domain - "split": number, // Split size of links - "progress": number, // Possible values: 0 to 100 - "status": "downloaded", // Current status of the torrent: magnet_error, magnet_conversion, waiting_files_selection, queued, downloading, downloaded, error, virus, compressing, uploading, dead - "added": string, // jsonDate - "files": [ - { - "id": number, - "path": string, // Path to the file inside the torrent, starting with "/" - "bytes": number, - "selected": number // 0 or 1 - }, - { - "id": number, - "path": string, // Path to the file inside the torrent, starting with "/" - "bytes": number, - "selected": number // 0 or 1 - } - ], - "links": [ - "string" // Host URL - ], - "ended": string, // !! Only present when finished, jsonDate - "speed": number, // !! Only present in "downloading", "compressing", "uploading" status - "seeders": number // !! Only present in "downloading", "magnet_conversion" status -} \ No newline at end of file + id: string; + filename: string; + original_filename: string; // Original name of the torrent + hash: string; // SHA1 Hash of the torrent + bytes: number; // Size of selected files only + original_bytes: number; // Total size of the torrent + host: string; // Host main domain + split: number; // Split size of links + progress: number; // Possible values: 0 to 100 + status: "downloaded"; // Current status of the torrent: magnet_error, magnet_conversion, waiting_files_selection, queued, downloading, downloaded, error, virus, compressing, uploading, dead + added: string; // jsonDate + files: [ + { + id: number; + path: string; // Path to the file inside the torrent, starting with "/" + bytes: number; + selected: number; // 0 or 1 + }, + { + id: number; + path: string; // Path to the file inside the torrent, starting with "/" + bytes: number; + selected: number; // 0 or 1 + }, + ]; + links: [ + "string", // Host URL + ]; + ended: string; // !! Only present when finished, jsonDate + speed: number; // !! Only present in "downloading", "compressing", "uploading" status + seeders: number; // !! Only present in "downloading", "magnet_conversion" status +} diff --git a/src/main/services/donwloaders/real-debrid.ts b/src/main/services/donwloaders/real-debrid.ts index e01cb3cf..9fb170a9 100644 --- a/src/main/services/donwloaders/real-debrid.ts +++ b/src/main/services/donwloaders/real-debrid.ts @@ -1,55 +1,61 @@ import { userPreferencesRepository } from "@main/repository"; import fetch from "node-fetch"; -import { RealDebridAddMagnet, RealDebridTorrentInfo, RealDebridUnrestrictLink } from "./real-debrid-types"; +import { + RealDebridAddMagnet, + RealDebridTorrentInfo, + RealDebridUnrestrictLink, +} from "./real-debrid-types"; const base = "https://api.real-debrid.com/rest/1.0"; export class RealDebridClient { - static async addMagnet(magnet: string) { - const response = await fetch(`${base}/torrents/addMagnet`, { - method: "POST", - headers: { - "Authorization": `Bearer ${await this.getApiToken()}`, - }, - body: `magnet=${encodeURIComponent(magnet)}` - }); + static async addMagnet(magnet: string) { + const response = await fetch(`${base}/torrents/addMagnet`, { + method: "POST", + headers: { + Authorization: `Bearer ${await this.getApiToken()}`, + }, + body: `magnet=${encodeURIComponent(magnet)}`, + }); - return response.json() as Promise; - } + return response.json() as Promise; + } - static async getInfo(id: string) { - const response = await fetch(`${base}/torrents/info/${id}`, { - headers: { - "Authorization": `Bearer ${await this.getApiToken()}` - } - }); + static async getInfo(id: string) { + const response = await fetch(`${base}/torrents/info/${id}`, { + headers: { + Authorization: `Bearer ${await this.getApiToken()}`, + }, + }); - return response.json() as Promise; - } + return response.json() as Promise; + } - static async selectAllFiles(id: string) { - const response = await fetch(`${base}/torrents/selectFiles/${id}`, { - method: "POST", - headers: { - "Authorization": `Bearer ${await this.getApiToken()}`, - }, - body: "files=all" - }); - } + static async selectAllFiles(id: string) { + await fetch(`${base}/torrents/selectFiles/${id}`, { + method: "POST", + headers: { + Authorization: `Bearer ${await this.getApiToken()}`, + }, + body: "files=all", + }); + } - static async unrestrictLink(link: string) { - const response = await fetch(`${base}/unrestrict/link`, { - method: "POST", - headers: { - "Authorization": `Bearer ${await this.getApiToken()}`, - }, - body: `link=${link}` - }); + static async unrestrictLink(link: string) { + const response = await fetch(`${base}/unrestrict/link`, { + method: "POST", + headers: { + Authorization: `Bearer ${await this.getApiToken()}`, + }, + body: `link=${link}`, + }); - return response.json() as Promise; - } + return response.json() as Promise; + } - static getApiToken() { - return userPreferencesRepository.findOne({ where: { id: 1 } }).then(userPreferences => userPreferences!.realDebridApiToken); - } -} \ No newline at end of file + static getApiToken() { + return userPreferencesRepository + .findOne({ where: { id: 1 } }) + .then((userPreferences) => userPreferences!.realDebridApiToken); + } +} diff --git a/src/main/services/donwloaders/torrent-client.ts b/src/main/services/donwloaders/torrent-client.ts index ed4e16dc..f5c5cdd8 100644 --- a/src/main/services/donwloaders/torrent-client.ts +++ b/src/main/services/donwloaders/torrent-client.ts @@ -131,4 +131,4 @@ export class TorrentClient { Sentry.captureException(err); } } -} \ No newline at end of file +} diff --git a/src/main/services/unrar.ts b/src/main/services/unrar.ts index 9410de23..fcfd1fb1 100644 --- a/src/main/services/unrar.ts +++ b/src/main/services/unrar.ts @@ -1,24 +1,26 @@ -import { Extractor, createExtractorFromFile } from 'node-unrar-js'; -import fs from 'node:fs'; +import { Extractor, createExtractorFromFile } from "node-unrar-js"; +import fs from "node:fs"; -const wasmBinary = fs.readFileSync(require.resolve('node-unrar-js/esm/js/unrar.wasm')); +const wasmBinary = fs.readFileSync( + require.resolve("node-unrar-js/esm/js/unrar.wasm") +); export class Unrar { - private constructor(private extractor: Extractor) { } + private constructor(private extractor: Extractor) {} - static async fromFilePath(filePath: string, targetFolder: string) { - const extractor = await createExtractorFromFile({ - filepath: filePath, - targetPath: targetFolder, - wasmBinary, - }); - return new Unrar(extractor); - } + static async fromFilePath(filePath: string, targetFolder: string) { + const extractor = await createExtractorFromFile({ + filepath: filePath, + targetPath: targetFolder, + wasmBinary, + }); + return new Unrar(extractor); + } - extract() { - const files = this.extractor.extract().files; - for (const file of files) { - console.log("File:", file.fileHeader.name); - } + extract() { + const files = this.extractor.extract().files; + for (const file of files) { + console.log("File:", file.fileHeader.name); } + } } diff --git a/src/renderer/src/components/sidebar/sidebar.tsx b/src/renderer/src/components/sidebar/sidebar.tsx index ab4ea26b..fe8e65d7 100644 --- a/src/renderer/src/components/sidebar/sidebar.tsx +++ b/src/renderer/src/components/sidebar/sidebar.tsx @@ -118,7 +118,8 @@ export function Sidebar() { }, [isResizing]); const getGameTitle = (game: Game) => { - if (game.status === GameStatus.Paused) return t("paused", { title: game.title }); + if (game.status === GameStatus.Paused) + return t("paused", { title: game.title }); if (gameDownloading?.id === game.id) { const isVerifying = GameStatus.isVerifying(gameDownloading.status); diff --git a/src/renderer/src/hooks/use-download.ts b/src/renderer/src/hooks/use-download.ts index 092b352f..ea7665a5 100644 --- a/src/renderer/src/hooks/use-download.ts +++ b/src/renderer/src/hooks/use-download.ts @@ -99,7 +99,7 @@ export function useDownload() { dispatch(setGameDeleting(gameId)); return window.electron.deleteGameFolder(gameId); }) - .catch(() => { }) + .catch(() => {}) .finally(() => { updateLibrary(); dispatch(removeGameFromDeleting(gameId)); diff --git a/src/renderer/src/pages/settings/settings.tsx b/src/renderer/src/pages/settings/settings.tsx index 4da8f07b..110124b3 100644 --- a/src/renderer/src/pages/settings/settings.tsx +++ b/src/renderer/src/pages/settings/settings.tsx @@ -111,12 +111,12 @@ export function Settings() { /> { - updateUserPreferences("realDebridApiToken", event.target.value); - }} - /> + label={t("real_debrid_api_token")} + value={form.realDebridApiToken ?? ""} + onChange={(event) => { + updateUserPreferences("realDebridApiToken", event.target.value); + }} + /> );