import { contextBridge, ipcRenderer } from 'electron' import { IpcChannels } from '../shared/ipc-channels' import type { WorkshopQueryParams, WorkshopQueryResult, WorkshopItem, CreatorWorkshopQueryParams, WallpaperMeta, WallpaperFolder, LibraryFilters, WorkshopAuthorInfo, ApplyWallpaperOptions, DownloadProgressEvent, WallpaperEnvironment, LweStatus, LweInstallProgress, LinuxDistro, LweSceneObject, LweProperty, LweAudioObject, BackupProgressEvent, Playlist, PlaylistSettings, PlaylistPlaybackState } from '../shared/types' const api = { workshop: { query: (params: WorkshopQueryParams): Promise => ipcRenderer.invoke(IpcChannels.WORKSHOP_QUERY, params), getItem: (publishedFileId: string): Promise => ipcRenderer.invoke(IpcChannels.WORKSHOP_GET_ITEM, publishedFileId), queryByCreator: ( creatorSteamId: string, params?: CreatorWorkshopQueryParams ): Promise => ipcRenderer.invoke(IpcChannels.WORKSHOP_QUERY_BY_CREATOR, creatorSteamId, params) }, steam: { isRunning: (): Promise => ipcRenderer.invoke(IpcChannels.STEAM_IS_RUNNING), subscribe: (itemId: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.STEAM_SUBSCRIBE, itemId), unsubscribe: (itemId: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.STEAM_UNSUBSCRIBE, itemId), redownload: (itemId: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.STEAM_REDOWNLOAD, itemId), getSubscribedItems: (): Promise => ipcRenderer.invoke(IpcChannels.STEAM_GET_SUBSCRIBED), downloadInfo: (itemId: string): Promise => ipcRenderer.invoke(IpcChannels.STEAM_DOWNLOAD_INFO, itemId), itemState: (itemId: string): Promise => ipcRenderer.invoke(IpcChannels.STEAM_ITEM_STATE, itemId), vote: (itemId: string, voteUp: boolean): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.STEAM_VOTE, itemId, voteUp), openWorkshopItem: (itemId: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.STEAM_OPEN_WORKSHOP, itemId), getVotedIds: (): Promise => ipcRenderer.invoke(IpcChannels.STEAM_GET_VOTED_IDS), getAuthorInfo: (steamId: string): Promise => ipcRenderer.invoke(IpcChannels.STEAM_GET_AUTHOR_INFO, steamId) }, library: { getAll: (filters?: LibraryFilters): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_GET_ALL, filters), getOne: (id: string): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_GET_ONE, id), update: (id: string, patch: Partial): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_UPDATE, id, patch), delete: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.LIBRARY_DELETE, id), addTag: (id: string, tag: string): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_ADD_TAG, id, tag), removeTag: (id: string, tag: string): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_REMOVE_TAG, id, tag), getTags: (): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_GET_TAGS), search: (query: string): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_SEARCH, query), scan: (): Promise<{ imported: number; skipped: number; removed: number }> => ipcRenderer.invoke(IpcChannels.LIBRARY_SCAN), distinctTags: (): Promise => ipcRenderer.invoke(IpcChannels.LIBRARY_DISTINCT_TAGS), resetFpsOverrides: (): Promise<{ count: number }> => ipcRenderer.invoke(IpcChannels.LIBRARY_RESET_FPS_OVERRIDES), checkUnavailable: (): Promise<{ checked: number; unavailable: number }> => ipcRenderer.invoke(IpcChannels.LIBRARY_CHECK_UNAVAILABLE) }, config: { get: (): Promise<{ workshopPath: string | null defaultWorkshopPath: string isConfigured: boolean defaultFps: number | null recommendedFpsEnabled: boolean recommendedWebFpsEnabled: boolean lweRepoUrl: string | null lweRepoBranch: string | null lweCmakeArgs: string | null defaultLweRepoUrl: string backupPath: string | null isBackupConfigured: boolean autoUnsubscribeAfterBackup: boolean trayEnabled: boolean autostartSupported: boolean autostartEnabled: boolean autostartMinimized: boolean autostartPlaylistId: string | null killLweOnQuit: boolean audioScreen: string | null ambientVolume: number | null defaultAudioSensitivity: number }> => ipcRenderer.invoke(IpcChannels.CONFIG_GET), setWorkshopPath: (p: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_WORKSHOP_PATH, p), setDefaultFps: (fps: number | null): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_DEFAULT_FPS, fps), setRecommendedFpsEnabled: (enabled: boolean): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_RECOMMENDED_FPS, enabled), setRecommendedWebFpsEnabled: (enabled: boolean): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_RECOMMENDED_WEB_FPS, enabled), setLweRepo: (url: string | null, branch: string | null): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_LWE_REPO, url, branch), setLweCmakeArgs: (args: string | null): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_LWE_CMAKE_ARGS, args), setBackupPath: (p: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_BACKUP_PATH, p), setAutoUnsubscribeAfterBackup: (enabled: boolean): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUTO_UNSUBSCRIBE, enabled), pickFolder: (): Promise => ipcRenderer.invoke(IpcChannels.CONFIG_PICK_FOLDER), pickFile: (): Promise => ipcRenderer.invoke(IpcChannels.CONFIG_PICK_FILE), importWE: (sourcePath: string): Promise<{ folders: number; playlists: number; configPath: string }> => ipcRenderer.invoke(IpcChannels.CONFIG_IMPORT_WE, sourcePath), createFresh: (): Promise<{ configPath: string }> => ipcRenderer.invoke(IpcChannels.CONFIG_CREATE_FRESH), setTrayEnabled: (enabled: boolean): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_TRAY_ENABLED, enabled), setKillLweOnQuit: (enabled: boolean): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_KILL_LWE_ON_QUIT, enabled), setAutostart: ( enabled: boolean, minimized: boolean, playlistId: string | null ): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUTOSTART, enabled, minimized, playlistId), getAutostartSupported: (): Promise => ipcRenderer.invoke(IpcChannels.CONFIG_GET_AUTOSTART_SUPPORTED), setAudioScreen: (screen: string | null): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUDIO_SCREEN, screen), setAmbientVolume: (volume: number | null): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_AMBIENT_VOLUME, volume), setDefaultAudioSensitivity: (multiplier: number): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.CONFIG_SET_DEFAULT_AUDIO_SENSITIVITY, multiplier) }, playlist: { getAll: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_ALL), getOne: (id: string): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_ONE, id), create: (title: string): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_CREATE, title), rename: (id: string, title: string): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_RENAME, id, title), delete: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.PLAYLIST_DELETE, id), updateSettings: (id: string, patch: Partial): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_UPDATE_SETTINGS, id, patch), addItems: (id: string, wallpaperIds: string[]): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_ADD_ITEMS, id, wallpaperIds), removeItems: (id: string, wallpaperIds: string[]): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_REMOVE_ITEMS, id, wallpaperIds), reorderItems: (id: string, orderedWallpaperIds: string[]): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_REORDER_ITEMS, id, orderedWallpaperIds), updateItem: ( id: string, wallpaperId: string, patch: { volume?: number; durationSec?: number } ): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_UPDATE_ITEM, id, wallpaperId, patch), start: (id: string): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_START, id), playItem: (id: string, wallpaperId: string): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_PLAY_ITEM, id, wallpaperId), stop: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_STOP), pause: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_PAUSE), resume: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_RESUME), next: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_NEXT), previous: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_PREVIOUS), getState: (): Promise => ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_STATE) }, folders: { getAll: (): Promise => ipcRenderer.invoke(IpcChannels.FOLDERS_GET_ALL), create: (title: string): Promise => ipcRenderer.invoke(IpcChannels.FOLDERS_CREATE, title), rename: (id: string, title: string): Promise => ipcRenderer.invoke(IpcChannels.FOLDERS_RENAME, id, title), delete: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.FOLDERS_DELETE, id), addItems: (folderId: string, itemIds: string[]): Promise => ipcRenderer.invoke(IpcChannels.FOLDERS_ADD_ITEMS, folderId, itemIds), removeItems: (folderId: string, itemIds: string[]): Promise => ipcRenderer.invoke(IpcChannels.FOLDERS_REMOVE_ITEMS, folderId, itemIds), importWEConfig: (configPath: string): Promise<{ folders: number; playlists: number }> => ipcRenderer.invoke(IpcChannels.FOLDERS_IMPORT_WE_CONFIG, configPath), cleanup: (): Promise<{ removed: number }> => ipcRenderer.invoke(IpcChannels.FOLDERS_CLEANUP) }, wallpaper: { apply: (options: ApplyWallpaperOptions): Promise<{ ok: boolean; appliedPath: string }> => ipcRenderer.invoke(IpcChannels.WALLPAPER_APPLY, options), getActive: (): Promise => ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_ACTIVE), detectEnvironment: (): Promise => ipcRenderer.invoke(IpcChannels.WALLPAPER_DETECT_ENV) }, lwe: { status: (): Promise => ipcRenderer.invoke(IpcChannels.LWE_STATUS), detectDistro: (): Promise => ipcRenderer.invoke(IpcChannels.LWE_DETECT_DISTRO), installDeps: (): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.LWE_INSTALL_DEPS), install: (): Promise => ipcRenderer.invoke(IpcChannels.LWE_INSTALL), uninstall: (): Promise<{ ok: boolean; message: string }> => ipcRenderer.invoke(IpcChannels.LWE_UNINSTALL), launch: (wallpaperPath: string, options?: { screenRoot?: string; fps?: number }): Promise<{ ok: boolean; running: boolean }> => ipcRenderer.invoke(IpcChannels.LWE_LAUNCH, wallpaperPath, options), stop: (): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.LWE_STOP), killAll: (): Promise<{ ok: boolean; message: string }> => ipcRenderer.invoke(IpcChannels.LWE_KILL_ALL), listObjects: (wallpaperPath: string): Promise => ipcRenderer.invoke(IpcChannels.LWE_LIST_OBJECTS, wallpaperPath), hotswapSettings: (options: { disabledObjects?: string[] enabledObjects?: string[] volume?: number xray?: boolean scaling?: string zoom?: number disableParallax?: boolean cornerColor?: string speed?: number propertyOverrides?: Record audioScreen?: string ambientVolume?: number audioSensitivity?: Record }): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.LWE_HOTSWAP_SETTINGS, options), listProperties: (wallpaperPath: string): Promise => ipcRenderer.invoke(IpcChannels.LWE_LIST_PROPERTIES, wallpaperPath), listScreens: (): Promise => ipcRenderer.invoke(IpcChannels.LWE_LIST_SCREENS), listAudioObjects: (wallpaperPath: string): Promise => ipcRenderer.invoke(IpcChannels.LWE_LIST_AUDIO_OBJECTS, wallpaperPath) }, backup: { item: (itemId: string): Promise<{ ok: boolean; unsubscribed: boolean }> => ipcRenderer.invoke(IpcChannels.BACKUP_ITEM, itemId), selection: (itemIds: string[]): Promise<{ backedUp: number; failed: number; unsubscribed: number }> => ipcRenderer.invoke(IpcChannels.BACKUP_SELECTION, itemIds), scan: (): Promise<{ imported: number; skipped: number; linked: number }> => ipcRenderer.invoke(IpcChannels.BACKUP_SCAN) }, desktopIcons: { setEnabled: (enabled: boolean): Promise<{ ok: boolean; enabled: boolean }> => ipcRenderer.invoke(IpcChannels.DESKTOP_ICONS_SET_ENABLED, enabled), getEnabled: (): Promise => ipcRenderer.invoke(IpcChannels.DESKTOP_ICONS_GET_ENABLED) }, shell: { openInFileManager: (folderPath: string): Promise<{ ok: boolean; error?: string }> => ipcRenderer.invoke(IpcChannels.SHELL_OPEN_IN_FILE_MANAGER, folderPath), openWithDefault: (filePath: string): Promise<{ ok: boolean; error?: string }> => ipcRenderer.invoke(IpcChannels.SHELL_OPEN_WITH_DEFAULT, filePath), openPath: (targetPath: string): Promise<{ ok: boolean; error?: string }> => ipcRenderer.invoke(IpcChannels.SHELL_OPEN_PATH, targetPath), openExternal: (url: string): Promise<{ ok: boolean; error?: string }> => ipcRenderer.invoke(IpcChannels.SHELL_OPEN_EXTERNAL, url) }, on: { downloadProgress: (cb: (info: DownloadProgressEvent) => void): (() => void) => { const listener = (_: Electron.IpcRendererEvent, info: DownloadProgressEvent) => cb(info) ipcRenderer.on(IpcChannels.EVENT_DOWNLOAD_PROGRESS, listener) return () => ipcRenderer.off(IpcChannels.EVENT_DOWNLOAD_PROGRESS, listener) }, wallpaperImported: (cb: (meta: WallpaperMeta) => void): (() => void) => { const listener = (_: Electron.IpcRendererEvent, meta: WallpaperMeta) => cb(meta) ipcRenderer.on(IpcChannels.EVENT_WALLPAPER_IMPORTED, listener) return () => ipcRenderer.off(IpcChannels.EVENT_WALLPAPER_IMPORTED, listener) }, steamStatus: (cb: (running: boolean) => void): (() => void) => { const listener = (_: Electron.IpcRendererEvent, running: boolean) => cb(running) ipcRenderer.on(IpcChannels.EVENT_STEAM_STATUS, listener) return () => ipcRenderer.off(IpcChannels.EVENT_STEAM_STATUS, listener) }, lweInstallProgress: (cb: (progress: LweInstallProgress) => void): (() => void) => { const listener = (_: Electron.IpcRendererEvent, progress: LweInstallProgress) => cb(progress) ipcRenderer.on(IpcChannels.EVENT_LWE_INSTALL_PROGRESS, listener) return () => ipcRenderer.off(IpcChannels.EVENT_LWE_INSTALL_PROGRESS, listener) }, backupProgress: (cb: (progress: BackupProgressEvent) => void): (() => void) => { const listener = (_: Electron.IpcRendererEvent, progress: BackupProgressEvent) => cb(progress) ipcRenderer.on(IpcChannels.EVENT_BACKUP_PROGRESS, listener) return () => ipcRenderer.off(IpcChannels.EVENT_BACKUP_PROGRESS, listener) }, playlistStateChanged: (cb: (state: PlaylistPlaybackState) => void): (() => void) => { const listener = (_: Electron.IpcRendererEvent, state: PlaylistPlaybackState) => cb(state) ipcRenderer.on(IpcChannels.EVENT_PLAYLIST_STATE_CHANGED, listener) return () => ipcRenderer.off(IpcChannels.EVENT_PLAYLIST_STATE_CHANGED, listener) } } } contextBridge.exposeInMainWorld('electronAPI', api) export type ElectronAPI = typeof api