using System.Net; using System.Text; using System.Text.Json; namespace PainoBar_Helper { /// /// Manages various output mechanisms for song metadata /// public class OutputManager : IDisposable { private readonly ProfileSettings _settings; private HttpListener? _webServer; private string? _currentMetadataJson; private bool _isActive; public OutputManager(ProfileSettings settings) { _settings = settings; } public event EventHandler? ActiveStateChanged; public bool IsActive { get => _isActive; private set { if (_isActive != value) { _isActive = value; ActiveStateChanged?.Invoke(this, EventArgs.Empty); } } } public void Start() { Stop(); if (_settings.EnableWebServer) StartWebServer(); UpdateActiveState(); } public void Stop() { StopWebServer(); UpdateActiveState(); } public void UpdateSongMetadata(SongChangedEventArgs metadata) { var metadataObj = new { title = metadata.Title, artist = metadata.Artist, album = metadata.Album, albumArtUrl = metadata.AlbumArtUrl, timestamp = DateTime.Now }; _currentMetadataJson = JsonSerializer.Serialize(metadataObj, new JsonSerializerOptions { WriteIndented = true }); if (_settings.EnableTextFile && !string.IsNullOrEmpty(_settings.TextFilePath)) WriteTextFile(metadata); if (_settings.EnableToastNotifications) ShowToastNotification(metadata); if (_settings.EnableSMTC) UpdateSMTC(metadata); } private void WriteTextFile(SongChangedEventArgs metadata) { try { var dir = Path.GetDirectoryName(_settings.TextFilePath); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); var sb = new StringBuilder(); sb.AppendLine($"Title: {metadata.Title}"); sb.AppendLine($"Artist: {metadata.Artist}"); sb.AppendLine($"Album: {metadata.Album}"); sb.AppendLine($"Album Art URL: {metadata.AlbumArtUrl}"); sb.AppendLine($"Updated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); File.WriteAllText(_settings.TextFilePath, sb.ToString()); } catch { // Silently fail } } private void StartWebServer() { try { _webServer = new HttpListener(); _webServer.Prefixes.Add($"http://localhost:{_settings.WebServerPort}/"); _webServer.Start(); Task.Run(() => WebServerLoop()); } catch { _webServer = null; } } private void StopWebServer() { if (_webServer != null) { try { _webServer.Stop(); _webServer.Close(); } catch { } finally { _webServer = null; } } } private async void WebServerLoop() { while (_webServer != null && _webServer.IsListening) { try { var context = await _webServer.GetContextAsync(); HandleWebRequest(context); } catch { break; } } } private void HandleWebRequest(HttpListenerContext context) { try { var response = context.Response; response.ContentType = "application/json"; response.ContentEncoding = Encoding.UTF8; string responseData = _currentMetadataJson ?? "{}"; byte[] buffer = Encoding.UTF8.GetBytes(responseData); response.ContentLength64 = buffer.Length; response.OutputStream.Write(buffer, 0, buffer.Length); response.OutputStream.Close(); } catch { } } private void ShowToastNotification(SongChangedEventArgs metadata) { // Windows Toast Notification implementation placeholder // In a full implementation, you would use Windows.UI.Notifications // For now, this is a placeholder that can be extended try { // TODO: Implement using Windows.UI.Notifications ToastNotificationManager // This requires adding Windows SDK references } catch { } } private void UpdateSMTC(SongChangedEventArgs metadata) { // Windows System Media Transport Controls implementation placeholder // In a full implementation, you would use Windows.Media.SystemMediaTransportControls // For now, this is a placeholder that can be extended try { // TODO: Implement using Windows.Media.SystemMediaTransportControls // This requires adding Windows SDK references } catch { } } private void UpdateActiveState() { bool anyActive = false; if (_settings.EnableTextFile && !string.IsNullOrEmpty(_settings.TextFilePath)) anyActive = true; if (_settings.EnableWebServer && _webServer != null && _webServer.IsListening) anyActive = true; if (_settings.EnableToastNotifications) anyActive = true; if (_settings.EnableSMTC) anyActive = true; IsActive = anyActive; } public void Dispose() { Stop(); } } }