diff --git a/src/main/index.ts b/src/main/index.ts index 7d69106..f7b3a68 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -13,6 +13,7 @@ import { subscriptionScheduler } from './lib/subscription-scheduler' import { ytdlpManager } from './lib/ytdlp-manager' import { settingsManager } from './settings' import { createTray, destroyTray } from './tray' +import { applyAutoLaunchSetting } from './utils/auto-launch' import { applyDockVisibility } from './utils/dock' // Initialize electron-log for main process @@ -216,6 +217,7 @@ app.whenReady().then(async () => { } applyDockVisibility(settingsManager.get('hideDockIcon')) + applyAutoLaunchSetting(settingsManager.get('launchAtLogin')) createWindow() diff --git a/src/main/ipc/services/settings-service.ts b/src/main/ipc/services/settings-service.ts index b85b2b0..c44d270 100644 --- a/src/main/ipc/services/settings-service.ts +++ b/src/main/ipc/services/settings-service.ts @@ -4,6 +4,7 @@ import { sanitizeFilenameTemplate } from '../../download-engine/args-builder' import { subscriptionScheduler } from '../../lib/subscription-scheduler' import { settingsManager } from '../../settings' import { updateTrayMenu } from '../../tray' +import { applyAutoLaunchSetting } from '../../utils/auto-launch' import { applyDockVisibility } from '../../utils/dock' class SettingsService extends IpcService { @@ -34,6 +35,10 @@ class SettingsService extends IpcService { applyDockVisibility(value as AppSettings['hideDockIcon']) } + if (key === 'launchAtLogin') { + applyAutoLaunchSetting(value as AppSettings['launchAtLogin']) + } + if (key === 'subscriptionCheckIntervalHours') { subscriptionScheduler.refreshInterval() } @@ -67,6 +72,10 @@ class SettingsService extends IpcService { applyDockVisibility(settings.hideDockIcon) } + if (typeof settings.launchAtLogin === 'boolean') { + applyAutoLaunchSetting(settings.launchAtLogin) + } + if (settings.subscriptionCheckIntervalHours !== undefined) { subscriptionScheduler.refreshInterval() } @@ -76,6 +85,7 @@ class SettingsService extends IpcService { reset(_context: IpcContext): void { settingsManager.reset() applyDockVisibility(settingsManager.get('hideDockIcon')) + applyAutoLaunchSetting(settingsManager.get('launchAtLogin')) subscriptionScheduler.refreshInterval() } } diff --git a/src/main/utils/auto-launch.ts b/src/main/utils/auto-launch.ts new file mode 100644 index 0000000..5f1e179 --- /dev/null +++ b/src/main/utils/auto-launch.ts @@ -0,0 +1,38 @@ +import { app } from 'electron' +import log from 'electron-log/main' + +const SUPPORTED_PLATFORMS = new Set(['darwin', 'win32']) + +export function isAutoLaunchSupported(): boolean { + return SUPPORTED_PLATFORMS.has(process.platform) +} + +export function applyAutoLaunchSetting(enabled: boolean): void { + if (!isAutoLaunchSupported()) { + log.info('Auto launch is not supported on this platform, skipping setting update') + return + } + + const updateSetting = () => { + try { + const options: Parameters[0] = { + openAtLogin: enabled + } + + if (process.platform === 'darwin') { + options.openAsHidden = true + } + + app.setLoginItemSettings(options) + log.info(`Auto launch ${enabled ? 'enabled' : 'disabled'}`) + } catch (error) { + log.error('Failed to update login item settings:', error) + } + } + + if (app.isReady()) { + updateSetting() + } else { + app.once('ready', updateSetting) + } +} diff --git a/src/renderer/src/locales/en.json b/src/renderer/src/locales/en.json index baf3fcc..0aa7629 100644 --- a/src/renderer/src/locales/en.json +++ b/src/renderer/src/locales/en.json @@ -340,6 +340,9 @@ "light": "Light", "hideDockIcon": "Hide Dock icon", "hideDockIconDescription": "Remove VidBee from the macOS Dock. Use the menu bar or tray icon to reopen the app.", + "launchAtLogin": "Launch at startup", + "launchAtLoginDescription": "Open VidBee automatically after you sign in to your computer.", + "launchAtLoginUnsupported": "Auto launch is only available on macOS and Windows.", "enableAnalytics": "Help improve VidBee", "enableAnalyticsDescription": "Share anonymous usage data to help us understand how the app is used and prioritize improvements.", "maxConcurrentDownloads": "Maximum number of active downloads", diff --git a/src/renderer/src/pages/Settings.tsx b/src/renderer/src/pages/Settings.tsx index a6f67c4..53cdddc 100644 --- a/src/renderer/src/pages/Settings.tsx +++ b/src/renderer/src/pages/Settings.tsx @@ -60,6 +60,8 @@ export function Settings() { fetchPlatform() }, []) + const autoLaunchSupported = platform === 'darwin' || platform === 'win32' + const handleSettingChange = async ( key: keyof typeof settings, value: (typeof settings)[keyof typeof settings] @@ -266,6 +268,46 @@ export function Settings() { )} + + {platform === 'darwin' && ( + <> + + + {t('settings.hideDockIcon')} + {t('settings.hideDockIconDescription')} + + + handleSettingChange('hideDockIcon', value)} + /> + + + + + )} + + + + {t('settings.launchAtLogin')} + + {autoLaunchSupported + ? t('settings.launchAtLoginDescription') + : t('settings.launchAtLoginUnsupported')} + + + + handleSettingChange('launchAtLogin', value)} + disabled={!autoLaunchSupported} + /> + + + + + + @@ -280,25 +322,6 @@ export function Settings() { - - - - {platform === 'darwin' && ( - - - - {t('settings.hideDockIcon')} - {t('settings.hideDockIconDescription')} - - - handleSettingChange('hideDockIcon', value)} - /> - - - - )} diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index 3445150..93b31e5 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -265,6 +265,7 @@ export interface AppSettings { oneClickQuality: OneClickQualityPreset closeToTray: boolean hideDockIcon: boolean + launchAtLogin: boolean autoUpdate: boolean subscriptionFilenameTemplate: string subscriptionOnlyLatestDefault: boolean @@ -288,6 +289,7 @@ export const defaultSettings: AppSettings = { oneClickQuality: 'best', closeToTray: false, hideDockIcon: false, + launchAtLogin: false, autoUpdate: true, subscriptionFilenameTemplate: '%(uploader)s - %(title)s.%(ext)s', subscriptionOnlyLatestDefault: true,