mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-18 00:33:59 +00:00
feat: sync download sources
This commit is contained in:
13
src/main/events/download-sources/create-download-source.ts
Normal file
13
src/main/events/download-sources/create-download-source.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { HydraApi } from "@main/services";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const createDownloadSource = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
url: string
|
||||
) => {
|
||||
return HydraApi.post("/profile/download-sources", {
|
||||
url,
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("createDownloadSource", createDownloadSource);
|
||||
8
src/main/events/download-sources/get-download-sources.ts
Normal file
8
src/main/events/download-sources/get-download-sources.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { HydraApi } from "@main/services";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const getDownloadSources = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
return HydraApi.get("/profile/download-sources");
|
||||
};
|
||||
|
||||
registerEvent("getDownloadSources", getDownloadSources);
|
||||
18
src/main/events/download-sources/remove-download-source.ts
Normal file
18
src/main/events/download-sources/remove-download-source.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { HydraApi } from "@main/services";
|
||||
import { registerEvent } from "../register-event";
|
||||
|
||||
const removeDownloadSource = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
url?: string,
|
||||
removeAll = false
|
||||
) => {
|
||||
const params = new URLSearchParams({
|
||||
all: removeAll.toString(),
|
||||
});
|
||||
|
||||
if (url) params.set("url", url);
|
||||
|
||||
return HydraApi.delete(`/profile/download-sources?${params.toString()}`);
|
||||
};
|
||||
|
||||
registerEvent("removeDownloadSource", removeDownloadSource);
|
||||
@@ -90,6 +90,9 @@ import "./themes/get-custom-theme-by-id";
|
||||
import "./themes/get-active-custom-theme";
|
||||
import "./themes/close-editor-window";
|
||||
import "./themes/toggle-custom-theme";
|
||||
import "./download-sources/create-download-source";
|
||||
import "./download-sources/remove-download-source";
|
||||
import "./download-sources/get-download-sources";
|
||||
import { isPortableVersion } from "@main/helpers";
|
||||
|
||||
ipcMain.handle("ping", () => "pong");
|
||||
|
||||
@@ -100,6 +100,11 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
/* Download sources */
|
||||
putDownloadSource: (objectIds: string[]) =>
|
||||
ipcRenderer.invoke("putDownloadSource", objectIds),
|
||||
createDownloadSource: (url: string) =>
|
||||
ipcRenderer.invoke("createDownloadSource", url),
|
||||
removeDownloadSource: (url: string, removeAll?: boolean) =>
|
||||
ipcRenderer.invoke("removeDownloadSource", url, removeAll),
|
||||
getDownloadSources: () => ipcRenderer.invoke("getDownloadSources"),
|
||||
|
||||
/* Library */
|
||||
toggleAutomaticCloudSync: (
|
||||
|
||||
@@ -136,6 +136,61 @@ export function App() {
|
||||
});
|
||||
}, [fetchUserDetails, updateUserDetails, dispatch]);
|
||||
|
||||
const syncDownloadSources = useCallback(async () => {
|
||||
const downloadSources = await window.electron.getDownloadSources();
|
||||
|
||||
await Promise.allSettled(
|
||||
downloadSources.map(async (source) => {
|
||||
return new Promise(async (resolve) => {
|
||||
const existingDownloadSource = await downloadSourcesTable
|
||||
.where({ url: source.url })
|
||||
.first();
|
||||
|
||||
if (!existingDownloadSource) {
|
||||
const channel = new BroadcastChannel(
|
||||
`download_sources:import:${source.url}`
|
||||
);
|
||||
|
||||
downloadSourcesWorker.postMessage([
|
||||
"IMPORT_DOWNLOAD_SOURCE",
|
||||
source.url,
|
||||
]);
|
||||
|
||||
channel.onmessage = () => {
|
||||
resolve(true);
|
||||
channel.close();
|
||||
};
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
updateRepacks();
|
||||
|
||||
const id = crypto.randomUUID();
|
||||
const channel = new BroadcastChannel(`download_sources:sync:${id}`);
|
||||
|
||||
channel.onmessage = async (event: MessageEvent<number>) => {
|
||||
const newRepacksCount = event.data;
|
||||
window.electron.publishNewRepacksNotification(newRepacksCount);
|
||||
updateRepacks();
|
||||
|
||||
const downloadSources = await downloadSourcesTable.toArray();
|
||||
|
||||
downloadSources
|
||||
.filter((source) => !source.fingerprint)
|
||||
.forEach(async (downloadSource) => {
|
||||
const { fingerprint } = await window.electron.putDownloadSource(
|
||||
downloadSource.objectIds
|
||||
);
|
||||
|
||||
downloadSourcesTable.update(downloadSource.id, { fingerprint });
|
||||
});
|
||||
};
|
||||
|
||||
downloadSourcesWorker.postMessage(["SYNC_DOWNLOAD_SOURCES", id]);
|
||||
}, [updateRepacks]);
|
||||
|
||||
const onSignIn = useCallback(() => {
|
||||
fetchUserDetails().then((response) => {
|
||||
if (response) {
|
||||
@@ -144,7 +199,15 @@ export function App() {
|
||||
showSuccessToast(t("successfully_signed_in"));
|
||||
}
|
||||
});
|
||||
}, [fetchUserDetails, t, showSuccessToast, updateUserDetails]);
|
||||
|
||||
syncDownloadSources();
|
||||
}, [
|
||||
fetchUserDetails,
|
||||
t,
|
||||
showSuccessToast,
|
||||
updateUserDetails,
|
||||
syncDownloadSources,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onSyncFriendRequests((result) => {
|
||||
@@ -212,31 +275,8 @@ export function App() {
|
||||
}, [dispatch, draggingDisabled]);
|
||||
|
||||
useEffect(() => {
|
||||
updateRepacks();
|
||||
|
||||
const id = crypto.randomUUID();
|
||||
const channel = new BroadcastChannel(`download_sources:sync:${id}`);
|
||||
|
||||
channel.onmessage = async (event: MessageEvent<number>) => {
|
||||
const newRepacksCount = event.data;
|
||||
window.electron.publishNewRepacksNotification(newRepacksCount);
|
||||
updateRepacks();
|
||||
|
||||
const downloadSources = await downloadSourcesTable.toArray();
|
||||
|
||||
downloadSources
|
||||
.filter((source) => !source.fingerprint)
|
||||
.forEach(async (downloadSource) => {
|
||||
const { fingerprint } = await window.electron.putDownloadSource(
|
||||
downloadSource.objectIds
|
||||
);
|
||||
|
||||
downloadSourcesTable.update(downloadSource.id, { fingerprint });
|
||||
});
|
||||
};
|
||||
|
||||
downloadSourcesWorker.postMessage(["SYNC_DOWNLOAD_SOURCES", id]);
|
||||
}, [updateRepacks]);
|
||||
syncDownloadSources();
|
||||
}, [syncDownloadSources]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadAndApplyTheme = async () => {
|
||||
|
||||
5
src/renderer/src/declaration.d.ts
vendored
5
src/renderer/src/declaration.d.ts
vendored
@@ -165,6 +165,11 @@ declare global {
|
||||
putDownloadSource: (
|
||||
objectIds: string[]
|
||||
) => Promise<{ fingerprint: string }>;
|
||||
createDownloadSource: (url: string) => Promise<void>;
|
||||
removeDownloadSource: (url: string, removeAll?: boolean) => Promise<void>;
|
||||
getDownloadSources: () => Promise<
|
||||
Pick<DownloadSource, "url" | "createdAt" | "updatedAt">[]
|
||||
>;
|
||||
|
||||
/* Hardware */
|
||||
getDiskFreeSpace: (path: string) => Promise<disk.DiskUsage>;
|
||||
|
||||
@@ -119,7 +119,8 @@ export function AddDownloadSourceModal({
|
||||
|
||||
downloadSourcesWorker.postMessage(["IMPORT_DOWNLOAD_SOURCE", url]);
|
||||
|
||||
channel.onmessage = async () => {
|
||||
channel.onmessage = () => {
|
||||
window.electron.createDownloadSource(url);
|
||||
setIsLoading(false);
|
||||
|
||||
putDownloadSource();
|
||||
|
||||
@@ -70,14 +70,20 @@ export function SettingsDownloadSources() {
|
||||
if (sourceUrl) setShowAddDownloadSourceModal(true);
|
||||
}, [sourceUrl]);
|
||||
|
||||
const handleRemoveSource = (id: number) => {
|
||||
const handleRemoveSource = (downloadSource: DownloadSource) => {
|
||||
setIsRemovingDownloadSource(true);
|
||||
const channel = new BroadcastChannel(`download_sources:delete:${id}`);
|
||||
const channel = new BroadcastChannel(
|
||||
`download_sources:delete:${downloadSource.id}`
|
||||
);
|
||||
|
||||
downloadSourcesWorker.postMessage(["DELETE_DOWNLOAD_SOURCE", id]);
|
||||
downloadSourcesWorker.postMessage([
|
||||
"DELETE_DOWNLOAD_SOURCE",
|
||||
downloadSource.id,
|
||||
]);
|
||||
|
||||
channel.onmessage = () => {
|
||||
showSuccessToast(t("removed_download_source"));
|
||||
window.electron.removeDownloadSource(downloadSource.url);
|
||||
|
||||
getDownloadSources();
|
||||
setIsRemovingDownloadSource(false);
|
||||
@@ -96,7 +102,7 @@ export function SettingsDownloadSources() {
|
||||
|
||||
channel.onmessage = () => {
|
||||
showSuccessToast(t("removed_download_sources"));
|
||||
|
||||
window.electron.removeDownloadSource("", true);
|
||||
getDownloadSources();
|
||||
setIsRemovingDownloadSource(false);
|
||||
setShowConfirmationDeleteAllSourcesModal(false);
|
||||
@@ -253,7 +259,7 @@ export function SettingsDownloadSources() {
|
||||
<Button
|
||||
type="button"
|
||||
theme="outline"
|
||||
onClick={() => handleRemoveSource(downloadSource.id)}
|
||||
onClick={() => handleRemoveSource(downloadSource)}
|
||||
disabled={isRemovingDownloadSource}
|
||||
>
|
||||
<NoEntryIcon />
|
||||
|
||||
@@ -22,6 +22,20 @@ export interface GameRepack {
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface DownloadSource {
|
||||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
repackCount: number;
|
||||
status: DownloadSourceStatus;
|
||||
objectIds: string[];
|
||||
downloadCount: number;
|
||||
fingerprint: string;
|
||||
etag: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export type ShopDetails = SteamAppDetails & {
|
||||
objectId: string;
|
||||
};
|
||||
@@ -197,20 +211,6 @@ export interface DownloadSourceValidationResult {
|
||||
downloadCount: number;
|
||||
}
|
||||
|
||||
export interface DownloadSource {
|
||||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
repackCount: number;
|
||||
status: DownloadSourceStatus;
|
||||
objectIds: string[];
|
||||
downloadCount: number;
|
||||
fingerprint: string;
|
||||
etag: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface GameStats {
|
||||
downloadCount: number;
|
||||
playerCount: number;
|
||||
|
||||
Reference in New Issue
Block a user