index.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. import { contextBridge, ipcRenderer } from 'electron'
  2. import { IpcChannels } from '../shared/ipc-channels'
  3. import type {
  4. WorkshopQueryParams,
  5. WorkshopQueryResult,
  6. WorkshopItem,
  7. CreatorWorkshopQueryParams,
  8. WallpaperMeta,
  9. WallpaperFolder,
  10. LibraryFilters,
  11. WorkshopAuthorInfo,
  12. ApplyWallpaperOptions,
  13. DownloadProgressEvent,
  14. WallpaperEnvironment,
  15. LweStatus,
  16. LweInstallProgress,
  17. LinuxDistro,
  18. LweSceneObject,
  19. LweProperty,
  20. LweAudioObject,
  21. LweSceneEffect,
  22. DesktopApplication,
  23. BackupProgressEvent,
  24. Playlist,
  25. PlaylistSettings,
  26. PlaylistPlaybackState,
  27. SteamIdentity,
  28. EngineFlags,
  29. EngineFlagPreset,
  30. DisplayMode,
  31. ScreenTarget,
  32. ScreenAssignment,
  33. ScheduleRule,
  34. CrashEvent
  35. } from '../shared/types'
  36. const api = {
  37. workshop: {
  38. query: (params: WorkshopQueryParams): Promise<WorkshopQueryResult> =>
  39. ipcRenderer.invoke(IpcChannels.WORKSHOP_QUERY, params),
  40. getItem: (publishedFileId: string): Promise<WorkshopItem | null> =>
  41. ipcRenderer.invoke(IpcChannels.WORKSHOP_GET_ITEM, publishedFileId),
  42. queryByCreator: (
  43. creatorSteamId: string,
  44. params?: CreatorWorkshopQueryParams
  45. ): Promise<WorkshopQueryResult> =>
  46. ipcRenderer.invoke(IpcChannels.WORKSHOP_QUERY_BY_CREATOR, creatorSteamId, params)
  47. },
  48. steam: {
  49. isRunning: (): Promise<boolean> => ipcRenderer.invoke(IpcChannels.STEAM_IS_RUNNING),
  50. subscribe: (itemId: string): Promise<{ ok: boolean }> =>
  51. ipcRenderer.invoke(IpcChannels.STEAM_SUBSCRIBE, itemId),
  52. unsubscribe: (itemId: string): Promise<{ ok: boolean }> =>
  53. ipcRenderer.invoke(IpcChannels.STEAM_UNSUBSCRIBE, itemId),
  54. redownload: (itemId: string): Promise<{ ok: boolean }> =>
  55. ipcRenderer.invoke(IpcChannels.STEAM_REDOWNLOAD, itemId),
  56. getSubscribedItems: (): Promise<string[]> =>
  57. ipcRenderer.invoke(IpcChannels.STEAM_GET_SUBSCRIBED),
  58. downloadInfo: (itemId: string): Promise<DownloadProgressEvent | null> =>
  59. ipcRenderer.invoke(IpcChannels.STEAM_DOWNLOAD_INFO, itemId),
  60. itemState: (itemId: string): Promise<number> =>
  61. ipcRenderer.invoke(IpcChannels.STEAM_ITEM_STATE, itemId),
  62. vote: (itemId: string, voteUp: boolean): Promise<{ ok: boolean; confirmed: boolean }> =>
  63. ipcRenderer.invoke(IpcChannels.STEAM_VOTE, itemId, voteUp),
  64. openWorkshopItem: (itemId: string): Promise<{ ok: boolean }> =>
  65. ipcRenderer.invoke(IpcChannels.STEAM_OPEN_WORKSHOP, itemId),
  66. getVotedIds: (): Promise<string[]> =>
  67. ipcRenderer.invoke(IpcChannels.STEAM_GET_VOTED_IDS),
  68. getFailedVotes: (): Promise<Record<string, string>> =>
  69. ipcRenderer.invoke(IpcChannels.STEAM_GET_FAILED_VOTES),
  70. checkVote: (itemId: string): Promise<boolean | null> =>
  71. ipcRenderer.invoke(IpcChannels.STEAM_CHECK_VOTE, itemId),
  72. getAuthorInfo: (steamId: string): Promise<WorkshopAuthorInfo | null> =>
  73. ipcRenderer.invoke(IpcChannels.STEAM_GET_AUTHOR_INFO, steamId)
  74. },
  75. library: {
  76. getAll: (filters?: LibraryFilters): Promise<WallpaperMeta[]> =>
  77. ipcRenderer.invoke(IpcChannels.LIBRARY_GET_ALL, filters),
  78. getOne: (id: string): Promise<WallpaperMeta | null> =>
  79. ipcRenderer.invoke(IpcChannels.LIBRARY_GET_ONE, id),
  80. update: (id: string, patch: Partial<WallpaperMeta>): Promise<WallpaperMeta | null> =>
  81. ipcRenderer.invoke(IpcChannels.LIBRARY_UPDATE, id, patch),
  82. delete: (id: string): Promise<{ ok: boolean }> =>
  83. ipcRenderer.invoke(IpcChannels.LIBRARY_DELETE, id),
  84. addTag: (id: string, tag: string): Promise<WallpaperMeta | null> =>
  85. ipcRenderer.invoke(IpcChannels.LIBRARY_ADD_TAG, id, tag),
  86. removeTag: (id: string, tag: string): Promise<WallpaperMeta | null> =>
  87. ipcRenderer.invoke(IpcChannels.LIBRARY_REMOVE_TAG, id, tag),
  88. getTags: (): Promise<string[]> => ipcRenderer.invoke(IpcChannels.LIBRARY_GET_TAGS),
  89. search: (query: string): Promise<WallpaperMeta[]> =>
  90. ipcRenderer.invoke(IpcChannels.LIBRARY_SEARCH, query),
  91. scan: (): Promise<{ imported: number; skipped: number; removed: number }> =>
  92. ipcRenderer.invoke(IpcChannels.LIBRARY_SCAN),
  93. distinctTags: (): Promise<string[]> =>
  94. ipcRenderer.invoke(IpcChannels.LIBRARY_DISTINCT_TAGS),
  95. resetFpsOverrides: (): Promise<{ count: number }> =>
  96. ipcRenderer.invoke(IpcChannels.LIBRARY_RESET_FPS_OVERRIDES),
  97. checkUnavailable: (): Promise<{ checked: number; unavailable: number; changed: boolean }> =>
  98. ipcRenderer.invoke(IpcChannels.LIBRARY_CHECK_UNAVAILABLE)
  99. },
  100. config: {
  101. get: (): Promise<{
  102. workshopPath: string | null
  103. defaultWorkshopPath: string
  104. isConfigured: boolean
  105. defaultFps: number | null
  106. recommendedFpsEnabled: boolean
  107. recommendedWebFpsEnabled: boolean
  108. lweRepoUrl: string | null
  109. lweRepoBranch: string | null
  110. lweCmakeArgs: string | null
  111. defaultLweRepoUrl: string
  112. backupPath: string | null
  113. isBackupConfigured: boolean
  114. autoUnsubscribeAfterBackup: boolean
  115. trayEnabled: boolean
  116. autostartSupported: boolean
  117. autostartEnabled: boolean
  118. autostartMinimized: boolean
  119. autostartPlaylistId: string | null
  120. killLweOnQuit: boolean
  121. voteBorders: boolean
  122. audioScreen: string | null
  123. ambientVolume: number | null
  124. defaultAudioSensitivity: number
  125. disablePuppetAnimation: boolean
  126. disableAnimations: boolean
  127. steamIdentity: SteamIdentity
  128. ignoredCreators: string[]
  129. engineFlags: EngineFlags
  130. engineFlagPresets: EngineFlagPreset[]
  131. displayMode: DisplayMode
  132. }> => ipcRenderer.invoke(IpcChannels.CONFIG_GET),
  133. setEngineFlags: (flags: EngineFlags): Promise<{ ok: boolean }> =>
  134. ipcRenderer.invoke(IpcChannels.CONFIG_SET_ENGINE_FLAGS, flags),
  135. setEnginePresets: (presets: EngineFlagPreset[]): Promise<{ ok: boolean }> =>
  136. ipcRenderer.invoke(IpcChannels.CONFIG_SET_ENGINE_PRESETS, presets),
  137. setDisplayMode: (mode: DisplayMode): Promise<{ ok: boolean }> =>
  138. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DISPLAY_MODE, mode),
  139. setWorkshopPath: (p: string): Promise<{ ok: boolean }> =>
  140. ipcRenderer.invoke(IpcChannels.CONFIG_SET_WORKSHOP_PATH, p),
  141. setDefaultFps: (fps: number | null): Promise<{ ok: boolean }> =>
  142. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DEFAULT_FPS, fps),
  143. setRecommendedFpsEnabled: (enabled: boolean): Promise<{ ok: boolean }> =>
  144. ipcRenderer.invoke(IpcChannels.CONFIG_SET_RECOMMENDED_FPS, enabled),
  145. setRecommendedWebFpsEnabled: (enabled: boolean): Promise<{ ok: boolean }> =>
  146. ipcRenderer.invoke(IpcChannels.CONFIG_SET_RECOMMENDED_WEB_FPS, enabled),
  147. setLweRepo: (url: string | null, branch: string | null): Promise<{ ok: boolean }> =>
  148. ipcRenderer.invoke(IpcChannels.CONFIG_SET_LWE_REPO, url, branch),
  149. setLweCmakeArgs: (args: string | null): Promise<{ ok: boolean }> =>
  150. ipcRenderer.invoke(IpcChannels.CONFIG_SET_LWE_CMAKE_ARGS, args),
  151. setBackupPath: (p: string): Promise<{ ok: boolean }> =>
  152. ipcRenderer.invoke(IpcChannels.CONFIG_SET_BACKUP_PATH, p),
  153. setAutoUnsubscribeAfterBackup: (enabled: boolean): Promise<{ ok: boolean }> =>
  154. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUTO_UNSUBSCRIBE, enabled),
  155. pickFolder: (): Promise<string | null> =>
  156. ipcRenderer.invoke(IpcChannels.CONFIG_PICK_FOLDER),
  157. pickFile: (): Promise<string | null> =>
  158. ipcRenderer.invoke(IpcChannels.CONFIG_PICK_FILE),
  159. importWE: (sourcePath: string): Promise<{ folders: number; playlists: number; configPath: string }> =>
  160. ipcRenderer.invoke(IpcChannels.CONFIG_IMPORT_WE, sourcePath),
  161. createFresh: (): Promise<{ configPath: string }> =>
  162. ipcRenderer.invoke(IpcChannels.CONFIG_CREATE_FRESH),
  163. setTrayEnabled: (enabled: boolean): Promise<{ ok: boolean }> =>
  164. ipcRenderer.invoke(IpcChannels.CONFIG_SET_TRAY_ENABLED, enabled),
  165. setKillLweOnQuit: (enabled: boolean): Promise<{ ok: boolean }> =>
  166. ipcRenderer.invoke(IpcChannels.CONFIG_SET_KILL_LWE_ON_QUIT, enabled),
  167. setVoteBorders: (enabled: boolean): Promise<{ ok: boolean }> =>
  168. ipcRenderer.invoke(IpcChannels.CONFIG_SET_VOTE_BORDERS, enabled),
  169. setAutostart: (
  170. enabled: boolean,
  171. minimized: boolean,
  172. playlistId: string | null
  173. ): Promise<{ ok: boolean }> =>
  174. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUTOSTART, enabled, minimized, playlistId),
  175. getAutostartSupported: (): Promise<boolean> =>
  176. ipcRenderer.invoke(IpcChannels.CONFIG_GET_AUTOSTART_SUPPORTED),
  177. setAudioScreen: (screen: string | null): Promise<{ ok: boolean }> =>
  178. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AUDIO_SCREEN, screen),
  179. setAmbientVolume: (volume: number | null): Promise<{ ok: boolean }> =>
  180. ipcRenderer.invoke(IpcChannels.CONFIG_SET_AMBIENT_VOLUME, volume),
  181. setDefaultAudioSensitivity: (multiplier: number): Promise<{ ok: boolean }> =>
  182. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DEFAULT_AUDIO_SENSITIVITY, multiplier),
  183. setDisablePuppetAnimation: (disabled: boolean): Promise<{ ok: boolean }> =>
  184. ipcRenderer.invoke(IpcChannels.CONFIG_SET_DISABLE_PUPPET_ANIMATION, disabled),
  185. setSteamIdentity: (identity: SteamIdentity): Promise<{ ok: boolean }> =>
  186. ipcRenderer.invoke(IpcChannels.CONFIG_SET_STEAM_IDENTITY, identity),
  187. ignoreCreator: (steamId: string): Promise<{ ok: boolean }> =>
  188. ipcRenderer.invoke(IpcChannels.CONFIG_IGNORE_CREATOR, steamId),
  189. unignoreCreator: (steamId: string): Promise<{ ok: boolean }> =>
  190. ipcRenderer.invoke(IpcChannels.CONFIG_UNIGNORE_CREATOR, steamId)
  191. },
  192. playlist: {
  193. getAll: (): Promise<Playlist[]> => ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_ALL),
  194. getOne: (id: string): Promise<Playlist | null> =>
  195. ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_ONE, id),
  196. create: (title: string): Promise<Playlist> =>
  197. ipcRenderer.invoke(IpcChannels.PLAYLIST_CREATE, title),
  198. rename: (id: string, title: string): Promise<Playlist | null> =>
  199. ipcRenderer.invoke(IpcChannels.PLAYLIST_RENAME, id, title),
  200. delete: (id: string): Promise<{ ok: boolean }> =>
  201. ipcRenderer.invoke(IpcChannels.PLAYLIST_DELETE, id),
  202. updateSettings: (id: string, patch: Partial<PlaylistSettings>): Promise<Playlist | null> =>
  203. ipcRenderer.invoke(IpcChannels.PLAYLIST_UPDATE_SETTINGS, id, patch),
  204. addItems: (id: string, wallpaperIds: string[]): Promise<Playlist | null> =>
  205. ipcRenderer.invoke(IpcChannels.PLAYLIST_ADD_ITEMS, id, wallpaperIds),
  206. removeItems: (id: string, wallpaperIds: string[]): Promise<Playlist | null> =>
  207. ipcRenderer.invoke(IpcChannels.PLAYLIST_REMOVE_ITEMS, id, wallpaperIds),
  208. reorderItems: (id: string, orderedWallpaperIds: string[]): Promise<Playlist | null> =>
  209. ipcRenderer.invoke(IpcChannels.PLAYLIST_REORDER_ITEMS, id, orderedWallpaperIds),
  210. updateItem: (
  211. id: string,
  212. wallpaperId: string,
  213. patch: { volume?: number; durationSec?: number }
  214. ): Promise<Playlist | null> =>
  215. ipcRenderer.invoke(IpcChannels.PLAYLIST_UPDATE_ITEM, id, wallpaperId, patch),
  216. start: (id: string, screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  217. ipcRenderer.invoke(IpcChannels.PLAYLIST_START, id, screen),
  218. playItem: (id: string, wallpaperId: string, screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  219. ipcRenderer.invoke(IpcChannels.PLAYLIST_PLAY_ITEM, id, wallpaperId, screen),
  220. stop: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  221. ipcRenderer.invoke(IpcChannels.PLAYLIST_STOP, screen),
  222. pause: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  223. ipcRenderer.invoke(IpcChannels.PLAYLIST_PAUSE, screen),
  224. resume: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  225. ipcRenderer.invoke(IpcChannels.PLAYLIST_RESUME, screen),
  226. next: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  227. ipcRenderer.invoke(IpcChannels.PLAYLIST_NEXT, screen),
  228. previous: (screen?: ScreenTarget): Promise<PlaylistPlaybackState[]> =>
  229. ipcRenderer.invoke(IpcChannels.PLAYLIST_PREVIOUS, screen),
  230. getState: (): Promise<PlaylistPlaybackState[]> =>
  231. ipcRenderer.invoke(IpcChannels.PLAYLIST_GET_STATE)
  232. },
  233. folders: {
  234. getAll: (): Promise<WallpaperFolder[]> =>
  235. ipcRenderer.invoke(IpcChannels.FOLDERS_GET_ALL),
  236. create: (title: string): Promise<WallpaperFolder> =>
  237. ipcRenderer.invoke(IpcChannels.FOLDERS_CREATE, title),
  238. rename: (id: string, title: string): Promise<WallpaperFolder | null> =>
  239. ipcRenderer.invoke(IpcChannels.FOLDERS_RENAME, id, title),
  240. delete: (id: string): Promise<{ ok: boolean }> =>
  241. ipcRenderer.invoke(IpcChannels.FOLDERS_DELETE, id),
  242. addItems: (folderId: string, itemIds: string[]): Promise<WallpaperFolder | null> =>
  243. ipcRenderer.invoke(IpcChannels.FOLDERS_ADD_ITEMS, folderId, itemIds),
  244. removeItems: (folderId: string, itemIds: string[]): Promise<WallpaperFolder | null> =>
  245. ipcRenderer.invoke(IpcChannels.FOLDERS_REMOVE_ITEMS, folderId, itemIds),
  246. importWEConfig: (configPath: string): Promise<{ folders: number; playlists: number }> =>
  247. ipcRenderer.invoke(IpcChannels.FOLDERS_IMPORT_WE_CONFIG, configPath),
  248. cleanup: (): Promise<{ removed: number }> =>
  249. ipcRenderer.invoke(IpcChannels.FOLDERS_CLEANUP)
  250. },
  251. wallpaper: {
  252. apply: (options: ApplyWallpaperOptions): Promise<{ ok: boolean; appliedPath: string }> =>
  253. ipcRenderer.invoke(IpcChannels.WALLPAPER_APPLY, options),
  254. getActive: (): Promise<WallpaperMeta | null> =>
  255. ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_ACTIVE),
  256. getAssignments: (): Promise<ScreenAssignment[]> =>
  257. ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_ASSIGNMENTS),
  258. getTargets: (): Promise<ScreenTarget[]> =>
  259. ipcRenderer.invoke(IpcChannels.WALLPAPER_GET_TARGETS),
  260. stop: (screen?: ScreenTarget): Promise<{ ok: boolean }> =>
  261. ipcRenderer.invoke(IpcChannels.WALLPAPER_STOP, screen),
  262. testLaunch: (wallpaperId: string, screen?: ScreenTarget): Promise<{ ok: boolean }> =>
  263. ipcRenderer.invoke(IpcChannels.WALLPAPER_TEST_LAUNCH, wallpaperId, screen),
  264. generateThumbnail: (wallpaperId: string): Promise<WallpaperMeta> =>
  265. ipcRenderer.invoke(IpcChannels.WALLPAPER_GENERATE_THUMBNAIL, wallpaperId),
  266. pickThumbnail: (wallpaperId: string): Promise<WallpaperMeta | null> =>
  267. ipcRenderer.invoke(IpcChannels.WALLPAPER_PICK_THUMBNAIL, wallpaperId),
  268. deleteThumbnail: (wallpaperId: string): Promise<WallpaperMeta> =>
  269. ipcRenderer.invoke(IpcChannels.WALLPAPER_DELETE_THUMBNAIL, wallpaperId),
  270. detectEnvironment: (): Promise<WallpaperEnvironment> =>
  271. ipcRenderer.invoke(IpcChannels.WALLPAPER_DETECT_ENV)
  272. },
  273. lwe: {
  274. status: (): Promise<LweStatus> =>
  275. ipcRenderer.invoke(IpcChannels.LWE_STATUS),
  276. detectDistro: (): Promise<LinuxDistro> =>
  277. ipcRenderer.invoke(IpcChannels.LWE_DETECT_DISTRO),
  278. installDeps: (): Promise<{ ok: boolean }> =>
  279. ipcRenderer.invoke(IpcChannels.LWE_INSTALL_DEPS),
  280. install: (): Promise<LweStatus> =>
  281. ipcRenderer.invoke(IpcChannels.LWE_INSTALL),
  282. uninstall: (): Promise<{ ok: boolean; message: string }> =>
  283. ipcRenderer.invoke(IpcChannels.LWE_UNINSTALL),
  284. launch: (wallpaperPath: string, options?: { screen?: ScreenTarget; fps?: number }): Promise<{ ok: boolean; running: boolean }> =>
  285. ipcRenderer.invoke(IpcChannels.LWE_LAUNCH, wallpaperPath, options),
  286. stop: (): Promise<{ ok: boolean }> =>
  287. ipcRenderer.invoke(IpcChannels.LWE_STOP),
  288. killAll: (): Promise<{ ok: boolean; message: string }> =>
  289. ipcRenderer.invoke(IpcChannels.LWE_KILL_ALL),
  290. listObjects: (wallpaperPath: string): Promise<LweSceneObject[]> =>
  291. ipcRenderer.invoke(IpcChannels.LWE_LIST_OBJECTS, wallpaperPath),
  292. hotswapSettings: (options: {
  293. disabledObjects?: string[]
  294. enabledObjects?: string[]
  295. volume?: number
  296. xray?: boolean
  297. scaling?: string
  298. zoom?: number
  299. offsetX?: number
  300. offsetY?: number
  301. disableParallax?: boolean
  302. expandCanvas?: boolean
  303. cornerColor?: string
  304. speed?: number
  305. propertyOverrides?: Record<string, string>
  306. audioScreen?: string
  307. ambientVolume?: number
  308. audioSensitivity?: Record<string, number>
  309. soundVolume?: Record<string, number>
  310. }, wallpaperPath?: string): Promise<{ ok: boolean }> =>
  311. ipcRenderer.invoke(IpcChannels.LWE_HOTSWAP_SETTINGS, options, wallpaperPath),
  312. listProperties: (wallpaperPath: string): Promise<LweProperty[]> =>
  313. ipcRenderer.invoke(IpcChannels.LWE_LIST_PROPERTIES, wallpaperPath),
  314. listScreens: (): Promise<string[]> =>
  315. ipcRenderer.invoke(IpcChannels.LWE_LIST_SCREENS),
  316. listAudioObjects: (wallpaperPath: string): Promise<LweAudioObject[]> =>
  317. ipcRenderer.invoke(IpcChannels.LWE_LIST_AUDIO_OBJECTS, wallpaperPath),
  318. listEffects: (wallpaperPath: string): Promise<LweSceneEffect[]> =>
  319. ipcRenderer.invoke(IpcChannels.LWE_LIST_EFFECTS, wallpaperPath),
  320. listApplications: (): Promise<DesktopApplication[]> =>
  321. ipcRenderer.invoke(IpcChannels.LWE_LIST_APPLICATIONS),
  322. pickShortcutPath: (kind: 'file' | 'directory'): Promise<string | null> =>
  323. ipcRenderer.invoke(IpcChannels.LWE_PICK_SHORTCUT_PATH, kind)
  324. },
  325. schedule: {
  326. getAll: (): Promise<ScheduleRule[]> => ipcRenderer.invoke(IpcChannels.SCHEDULE_GET_ALL),
  327. save: (rule: Omit<ScheduleRule, 'id'> & { id?: string }): Promise<ScheduleRule> =>
  328. ipcRenderer.invoke(IpcChannels.SCHEDULE_SAVE, rule),
  329. delete: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.SCHEDULE_DELETE, id),
  330. run: (id: string): Promise<{ ok: boolean }> => ipcRenderer.invoke(IpcChannels.SCHEDULE_RUN, id)
  331. },
  332. backup: {
  333. item: (itemId: string): Promise<{ ok: boolean; unsubscribed: boolean }> =>
  334. ipcRenderer.invoke(IpcChannels.BACKUP_ITEM, itemId),
  335. selection: (itemIds: string[]): Promise<{ backedUp: number; failed: number; unsubscribed: number }> =>
  336. ipcRenderer.invoke(IpcChannels.BACKUP_SELECTION, itemIds),
  337. scan: (): Promise<{ imported: number; skipped: number; linked: number }> =>
  338. ipcRenderer.invoke(IpcChannels.BACKUP_SCAN)
  339. },
  340. desktopIcons: {
  341. setEnabled: (enabled: boolean): Promise<{ ok: boolean; enabled: boolean }> =>
  342. ipcRenderer.invoke(IpcChannels.DESKTOP_ICONS_SET_ENABLED, enabled),
  343. getEnabled: (): Promise<boolean> =>
  344. ipcRenderer.invoke(IpcChannels.DESKTOP_ICONS_GET_ENABLED)
  345. },
  346. shell: {
  347. openInFileManager: (folderPath: string): Promise<{ ok: boolean; error?: string }> =>
  348. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_IN_FILE_MANAGER, folderPath),
  349. openWithDefault: (filePath: string): Promise<{ ok: boolean; error?: string }> =>
  350. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_WITH_DEFAULT, filePath),
  351. openPath: (targetPath: string): Promise<{ ok: boolean; error?: string }> =>
  352. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_PATH, targetPath),
  353. openPaths: (targetPaths: string[]): Promise<{ ok: boolean; error?: string }> =>
  354. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_PATHS, targetPaths),
  355. openExternal: (url: string): Promise<{ ok: boolean; error?: string }> =>
  356. ipcRenderer.invoke(IpcChannels.SHELL_OPEN_EXTERNAL, url)
  357. },
  358. on: {
  359. downloadProgress: (cb: (info: DownloadProgressEvent) => void): (() => void) => {
  360. const listener = (_: Electron.IpcRendererEvent, info: DownloadProgressEvent) => cb(info)
  361. ipcRenderer.on(IpcChannels.EVENT_DOWNLOAD_PROGRESS, listener)
  362. return () => ipcRenderer.off(IpcChannels.EVENT_DOWNLOAD_PROGRESS, listener)
  363. },
  364. wallpaperImported: (cb: (meta: WallpaperMeta) => void): (() => void) => {
  365. const listener = (_: Electron.IpcRendererEvent, meta: WallpaperMeta) => cb(meta)
  366. ipcRenderer.on(IpcChannels.EVENT_WALLPAPER_IMPORTED, listener)
  367. return () => ipcRenderer.off(IpcChannels.EVENT_WALLPAPER_IMPORTED, listener)
  368. },
  369. steamStatus: (cb: (running: boolean) => void): (() => void) => {
  370. const listener = (_: Electron.IpcRendererEvent, running: boolean) => cb(running)
  371. ipcRenderer.on(IpcChannels.EVENT_STEAM_STATUS, listener)
  372. return () => ipcRenderer.off(IpcChannels.EVENT_STEAM_STATUS, listener)
  373. },
  374. lweInstallProgress: (cb: (progress: LweInstallProgress) => void): (() => void) => {
  375. const listener = (_: Electron.IpcRendererEvent, progress: LweInstallProgress) => cb(progress)
  376. ipcRenderer.on(IpcChannels.EVENT_LWE_INSTALL_PROGRESS, listener)
  377. return () => ipcRenderer.off(IpcChannels.EVENT_LWE_INSTALL_PROGRESS, listener)
  378. },
  379. backupProgress: (cb: (progress: BackupProgressEvent) => void): (() => void) => {
  380. const listener = (_: Electron.IpcRendererEvent, progress: BackupProgressEvent) => cb(progress)
  381. ipcRenderer.on(IpcChannels.EVENT_BACKUP_PROGRESS, listener)
  382. return () => ipcRenderer.off(IpcChannels.EVENT_BACKUP_PROGRESS, listener)
  383. },
  384. playlistStateChanged: (cb: (states: PlaylistPlaybackState[]) => void): (() => void) => {
  385. const listener = (_: Electron.IpcRendererEvent, states: PlaylistPlaybackState[]) => cb(states)
  386. ipcRenderer.on(IpcChannels.EVENT_PLAYLIST_STATE_CHANGED, listener)
  387. return () => ipcRenderer.off(IpcChannels.EVENT_PLAYLIST_STATE_CHANGED, listener)
  388. },
  389. votedIdsChanged: (cb: (ids: string[]) => void): (() => void) => {
  390. const listener = (_: Electron.IpcRendererEvent, ids: string[]) => cb(ids)
  391. ipcRenderer.on(IpcChannels.EVENT_VOTED_IDS_CHANGED, listener)
  392. return () => ipcRenderer.off(IpcChannels.EVENT_VOTED_IDS_CHANGED, listener)
  393. },
  394. failedVotesChanged: (cb: (failed: Record<string, string>) => void): (() => void) => {
  395. const listener = (_: Electron.IpcRendererEvent, failed: Record<string, string>) => cb(failed)
  396. ipcRenderer.on(IpcChannels.EVENT_FAILED_VOTES_CHANGED, listener)
  397. return () => ipcRenderer.off(IpcChannels.EVENT_FAILED_VOTES_CHANGED, listener)
  398. },
  399. libraryChanged: (cb: () => void): (() => void) => {
  400. const listener = () => cb()
  401. ipcRenderer.on(IpcChannels.EVENT_LIBRARY_CHANGED, listener)
  402. return () => ipcRenderer.off(IpcChannels.EVENT_LIBRARY_CHANGED, listener)
  403. },
  404. displayChanged: (cb: () => void): (() => void) => {
  405. const listener = () => cb()
  406. ipcRenderer.on(IpcChannels.EVENT_DISPLAY_CHANGED, listener)
  407. return () => ipcRenderer.off(IpcChannels.EVENT_DISPLAY_CHANGED, listener)
  408. },
  409. wallpaperCrashed: (cb: (event: CrashEvent) => void): (() => void) => {
  410. const listener = (_: Electron.IpcRendererEvent, event: CrashEvent) => cb(event)
  411. ipcRenderer.on(IpcChannels.EVENT_WALLPAPER_CRASHED, listener)
  412. return () => ipcRenderer.off(IpcChannels.EVENT_WALLPAPER_CRASHED, listener)
  413. },
  414. scheduleFired: (cb: (ruleName: string) => void): (() => void) => {
  415. const listener = (_: Electron.IpcRendererEvent, ruleName: string) => cb(ruleName)
  416. ipcRenderer.on(IpcChannels.EVENT_SCHEDULE_FIRED, listener)
  417. return () => ipcRenderer.off(IpcChannels.EVENT_SCHEDULE_FIRED, listener)
  418. }
  419. }
  420. }
  421. contextBridge.exposeInMainWorld('electronAPI', api)
  422. export type ElectronAPI = typeof api