feat: add Restart and Shutdown tray actions with confirmation dialogs
Lint & Test / test (push) Successful in 24s
Release / create-release (push) Successful in 1s
Release / build-linux (push) Successful in 31s
Release / build-windows (push) Successful in 1m13s

This commit is contained in:
2026-03-24 14:19:15 +03:00
parent 26b5f74c24
commit 3f14512e5d
+35 -2
View File
@@ -4,6 +4,8 @@ import io
import logging import logging
import os import os
import signal import signal
import subprocess
import sys
import threading import threading
import webbrowser import webbrowser
@@ -17,6 +19,26 @@ try:
except ImportError: except ImportError:
pystray = None pystray = None
# tkinter is optional — used for confirmation dialogs
try:
import tkinter as tk
from tkinter import messagebox
except ImportError:
tk = None
messagebox = None
def _confirm(title: str, message: str) -> bool:
"""Show a Yes/No confirmation dialog. Returns True if user clicks Yes."""
if messagebox is None:
return True # No tkinter — skip confirmation
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True)
result = messagebox.askyesno(title, message, parent=root)
root.destroy()
return result
def _create_icon_image(size: int = 64) -> Image.Image: def _create_icon_image(size: int = 64) -> Image.Image:
"""Create a tray icon: green circle with white play triangle.""" """Create a tray icon: green circle with white play triangle."""
@@ -75,16 +97,27 @@ def start_tray(host: str, port: int) -> "pystray.Icon | None":
def on_show_ui(_icon, _item): def on_show_ui(_icon, _item):
webbrowser.open(url) webbrowser.open(url)
def on_restart(_icon, _item):
if not _confirm("Restart Media Server", "Are you sure you want to restart the server?"):
return
logger.info("Restart requested from tray")
_icon.stop()
# Re-launch the same process, then exit current
subprocess.Popen([sys.executable] + sys.argv)
os.kill(os.getpid(), signal.SIGINT)
def on_exit(_icon, _item): def on_exit(_icon, _item):
if not _confirm("Exit Media Server", "Are you sure you want to shut down the server?"):
return
logger.info("Exit requested from tray") logger.info("Exit requested from tray")
_icon.stop() _icon.stop()
# Signal the main process to shut down gracefully
os.kill(os.getpid(), signal.SIGINT) os.kill(os.getpid(), signal.SIGINT)
menu = pystray.Menu( menu = pystray.Menu(
pystray.MenuItem("Show UI", on_show_ui, default=True), pystray.MenuItem("Show UI", on_show_ui, default=True),
pystray.Menu.SEPARATOR, pystray.Menu.SEPARATOR,
pystray.MenuItem("Exit", on_exit), pystray.MenuItem("Restart", on_restart),
pystray.MenuItem("Shutdown", on_exit),
) )
icon = pystray.Icon( icon = pystray.Icon(