diff --git a/RadioDJViewer/Main.cs b/RadioDJViewer/Main.cs index d3599ef..d4c5d26 100644 --- a/RadioDJViewer/Main.cs +++ b/RadioDJViewer/Main.cs @@ -21,6 +21,8 @@ using System.Security; namespace RadioDJViewer { + using System; + public partial class Main : Form { private string _currentTrackKey = string.Empty; @@ -59,6 +61,7 @@ namespace RadioDJViewer public Main() { InitializeComponent(); + EnsureDefaultImageExists(); UpdateStatusBar(); // Set up timer for polling API every 3 seconds apiTimer = new System.Windows.Forms.Timer(); @@ -70,6 +73,7 @@ namespace RadioDJViewer // Wire up dark mode button this.uicolor.Click += Uicolor_Click; this.load_profile_button.Click += load_profile_button_Click; + this.FormClosed += Main_FormClosed; PopulateProfileDropBox(); UpdateTheme(); } @@ -184,6 +188,7 @@ namespace RadioDJViewer WidgetServer.CachedDuration = "0"; WidgetServer.CachedTime = "No Data"; WidgetServer.CachedPaused = true; + SmtcService.Disable(); // Stop widget server when disconnecting try { @@ -581,7 +586,7 @@ namespace RadioDJViewer { WidgetServer.CachedArtist = artistText ?? string.Empty; WidgetServer.CachedTitle = titleText ?? string.Empty; - + byte[] imgBytes = null; // Prefer album art from main images folder if (!string.IsNullOrEmpty(albumArt) && !string.IsNullOrEmpty(mainImagesFolderPath)) @@ -630,6 +635,24 @@ namespace RadioDJViewer UpdateCurrentSongImage(null); } + if (IsSmtcEnabledForActiveProfile()) + { + if (HasValidSmtcMetadata(titleText, artistText)) + { + string smtcImagePath = ResolveSmtcImagePath(); +#if DEBUG + System.Diagnostics.Debug.WriteLine($"[SMTC] Resolved artwork path: '{smtcImagePath}' (exists={(!string.IsNullOrWhiteSpace(smtcImagePath) && File.Exists(smtcImagePath))})"); +#endif + SmtcService.PublishNowPlaying(titleText, artistText, smtcImagePath, _playbackPaused); + } + else + SmtcService.Disable(); + } + else + { + SmtcService.Disable(); + } + if (trackChanged) { #if DEBUG @@ -658,130 +681,10 @@ namespace RadioDJViewer WidgetServer.CachedTime = "No Data"; WidgetServer.CachedPaused = true; pictureBox1.Image = null; + SmtcService.Disable(); } } - private void UpdateStatusBar() - { - try - { - if (!isConnected) - { - toolStripStatusLabel2.BackColor = Color.Red; - } - else - { - if (isConnected && widgetRunning) - toolStripStatusLabel2.BackColor = Color.Blue; - else - toolStripStatusLabel2.BackColor = Color.Green; - } - } - catch { } - - toolStripStatusLabel4.Text = $"Profile: {currentProfile}"; - if (statusCts == null) - { - toolStripStatusLabel3.Text = isConnected ? "Connected to API" : "Disconnected"; - } - } - - private void ShowTemporaryStatus(string message, int milliseconds) - { - try - { - statusCts?.Cancel(); - } - catch { } - statusCts = null; - - if (milliseconds <= 0) - { - var persistent = new CancellationTokenSource(); - statusCts = persistent; - toolStripStatusLabel3.Text = message; - return; - } - - var cts = new CancellationTokenSource(); - statusCts = cts; - toolStripStatusLabel3.Text = message; - - Task.Run(async () => - { - try - { - await Task.Delay(milliseconds, cts.Token); - if (!cts.IsCancellationRequested) - { - statusCts = null; - this.BeginInvoke((Action)(() => { - toolStripStatusLabel3.Text = isConnected ? "Connected to API" : "Disconnected"; - })); - } - } - catch { } - }); - } - - private void ClearStatusMessage() - { - try { statusCts?.Cancel(); } catch { } - statusCts = null; - try { toolStripStatusLabel3.Text = isConnected ? "Connected to API" : "Disconnected"; } catch { } - } - - private void StartWidgetServerIfEnabled() - { - if (loadedProfile == null || !loadedProfile.WebServerEnabled) - return; - - try - { - WidgetServer.CachedClockVisibility = loadedProfile.ClockVisibilityEnabled; - - if (widgetServer == null) - { - int port = loadedProfile.WebServerPort > 0 ? loadedProfile.WebServerPort : 8080; - widgetServer = new WidgetServer(port, () => _previousToastArtist, () => _previousToastTitle, () => this.currentSongImagePath ?? this.defaultImagePath); - } - widgetServer.Start(); - widgetRunning = true; - UpdateStatusBar(); - ShowTemporaryStatus($"Web: Running on {loadedProfile.WebServerPort}", 5000); - } - catch (Exception ex) - { - widgetRunning = false; - UpdateStatusBar(); - ShowTemporaryStatus($"Web server error: {ex.Message}", 5000); - } - } - - private void restAPISettingToolStripMenuItem_Click(object sender, EventArgs e) - { - var settingsForm = new Form1(); - settingsForm.ApplyTheme(isDarkMode); - settingsForm.ShowDialog(); - } - - private void aboutToolStripMenuItem_Click(object sender, EventArgs e) - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - string version = assembly.GetName().Version.ToString(); - string message = $"RadioDJViewer\nVersion: {version}\nGitHub: https://git.smartcraft.me/minster586/RadioDJViewer"; - MessageBox.Show(message, "About RadioDJViewer", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void exitToolStripMenuItem_Click(object sender, EventArgs e) - { - Application.Exit(); - } - - private void toolStripStatusLabel4_Click(object sender, EventArgs e) - { - } - public void LoadProfile(Profile profile) { currentProfile = profile.Name; @@ -792,6 +695,8 @@ namespace RadioDJViewer int pollingRate = profile.PollingRateSeconds > 0 ? profile.PollingRateSeconds : 3; apiTimer.Interval = pollingRate * 1000; WidgetServer.CachedClockVisibility = profile.ClockVisibilityEnabled; + if (!profile.SmtcEnabled) + SmtcService.Disable(); UpdateStatusBar(); } @@ -911,6 +816,22 @@ namespace RadioDJViewer return loadedProfile != null && loadedProfile.ToastNotificationsEnabled; } + private bool IsSmtcEnabledForActiveProfile() + { + return loadedProfile != null && loadedProfile.SmtcEnabled; + } + + private static bool HasValidSmtcMetadata(string title, string artist) + { + if (string.IsNullOrWhiteSpace(title) || string.IsNullOrWhiteSpace(artist)) + return false; + + string t = title.Trim(); + string a = artist.Trim(); + return !t.Equals("No title", StringComparison.OrdinalIgnoreCase) + && !a.Equals("No artist", StringComparison.OrdinalIgnoreCase); + } + private static string NormalizeTrackMetadata(string value) { return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim(); @@ -951,6 +872,26 @@ namespace RadioDJViewer } } + private string ResolveSmtcImagePath() + { + try + { + string outputImage = GetProfileOutputImagePath(); + if (!string.IsNullOrWhiteSpace(outputImage) && File.Exists(outputImage)) + return outputImage; + + if (!string.IsNullOrWhiteSpace(currentSongImagePath) && File.Exists(currentSongImagePath)) + return Path.GetFullPath(currentSongImagePath); + + EnsureDefaultImageExists(); + if (File.Exists(defaultImagePath)) + return Path.GetFullPath(defaultImagePath); + } + catch { } + + return string.Empty; + } + private void ShowTrackChangeToast(string title, string artist, string outputImagePath) { if (IsDisposed || _isDisconnecting || !isConnected) @@ -1004,6 +945,623 @@ namespace RadioDJViewer private void label7_Click_1(object sender, EventArgs e) { } + + private void UpdateStatusBar() + { + try + { + if (!isConnected) + { + toolStripStatusLabel2.BackColor = Color.Red; + } + else + { + if (isConnected && widgetRunning) + toolStripStatusLabel2.BackColor = Color.Blue; + else + toolStripStatusLabel2.BackColor = Color.Green; + } + } + catch { } + + toolStripStatusLabel4.Text = $"Profile: {currentProfile}"; + if (statusCts == null) + { + toolStripStatusLabel3.Text = isConnected ? "Connected to API" : "Disconnected"; + } + } + + private void ShowTemporaryStatus(string message, int milliseconds) + { + try + { + statusCts?.Cancel(); + } + catch { } + statusCts = null; + + if (milliseconds <= 0) + { + var persistent = new CancellationTokenSource(); + statusCts = persistent; + toolStripStatusLabel3.Text = message; + return; + } + + var cts = new CancellationTokenSource(); + statusCts = cts; + toolStripStatusLabel3.Text = message; + + Task.Run(async () => + { + try + { + await Task.Delay(milliseconds, cts.Token); + if (!cts.IsCancellationRequested) + { + statusCts = null; + this.BeginInvoke((Action)(() => { + toolStripStatusLabel3.Text = isConnected ? "Connected to API" : "Disconnected"; + })); + } + } + catch { } + }); + } + + private void ClearStatusMessage() + { + try { statusCts?.Cancel(); } catch { } + statusCts = null; + try { toolStripStatusLabel3.Text = isConnected ? "Connected to API" : "Disconnected"; } catch { } + } + + private void StartWidgetServerIfEnabled() + { + if (loadedProfile == null || !loadedProfile.WebServerEnabled) + return; + + try + { + WidgetServer.CachedClockVisibility = loadedProfile.ClockVisibilityEnabled; + + if (widgetServer == null) + { + int port = loadedProfile.WebServerPort > 0 ? loadedProfile.WebServerPort : 8080; + widgetServer = new WidgetServer(port, () => _previousToastArtist, () => _previousToastTitle, () => this.currentSongImagePath ?? this.defaultImagePath); + } + widgetServer.Start(); + widgetRunning = true; + UpdateStatusBar(); + ShowTemporaryStatus($"Web: Running on {loadedProfile.WebServerPort}", 5000); + } + catch (Exception ex) + { + widgetRunning = false; + UpdateStatusBar(); + ShowTemporaryStatus($"Web server error: {ex.Message}", 5000); + } + } + + private void restAPISettingToolStripMenuItem_Click(object sender, EventArgs e) + { + var settingsForm = new Form1(); + settingsForm.ApplyTheme(isDarkMode); + settingsForm.ShowDialog(); + } + + private void aboutToolStripMenuItem_Click(object sender, EventArgs e) + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + string version = assembly.GetName().Version.ToString(); + string message = $"RadioDJViewer\nVersion: {version}\nGitHub: https://git.smartcraft.me/minster586/RadioDJViewer"; + MessageBox.Show(message, "About RadioDJViewer", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + Application.Exit(); + } + + private void toolStripStatusLabel4_Click(object sender, EventArgs e) + { + } + + private void Main_FormClosed(object sender, FormClosedEventArgs e) + { + try + { + if (!string.IsNullOrWhiteSpace(_lastToastImagePath) && File.Exists(_lastToastImagePath)) + File.Delete(_lastToastImagePath); + } + catch { } + + try + { + string toastDir = Path.Combine(Path.GetTempPath(), "RadioDJViewer", "ToastImages"); + if (Directory.Exists(toastDir)) + { + foreach (var file in Directory.GetFiles(toastDir, "*.*", SearchOption.TopDirectoryOnly)) + { + try { File.Delete(file); } catch { } + } + } + } + catch { } + + try { SmtcService.CleanupTempArtwork(); } catch { } + } + } + + internal static class SmtcService + { + private static object _mediaPlayer; + private static object _smtc; + private static string _lastThumbnailTempPath; + + public static void CleanupTempArtwork() + { + try + { + string tempDir = Path.Combine(Path.GetTempPath(), "RadioDJViewer", "SmtcArt"); + if (!Directory.Exists(tempDir)) + return; + + foreach (var file in Directory.GetFiles(tempDir, "*.*", SearchOption.TopDirectoryOnly)) + { + try { File.Delete(file); } catch { } + } + } + catch { } + } + + public static void PublishNowPlaying(string title, string artist, string imagePath, bool paused) + { + try + { + if (!EnsureInitialized()) + return; + + SetPropertyIfExists(_smtc, "IsEnabled", true); + SetPropertyIfExists(_smtc, "IsPlayEnabled", true); + SetPropertyIfExists(_smtc, "IsPauseEnabled", true); + SetPropertyIfExists(_smtc, "IsStopEnabled", true); + SetPropertyIfExists(_smtc, "IsNextEnabled", false); + SetPropertyIfExists(_smtc, "IsPreviousEnabled", false); + SetPlaybackStatus(paused ? "Paused" : "Playing"); + + object updater = GetPropertyValue(_smtc, "DisplayUpdater"); + if (updater == null) + return; + + SetPropertyIfExists(updater, "AppMediaId", "RadioDJViewer.NowPlaying"); + + Type mediaPlaybackType = Type.GetType("Windows.Media.MediaPlaybackType, Windows, ContentType=WindowsRuntime"); + if (mediaPlaybackType != null) + { + object musicValue = Enum.Parse(mediaPlaybackType, "Music"); + SetPropertyIfExists(updater, "Type", musicValue); + } + + object musicProperties = GetPropertyValue(updater, "MusicProperties"); + if (musicProperties != null) + { + SetPropertyIfExists(musicProperties, "Title", title); + SetPropertyIfExists(musicProperties, "Artist", artist); + } + + TrySetThumbnail(updater, imagePath); + InvokeIfExists(updater, "Update"); + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Publish failed: " + ex); +#endif + } + } + + public static void Disable() + { + try + { + if (_smtc != null) + { + SetPlaybackStatus("Stopped"); + SetPropertyIfExists(_smtc, "IsEnabled", false); + object updater = GetPropertyValue(_smtc, "DisplayUpdater"); + if (updater != null) + { + InvokeIfExists(updater, "ClearAll"); + InvokeIfExists(updater, "Update"); + } + } + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Disable failed: " + ex); +#endif + } + } + + private static bool EnsureInitialized() + { + if (_mediaPlayer != null && _smtc != null) + return true; + + try + { + Type mediaPlayerType = Type.GetType("Windows.Media.Playback.MediaPlayer, Windows, ContentType=WindowsRuntime"); + if (mediaPlayerType == null) + return false; + + _mediaPlayer = Activator.CreateInstance(mediaPlayerType); + if (_mediaPlayer == null) + return false; + + object commandManager = GetPropertyValue(_mediaPlayer, "CommandManager"); + if (commandManager != null) + SetPropertyIfExists(commandManager, "IsEnabled", true); + + _smtc = GetPropertyValue(_mediaPlayer, "SystemMediaTransportControls"); + return _smtc != null; + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Init failed: " + ex); +#endif + return false; + } + } + + private static void SetPlaybackStatus(string statusName) + { + try + { + Type playbackStatusType = Type.GetType("Windows.Media.MediaPlaybackStatus, Windows, ContentType=WindowsRuntime"); + if (playbackStatusType == null) + return; + + object statusValue = Enum.Parse(playbackStatusType, statusName); + SetPropertyIfExists(_smtc, "PlaybackStatus", statusValue); + } + catch { } + } + + private static string CreateSmtcThumbnailTempFile(string sourcePath) + { + try + { + string ext = Path.GetExtension(sourcePath); + if (string.IsNullOrWhiteSpace(ext)) + ext = ".png"; + + string tempDir = Path.Combine(Path.GetTempPath(), "RadioDJViewer", "SmtcArt"); + Directory.CreateDirectory(tempDir); + string tempPath = Path.Combine(tempDir, $"art-{DateTime.UtcNow.Ticks}{ext}"); + + using (var src = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var dst = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + { + src.CopyTo(dst); + dst.Flush(true); + } + + _lastThumbnailTempPath = tempPath; + CleanupOldTempArtwork(tempDir, keepCount: 10); + return tempPath; + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Temp art copy failed: " + ex); +#endif + return sourcePath; + } + } + + private static void CleanupOldTempArtwork(string tempDir, int keepCount) + { + try + { + var files = new DirectoryInfo(tempDir) + .GetFiles("*.*", SearchOption.TopDirectoryOnly) + .OrderByDescending(f => f.CreationTimeUtc) + .ToList(); + + foreach (var file in files.Skip(Math.Max(keepCount, 1))) + { + try { file.Delete(); } catch { } + } + } + catch { } + } + + private static object WaitForAsyncOperation(object asyncOp) + { + if (asyncOp == null) + return null; + + try + { + MethodInfo getResults = asyncOp.GetType().GetMethod("GetResults", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); + if (getResults == null) + return null; + + // First, quick poll + for (int i = 0; i < 40; i++) + { + object statusObj = GetPropertyValue(asyncOp, "Status"); + string statusText = statusObj != null ? statusObj.ToString() : string.Empty; + if (string.Equals(statusText, "Completed", StringComparison.OrdinalIgnoreCase) || (statusObj != null && statusObj.ToString() == "1")) + return getResults.Invoke(asyncOp, null); + + if (string.Equals(statusText, "Canceled", StringComparison.OrdinalIgnoreCase) || string.Equals(statusText, "Error", StringComparison.OrdinalIgnoreCase)) + break; + + System.Threading.Thread.Sleep(25); + } + + // Then wait on Completed event (more reliable for WinRT async interop) + EventInfo completedEvent = asyncOp.GetType().GetEvent("Completed"); + if (completedEvent != null) + { + using (var waitHandle = new System.Threading.ManualResetEvent(false)) + { + Delegate handler = BuildCompletedHandler(completedEvent.EventHandlerType, waitHandle); + if (handler != null) + { + completedEvent.AddEventHandler(asyncOp, handler); + waitHandle.WaitOne(2000); + completedEvent.RemoveEventHandler(asyncOp, handler); + } + } + } + + try + { + object result = getResults.Invoke(asyncOp, null); + if (result != null) + return result; + } + catch { } + +#if DEBUG + object finalStatus = GetPropertyValue(asyncOp, "Status"); + System.Diagnostics.Debug.WriteLine($"[SMTC] Async operation did not yield result. FinalStatus={finalStatus}"); +#endif + return null; + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] WaitForAsyncOperation failed: " + ex.Message); +#endif + return null; + } + } + + private static Delegate BuildCompletedHandler(Type handlerType, System.Threading.ManualResetEvent waitHandle) + { + try + { + MethodInfo invoke = handlerType.GetMethod("Invoke"); + if (invoke == null) + return null; + + var parameters = invoke.GetParameters(); + var paramExpr = new System.Linq.Expressions.ParameterExpression[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + paramExpr[i] = System.Linq.Expressions.Expression.Parameter(parameters[i].ParameterType, parameters[i].Name); + } + + var setMethod = typeof(System.Threading.ManualResetEvent).GetMethod("Set", Type.EmptyTypes); + var body = System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression.Constant(waitHandle), setMethod); + var lambda = System.Linq.Expressions.Expression.Lambda(handlerType, body, paramExpr); + return lambda.Compile(); + } + catch + { + return null; + } + } + + private static object GetPropertyValue(object instance, string propertyName) + { + if (instance == null) + return null; + + PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); + if (property == null) + return null; + + return property.GetValue(instance, null); + } + + private static void SetPropertyIfExists(object instance, string propertyName, object value) + { + if (instance == null) + return; + + PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); + if (property == null || !property.CanWrite) + return; + + property.SetValue(instance, value, null); + } + + private static object InvokeIfExists(object instance, string methodName) + { + if (instance == null) + return null; + + MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); + if (method == null) + return null; + + return method.Invoke(instance, null); + } + + private static void TrySetThumbnail(object updater, string imagePath) + { + try + { + if (updater == null || string.IsNullOrWhiteSpace(imagePath)) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Thumbnail skipped: updater null or image path empty."); +#endif + return; + } + + string fullPath = Path.GetFullPath(imagePath); + if (!File.Exists(fullPath)) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine($"[SMTC] Thumbnail file missing: '{fullPath}'"); +#endif + return; + } + + string smtcTempPath = CreateSmtcThumbnailTempFile(fullPath); + if (string.IsNullOrWhiteSpace(smtcTempPath) || !File.Exists(smtcTempPath)) + return; + + Type randomAccessType = Type.GetType("Windows.Storage.Streams.RandomAccessStreamReference, Windows, ContentType=WindowsRuntime"); + if (randomAccessType == null) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Thumbnail failed: RandomAccessStreamReference type unavailable."); +#endif + return; + } + + object streamRef = null; + string source = "Unknown"; + + try + { + streamRef = CreateThumbnailFromMemory(randomAccessType, smtcTempPath); + if (streamRef != null) + source = "CreateFromStream"; + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] CreateFromStream path failed: " + ex.Message); +#endif + } + + if (streamRef == null) + { + try + { + Type storageFileType = Type.GetType("Windows.Storage.StorageFile, Windows, ContentType=WindowsRuntime"); + MethodInfo getFileMethod = storageFileType?.GetMethod("GetFileFromPathAsync", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null); + MethodInfo createFromFileMethod = randomAccessType.GetMethod("CreateFromFile", BindingFlags.Public | BindingFlags.Static); + if (getFileMethod != null && createFromFileMethod != null) + { + object op = getFileMethod.Invoke(null, new object[] { smtcTempPath }); + object storageFile = WaitForAsyncOperation(op); + if (storageFile != null) + { + streamRef = createFromFileMethod.Invoke(null, new[] { storageFile }); + if (streamRef != null) source = "CreateFromFile"; +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Thumbnail stream created via CreateFromFile."); +#endif + } +#if DEBUG + else + { + System.Diagnostics.Debug.WriteLine("[SMTC] CreateFromFile path: StorageFile result was null."); + } +#endif + } + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] CreateFromFile path failed: " + ex.Message); +#endif + } + } + + if (streamRef == null) + { + MethodInfo createFromUriMethod = randomAccessType.GetMethod("CreateFromUri", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Uri) }, null); + if (createFromUriMethod == null) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Thumbnail failed: CreateFromUri method unavailable."); +#endif + return; + } + + var fileUri = new Uri(smtcTempPath); +#if DEBUG + System.Diagnostics.Debug.WriteLine($"[SMTC] Thumbnail URI: '{fileUri.AbsoluteUri}'"); +#endif + streamRef = createFromUriMethod.Invoke(null, new object[] { fileUri }); + if (streamRef != null) source = "CreateFromUri"; + } + + if (streamRef != null) + { + SetPropertyIfExists(updater, "Thumbnail", streamRef); +#if DEBUG + System.Diagnostics.Debug.WriteLine($"[SMTC] Thumbnail assigned to DisplayUpdater. Source={source}"); +#endif + } + else + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Thumbnail streamRef is null."); +#endif + } + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("[SMTC] Thumbnail failed: " + ex); +#endif + } + } + + private static object CreateThumbnailFromMemory(Type randomAccessType, string filePath) + { + byte[] bytes = File.ReadAllBytes(filePath); + if (bytes == null || bytes.Length == 0) + return null; + + Type memoryStreamType = Type.GetType("Windows.Storage.Streams.InMemoryRandomAccessStream, Windows, ContentType=WindowsRuntime"); + Type dataWriterType = Type.GetType("Windows.Storage.Streams.DataWriter, Windows, ContentType=WindowsRuntime"); + if (memoryStreamType == null || dataWriterType == null) + return null; + + object memoryStream = Activator.CreateInstance(memoryStreamType); + MethodInfo getOutputStreamAt = memoryStreamType.GetMethod("GetOutputStreamAt", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(ulong) }, null); + object outputStream = getOutputStreamAt?.Invoke(memoryStream, new object[] { 0UL }); + if (outputStream == null) + return null; + + object writer = Activator.CreateInstance(dataWriterType, new[] { outputStream }); + dataWriterType.GetMethod("WriteBytes", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(byte[]) }, null)?.Invoke(writer, new object[] { bytes }); + + object storeOp = dataWriterType.GetMethod("StoreAsync", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null)?.Invoke(writer, null); + WaitForAsyncOperation(storeOp); + object flushOp = dataWriterType.GetMethod("FlushAsync", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null)?.Invoke(writer, null); + WaitForAsyncOperation(flushOp); + + dataWriterType.GetMethod("DetachStream", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null)?.Invoke(writer, null); + memoryStreamType.GetMethod("Seek", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(ulong) }, null)?.Invoke(memoryStream, new object[] { 0UL }); + + MethodInfo createFromStream = randomAccessType.GetMethod("CreateFromStream", BindingFlags.Public | BindingFlags.Static); + return createFromStream?.Invoke(null, new[] { memoryStream }); + } } internal static class ToastNotificationService diff --git a/RadioDJViewer/ProfileStorage.cs b/RadioDJViewer/ProfileStorage.cs index 76100b5..ec15559 100644 --- a/RadioDJViewer/ProfileStorage.cs +++ b/RadioDJViewer/ProfileStorage.cs @@ -26,6 +26,7 @@ namespace RadioDJViewer // Clock visibility setting public bool ClockVisibilityEnabled { get; set; } public bool ToastNotificationsEnabled { get; set; } + public bool SmtcEnabled { get; set; } } public static class ProfileStorage diff --git a/RadioDJViewer/Properties/AssemblyInfo.cs b/RadioDJViewer/Properties/AssemblyInfo.cs index 3342d4d..2ac9191 100644 --- a/RadioDJViewer/Properties/AssemblyInfo.cs +++ b/RadioDJViewer/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("1.14.5")] -[assembly: AssemblyFileVersion("1.14.5")] +[assembly: AssemblyVersion("1.15.0")] +[assembly: AssemblyFileVersion("1.15.0")] diff --git a/RadioDJViewer/radiodj-restapi-template.Designer.cs b/RadioDJViewer/radiodj-restapi-template.Designer.cs index 45728b0..a11bf20 100644 --- a/RadioDJViewer/radiodj-restapi-template.Designer.cs +++ b/RadioDJViewer/radiodj-restapi-template.Designer.cs @@ -67,11 +67,29 @@ this.web_server_label = new System.Windows.Forms.Label(); this.web_server_checkbox = new System.Windows.Forms.CheckBox(); this.label12 = new System.Windows.Forms.Label(); + this.tab_controls = new System.Windows.Forms.TabControl(); + this.settings_tab_page = new System.Windows.Forms.TabPage(); + this.output_settings_tab_page = new System.Windows.Forms.TabPage(); + this.connection_settings_box = new System.Windows.Forms.GroupBox(); + this.notice_one = new System.Windows.Forms.Label(); + this.misc_tab_page = new System.Windows.Forms.TabPage(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.smtc_enable_label = new System.Windows.Forms.Label(); + this.smtc_check_box = new System.Windows.Forms.CheckBox(); + this.notice_two = new System.Windows.Forms.Label(); + this.loaded_profile_label = new System.Windows.Forms.Label(); + this.profile_loaded_data = new System.Windows.Forms.Label(); this.groupBox1.SuspendLayout(); this.groupBox3.SuspendLayout(); this.groupBox2.SuspendLayout(); this.toast_box_group_box.SuspendLayout(); this.web_server_settings_groupbox.SuspendLayout(); + this.tab_controls.SuspendLayout(); + this.settings_tab_page.SuspendLayout(); + this.output_settings_tab_page.SuspendLayout(); + this.connection_settings_box.SuspendLayout(); + this.misc_tab_page.SuspendLayout(); + this.groupBox4.SuspendLayout(); this.SuspendLayout(); // // groupBox1 @@ -139,7 +157,7 @@ // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(20, 100); + this.label3.Location = new System.Drawing.Point(20, 27); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(57, 13); this.label3.TabIndex = 2; @@ -147,41 +165,41 @@ // // textBox2 // - this.textBox2.Location = new System.Drawing.Point(120, 97); + this.textBox2.Location = new System.Drawing.Point(103, 24); this.textBox2.Name = "textBox2"; - this.textBox2.Size = new System.Drawing.Size(290, 20); + this.textBox2.Size = new System.Drawing.Size(122, 20); this.textBox2.TabIndex = 3; // // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(20, 135); + this.label4.Location = new System.Drawing.Point(20, 60); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(26, 13); + this.label4.Size = new System.Drawing.Size(29, 13); this.label4.TabIndex = 4; - this.label4.Text = "Port"; + this.label4.Text = "Port:"; // // textBox3 // - this.textBox3.Location = new System.Drawing.Point(120, 132); + this.textBox3.Location = new System.Drawing.Point(103, 54); this.textBox3.Name = "textBox3"; - this.textBox3.Size = new System.Drawing.Size(290, 20); + this.textBox3.Size = new System.Drawing.Size(122, 20); this.textBox3.TabIndex = 5; // // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(20, 170); + this.label5.Location = new System.Drawing.Point(20, 88); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(53, 13); + this.label5.Size = new System.Drawing.Size(56, 13); this.label5.TabIndex = 6; - this.label5.Text = "Password"; + this.label5.Text = "Password:"; // // textBox4 // - this.textBox4.Location = new System.Drawing.Point(120, 167); + this.textBox4.Location = new System.Drawing.Point(103, 83); this.textBox4.Name = "textBox4"; - this.textBox4.Size = new System.Drawing.Size(290, 20); + this.textBox4.Size = new System.Drawing.Size(122, 20); this.textBox4.TabIndex = 7; // // button3 @@ -204,20 +222,21 @@ // // groupBox3 // + this.groupBox3.Controls.Add(this.notice_one); this.groupBox3.Controls.Add(this.buttonSelectOutputFolder); this.groupBox3.Controls.Add(this.labelOutputFolderPath); this.groupBox3.Controls.Add(this.textBox5); this.groupBox3.Controls.Add(this.label10); - this.groupBox3.Location = new System.Drawing.Point(26, 368); + this.groupBox3.Location = new System.Drawing.Point(74, 127); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(476, 115); + this.groupBox3.Size = new System.Drawing.Size(256, 229); this.groupBox3.TabIndex = 12; this.groupBox3.TabStop = false; this.groupBox3.Text = "Output Setting"; // // buttonSelectOutputFolder // - this.buttonSelectOutputFolder.Location = new System.Drawing.Point(20, 36); + this.buttonSelectOutputFolder.Location = new System.Drawing.Point(63, 58); this.buttonSelectOutputFolder.Name = "buttonSelectOutputFolder"; this.buttonSelectOutputFolder.Size = new System.Drawing.Size(140, 23); this.buttonSelectOutputFolder.TabIndex = 17; @@ -227,23 +246,24 @@ // labelOutputFolderPath // this.labelOutputFolderPath.AutoSize = true; - this.labelOutputFolderPath.Location = new System.Drawing.Point(166, 41); + this.labelOutputFolderPath.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelOutputFolderPath.Location = new System.Drawing.Point(78, 89); this.labelOutputFolderPath.Name = "labelOutputFolderPath"; - this.labelOutputFolderPath.Size = new System.Drawing.Size(93, 13); + this.labelOutputFolderPath.Size = new System.Drawing.Size(111, 13); this.labelOutputFolderPath.TabIndex = 16; this.labelOutputFolderPath.Text = "No folder selected"; // // textBox5 // - this.textBox5.Location = new System.Drawing.Point(149, 80); + this.textBox5.Location = new System.Drawing.Point(159, 29); this.textBox5.Name = "textBox5"; - this.textBox5.Size = new System.Drawing.Size(247, 20); + this.textBox5.Size = new System.Drawing.Size(83, 20); this.textBox5.TabIndex = 16; // // label10 // this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(17, 83); + this.label10.Location = new System.Drawing.Point(19, 32); this.label10.Name = "label10"; this.label10.Size = new System.Drawing.Size(126, 13); this.label10.TabIndex = 15; @@ -267,7 +287,7 @@ // // button6 // - this.button6.Location = new System.Drawing.Point(91, 234); + this.button6.Location = new System.Drawing.Point(53, 149); this.button6.Name = "button6"; this.button6.Size = new System.Drawing.Size(140, 23); this.button6.TabIndex = 18; @@ -277,7 +297,7 @@ // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(306, 239); + this.label6.Location = new System.Drawing.Point(78, 181); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(93, 13); this.label6.TabIndex = 19; @@ -286,38 +306,28 @@ // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(20, 211); + this.label7.Location = new System.Drawing.Point(20, 117); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(124, 13); + this.label7.Size = new System.Drawing.Size(127, 13); this.label7.TabIndex = 20; - this.label7.Text = "Polling Rate (in seconds)"; + this.label7.Text = "Polling Rate (in seconds):"; // // polling_rate_textbox // - this.polling_rate_textbox.Location = new System.Drawing.Point(150, 208); + this.polling_rate_textbox.Location = new System.Drawing.Point(176, 114); this.polling_rate_textbox.Name = "polling_rate_textbox"; this.polling_rate_textbox.Size = new System.Drawing.Size(49, 20); this.polling_rate_textbox.TabIndex = 21; // // groupBox2 // - this.groupBox2.Controls.Add(this.toast_box_group_box); - this.groupBox2.Controls.Add(this.web_server_settings_groupbox); + this.groupBox2.Controls.Add(this.profile_loaded_data); + this.groupBox2.Controls.Add(this.loaded_profile_label); + this.groupBox2.Controls.Add(this.tab_controls); this.groupBox2.Controls.Add(this.textBox6); this.groupBox2.Controls.Add(this.label11); - this.groupBox2.Controls.Add(this.polling_rate_textbox); - this.groupBox2.Controls.Add(this.label7); - this.groupBox2.Controls.Add(this.label6); - this.groupBox2.Controls.Add(this.button6); - this.groupBox2.Controls.Add(this.groupBox3); this.groupBox2.Controls.Add(this.button4); this.groupBox2.Controls.Add(this.button3); - this.groupBox2.Controls.Add(this.textBox4); - this.groupBox2.Controls.Add(this.label5); - this.groupBox2.Controls.Add(this.textBox3); - this.groupBox2.Controls.Add(this.label4); - this.groupBox2.Controls.Add(this.textBox2); - this.groupBox2.Controls.Add(this.label3); this.groupBox2.Controls.Add(this.label2); this.groupBox2.Controls.Add(this.comboBox1); this.groupBox2.Location = new System.Drawing.Point(12, 100); @@ -331,7 +341,7 @@ // this.toast_box_group_box.Controls.Add(this.toast_check_box_enable); this.toast_box_group_box.Controls.Add(this.toast_label); - this.toast_box_group_box.Location = new System.Drawing.Point(120, 489); + this.toast_box_group_box.Location = new System.Drawing.Point(20, 22); this.toast_box_group_box.Name = "toast_box_group_box"; this.toast_box_group_box.Size = new System.Drawing.Size(248, 42); this.toast_box_group_box.TabIndex = 4; @@ -365,9 +375,9 @@ this.web_server_settings_groupbox.Controls.Add(this.web_server_port_label); this.web_server_settings_groupbox.Controls.Add(this.web_server_label); this.web_server_settings_groupbox.Controls.Add(this.web_server_checkbox); - this.web_server_settings_groupbox.Location = new System.Drawing.Point(26, 263); + this.web_server_settings_groupbox.Location = new System.Drawing.Point(80, 26); this.web_server_settings_groupbox.Name = "web_server_settings_groupbox"; - this.web_server_settings_groupbox.Size = new System.Drawing.Size(476, 99); + this.web_server_settings_groupbox.Size = new System.Drawing.Size(236, 95); this.web_server_settings_groupbox.TabIndex = 35; this.web_server_settings_groupbox.TabStop = false; this.web_server_settings_groupbox.Text = "Web Server Settings"; @@ -375,7 +385,7 @@ // clock_visibility_checkBox // this.clock_visibility_checkBox.AutoSize = true; - this.clock_visibility_checkBox.Location = new System.Drawing.Point(119, 55); + this.clock_visibility_checkBox.Location = new System.Drawing.Point(156, 67); this.clock_visibility_checkBox.Name = "clock_visibility_checkBox"; this.clock_visibility_checkBox.Size = new System.Drawing.Size(65, 17); this.clock_visibility_checkBox.TabIndex = 38; @@ -385,7 +395,7 @@ // clock_label // this.clock_label.AutoSize = true; - this.clock_label.Location = new System.Drawing.Point(44, 56); + this.clock_label.Location = new System.Drawing.Point(44, 68); this.clock_label.Name = "clock_label"; this.clock_label.Size = new System.Drawing.Size(76, 13); this.clock_label.TabIndex = 37; @@ -393,7 +403,7 @@ // // web_server_port_textbox // - this.web_server_port_textbox.Location = new System.Drawing.Point(246, 19); + this.web_server_port_textbox.Location = new System.Drawing.Point(139, 42); this.web_server_port_textbox.Name = "web_server_port_textbox"; this.web_server_port_textbox.Size = new System.Drawing.Size(77, 20); this.web_server_port_textbox.TabIndex = 36; @@ -401,7 +411,7 @@ // web_server_port_label // this.web_server_port_label.AutoSize = true; - this.web_server_port_label.Location = new System.Drawing.Point(211, 23); + this.web_server_port_label.Location = new System.Drawing.Point(45, 46); this.web_server_port_label.Name = "web_server_port_label"; this.web_server_port_label.Size = new System.Drawing.Size(29, 13); this.web_server_port_label.TabIndex = 35; @@ -419,7 +429,7 @@ // web_server_checkbox // this.web_server_checkbox.AutoSize = true; - this.web_server_checkbox.Location = new System.Drawing.Point(111, 23); + this.web_server_checkbox.Location = new System.Drawing.Point(154, 23); this.web_server_checkbox.Name = "web_server_checkbox"; this.web_server_checkbox.Size = new System.Drawing.Size(65, 17); this.web_server_checkbox.TabIndex = 34; @@ -435,6 +445,140 @@ this.label12.TabIndex = 27; this.label12.Text = "Separating character format"; // + // tab_controls + // + this.tab_controls.Controls.Add(this.settings_tab_page); + this.tab_controls.Controls.Add(this.output_settings_tab_page); + this.tab_controls.Controls.Add(this.misc_tab_page); + this.tab_controls.Location = new System.Drawing.Point(42, 133); + this.tab_controls.Name = "tab_controls"; + this.tab_controls.SelectedIndex = 0; + this.tab_controls.Size = new System.Drawing.Size(423, 398); + this.tab_controls.TabIndex = 22; + // + // settings_tab_page + // + this.settings_tab_page.Controls.Add(this.connection_settings_box); + this.settings_tab_page.Location = new System.Drawing.Point(4, 22); + this.settings_tab_page.Name = "settings_tab_page"; + this.settings_tab_page.Padding = new System.Windows.Forms.Padding(3); + this.settings_tab_page.Size = new System.Drawing.Size(415, 372); + this.settings_tab_page.TabIndex = 0; + this.settings_tab_page.Text = "Profile Settings"; + this.settings_tab_page.UseVisualStyleBackColor = true; + // + // output_settings_tab_page + // + this.output_settings_tab_page.Controls.Add(this.web_server_settings_groupbox); + this.output_settings_tab_page.Controls.Add(this.groupBox3); + this.output_settings_tab_page.Location = new System.Drawing.Point(4, 22); + this.output_settings_tab_page.Name = "output_settings_tab_page"; + this.output_settings_tab_page.Padding = new System.Windows.Forms.Padding(3); + this.output_settings_tab_page.Size = new System.Drawing.Size(415, 372); + this.output_settings_tab_page.TabIndex = 1; + this.output_settings_tab_page.Text = "Output Settings"; + this.output_settings_tab_page.UseVisualStyleBackColor = true; + // + // connection_settings_box + // + this.connection_settings_box.Controls.Add(this.textBox2); + this.connection_settings_box.Controls.Add(this.label3); + this.connection_settings_box.Controls.Add(this.label4); + this.connection_settings_box.Controls.Add(this.label6); + this.connection_settings_box.Controls.Add(this.polling_rate_textbox); + this.connection_settings_box.Controls.Add(this.button6); + this.connection_settings_box.Controls.Add(this.textBox3); + this.connection_settings_box.Controls.Add(this.label7); + this.connection_settings_box.Controls.Add(this.label5); + this.connection_settings_box.Controls.Add(this.textBox4); + this.connection_settings_box.Location = new System.Drawing.Point(74, 82); + this.connection_settings_box.Name = "connection_settings_box"; + this.connection_settings_box.Size = new System.Drawing.Size(248, 215); + this.connection_settings_box.TabIndex = 13; + this.connection_settings_box.TabStop = false; + this.connection_settings_box.Text = "Connection Settings"; + // + // notice_one + // + this.notice_one.AutoSize = true; + this.notice_one.Location = new System.Drawing.Point(53, 117); + this.notice_one.Name = "notice_one"; + this.notice_one.Size = new System.Drawing.Size(182, 65); + this.notice_one.TabIndex = 18; + this.notice_one.Text = "It is asking for an image file name.\r\nThis is what you would use\r\nto put a name o" + + "f what\r\nthe saved image will be outputted as.\r\nFor example, it might be img.png"; + // + // misc_tab_page + // + this.misc_tab_page.Controls.Add(this.groupBox4); + this.misc_tab_page.Controls.Add(this.toast_box_group_box); + this.misc_tab_page.Location = new System.Drawing.Point(4, 22); + this.misc_tab_page.Name = "misc_tab_page"; + this.misc_tab_page.Padding = new System.Windows.Forms.Padding(3); + this.misc_tab_page.Size = new System.Drawing.Size(415, 372); + this.misc_tab_page.TabIndex = 2; + this.misc_tab_page.Text = "Misc Settings"; + this.misc_tab_page.UseVisualStyleBackColor = true; + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.notice_two); + this.groupBox4.Controls.Add(this.smtc_check_box); + this.groupBox4.Controls.Add(this.smtc_enable_label); + this.groupBox4.Location = new System.Drawing.Point(20, 92); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(370, 155); + this.groupBox4.TabIndex = 4; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "SMTC Control"; + // + // smtc_enable_label + // + this.smtc_enable_label.AutoSize = true; + this.smtc_enable_label.Location = new System.Drawing.Point(115, 27); + this.smtc_enable_label.Name = "smtc_enable_label"; + this.smtc_enable_label.Size = new System.Drawing.Size(73, 13); + this.smtc_enable_label.TabIndex = 0; + this.smtc_enable_label.Text = "SMTC Enable"; + // + // smtc_check_box + // + this.smtc_check_box.AutoSize = true; + this.smtc_check_box.Location = new System.Drawing.Point(194, 27); + this.smtc_check_box.Name = "smtc_check_box"; + this.smtc_check_box.Size = new System.Drawing.Size(59, 17); + this.smtc_check_box.TabIndex = 2; + this.smtc_check_box.Text = "Enable"; + this.smtc_check_box.UseVisualStyleBackColor = true; + // + // notice_two + // + this.notice_two.AutoSize = true; + this.notice_two.Location = new System.Drawing.Point(52, 62); + this.notice_two.Name = "notice_two"; + this.notice_two.Size = new System.Drawing.Size(274, 78); + this.notice_two.TabIndex = 3; + this.notice_two.Text = resources.GetString("notice_two.Text"); + // + // loaded_profile_label + // + this.loaded_profile_label.AutoSize = true; + this.loaded_profile_label.Location = new System.Drawing.Point(134, 103); + this.loaded_profile_label.Name = "loaded_profile_label"; + this.loaded_profile_label.Size = new System.Drawing.Size(77, 13); + this.loaded_profile_label.TabIndex = 23; + this.loaded_profile_label.Text = "Loaded profile:"; + // + // profile_loaded_data + // + this.profile_loaded_data.AutoSize = true; + this.profile_loaded_data.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.profile_loaded_data.Location = new System.Drawing.Point(218, 102); + this.profile_loaded_data.Name = "profile_loaded_data"; + this.profile_loaded_data.Size = new System.Drawing.Size(104, 13); + this.profile_loaded_data.TabIndex = 24; + this.profile_loaded_data.Text = "No profile loaded"; + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -457,6 +601,14 @@ this.toast_box_group_box.PerformLayout(); this.web_server_settings_groupbox.ResumeLayout(false); this.web_server_settings_groupbox.PerformLayout(); + this.tab_controls.ResumeLayout(false); + this.settings_tab_page.ResumeLayout(false); + this.output_settings_tab_page.ResumeLayout(false); + this.connection_settings_box.ResumeLayout(false); + this.connection_settings_box.PerformLayout(); + this.misc_tab_page.ResumeLayout(false); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); this.ResumeLayout(false); } @@ -503,5 +655,17 @@ private System.Windows.Forms.GroupBox toast_box_group_box; private System.Windows.Forms.CheckBox toast_check_box_enable; private System.Windows.Forms.Label toast_label; + private System.Windows.Forms.TabControl tab_controls; + private System.Windows.Forms.TabPage settings_tab_page; + private System.Windows.Forms.TabPage output_settings_tab_page; + private System.Windows.Forms.GroupBox connection_settings_box; + private System.Windows.Forms.Label notice_one; + private System.Windows.Forms.TabPage misc_tab_page; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.Label notice_two; + private System.Windows.Forms.CheckBox smtc_check_box; + private System.Windows.Forms.Label smtc_enable_label; + private System.Windows.Forms.Label profile_loaded_data; + private System.Windows.Forms.Label loaded_profile_label; } } \ No newline at end of file diff --git a/RadioDJViewer/radiodj-restapi-template.cs b/RadioDJViewer/radiodj-restapi-template.cs index c760578..8e411b4 100644 --- a/RadioDJViewer/radiodj-restapi-template.cs +++ b/RadioDJViewer/radiodj-restapi-template.cs @@ -64,6 +64,7 @@ namespace RadioDJViewer label6.Text = mainImagesFolderPath; textBox5.Text = profile.OutputImageName; textBox1.Text = profile.UrlFormat; + profile_loaded_data.Text = profile.Name; // Default polling rate to 3 if missing or zero polling_rate_textbox.Text = (profile.PollingRateSeconds > 0 ? profile.PollingRateSeconds : 3).ToString(); // Web server settings @@ -74,10 +75,14 @@ namespace RadioDJViewer // Clock visibility setting clock_visibility_checkBox.Checked = profile.ClockVisibilityEnabled; toast_check_box_enable.Checked = profile.ToastNotificationsEnabled; + smtc_check_box.Checked = profile.SmtcEnabled; } catch { } + return; } } + + profile_loaded_data.Text = "No profile loaded"; } private void ButtonSelectOutputFolder_Click(object sender, EventArgs e) @@ -133,13 +138,16 @@ namespace RadioDJViewer WebServerPort = int.TryParse(web_server_port_textbox.Text, out int wp) ? wp : 8080, // Clock visibility setting ClockVisibilityEnabled = clock_visibility_checkBox.Checked, - ToastNotificationsEnabled = toast_check_box_enable.Checked + ToastNotificationsEnabled = toast_check_box_enable.Checked, + SmtcEnabled = smtc_check_box.Checked }; ProfileStorage.SaveProfile(profile); // Refresh profile list comboBox1.Items.Clear(); var names = ProfileStorage.GetProfileNames(); comboBox1.Items.AddRange(names.ToArray()); + comboBox1.SelectedItem = profile.Name; + profile_loaded_data.Text = profile.Name; MessageBox.Show("Profile saved successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } @@ -148,10 +156,15 @@ namespace RadioDJViewer // Remove Profile (Remove Profile button) if (comboBox1.SelectedItem != null) { - ProfileStorage.DeleteProfile(comboBox1.SelectedItem.ToString()); + string removed = comboBox1.SelectedItem.ToString(); + ProfileStorage.DeleteProfile(removed); comboBox1.Items.Clear(); var names = ProfileStorage.GetProfileNames(); comboBox1.Items.AddRange(names.ToArray()); + if (comboBox1.Items.Count > 0) + comboBox1.SelectedIndex = 0; + else + profile_loaded_data.Text = "No profile loaded"; } } diff --git a/RadioDJViewer/radiodj-restapi-template.resx b/RadioDJViewer/radiodj-restapi-template.resx index 8ee15e7..1fe0a6a 100644 --- a/RadioDJViewer/radiodj-restapi-template.resx +++ b/RadioDJViewer/radiodj-restapi-template.resx @@ -117,6 +117,14 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + With this option, it will enable the output +to Simple Media Transport Control Protocol (AKA SMTC). +You will not be able to control Radio DJ, +but you will get push notifications +or it will be pushed out to the SMTC protocol +with the ability to use it with other applications. +