"""Windows service installer for Media Server. This module allows the media server to be installed as a Windows service that starts automatically on boot. Usage: Install: python -m media_server.service.install_windows install Start: python -m media_server.service.install_windows start Stop: python -m media_server.service.install_windows stop Remove: python -m media_server.service.install_windows remove Debug: python -m media_server.service.install_windows debug """ import os import sys import socket import logging try: import win32serviceutil import win32service import win32event import servicemanager import win32api WIN32_AVAILABLE = True except ImportError: WIN32_AVAILABLE = False print("pywin32 not installed. Install with: pip install pywin32") class MediaServerService: """Windows service wrapper for the Media Server.""" _svc_name_ = "MediaServer" _svc_display_name_ = "Media Server" _svc_description_ = "REST API server for controlling system media playback" def __init__(self, args=None): if WIN32_AVAILABLE: win32serviceutil.ServiceFramework.__init__(self, args) self.stop_event = win32event.CreateEvent(None, 0, 0, None) self.is_running = False self.server = None def SvcStop(self): """Stop the service.""" self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.stop_event) self.is_running = False if self.server: self.server.should_exit = True def SvcDoRun(self): """Run the service.""" servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ""), ) self.is_running = True self.main() def main(self): """Main service loop.""" import uvicorn from media_server.main import app from media_server.config import settings config = uvicorn.Config( app, host=settings.host, port=settings.port, log_level=settings.log_level.lower(), ) self.server = uvicorn.Server(config) self.server.run() if WIN32_AVAILABLE: # Dynamically inherit from ServiceFramework when available MediaServerService = type( "MediaServerService", (win32serviceutil.ServiceFramework,), dict(MediaServerService.__dict__), ) def install_service(): """Install the Windows service.""" if not WIN32_AVAILABLE: print("Error: pywin32 is required for Windows service installation") print("Install with: pip install pywin32") return False try: # Get the path to the Python executable python_exe = sys.executable # Get the path to this module module_path = os.path.abspath(__file__) win32serviceutil.InstallService( MediaServerService._svc_name_, MediaServerService._svc_name_, MediaServerService._svc_display_name_, startType=win32service.SERVICE_AUTO_START, description=MediaServerService._svc_description_, ) print(f"Service '{MediaServerService._svc_display_name_}' installed successfully") print("Start the service with: sc start MediaServer") return True except Exception as e: print(f"Failed to install service: {e}") return False def remove_service(): """Remove the Windows service.""" if not WIN32_AVAILABLE: print("Error: pywin32 is required") return False try: win32serviceutil.RemoveService(MediaServerService._svc_name_) print(f"Service '{MediaServerService._svc_display_name_}' removed successfully") return True except Exception as e: print(f"Failed to remove service: {e}") return False def main(): """Main entry point for service management.""" if not WIN32_AVAILABLE: print("Error: pywin32 is required for Windows service support") print("Install with: pip install pywin32") sys.exit(1) if len(sys.argv) == 1: # Running as a service servicemanager.Initialize() servicemanager.PrepareToHostSingle(MediaServerService) servicemanager.StartServiceCtrlDispatcher() else: # Command line management win32serviceutil.HandleCommandLine(MediaServerService) if __name__ == "__main__": main()