Reworked UI and added SMTC Output (Works with Nutty SMTC bridge)
This commit is contained in:
+680
-122
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")]
|
||||
|
||||
+212
-48
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,14 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="notice_two.Text" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
Reference in New Issue
Block a user