feat: denshi settings

feat: use typescript-go
This commit is contained in:
5rahim
2026-02-21 15:17:36 +01:00
parent dff43024df
commit e230ebeb34
10 changed files with 393 additions and 71 deletions

View File

@@ -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() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -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()

View File

@@ -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),
},
}
);

View File

@@ -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",

View File

@@ -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"
}
}
}

View File

@@ -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<DenshiSettings | null>(null)
const settingsRef = React.useRef<DenshiSettings | null>(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 (
<div className="space-y-4">
<SettingsCard title="Window">
<Switch
side="right"
value={settings.minimizeToTray}
onValueChange={(v) => 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."
/>
<Switch
side="right"
value={settings.openInBackground}
onValueChange={(v) => updateSetting("openInBackground", v)}
label="Open in background"
help="When enabled, the app will start hidden. You can show it from the system tray."
/>
</SettingsCard>
<SettingsCard title="System">
<Switch
side="right"
value={settings.openAtLaunch}
onValueChange={(v) => 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"}
/>
</SettingsCard>
<div className="flex items-center gap-2 text-sm text-gray-500 bg-gray-50 dark:bg-gray-900/30 rounded-lg p-3 border border-gray-200 dark:border-gray-800 border-dashed">
<RiSettings3Fill className="text-base" />
<span>Settings are saved automatically and applied after a restart</span>
</div>
</div>
)
}

View File

@@ -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() {
{/*</div>*/}
<Card className="lg:p-2 contents lg:block border-0 bg-transparent lg:border lg:bg-gray-950/80">
{__isElectronDesktop__ && (
<TabsTrigger
value="denshi"
className="group"
><LuMonitor className="text-xl mr-3 transition-transform duration-200" /> Denshi</TabsTrigger>
)}
<TabsTrigger
value="ui"
className="group"
@@ -410,7 +418,7 @@ export default function Page() {
mediaPlayerHost: status?.settings?.mediaPlayer?.host,
torrentProvider: status?.settings?.library?.torrentProvider || DEFAULT_TORRENT_PROVIDER, // (Backwards compatibility)
autoSelectTorrentProvider: status?.settings?.library?.autoSelectTorrentProvider || DEFAULT_TORRENT_PROVIDER, // (Backwards
// compatibility)
// compatibility)
autoScan: status?.settings?.library?.autoScan,
defaultPlayer: status?.settings?.mediaPlayer?.defaultPlayer,
vlcPort: status?.settings?.mediaPlayer?.vlcPort,
@@ -869,6 +877,20 @@ export default function Page() {
</TabsContent>
{__isElectronDesktop__ && (
<TabsContent value="denshi" className={tabContentClass}>
<SettingsPageHeader
title="Denshi"
description="Desktop client settings"
icon={LuMonitor}
/>
<DenshiSettings />
</TabsContent>
)}
{/*<TabsContent value="data" className="space-y-4">*/}

View File

@@ -67,8 +67,18 @@ declare global {
checkForUpdates: () => Promise<any>;
installUpdate: () => Promise<any>;
killServer: () => Promise<any>;
denshiSettings: {
get: () => Promise<DenshiSettings>;
set: (settings: DenshiSettings) => Promise<DenshiSettings>;
};
};
__isElectronDesktop__?: boolean;
}
interface DenshiSettings {
minimizeToTray: boolean;
openInBackground: boolean;
openAtLaunch: boolean;
}
}

View File

@@ -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"
}
]
}
}