diff --git a/internal/library/autodownloader/autodownloader.go b/internal/library/autodownloader/autodownloader.go index bf31d949..19e4c78e 100644 --- a/internal/library/autodownloader/autodownloader.go +++ b/internal/library/autodownloader/autodownloader.go @@ -1430,6 +1430,10 @@ func (ad *AutoDownloader) isSeasonAndEpisodeMatch( if rule.CustomEpisodeNumberAbsoluteOffset > 0 { episode = episode - rule.CustomEpisodeNumberAbsoluteOffset hasAbsoluteEpisode = true + if episode < 1 { + episode = 1 + hasAbsoluteEpisode = false + } } else { // Handle absolute episode numbers from metadata if listEntry.GetMedia().GetCurrentEpisodeCount() != -1 && episode > listEntry.GetMedia().GetCurrentEpisodeCount() { diff --git a/seanime-denshi/assets/iconTemplate.png b/seanime-denshi/assets/iconTemplate.png new file mode 100644 index 00000000..53c2ed3f Binary files /dev/null and b/seanime-denshi/assets/iconTemplate.png differ diff --git a/seanime-denshi/src/main.js b/seanime-denshi/src/main.js index 6fb143f7..1961b518 100644 --- a/seanime-denshi/src/main.js +++ b/seanime-denshi/src/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow, Menu, Tray, ipcMain, shell, dialog, remote, net, protocol, contextBridge } = require("electron") +const { app, BrowserWindow, Menu, Tray, ipcMain, shell, dialog, remote, net, protocol, nativeImage } = require("electron") const path = require("path") const { spawn } = require("child_process") const fs = require("fs") @@ -11,6 +11,44 @@ const { autoUpdater } = require("electron-updater") const log = require("electron-log/main") log.initialize() +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Settings +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const DENSHI_SETTINGS_DEFAULTS = { + minimizeToTray: true, + openInBackground: false, + openAtLaunch: false, +} + +function getDenshiSettingsPath() { + return path.join(app.getPath("userData"), "denshi-settings.json") +} + +function loadDenshiSettings() { + try { + const settingsPath = getDenshiSettingsPath() + if (fs.existsSync(settingsPath)) { + const data = JSON.parse(fs.readFileSync(settingsPath, "utf-8")) + return { ...DENSHI_SETTINGS_DEFAULTS, ...data } + } + } catch (err) { + log.error("[Denshi] Failed to load settings:", err) + } + return { ...DENSHI_SETTINGS_DEFAULTS } +} + +function saveDenshiSettings(settings) { + try { + const settingsPath = getDenshiSettingsPath() + fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8") + } catch (err) { + log.error("[Denshi] Failed to save settings:", err) + } +} + +let denshiSettings = DENSHI_SETTINGS_DEFAULTS + const _isRsbuildFrontend = true ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -452,14 +490,17 @@ if (!gotTheLock) { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function createTray() { - let iconPath = path.join(__dirname, "../assets/icon.png") - if (process.platform === "darwin") { - iconPath = path.join(__dirname, "../assets/18x18.png") + const iconName = process.platform === "darwin" ? "18x18.png" : "icon.png" + + let iconPath = path.join(__dirname, "../assets", iconName) + if (_development) { + iconPath = path.join(app.getAppPath(), "assets", iconName) } - tray = new Tray(iconPath) + const icon = nativeImage.createFromPath(iconPath) + tray = new Tray(icon) const contextMenu = Menu.buildFromTemplate([{ - id: "toggle_visibility", label: "Toggle visibility", click: () => { + id: "toggle_visibility", label: "Toggle Visibility", click: () => { if (mainWindow.isVisible()) { mainWindow.hide() if (process.platform === "darwin") { @@ -474,7 +515,7 @@ function createTray() { } } }, ...(process.platform === "darwin" ? [{ - id: "accessory_mode", label: "Remove from dock", click: () => { + id: "accessory_mode", label: "Remove from Dock", click: () => { app.dock.hide() } } @@ -529,7 +570,7 @@ async function launchSeanimeServer(isRestart) { splashScreen.close() splashScreen = null } - if (mainWindow && !mainWindow.isDestroyed()) { + if (mainWindow && !mainWindow.isDestroyed() && !denshiSettings.openInBackground) { mainWindow.maximize() mainWindow.show() } @@ -626,8 +667,14 @@ async function launchSeanimeServer(isRestart) { console.log("[Main] Server started close splash screen") setTimeout(() => { if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.maximize() - mainWindow.show() + if (denshiSettings.openInBackground) { + // Keep window hidden, just maximize it for when user shows it + mainWindow.maximize() + log.info("[Denshi] Opened in background") + } else { + mainWindow.maximize() + mainWindow.show() + } } }, 1000) resolve() @@ -772,10 +819,15 @@ function createMainWindow() { mainWindow.on("close", (event) => { if (!isShutdown) { - event.preventDefault() - mainWindow.hide() - if (process.platform === "darwin") { - app.dock.hide() + if (denshiSettings.minimizeToTray) { + event.preventDefault() + mainWindow.hide() + if (process.platform === "darwin") { + app.dock.hide() + } + } else { + // Close the app completely + cleanupAndExit() } } }) @@ -788,7 +840,7 @@ function createMainWindow() { function createSplashScreen() { logStartupEvent("Creating splash screen") splashScreen = new BrowserWindow({ - width: 800, height: 600, frame: false, resizable: false, backgroundColor: "#0c0c0c", webPreferences: { + width: 800, height: 600, frame: false, resizable: false, show: !denshiSettings.openInBackground, backgroundColor: "#0c0c0c", webPreferences: { nodeIntegration: false, contextIsolation: true, preload: path.join(__dirname, "preload.js") } }) @@ -886,6 +938,20 @@ function cleanupAndExit() { app.whenReady().then(async () => { logStartupEvent("App ready") + // Load denshi settings early + denshiSettings = loadDenshiSettings() + if (_development) { + denshiSettings.openInBackground = false + } + log.info("[Denshi] Loaded settings:", JSON.stringify(denshiSettings)) + + // Apply openAtLaunch setting (only supported on macOS and Windows) + if (!_development && (process.platform === "darwin" || process.platform === "win32")) { + app.setLoginItemSettings({ + openAtLogin: denshiSettings.openAtLaunch, + }) + } + // Set up Chromium flags for better video playback setupChromiumFlags() @@ -1138,6 +1204,26 @@ app.whenReady().then(async () => { ipcMain.handle("get-local-server-port", () => localServerPort) + // Denshi settings IPC handlers + ipcMain.handle("denshi:getSettings", () => { + return { ...denshiSettings } + }) + + ipcMain.handle("denshi:setSettings", (_, newSettings) => { + denshiSettings = { ...DENSHI_SETTINGS_DEFAULTS, ...newSettings } + saveDenshiSettings(denshiSettings) + log.info("[Denshi] Settings updated:", JSON.stringify(denshiSettings)) + + // Apply openAtLaunch immediately (only supported on macOS and Windows) + if (!_development && (process.platform === "darwin" || process.platform === "win32")) { + app.setLoginItemSettings({ + openAtLogin: denshiSettings.openAtLaunch, + }) + } + + return { ...denshiSettings } + }) + app.on("window-all-closed", () => { if (process.platform !== "darwin") { app.quit() diff --git a/seanime-denshi/src/preload.js b/seanime-denshi/src/preload.js index 58d1e29b..24462329 100644 --- a/seanime-denshi/src/preload.js +++ b/seanime-denshi/src/preload.js @@ -1,4 +1,4 @@ -const {contextBridge, ipcRenderer, ipcMain, shell, BrowserWindow} = require('electron'); +const { contextBridge, ipcRenderer, ipcMain, shell, BrowserWindow } = require("electron") // Expose protected methods that allow the renderer process to use // the ipcRenderer without exposing the entire object @@ -6,22 +6,22 @@ contextBridge.exposeInMainWorld( 'electron', { // Window Controls window: { - minimize: () => ipcRenderer.send('window:minimize'), - maximize: () => ipcRenderer.send('window:maximize'), - close: () => ipcRenderer.send('window:close'), - isMaximized: () => ipcRenderer.invoke('window:isMaximized'), - isMinimizable: () => ipcRenderer.invoke('window:isMinimizable'), - isMaximizable: () => ipcRenderer.invoke('window:isMaximizable'), - isClosable: () => ipcRenderer.invoke('window:isClosable'), - isFullscreen: () => ipcRenderer.invoke('window:isFullscreen'), - setFullscreen: (fullscreen) => ipcRenderer.send('window:setFullscreen', fullscreen), - toggleMaximize: () => ipcRenderer.send('window:toggleMaximize'), - hide: () => ipcRenderer.send('window:hide'), - show: () => ipcRenderer.send('window:show'), - isVisible: () => ipcRenderer.invoke('window:isVisible'), - setTitleBarStyle: (style) => ipcRenderer.send('window:setTitleBarStyle', style), - getCurrentWindow: () => ipcRenderer.invoke('window:getCurrentWindow'), - isMainWindow: () => ipcRenderer.send('window:isMainWindow'), + minimize: () => ipcRenderer.send("window:minimize"), + maximize: () => ipcRenderer.send("window:maximize"), + close: () => ipcRenderer.send("window:close"), + isMaximized: () => ipcRenderer.invoke("window:isMaximized"), + isMinimizable: () => ipcRenderer.invoke("window:isMinimizable"), + isMaximizable: () => ipcRenderer.invoke("window:isMaximizable"), + isClosable: () => ipcRenderer.invoke("window:isClosable"), + isFullscreen: () => ipcRenderer.invoke("window:isFullscreen"), + setFullscreen: (fullscreen) => ipcRenderer.send("window:setFullscreen", fullscreen), + toggleMaximize: () => ipcRenderer.send("window:toggleMaximize"), + hide: () => ipcRenderer.send("window:hide"), + show: () => ipcRenderer.send("window:show"), + isVisible: () => ipcRenderer.invoke("window:isVisible"), + setTitleBarStyle: (style) => ipcRenderer.send("window:setTitleBarStyle", style), + getCurrentWindow: () => ipcRenderer.invoke("window:getCurrentWindow"), + isMainWindow: () => ipcRenderer.send("window:isMainWindow"), }, localServer: { @@ -32,28 +32,28 @@ contextBridge.exposeInMainWorld( on: (channel, callback) => { // Whitelist channels const validChannels = [ - 'message', - 'crash', - 'window:maximized', - 'window:unmaximized', - 'window:fullscreen', - 'update-downloaded', - 'update-error', - 'update-available', - 'download-progress', - 'window:currentWindow', - 'window:isMainWindow', - ]; + "message", + "crash", + "window:maximized", + "window:unmaximized", + "window:fullscreen", + "update-downloaded", + "update-error", + "update-available", + "download-progress", + "window:currentWindow", + "window:isMainWindow", + ] if (validChannels.includes(channel)) { // Remove the event listener to avoid memory leaks - ipcRenderer.removeAllListeners(channel); + ipcRenderer.removeAllListeners(channel) // Add the event listener - ipcRenderer.on(channel, (_, ...args) => callback(...args)); + ipcRenderer.on(channel, (_, ...args) => callback(...args)) // Return a function to remove the listener return () => { - ipcRenderer.removeAllListeners(channel); - }; + ipcRenderer.removeAllListeners(channel) + } } }, @@ -61,13 +61,13 @@ contextBridge.exposeInMainWorld( emit: (channel, data) => { // Whitelist channels const validChannels = [ - 'restart-server', - 'kill-server', - 'macos-activation-policy-accessory', - 'macos-activation-policy-regular' - ]; + "restart-server", + "kill-server", + "macos-activation-policy-accessory", + "macos-activation-policy-regular" + ] if (validChannels.includes(channel)) { - ipcRenderer.send(channel, data); + ipcRenderer.send(channel, data) } }, @@ -75,11 +75,11 @@ contextBridge.exposeInMainWorld( send: (channel, ...args) => { // Whitelist channels const validChannels = [ - 'restart-app', - 'quit-app' - ]; + "restart-app", + "quit-app" + ] if (validChannels.includes(channel)) { - ipcRenderer.send(channel, ...args); + ipcRenderer.send(channel, ...args) } }, @@ -93,13 +93,19 @@ contextBridge.exposeInMainWorld( // Clipboard clipboard: { - writeText: (text) => ipcRenderer.invoke('clipboard:writeText', text) + writeText: (text) => ipcRenderer.invoke("clipboard:writeText", text) }, // Update functions - checkForUpdates: () => ipcRenderer.invoke('check-for-updates'), - installUpdate: () => ipcRenderer.invoke('install-update'), - killServer: () => ipcRenderer.invoke('kill-server') + checkForUpdates: () => ipcRenderer.invoke("check-for-updates"), + installUpdate: () => ipcRenderer.invoke("install-update"), + killServer: () => ipcRenderer.invoke("kill-server"), + + // Denshi Settings + denshiSettings: { + get: () => ipcRenderer.invoke("denshi:getSettings"), + set: (settings) => ipcRenderer.invoke("denshi:setSettings", settings), + }, } ); diff --git a/seanime-web/package-lock.json b/seanime-web/package-lock.json index a37b9ae9..fca3ccaf 100644 --- a/seanime-web/package-lock.json +++ b/seanime-web/package-lock.json @@ -148,6 +148,7 @@ "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@types/react-window": "^1.8.8", + "@typescript/native-preview": "^7.0.0-dev.20260221.1", "autoprefixer": "^10", "babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405", "encoding": "^0.1.13", @@ -6073,6 +6074,123 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@typescript/native-preview": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-tEUzcnj6pD+z1vANchRzhpPl+3RMD+xQRvIN//0+qjtP5zyYB5T+MIaAWycpKDwlHP9C13JnQgcgYnC+LlNkrg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsgo": "bin/tsgo.js" + }, + "optionalDependencies": { + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260221.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260221.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20260221.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260221.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20260221.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260221.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20260221.1" + } + }, + "node_modules/@typescript/native-preview-darwin-arm64": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-m3ttEpK+eXV7P06RVZZuSuUvNDj8psXODrMJRRQWpTNsk3qITbIdBSgOx2Q/M3tbQ9Mo2IBHt6jUjqOdRW9oZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@typescript/native-preview-darwin-x64": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-BNaNe3rox2rpkh5sWcnZZob6sDA/at9KK55/WSRAH4W+9dFReOLFAR9YXhKxrLGZ1QpleuIBahKbV8o037S+pA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@typescript/native-preview-linux-arm": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-+/uyIw7vg4FyAnNpsCJHmSOhMiR2m56lqaEo1J5pMAstJmfLTTKQdJ1muIWCDCqc24k2U30IStHOaCqUerp/nQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-linux-arm64": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-Y4jsvwDq86LXq63UYRLqCAd+nD1r6C2NVaGNR39H+c6D8SgOBkPLJa8quTH0Ir8E5bsR8vTN4E6xHY9jD4J2PA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-linux-x64": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-7agd5FtVLPp+gRMvsecSDmdQ/XM80q/uaQ6+Kahan9uNrCuPJIyMiAtJvCoYYgT1nXX2AjwZk39DH63fRaw/Mg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-win32-arm64": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-lXbsy5vDzS//oE0evX+QwZBwpKselXTd8H18lT42CBQo2hL2r0+w9YBguaYXrnGkAoHjDXEfKA2xii8yVZKVUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@typescript/native-preview-win32-x64": { + "version": "7.0.0-dev.20260221.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260221.1.tgz", + "integrity": "sha512-O02pfQlVlRTsBmp0hODs/bOHm2ic2kXZpIchBP5Qm0wKCp1Ytz/7i3SNT1gN47I+KC4axn/AHhFmkWQyIu9kRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@uidotdev/usehooks": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz", diff --git a/seanime-web/package.json b/seanime-web/package.json index ab17730a..ba29075d 100644 --- a/seanime-web/package.json +++ b/seanime-web/package.json @@ -8,11 +8,11 @@ "dev:mobile": "env-cmd -f .env.mobile rsbuild dev", "dev:desktop": "env-cmd -f .env.desktop rsbuild dev", "dev:denshi": "env-cmd -f .env.denshi rsbuild dev", - "build": "tsc && rsbuild build", + "build": "tsgo && rsbuild build", "build:rsdoctor": "RSDOCTOR=true rsbuild build", - "build:desktop": "tsc && env-cmd -f .env.desktop rsbuild build", - "build:denshi": "tsc && env-cmd -f .env.denshi rsbuild build", - "build:development:desktop": "tsc && env-cmd -f .env.development.desktop rsbuild build", + "build:desktop": "tsgo && env-cmd -f .env.desktop rsbuild build", + "build:denshi": "tsgo && env-cmd -f .env.denshi rsbuild build", + "build:development:desktop": "tsgo && env-cmd -f .env.development.desktop rsbuild build", "preview": "rsbuild preview" }, "dependencies": { @@ -156,6 +156,7 @@ "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@types/react-window": "^1.8.8", + "@typescript/native-preview": "^7.0.0-dev.20260221.1", "autoprefixer": "^10", "babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405", "encoding": "^0.1.13", @@ -164,4 +165,4 @@ "typescript": "^5", "workbox-webpack-plugin": "^7.4.0" } -} +} \ No newline at end of file diff --git a/seanime-web/src/app/(main)/settings/_containers/denshi-settings.tsx b/seanime-web/src/app/(main)/settings/_containers/denshi-settings.tsx new file mode 100644 index 00000000..b322b55b --- /dev/null +++ b/seanime-web/src/app/(main)/settings/_containers/denshi-settings.tsx @@ -0,0 +1,73 @@ +import { SettingsCard } from "@/app/(main)/settings/_components/settings-card" +import { Switch } from "@/components/ui/switch" +import React from "react" +import { RiSettings3Fill } from "react-icons/ri" + +export function DenshiSettings() { + + const [settings, setSettings] = React.useState(null) + const settingsRef = React.useRef(null) + const [loading, setLoading] = React.useState(true) + + React.useEffect(() => { + if (window.electron?.denshiSettings) { + window.electron.denshiSettings.get().then((s) => { + setSettings(s) + settingsRef.current = s + setLoading(false) + }) + } + }, []) + + function updateSetting(key: keyof DenshiSettings, value: boolean) { + if (!settingsRef.current || !window.electron?.denshiSettings) return + + const newSettings = { ...settingsRef.current, [key]: value } + settingsRef.current = newSettings + setSettings(newSettings) + window.electron.denshiSettings.set(newSettings) + } + + if (loading || !settings) { + return null + } + + return ( +
+ + updateSetting("minimizeToTray", v)} + label="Minimize to tray on close" + help="When enabled, closing the window will minimize the app to the system tray instead of quitting." + /> + updateSetting("openInBackground", v)} + label="Open in background" + help="When enabled, the app will start hidden. You can show it from the system tray." + /> + + + + updateSetting("openAtLaunch", v)} + label="Open at launch" + help={window.electron?.platform === "linux" + ? "This feature is not supported on Linux." + : "When enabled, the app will start automatically when you log in to your computer."} + disabled={window.electron?.platform === "linux"} + /> + + +
+ + Settings are saved automatically and applied after a restart +
+
+ ) +} diff --git a/seanime-web/src/app/(main)/settings/page.tsx b/seanime-web/src/app/(main)/settings/page.tsx index 77cdf612..53754f82 100644 --- a/seanime-web/src/app/(main)/settings/page.tsx +++ b/seanime-web/src/app/(main)/settings/page.tsx @@ -46,6 +46,7 @@ import { LuCirclePlay, LuFileSearch, LuLibrary, + LuMonitor, LuMonitorPlay, LuPalette, LuTabletSmartphone, @@ -57,6 +58,7 @@ import { SiBittorrent, SiQbittorrent, SiTransmission } from "react-icons/si" import { TbDatabaseExclamation } from "react-icons/tb" import { VscDebugAlt } from "react-icons/vsc" import { SettingsCard, SettingsNavCard, SettingsPageHeader } from "./_components/settings-card" +import { DenshiSettings } from "./_containers/denshi-settings" import { DiscordRichPresenceSettings } from "./_containers/discord-rich-presence-settings" import { LocalSettings } from "./_containers/local-settings" import { NakamaSettings } from "./_containers/nakama-settings" @@ -259,6 +261,12 @@ export default function Page() { {/**/} + {__isElectronDesktop__ && ( + Denshi + )} + {__isElectronDesktop__ && ( + + + + + + + + )} + {/**/} diff --git a/seanime-web/src/types/index.d.ts b/seanime-web/src/types/index.d.ts index 67c10560..f6e28728 100644 --- a/seanime-web/src/types/index.d.ts +++ b/seanime-web/src/types/index.d.ts @@ -67,8 +67,18 @@ declare global { checkForUpdates: () => Promise; installUpdate: () => Promise; killServer: () => Promise; + denshiSettings: { + get: () => Promise; + set: (settings: DenshiSettings) => Promise; + }; }; __isElectronDesktop__?: boolean; } + + interface DenshiSettings { + minimizeToTray: boolean; + openInBackground: boolean; + openAtLaunch: boolean; + } } diff --git a/seanime-web/tsconfig.json b/seanime-web/tsconfig.json index 3e811147..5be0ed63 100644 --- a/seanime-web/tsconfig.json +++ b/seanime-web/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "types": [ "node", - "@rsbuild/core/types" + "@rsbuild/core/types" ], "target": "ES2020", "useDefineForClassFields": true, @@ -26,8 +26,10 @@ "noUnusedLocals": false, "noUnusedParameters": false, "noFallthroughCasesInSwitch": true, - "baseUrl": ".", "paths": { + "*": [ + "./*" + ], "@/*": [ "./src/*" ] @@ -45,4 +47,4 @@ "path": "./tsconfig.node.json" } ] -} +} \ No newline at end of file