mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-28 04:49:39 +00:00
fix(downloads): harden power management and aria2 recovery
This commit is contained in:
+32
-11
@@ -101,6 +101,7 @@ const PageLoadingFallback = () => {
|
||||
|
||||
let automaticUpdateCheckStarted = false;
|
||||
const processingScheduleKeys = new Set<string>();
|
||||
let powerPreferencesSync: Promise<void> = Promise.resolve();
|
||||
|
||||
const waitForSettingsHydration = (): Promise<void> => {
|
||||
if (useSettingsStore.persist.hasHydrated()) return Promise.resolve();
|
||||
@@ -245,6 +246,9 @@ function App() {
|
||||
>>([]);
|
||||
const maxConcurrentDownloads = useSettingsStore(state => state.maxConcurrentDownloads);
|
||||
const preventsSleepWhileDownloading = useSettingsStore(state => state.preventsSleepWhileDownloading);
|
||||
const preventsDisplaySleepWhileDownloading = useSettingsStore(
|
||||
state => state.preventsDisplaySleepWhileDownloading
|
||||
);
|
||||
const activeTransferCount = downloads.filter(download => isTransferActiveStatus(download.status)).length;
|
||||
const { addToast, removeToast } = useToast();
|
||||
const isMacUserAgent = navigator.userAgent.includes('Mac');
|
||||
@@ -716,17 +720,34 @@ function App() {
|
||||
}, [platform.os, showDockBadge, dockBadgeSyncVersion, activeDownloadCount]);
|
||||
|
||||
useEffect(() => {
|
||||
invoke('set_prevent_sleep', {
|
||||
prevent: preventsSleepWhileDownloading && activeTransferCount > 0
|
||||
}).catch(error => {
|
||||
console.error('Failed to update sleep prevention:', error);
|
||||
addToast({
|
||||
message: t($ => $.app.sleepPreventionFailed, { detail: String(error) }),
|
||||
variant: 'error',
|
||||
isActionable: true
|
||||
});
|
||||
});
|
||||
}, [addToast, preventsSleepWhileDownloading, activeTransferCount]);
|
||||
const sync = () => {
|
||||
powerPreferencesSync = powerPreferencesSync
|
||||
.catch(() => undefined)
|
||||
.then(() => invoke('set_power_preferences', {
|
||||
preventSystemSleep: preventsSleepWhileDownloading,
|
||||
preventDisplaySleep: preventsDisplaySleepWhileDownloading
|
||||
}))
|
||||
.catch(error => {
|
||||
console.error('Failed to update power prevention:', error);
|
||||
addToast({
|
||||
message: t($ => $.app.sleepPreventionFailed, { detail: String(error) }),
|
||||
variant: 'error',
|
||||
isActionable: true
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (useSettingsStore.persist.hasHydrated()) {
|
||||
sync();
|
||||
return;
|
||||
}
|
||||
return useSettingsStore.persist.onFinishHydration(sync);
|
||||
}, [
|
||||
addToast,
|
||||
preventsDisplaySleepWhileDownloading,
|
||||
preventsSleepWhileDownloading,
|
||||
t
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
invoke('toggle_tray_icon', { show: showMenuBarIcon }).catch(console.error);
|
||||
|
||||
@@ -11,4 +11,4 @@ import type { SiteLogin } from "./SiteLogin";
|
||||
import type { Theme } from "./Theme";
|
||||
import type { WindowControlStyle } from "./WindowControlStyle";
|
||||
|
||||
export type PersistedSettings = { theme: Theme, fontFamily: FontFamily, windowControlStyle: WindowControlStyle, calendarPreference: CalendarPreference, language: string, baseDownloadFolder: string, categorySubfoldersEnabled: boolean, categorySubfolders: { [key in string]: string }, categoryDirectoryOverrides: { [key in string]: string }, approvedDownloadRoots: Array<string>, maxConcurrentDownloads: number, globalSpeedLimit: string, speedLimitPresetValues: Array<number>, logsEnabled: boolean, isSidebarVisible: boolean, sidebarPosition: string, activeSettingsTab: SettingsTab, scheduler: SchedulerSettings, schedulerRunning: boolean, schedulerActiveDownloadIds: Array<string>, schedulerLastStartKey: string, schedulerLastStopKey: string, lastCustomSpeedLimitKiB: number, lastCustomSpeedLimitUnit: string, perServerConnections: number, maxAutomaticRetries: number, showNotifications: boolean, playCompletionSound: boolean, autoAddClipboardLinks: boolean, appFontSize: AppFontSize, listRowDensity: ListRowDensity, showDockBadge: boolean, showMenuBarIcon: boolean, proxyMode: ProxyMode, proxyHost: string, proxyPort: number, customUserAgent: string, askWhereToSaveEachFile: boolean, rememberLastUsedDownloadDirectory: boolean, preventsSleepWhileDownloading: boolean, mediaCookieSource: MediaCookieSource, siteLogins: Array<SiteLogin>, autoCheckUpdates: boolean, keychainAccessGranted: boolean, };
|
||||
export type PersistedSettings = { theme: Theme, fontFamily: FontFamily, windowControlStyle: WindowControlStyle, calendarPreference: CalendarPreference, language: string, baseDownloadFolder: string, categorySubfoldersEnabled: boolean, categorySubfolders: { [key in string]: string }, categoryDirectoryOverrides: { [key in string]: string }, approvedDownloadRoots: Array<string>, maxConcurrentDownloads: number, globalSpeedLimit: string, speedLimitPresetValues: Array<number>, logsEnabled: boolean, isSidebarVisible: boolean, sidebarPosition: string, activeSettingsTab: SettingsTab, scheduler: SchedulerSettings, schedulerRunning: boolean, schedulerActiveDownloadIds: Array<string>, schedulerLastStartKey: string, schedulerLastStopKey: string, lastCustomSpeedLimitKiB: number, lastCustomSpeedLimitUnit: string, perServerConnections: number, maxAutomaticRetries: number, showNotifications: boolean, playCompletionSound: boolean, autoAddClipboardLinks: boolean, appFontSize: AppFontSize, listRowDensity: ListRowDensity, showDockBadge: boolean, showMenuBarIcon: boolean, proxyMode: ProxyMode, proxyHost: string, proxyPort: number, customUserAgent: string, askWhereToSaveEachFile: boolean, rememberLastUsedDownloadDirectory: boolean, preventsSleepWhileDownloading: boolean, preventsDisplaySleepWhileDownloading: boolean, mediaCookieSource: MediaCookieSource, siteLogins: Array<SiteLogin>, autoCheckUpdates: boolean, keychainAccessGranted: boolean, };
|
||||
|
||||
@@ -1475,6 +1475,19 @@ runEngineChecks(false);
|
||||
<p className="text-text-muted text-xs mt-0.5">{t($ => $.settings.power.preventSleepDescription)}</p>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="flex items-start gap-3 cursor-default select-none text-[13px] text-text-secondary">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.preventsDisplaySleepWhileDownloading}
|
||||
onChange={(e) => settings.setPreventsDisplaySleepWhileDownloading(e.target.checked)}
|
||||
className="mt-0.5 rounded accent-accent"
|
||||
/>
|
||||
<div>
|
||||
<p className="font-semibold text-text-primary">{t($ => $.settings.power.preventDisplaySleep)}</p>
|
||||
<p className="text-text-muted text-xs mt-0.5">{t($ => $.settings.power.preventDisplaySleepDescription)}</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -738,6 +738,8 @@ const common = {
|
||||
title: 'Power Management',
|
||||
preventSleep: 'Prevent system sleep while downloads are active',
|
||||
preventSleepDescription: 'The display may still turn off. Firelink only keeps the device awake enough to complete active transfers.',
|
||||
preventDisplaySleep: 'Keep the display awake while downloads are active',
|
||||
preventDisplaySleepDescription: 'Optional and separate from system-sleep prevention. The display will remain on until active transfers finish.',
|
||||
},
|
||||
engine: {
|
||||
title: 'Media Downloader & Engines',
|
||||
|
||||
@@ -738,6 +738,8 @@ const fa = {
|
||||
title: 'مدیریت انرژی',
|
||||
preventSleep: 'جلوگیری از خواب سیستم در حالی که دانلودها فعال هستند',
|
||||
preventSleepDescription: 'نمایشگر همچنان میتواند خاموش شود. Firelink تنها به اندازهای دستگاه را بیدار نگه میدارد تا انتقالهای فعال را تکمیل کند.',
|
||||
preventDisplaySleep: 'روشن نگه داشتن نمایشگر هنگام فعال بودن دانلودها',
|
||||
preventDisplaySleepDescription: 'این گزینه جدا از جلوگیری از خواب سیستم است و اختیاری است. نمایشگر تا پایان انتقالهای فعال روشن میماند.',
|
||||
},
|
||||
engine: {
|
||||
title: 'دانلودکننده رسانه و موتورها',
|
||||
|
||||
@@ -738,6 +738,8 @@ const he = {
|
||||
title: 'ניהול צריכת חשמל',
|
||||
preventSleep: 'מנע שינה של המערכת בזמן שהורדות פעילות',
|
||||
preventSleepDescription: 'התצוגה עדיין עשויה להכבות. Firelink משאיר את המכשיר ער רק במידה המספקת להשלמת העברות פעילות.',
|
||||
preventDisplaySleep: 'השאר את התצוגה פעילה בזמן שהורדות פעילות',
|
||||
preventDisplaySleepDescription: 'אפשרות זו נפרדת ממניעת שינת המערכת. התצוגה תישאר פעילה עד לסיום ההעברות הפעילות.',
|
||||
},
|
||||
engine: {
|
||||
title: 'מוריד מדיה ומנועים',
|
||||
|
||||
@@ -738,6 +738,8 @@ const ru = {
|
||||
title: 'Управление питанием',
|
||||
preventSleep: 'Запрещать спящий режим системы во время активных загрузок',
|
||||
preventSleepDescription: 'Экран всё ещё может выключаться. Firelink предотвращает засыпание устройства только настолько, чтобы завершить активные передачи.',
|
||||
preventDisplaySleep: 'Не выключать экран во время активных загрузок',
|
||||
preventDisplaySleepDescription: 'Это отдельная необязательная настройка, не связанная с запретом сна системы. Экран останется включённым до завершения передач.',
|
||||
},
|
||||
engine: {
|
||||
title: 'Загрузчик медиа и движки',
|
||||
|
||||
@@ -738,6 +738,8 @@ const uk = {
|
||||
title: 'Керування живленням',
|
||||
preventSleep: 'Запобігати переходу системи в сплячий режим під час активних завантажень',
|
||||
preventSleepDescription: 'Дисплей може все одно вимкнутися. Firelink лише не дає пристрою заснути, щоб завершити активні передачі.',
|
||||
preventDisplaySleep: 'Не вимикати дисплей під час активних завантажень',
|
||||
preventDisplaySleepDescription: 'Це окреме необов’язкове налаштування, незалежне від запобігання сну системи. Дисплей залишатиметься ввімкненим до завершення передач.',
|
||||
},
|
||||
engine: {
|
||||
title: 'Завантажувач медіа та рушії',
|
||||
|
||||
@@ -738,6 +738,8 @@ const zhCN = {
|
||||
title: '电源管理',
|
||||
preventSleep: '下载活动时阻止系统睡眠',
|
||||
preventSleepDescription: '显示器可能仍会关闭。Firelink 仅保持设备唤醒足以完成活动的传输。',
|
||||
preventDisplaySleep: '下载活动时保持显示器唤醒',
|
||||
preventDisplaySleepDescription: '这是与阻止系统睡眠分开的可选设置。活动传输完成前,显示器将保持开启。',
|
||||
},
|
||||
engine: {
|
||||
title: '媒体下载器和引擎',
|
||||
|
||||
@@ -46,6 +46,10 @@ type CommandMap = {
|
||||
get_platform_info: { args: undefined; result: PlatformInfo };
|
||||
approve_download_root: { args: { path: string }; result: string };
|
||||
set_prevent_sleep: { args: { prevent: boolean }; result: void };
|
||||
set_power_preferences: {
|
||||
args: { preventSystemSleep: boolean; preventDisplaySleep: boolean };
|
||||
result: void;
|
||||
};
|
||||
perform_system_action: { args: { action: PostQueueAction }; result: void };
|
||||
ack_schedule_trigger: { args: { action: 'start' | 'stop'; key: string }; result: void };
|
||||
set_concurrent_limit: { args: { limit: number }; result: void };
|
||||
|
||||
@@ -237,6 +237,7 @@ export interface SettingsState {
|
||||
customUserAgent: string;
|
||||
askWhereToSaveEachFile: boolean;
|
||||
preventsSleepWhileDownloading: boolean;
|
||||
preventsDisplaySleepWhileDownloading: boolean;
|
||||
mediaCookieSource: MediaCookieSource;
|
||||
siteLogins: SiteLogin[];
|
||||
extensionPairingToken: string;
|
||||
@@ -286,6 +287,7 @@ export interface SettingsState {
|
||||
setCustomUserAgent: (userAgent: string) => void;
|
||||
setAskWhereToSaveEachFile: (ask: boolean) => void;
|
||||
setPreventsSleepWhileDownloading: (prevent: boolean) => void;
|
||||
setPreventsDisplaySleepWhileDownloading: (prevent: boolean) => void;
|
||||
setMediaCookieSource: (source: MediaCookieSource) => void;
|
||||
setRememberLastUsedDownloadDirectory: (enabled: boolean) => void;
|
||||
setLastUsedDownloadDirectory: (path: string) => void;
|
||||
@@ -361,6 +363,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
customUserAgent: '',
|
||||
askWhereToSaveEachFile: false,
|
||||
preventsSleepWhileDownloading: true,
|
||||
preventsDisplaySleepWhileDownloading: false,
|
||||
mediaCookieSource: 'none',
|
||||
siteLogins: [],
|
||||
extensionPairingToken: '',
|
||||
@@ -457,6 +460,10 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
info('Settings updated: preventsSleepWhileDownloading');
|
||||
set({ preventsSleepWhileDownloading });
|
||||
},
|
||||
setPreventsDisplaySleepWhileDownloading: (preventsDisplaySleepWhileDownloading) => {
|
||||
info('Settings updated: preventsDisplaySleepWhileDownloading');
|
||||
set({ preventsDisplaySleepWhileDownloading });
|
||||
},
|
||||
setMediaCookieSource: (mediaCookieSource) => { info('Settings updated: mediaCookieSource'); set({ mediaCookieSource }); },
|
||||
setRememberLastUsedDownloadDirectory: (rememberLastUsedDownloadDirectory) => {
|
||||
info('Settings updated: rememberLastUsedDownloadDirectory');
|
||||
@@ -631,6 +638,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
customUserAgent: state.customUserAgent,
|
||||
askWhereToSaveEachFile: state.askWhereToSaveEachFile,
|
||||
preventsSleepWhileDownloading: state.preventsSleepWhileDownloading,
|
||||
preventsDisplaySleepWhileDownloading: state.preventsDisplaySleepWhileDownloading,
|
||||
mediaCookieSource: state.mediaCookieSource,
|
||||
siteLogins: state.siteLogins,
|
||||
keychainAccessGranted: state.keychainAccessGranted,
|
||||
@@ -704,6 +712,10 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
persisted.preventsSleepWhileDownloading,
|
||||
currentState.preventsSleepWhileDownloading
|
||||
),
|
||||
preventsDisplaySleepWhileDownloading: persistedBoolean(
|
||||
persisted.preventsDisplaySleepWhileDownloading,
|
||||
currentState.preventsDisplaySleepWhileDownloading
|
||||
),
|
||||
keychainAccessGranted: persistedBoolean(
|
||||
persisted.keychainAccessGranted,
|
||||
currentState.keychainAccessGranted
|
||||
|
||||
Reference in New Issue
Block a user