From 8046eb5a3545f5a2f85a0b3e01ebd161132a4693 Mon Sep 17 00:00:00 2001 From: jasonchenwork Date: Thu, 3 Jul 2025 18:11:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E6=AA=94=20=E8=AA=BF=E6=95=B4=20=E5=BF=83=E8=B7=B3=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=20=E4=BF=AE=E6=AD=A3=20=E8=97=8F=E9=8F=A1=E4=BA=BA=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20=E6=9C=8D=E5=8B=99=E9=88=B4=2020250703?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CommandHandler.cs | 17 +- DBObj/SongListManager.cs | 4 +- DataCheck.cs | 140 --------- Env.cs | 61 ++++ HeartbeatSender.cs | 290 ++++++++---------- HttpServer.cs | 20 +- OverlayFormObj/OverlayForm.Labels.cs | 76 ++++- OverlayFormObj/OverlayForm.cs | 66 +++- .../HotSong/PrimaryForm.HotSong.cs | 156 ++++------ .../HotSong/PrimaryForm.HotSongMandarinNew.cs | 3 +- .../PrimaryForm.HotSongTaiwaneseNew.cs | 4 +- .../NewSongAlert/PrimaryForm.NewSongAlert.cs | 34 +- .../PrimaryForm.NewSongAlertCantonese.cs | 12 +- .../PrimaryForm.NewSongAlertChinese.cs | 12 +- .../PrimaryForm.NewSongAlertEnglish.cs | 12 +- .../PrimaryForm.NewSongAlertJapanese.cs | 12 +- .../PrimaryForm.NewSongAlertTaiwanese.cs | 12 +- PrimaryFormParts/PrimaryForm.Promotions.cs | 33 -- .../PrimaryForm.PromotionsAndMenuPanel.cs | 48 ++- PrimaryFormParts/PrimaryForm.SQLSearch.cs | 53 +--- PrimaryFormParts/PrimaryForm.SoundEffects.cs | 52 +++- PrimaryFormParts/PrimaryForm.cs | 67 +--- Program.cs | 81 ++--- TCPServer.cs | 69 +---- VideoPlayerForm.cs | 11 +- superstar_1.0.0.csproj | 15 - 26 files changed, 532 insertions(+), 828 deletions(-) delete mode 100644 DataCheck.cs create mode 100644 Env.cs diff --git a/CommandHandler.cs b/CommandHandler.cs index 04fd8b4..1e54917 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -70,7 +70,6 @@ namespace DualScreenDemo case "A26CA4": Console.WriteLine("ToggleVocalRemoval Invoked"); SafeInvokeAction("A26CA4",() => VideoPlayerForm.Instance.ToggleVocalRemoval()); - SafeInvokeAction("A26CA4",() => OverlayForm.MainForm.ShowOriginalSongLabel()); break; // 導唱 case "A26EA4": @@ -180,6 +179,10 @@ namespace DualScreenDemo SafeInvokeAction("A27BA4",() => OverlayForm.MainForm.HideAllLabels()); SafeInvokeAction("A27BA4",() => OverlayForm.MainForm.ShowKeyDownLabel("↓降4調")); break; + case "A266A4": + SafeInvokeAction("A266A4",() => OverlayForm.MainForm.HideAllLabels()); + SafeInvokeAction("A266A4",() => OverlayForm.MainForm.ShowServiceBell()); + break; default: if (Regex.IsMatch(indata, @"^A23\d+A4$")) { @@ -189,20 +192,8 @@ namespace DualScreenDemo } } - private Dictionary _recentCommands = new(); - private readonly TimeSpan _debounceInterval = TimeSpan.FromMilliseconds(300); // 最短觸發間隔 private void SafeInvokeAction(string commandKey, Action action) { - /*var now = DateTime.Now; - - if (_recentCommands.TryGetValue(commandKey, out DateTime lastTime)) - { - if (now - lastTime < _debounceInterval) - return; // 忽略短時間內的重複指令 - } - - _recentCommands[commandKey] = now; - */ // 真正執行 UI 操作 if (OverlayForm.MainForm.InvokeRequired) { diff --git a/DBObj/SongListManager.cs b/DBObj/SongListManager.cs index 0e177d1..e7f97c1 100644 --- a/DBObj/SongListManager.cs +++ b/DBObj/SongListManager.cs @@ -51,11 +51,11 @@ namespace DBObj } */ public List SearchNewSongs(){ - string query= $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY add_date DESC LIMIT {PrimaryForm.ReadNewSongLimit()};"; + string query= $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY add_date DESC LIMIT {Utils.Env.GetInt("NewSongLimit", 100)};"; return PrimaryForm.Instance.SearchSongs_Mysql(query); } public List SearchHotSongs(){ - string query= $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY song_counts DESC LIMIT {PrimaryForm.ReadHotSongLimit()};"; + string query= $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY song_counts DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};"; return PrimaryForm.Instance.SearchSongs_Mysql(query); } public List SearchSongsBySinger(string keyword) diff --git a/DataCheck.cs b/DataCheck.cs deleted file mode 100644 index b7bebff..0000000 --- a/DataCheck.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System.IO; -namespace DataCheck -{ - public class dataCheck - { - public dataCheck() - { - menu_check(); - news_check(); - } - private void menu_check() - { - string menuPath = @"\\JLDKTV\foods"; - string menuPath_local = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "foods"); - - if (!Directory.Exists(menuPath_local)) - { - Directory.CreateDirectory(menuPath_local); - } - var serverFiles = Directory.GetFiles(menuPath, "*.jpg") - .Select(f => new FileInfo(f)) - .ToDictionary(f => f.Name, f => f); - - var localFiles = Directory.GetFiles(menuPath_local, "*.jpg") - .Select(f => new FileInfo(f)) - .ToDictionary(f => f.Name, f => f); - foreach (var serverFile in serverFiles) - { - bool needsCopy = false; - string localFilePath = Path.Combine(menuPath_local, serverFile.Key); - if (!localFiles.ContainsKey(serverFile.Key)) - { - needsCopy = true; - } - else - { - var localFile = localFiles[serverFile.Key]; - if (serverFile.Value.LastWriteTime > localFile.LastWriteTime) - { - needsCopy = true; - } - } - - if (needsCopy) - { - try - { - File.Copy(serverFile.Value.FullName, localFilePath, true); - Console.WriteLine($"更新菜單: {serverFile.Key}"); - } - catch (Exception ex) - { - Console.WriteLine($"複製菜單失敗 {serverFile.Key}: {ex.Message}"); - } - } - } - // 3-2. 清除本地有但伺服器已經沒有的檔案 - foreach (var localFile in localFiles) - { - if (!serverFiles.ContainsKey(localFile.Key)) - { - try - { - File.Delete(localFile.Value.FullName); - Console.WriteLine($"刪除本地多餘菜單: {localFile.Key}"); - } - catch (Exception ex) - { - Console.WriteLine($"刪除菜單失敗 {localFile.Key}: {ex.Message}"); - } - } - } - } - private void news_check() - { - string newsPath = @"\\JLDKTV\news"; - string newsPath_local = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "news"); - - if (!Directory.Exists(newsPath_local)) - { - Directory.CreateDirectory(newsPath_local); - } - var serverFiles = Directory.GetFiles(newsPath, "*.jpg") - .Select(f => new FileInfo(f)) - .ToDictionary(f => f.Name, f => f); - - var localFiles = Directory.GetFiles(newsPath_local, "*.jpg") - .Select(f => new FileInfo(f)) - .ToDictionary(f => f.Name, f => f); - foreach (var serverFile in serverFiles) - { - bool needsCopy = false; - string localFilePath = Path.Combine(newsPath_local, serverFile.Key); - if (!localFiles.ContainsKey(serverFile.Key)) - { - needsCopy = true; - } - else - { - var localFile = localFiles[serverFile.Key]; - if (serverFile.Value.LastWriteTime > localFile.LastWriteTime) - { - needsCopy = true; - } - } - - if (needsCopy) - { - try - { - File.Copy(serverFile.Value.FullName, localFilePath, true); - Console.WriteLine($"更新新聞: {serverFile.Key}"); - } - catch (Exception ex) - { - Console.WriteLine($"複製新聞失敗 {serverFile.Key}: {ex.Message}"); - } - } - } - // 3-2. 清除本地有但伺服器已經沒有的檔案 - foreach (var localFile in localFiles) - { - if (!serverFiles.ContainsKey(localFile.Key)) - { - try - { - File.Delete(localFile.Value.FullName); - Console.WriteLine($"刪除本地多餘新聞: {localFile.Key}"); - } - catch (Exception ex) - { - Console.WriteLine($"刪除新聞失敗 {localFile.Key}: {ex.Message}"); - } - } - } - - } - - } -} \ No newline at end of file diff --git a/Env.cs b/Env.cs new file mode 100644 index 0000000..1ac982f --- /dev/null +++ b/Env.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Utils +{ + public static class Env + { + public static readonly string KtvPath = @"\\pc101\KTVData"; + private static readonly Dictionary _values; + static Env() + { + var path = Path.Combine(KtvPath, "config.ini"); + _values = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (!File.Exists(path)) + { + Console.WriteLine($"❌ 找不到環境檔案:{path}"); + return; + } + + foreach (var line in File.ReadAllLines(path)) + { + var trimmed = line.Trim(); + if (string.IsNullOrWhiteSpace(trimmed) || trimmed.StartsWith("#")) continue; + + var index = trimmed.IndexOf('='); + if (index < 0) continue; + + var key = trimmed[..index].Trim(); + var value = trimmed[(index + 1)..].Trim(); + + if (value.StartsWith("\"") && value.EndsWith("\"")) + value = value[1..^1]; // 去除引號 + + _values[key] = value; + } + } + + public static string Get(string key, string fallback = "") + { + return _values.TryGetValue(key, out var value) ? value : fallback; + } + + public static bool GetBool(string key, bool fallback = false) + { + return _values.TryGetValue(key, out var value) && bool.TryParse(value, out var result) + ? result + : fallback; + } + + public static int GetInt(string key, int fallback = 0) + { + return _values.TryGetValue(key, out var value) && int.TryParse(value, out var result) + ? result + : fallback; + } + + // 可加上 GetFloat、GetDouble、GetTimeSpan ... 視需要 + } +} diff --git a/HeartbeatSender.cs b/HeartbeatSender.cs index 19b3a93..c8d6672 100644 --- a/HeartbeatSender.cs +++ b/HeartbeatSender.cs @@ -1,182 +1,156 @@ using System.Net.Http; using System.Text; -using System.Text.Json; // 適用於 .NET Core 3.0+ / .NET 5/6/7/8 +using System.Text.Json; using System.Net; using System.Net.Sockets; using System.Diagnostics; using System.IO; +using System.Threading; +using System.Threading.Tasks; using Microsoft.VisualBasic.Devices; -namespace HeartbeatSender +namespace HeartbeatSender; + +public class heartbeatSender { + private readonly HttpClient httpClient = new(); + private string token = ""; + private string branchName = ""; + private string heartbeatDomain = ""; + private CancellationTokenSource? cancellationTokenSource; - public class heartbeatSender + public heartbeatSender() { - private readonly HttpClient httpClient = new HttpClient(); - private string token; - private string token_heartbeatUrl; - private string init_heartbeatUrl; + this.heartbeatDomain = Utils.Env.Get("HeartBeatUrl", ""); - public heartbeatSender() + // 在建構子中啟動背景心跳任務 + _ = Task.Run(() => StartAsync()); + } + public async Task StartAsync() + { + cancellationTokenSource = new CancellationTokenSource(); + + while (!cancellationTokenSource.IsCancellationRequested) { - LoadHeartbeatUrls("txt/HeartBeat.txt"); - } - /// - /// 讀取URL - /// - /// 路徑 - private void LoadHeartbeatUrls(string filePath) - { - if (!File.Exists(filePath)) - { - Console.WriteLine("找不到 HeartBeat.txt"); - return; - } - - string[] lines = File.ReadAllLines(filePath); - - foreach (string line in lines) - { - if (line.StartsWith("init:")) - { - init_heartbeatUrl = line.Substring("init:".Length).Trim(); - } - else if (line.StartsWith("token:")) - { - token_heartbeatUrl = line.Substring("token:".Length).Trim(); - } - } - - Console.WriteLine("init URL: " + init_heartbeatUrl); - Console.WriteLine("token URL: " + token_heartbeatUrl); - } - - public static string GetLocalIPv4() - { - foreach (var ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList) - { - if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip)) - { - return ip.ToString(); - } - } - return "127.0.0.1"; // fallback - } - public async Task LoginAndGetTokenAsync() - { - // init_heartbeat - //var loginUrl = "http://zqd.superstar.dnsnet.cc/api/room/receiveRegister"; - string hostName = System.Net.Dns.GetHostName(); - - var loginPayload = new - { - branch_name = "測試", - room_name = "PC" + hostName.Substring(Math.Max(0, hostName.Length - 3)), - room_ip = GetLocalIPv4(), - email = "MachineKTV@gmail.com", - password = "aa147258-" - }; - - var json = JsonSerializer.Serialize(loginPayload); - var content = new StringContent(json, Encoding.UTF8, "application/json"); - try { - var response = await httpClient.PostAsync(init_heartbeatUrl, content); - response.EnsureSuccessStatusCode(); - - var responseJson = await response.Content.ReadAsStringAsync(); - // Console.WriteLine("API 回傳內容:" + responseJson); - - using var doc = JsonDocument.Parse(responseJson); - if (doc.RootElement.TryGetProperty("data", out JsonElement dataElement) && - dataElement.ValueKind == JsonValueKind.Object) + if (string.IsNullOrEmpty(token)) { - if (dataElement.TryGetProperty("token", out JsonElement tokenElement)) - { - token = tokenElement.GetString(); - } + bool loginSuccess = await LoginAndGetTokenAsync(); + Console.WriteLine(loginSuccess ? "心跳登入成功" : "心跳登入失敗"); } - // Console.WriteLine("登入成功,取得 token:" + token); - return true; + + if (!string.IsNullOrEmpty(token)) + { + await SendHeartbeatAsync(); + } + + await Task.Delay(TimeSpan.FromMinutes(1), cancellationTokenSource.Token); } catch (Exception ex) { - Console.WriteLine($"登入失敗:{ex.Message}"); - return false; + Console.WriteLine($"心跳任務錯誤:{ex.Message}"); + await Task.Delay(5000); // 錯誤後延遲再跑 } } - - public async Task SendHeartbeatAsync() - { - if (string.IsNullOrEmpty(token)) - { - Console.WriteLine("請先登入取得 token"); - return; - } - //Console.WriteLine(GetLocalIPv4()); - string hostName = System.Net.Dns.GetHostName(); - - var heartbeatData = new - { - branch_name = "測試", - hostname = "PC" + hostName.Substring(Math.Max(0, hostName.Length - 3)), - ip = GetLocalIPv4(), - cpu = GetCpuUsage(), - memory = GetTotalMemoryInMB(), - disk = GetDiskTotalSizeInGB() - }; - - var json = JsonSerializer.Serialize(heartbeatData); - var content = new StringContent(json, Encoding.UTF8, "application/json"); - // token_heartbeat - // heartbeatUrl = "http://zqd.superstar.dnsnet.cc/api/room/heartbeat"; - var request = new HttpRequestMessage(HttpMethod.Post, token_heartbeatUrl); - request.Content = content; - request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - // Console.WriteLine("送出的 JSON:"); - // Console.WriteLine(json); - var response = await httpClient.SendAsync(request); - try - { - - // Console.WriteLine($"心跳送出狀態:{response.StatusCode}"); - - response.EnsureSuccessStatusCode(); - - var responseJson = await response.Content.ReadAsStringAsync(); - - using var doc = JsonDocument.Parse(responseJson); - // Console.WriteLine("API 回傳內容:" + responseJson); - - } - catch (Exception ex) - { - var errorContent = await response.Content.ReadAsStringAsync(); - Console.WriteLine($"送出心跳錯誤:{ex.Message}"); - Console.WriteLine($"後端回應內容:{errorContent}"); - } - } - - private float GetCpuUsage() - { - using var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); - cpuCounter.NextValue(); // 需要呼叫兩次 - System.Threading.Thread.Sleep(100); - return cpuCounter.NextValue(); // 回傳的是百分比,例如 25.3 - } - private float GetTotalMemoryInMB() - { - var computerInfo = new ComputerInfo(); - var totalMB = computerInfo.TotalPhysicalMemory / (1024f); - var availableMB = computerInfo.AvailablePhysicalMemory / (1024f); - var usedMB = totalMB - availableMB; - return usedMB; // 轉 MB - } - private float GetDiskTotalSizeInGB(string driveLetter = "C") - { - var drive = new DriveInfo(driveLetter); - return drive.TotalSize / (1024f * 1024f * 1024f); // 轉 GB - } + } + + public void Stop() + { + cancellationTokenSource?.Cancel(); + Console.WriteLine("心跳任務已停止"); + } + + public async Task LoginAndGetTokenAsync() + { + var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/receiveRegister"; + var loginPayload = new + { + email = "MachineKTV@gmail.com", + password = "aa147258-" + }; + + var result = await SendPostAsync(url, loginPayload); + + if (result.ValueKind == JsonValueKind.Object && + result.TryGetProperty("data", out JsonElement data)) + { + token = data.GetProperty("token").GetString()!; + branchName = data.GetProperty("branch_name").GetString()!; + return true; + } + + return false; + } + + public async Task SendHeartbeatAsync() + { + var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/heartbeat"; + string hostName = Dns.GetHostName(); + + var heartbeatPayload = new + { + branch_name = branchName, + hostname = "PC" + hostName[^3..], + ip = GetLocalIPv4(), + cpu = GetCpuUsage(), + memory = GetTotalMemoryInMB(), + disk = GetDiskTotalSizeInGB() + }; + + await SendPostAsync(url, heartbeatPayload, token); + Console.WriteLine($"心跳送出成功: {DateTime.Now:HH:mm:ss}"); + } + + private async Task SendPostAsync(string url, object payload, string? bearerToken = null) + { + var json = JsonSerializer.Serialize(payload); + var content = new StringContent(json, Encoding.UTF8, "application/json"); + + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = content + }; + + if (!string.IsNullOrWhiteSpace(bearerToken)) + { + request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken); + } + + var response = await httpClient.SendAsync(request); + response.EnsureSuccessStatusCode(); + + string responseJson = await response.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(responseJson); + } + + private static string GetLocalIPv4() + { + foreach (var ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList) + { + if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip)) + return ip.ToString(); + } + return "127.0.0.1"; + } + + private float GetCpuUsage() + { + using var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); + cpuCounter.NextValue(); + Thread.Sleep(100); + return cpuCounter.NextValue(); + } + + private float GetTotalMemoryInMB() + { + var ci = new ComputerInfo(); + return (ci.TotalPhysicalMemory - ci.AvailablePhysicalMemory) / 1024f; + } + + private float GetDiskTotalSizeInGB(string driveLetter = "C") + { + var drive = new DriveInfo(driveLetter); + return drive.TotalSize / (1024f * 1024f * 1024f); } } diff --git a/HttpServer.cs b/HttpServer.cs index bfd4757..be3cea9 100644 --- a/HttpServer.cs +++ b/HttpServer.cs @@ -42,9 +42,7 @@ namespace DualScreenDemo // 安裝包更新 string localAddress = GetLocalIPAddress(); - string externalAddress = File.Exists(@"\\JLDKTV\txt\ip.txt") - ? File.ReadAllText(@"\\JLDKTV\txt\ip.txt").Trim() - : ""; + string externalAddress = Utils.Env.Get("PhoneIP", "").Trim(); _listener = new HttpListener(); _listener.Prefixes.Add($"http://{localAddress}:{port}/"); @@ -538,7 +536,7 @@ namespace DualScreenDemo // 执行服务操作 PrimaryForm.SendCommandThroughSerialPort("a2 53 a4"); OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowServiceBellLabel(); + OverlayForm.MainForm.ShowServiceBell(); })); // 异步处理等待和隐藏标签 await HttpServer.HandleServiceBellAsync(); @@ -983,9 +981,19 @@ namespace DualScreenDemo string Messagelast=""; for(int j=0;j < message.Length;j++){ Messagelast += message[j]; - await Task.Delay(300); + await Task.Delay(10); // 将读取到的 "message" 字段传递给 UI 控件显示 - InvokeAction(() => OverlayForm.MainForm.ShowmessageLabel(Messagefist+Messagelast+'_')); + if (OverlayForm.MainForm.InvokeRequired) + { + OverlayForm.MainForm.Invoke(new System.Action(() => + { + OverlayForm.MainForm.ShowmessageLabel(Messagefist + Messagelast + '_'); + })); + } + else + { + OverlayForm.MainForm.ShowmessageLabel(Messagefist + Messagelast + '_'); + } } // 真情告白顯示秒數 await Task.Delay(3000); diff --git a/OverlayFormObj/OverlayForm.Labels.cs b/OverlayFormObj/OverlayForm.Labels.cs index aa44781..981ae7c 100644 --- a/OverlayFormObj/OverlayForm.Labels.cs +++ b/OverlayFormObj/OverlayForm.Labels.cs @@ -14,8 +14,12 @@ namespace OverlayFormObj public Label originalSongLabel; public Label nextSongLabel; private Label serviceBellLabel; + private Label BellLabel; + private Label OriginalLabel; public Label volumeUpLabel; // New volume up label public Label volumeDownLabel; // New volume down label + private System.Windows.Forms.Timer BellTimer = new System.Windows.Forms.Timer(); + private System.Windows.Forms.Timer OriginalTimer = new System.Windows.Forms.Timer(); private System.Windows.Forms.Timer volumeUpTimer = new System.Windows.Forms.Timer(); private System.Windows.Forms.Timer volumeDownTimer = new System.Windows.Forms.Timer(); private System.Windows.Forms.Timer micUpTimer = new System.Windows.Forms.Timer(); @@ -60,6 +64,10 @@ namespace OverlayFormObj InitializeMuteLabel(); // Initialize the new mute label InitializeOriginalSongLabel(); // 初始化原唱标签 InitializeServiceBellLabel(); + + InitializeBellLabel(); + InitializeOriginalLabel(); + InitializeVolumeUpLabel(); // Initialize the volume up label InitializeVolumeDownLabel(); // Initialize the volume down label InitializeMicUpLabel(); // Initialize the microphone up label @@ -89,6 +97,12 @@ namespace OverlayFormObj private void ConfigureKeyTimers() { + OriginalTimer.Interval = 1000; + OriginalTimer.Tick += (sender, e) => {OriginalLabel.Visible = false;OriginalTimer.Stop();keepshowmic();}; + + BellTimer.Interval = 1000; + BellTimer.Tick += (sender, e) => {BellLabel.Visible = false;BellTimer.Stop();keepshowmic();}; + volumeUpTimer.Interval = 1000; volumeUpTimer.Tick += (sender, e) => {volumeUpLabel.Visible = false;volumeUpTimer.Stop();keepshowmic();}; @@ -422,13 +436,47 @@ namespace OverlayFormObj volumeUpLabel.Location = new Point(blackBackgroundPanel.Width - volumeUpLabel.Width - 10, 56); }; } + private void InitializeOriginalLabel() + { + OriginalLabel = new Label + { + AutoSize = true, + ForeColor = Color.White, + Font = new Font("Microsoft JhengHei", 34, FontStyle.Bold), + BackColor = Color.Transparent, + Text = "有人聲", + Visible = false + }; + blackBackgroundPanel.Controls.Add(OriginalLabel); + blackBackgroundPanel.Resize += (s, e) => + { + OriginalLabel.Location = new Point(blackBackgroundPanel.Width - OriginalLabel.Width - 10, 56); + }; + } + private void InitializeBellLabel() + { + BellLabel = new Label + { + AutoSize = true, + ForeColor = Color.White, + Font = new Font("Microsoft JhengHei", 34, FontStyle.Bold), + BackColor = Color.Transparent, + Text = "服務鈴", + Visible = false + }; + blackBackgroundPanel.Controls.Add(BellLabel); + blackBackgroundPanel.Resize += (s, e) => + { + BellLabel.Location = new Point(blackBackgroundPanel.Width - BellLabel.Width - 10, 56); + }; + } private void InitializeVolumeDownLabel() { volumeDownLabel = new Label { AutoSize = true, ForeColor = Color.White, - Font = new Font("Microsoft JhengHei",34, FontStyle.Bold), + Font = new Font("Microsoft JhengHei", 34, FontStyle.Bold), BackColor = Color.Transparent, Text = "音量 ↓", Visible = false @@ -808,23 +856,18 @@ public void UpdateNextSongLabelFromPlaylist(bool isUserPlaylistPlaying, SongData // 显示服务铃标签 public void ShowServiceBellLabel() { - if (serviceBellLabel != null) - { whichoneshowmic(); HideAllLabels(); serviceBellLabel.Visible = true; - // Console.WriteLine("服務鈴顯示: " + serviceBellLabel.Text); // 输出标签文本内容 - } + Console.WriteLine("服務鈴顯示: " + serviceBellLabel.Text); // 输出标签文本内容 } public void HideServiceBellLabel() - { - if (serviceBellLabel != null) - { + { /* serviceBellLabel.Visible = false; - // Console.WriteLine("服務鈴隱藏: " + serviceBellLabel.Text); // 输出标签文本内容 + Console.WriteLine("服務鈴隱藏: " + serviceBellLabel.Text); // 输出标签文本内容 keepshowmic(); - } + */ } // 显示标准标签 @@ -1028,6 +1071,19 @@ public void UpdateNextSongLabelFromPlaylist(bool isUserPlaylistPlaying, SongData volumeUpLabel.Visible = true; volumeUpTimer.Start(); } + public void ShowServiceBell() + { + BellLabel.Visible = true; + BellTimer.Start(); + + } + public void ShowOriginalLabel(string text = "有人聲") + { + OriginalLabel.Text = text; + OriginalLabel.Visible = true; + OriginalTimer.Start(); + + } // 显示音量-标签 public void ShowVolumeDownLabel() { diff --git a/OverlayFormObj/OverlayForm.cs b/OverlayFormObj/OverlayForm.cs index 11a84b4..8a75707 100644 --- a/OverlayFormObj/OverlayForm.cs +++ b/OverlayFormObj/OverlayForm.cs @@ -444,35 +444,67 @@ private static void DisplayTimer_Tick(object sender, EventArgs e) // 當 songDisplayTimer 計時完成時會呼叫此函式 private static void SongDisplayTimer_Elapsed(object sender, EventArgs e) { + if (MainForm == null || MainForm.IsDisposed || MainForm.Disposing) + { + Console.WriteLine("MainForm is not valid."); + return; + } + // 檢查是否需要跨執行緒操作 UI 控制項 if (MainForm.InvokeRequired) { - // 如果目前不在 UI 執行緒上,必須透過 Invoke 安全執行 UI 更新邏輯 - Console.WriteLine("SongDisplayTimer_Tick invoked on UI thread."); - - MainForm.BeginInvoke(new Action(() => + try { - if (MainForm.songDisplayLabel != null) - MainForm.songDisplayLabel.Text = ""; + MainForm.BeginInvoke(new Action(() => + { + try + { + if (MainForm.songDisplayLabel != null && !MainForm.songDisplayLabel.IsDisposed) + MainForm.songDisplayLabel.Text = ""; - if (MainForm.nextSongLabel != null) - MainForm.nextSongLabel.Visible = true; - })); + if (MainForm.nextSongLabel != null && !MainForm.nextSongLabel.IsDisposed) + MainForm.nextSongLabel.Visible = true; + } + catch (Exception ex) + { + Console.WriteLine("Invoke UI update failed: " + ex.Message); + } + })); + } + catch (ObjectDisposedException ex) + { + Console.WriteLine("BeginInvoke failed: MainForm already disposed. " + ex.Message); + } } else { - // 如果已經在 UI 執行緒,就直接更新 UI 控制項 - Console.WriteLine("SongDisplayTimer_Tick invoked on background thread."); - MainForm.songDisplayLabel.Text = ""; - MainForm.nextSongLabel.Visible = true; + try + { + if (MainForm.songDisplayLabel != null && !MainForm.songDisplayLabel.IsDisposed) + MainForm.songDisplayLabel.Text = ""; + + if (MainForm.nextSongLabel != null && !MainForm.nextSongLabel.IsDisposed) + MainForm.nextSongLabel.Visible = true; + } + catch (Exception ex) + { + Console.WriteLine("Direct UI update failed: " + ex.Message); + } } - // 停止計時器,避免重複觸發 - songDisplayTimer.Stop(); + try + { + songDisplayTimer.Stop(); + } + catch (Exception ex) + { + Console.WriteLine("Failed to stop timer: " + ex.Message); + } } + private readonly object _lockObject = new object(); private bool _handlingTimeout = false; private async void UnifiedTimer_Elapsed(object sender, EventArgs e) @@ -1495,11 +1527,11 @@ private void DisplayArtists(List artists, int page)//歌星點進去後 if (category == Category.NewSongs) { - sqlQuery = $"SELECT * FROM song_library_cache WHERE language_name = '{language}' ORDER BY add_date DESC LIMIT {PrimaryForm.ReadNewSongLimit()};"; + sqlQuery = $"SELECT * FROM song_library_cache WHERE language_name = '{language}' ORDER BY add_date DESC LIMIT {Utils.Env.GetInt("NewSongLimit", 100)};"; } else if (category == Category.HotSongs) { - sqlQuery = $"SELECT * FROM song_library_cache WHERE language_name = '{language}' ORDER BY song_counts DESC LIMIT {PrimaryForm.ReadHotSongLimit()};"; + sqlQuery = $"SELECT * FROM song_library_cache WHERE language_name = '{language}' ORDER BY song_counts DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};"; } else { diff --git a/PrimaryFormParts/HotSong/PrimaryForm.HotSong.cs b/PrimaryFormParts/HotSong/PrimaryForm.HotSong.cs index b7b8dd7..2b54fe2 100644 --- a/PrimaryFormParts/HotSong/PrimaryForm.HotSong.cs +++ b/PrimaryFormParts/HotSong/PrimaryForm.HotSong.cs @@ -5,8 +5,8 @@ namespace DualScreenDemo public partial class PrimaryForm { private Button hotPlayButton; - private Bitmap hotPlayNormalBackground; - private Bitmap hotPlayActiveBackground; + private Bitmap hotPlayNormalBackground; + private Bitmap hotPlayActiveBackground; private Button guoYuButtonHotSong; private Bitmap guoYuHotSongNormalBackground; @@ -36,18 +36,18 @@ namespace DualScreenDemo private void SetHotSongButtonsVisibility(bool isVisible) { - - - + + + Button[] hotSongButtons = { guoYuButtonHotSong, taiYuButtonHotSong, taiYuNewSongButtonHotSong, guoYuNewSongButtonHotSong, yingWenButtonHotSong, riYuButtonHotSong, hanYuButtonHotSong }; - + foreach (var button in hotSongButtons) { button.Visible = isVisible; - + if (isVisible) { button.BringToFront(); @@ -62,11 +62,10 @@ namespace DualScreenDemo isOnOrderedSongsPage = false; /* 清空搜尋欄 */ ResetinputBox(); - int songLimit = ReadHotSongLimit(); - string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY `song_counts` DESC LIMIT {songLimit};"; + string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY `song_counts` DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};"; var guoYuSongs = SearchSongs_Mysql(query); UpdateSongList(guoYuSongs); - + SetButtonsVisibility(); //HideQRCode(); } @@ -91,8 +90,7 @@ namespace DualScreenDemo { UpdateHotSongButtons(activeButton, activeBackground); - int songLimit = ReadHotSongLimit(); - string query = $"SELECT * FROM song_library_cache WHERE language_name = '{category}' ORDER BY `song_counts` DESC LIMIT {songLimit};"; + string query = $"SELECT * FROM song_library_cache WHERE language_name = '{category}' ORDER BY `song_counts` DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};"; var selectedSongs = SearchSongs_Mysql(query); UpdateSongList(selectedSongs); @@ -113,11 +111,11 @@ namespace DualScreenDemo private void UpdateSongList(List songs) { - currentPage = 0; - currentSongList = songs; + currentPage = 0; + currentSongList = songs; totalPages = (int)Math.Ceiling((double)songs.Count / itemsPerPage); - + multiPagePanel.currentPageIndex = 0; multiPagePanel.LoadSongs(currentSongList); } @@ -148,85 +146,86 @@ namespace DualScreenDemo } private void InitializeButtonsForHotSong() - { + { - InitializeHotSongButton(ref guoYuNewSongButtonHotSong, "國語新歌", 1214, 230, 209, 58, - normalStateImageHotSong, - out guoYuNewSongHotSongNormalBackground, - mouseDownImageHotSong, - out guoYuNewSongHotSongActiveBackground, + InitializeHotSongButton(ref guoYuNewSongButtonHotSong, "國語新歌", 1214, 230, 209, 58, + normalStateImageHotSong, + out guoYuNewSongHotSongNormalBackground, + mouseDownImageHotSong, + out guoYuNewSongHotSongActiveBackground, GuoYuNewSongButtonHotSong_Click); - InitializeHotSongButton(ref taiYuNewSongButtonHotSong, "台語新歌", 1214, 293, 209, 58, - normalStateImageHotSong, - out taiYuNewSongHotSongNormalBackground, - mouseDownImageHotSong, - out taiYuNewSongHotSongActiveBackground, + InitializeHotSongButton(ref taiYuNewSongButtonHotSong, "台語新歌", 1214, 293, 209, 58, + normalStateImageHotSong, + out taiYuNewSongHotSongNormalBackground, + mouseDownImageHotSong, + out taiYuNewSongHotSongActiveBackground, TaiYuNewSongButtonHotSong_Click); - InitializeHotSongButton(ref taiYuButtonHotSong, "台語", 1214, 418, 209, 58, - normalStateImageHotSong, - out taiYuHotSongNormalBackground, - mouseDownImageHotSong, - out taiYuHotSongActiveBackground, + InitializeHotSongButton(ref taiYuButtonHotSong, "台語", 1214, 418, 209, 58, + normalStateImageHotSong, + out taiYuHotSongNormalBackground, + mouseDownImageHotSong, + out taiYuHotSongActiveBackground, TaiYuButtonHotSong_Click); - InitializeHotSongButton(ref yueYuButtonHotSong, "粵語", 1214, 356, 209, 58, - normalStateImageHotSong, - out yueYuHotSongNormalBackground, - mouseDownImageHotSong, - out yueYuHotSongActiveBackground, + InitializeHotSongButton(ref yueYuButtonHotSong, "粵語", 1214, 356, 209, 58, + normalStateImageHotSong, + out yueYuHotSongNormalBackground, + mouseDownImageHotSong, + out yueYuHotSongActiveBackground, YueYuButtonHotSong_Click); - InitializeHotSongButton(ref guoYuButtonHotSong, "國語", 1214, 356, 209, 59, - normalStateImageHotSong, - out guoYuHotSongNormalBackground, - mouseDownImageHotSong, - out guoYuHotSongActiveBackground, + InitializeHotSongButton(ref guoYuButtonHotSong, "國語", 1214, 356, 209, 59, + normalStateImageHotSong, + out guoYuHotSongNormalBackground, + mouseDownImageHotSong, + out guoYuHotSongActiveBackground, GuoYuButtonHotSong_Click); - InitializeHotSongButton(ref yingWenButtonHotSong, "英文", 1214, 481, 209, 59, - normalStateImageHotSong, - out yingWenHotSongNormalBackground, - mouseDownImageHotSong, - out yingWenHotSongActiveBackground, + InitializeHotSongButton(ref yingWenButtonHotSong, "英文", 1214, 481, 209, 59, + normalStateImageHotSong, + out yingWenHotSongNormalBackground, + mouseDownImageHotSong, + out yingWenHotSongActiveBackground, YingWenButtonHotSong_Click); - InitializeHotSongButton(ref riYuButtonHotSong, "日語", 1214, 544, 209, 59, - normalStateImageHotSong, - out riYuHotSongNormalBackground, - mouseDownImageHotSong, - out riYuHotSongActiveBackground, + InitializeHotSongButton(ref riYuButtonHotSong, "日語", 1214, 544, 209, 59, + normalStateImageHotSong, + out riYuHotSongNormalBackground, + mouseDownImageHotSong, + out riYuHotSongActiveBackground, RiYuButtonHotSong_Click); - InitializeHotSongButton(ref hanYuButtonHotSong, "韓語", 1214, 607, 209, 58, - normalStateImageHotSong, - out hanYuHotSongNormalBackground, - mouseDownImageHotSong, - out hanYuHotSongActiveBackground, + InitializeHotSongButton(ref hanYuButtonHotSong, "韓語", 1214, 607, 209, 58, + normalStateImageHotSong, + out hanYuHotSongNormalBackground, + mouseDownImageHotSong, + out hanYuHotSongActiveBackground, HanYuButtonHotSong_Click); } - private void InitializeHotSongButton(ref Button button, string buttonText, int x, int y, int width, int height, - Image normalBackground, out Bitmap normalBackgroundOut, - Image activeBackground, out Bitmap activeBackgroundOut, + private void InitializeHotSongButton(ref Button button, string buttonText, int x, int y, int width, int height, + Image normalBackground, out Bitmap normalBackgroundOut, + Image activeBackground, out Bitmap activeBackgroundOut, EventHandler clickEventHandler) { - button = new Button { + button = new Button + { Text = "", // 移除文字 - Visible = false + Visible = false }; ResizeAndPositionButton(button, x, y, width, height); // 修改裁剪區域,避開文字部分 Rectangle cropArea = new Rectangle(1214, y, 209, 58); // 使用固定的裁剪區域 - + normalBackgroundOut = new Bitmap(normalBackground).Clone(cropArea, normalBackground.PixelFormat); activeBackgroundOut = new Bitmap(activeBackground).Clone(cropArea, activeBackground.PixelFormat); - + button.BackgroundImage = normalBackgroundOut; button.BackgroundImageLayout = ImageLayout.Stretch; button.FlatStyle = FlatStyle.Flat; @@ -234,36 +233,5 @@ namespace DualScreenDemo button.Click += clickEventHandler; this.Controls.Add(button); } - - public static int ReadHotSongLimit() - { - string filePath = Path.Combine(Application.StartupPath,"txt","SongLimitsSettings.txt"); - try - { - - var lines = File.ReadAllLines(filePath); - foreach (var line in lines) - { - - if (line.StartsWith("HotSongLimit:")) - { - string valuePart = line.Split(':')[1].Trim(); - int limit; - if (int.TryParse(valuePart, out limit)) - { - return limit; - } - break; - } - } - } - catch (Exception ex) - { - Console.WriteLine("Failed to read song limits from file: " + ex.Message); - return 100; - } - - return 100; - } } } \ No newline at end of file diff --git a/PrimaryFormParts/HotSong/PrimaryForm.HotSongMandarinNew.cs b/PrimaryFormParts/HotSong/PrimaryForm.HotSongMandarinNew.cs index 1f9e1c2..bafbc7a 100644 --- a/PrimaryFormParts/HotSong/PrimaryForm.HotSongMandarinNew.cs +++ b/PrimaryFormParts/HotSong/PrimaryForm.HotSongMandarinNew.cs @@ -7,8 +7,7 @@ namespace DualScreenDemo // 重置其他按钮背景 UpdateHotSongButtons(guoYuNewSongButtonHotSong, guoYuNewSongHotSongActiveBackground); - int songLimit = ReadHotSongLimit(); - string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY `add_date` DESC, `song_counts` DESC LIMIT {songLimit};"; + string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY `add_date` DESC, `song_counts` DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};"; var selectedSongs = PrimaryForm.Instance.SearchSongs_Mysql(query); currentPage = 0; diff --git a/PrimaryFormParts/HotSong/PrimaryForm.HotSongTaiwaneseNew.cs b/PrimaryFormParts/HotSong/PrimaryForm.HotSongTaiwaneseNew.cs index 3cb2601..f138d02 100644 --- a/PrimaryFormParts/HotSong/PrimaryForm.HotSongTaiwaneseNew.cs +++ b/PrimaryFormParts/HotSong/PrimaryForm.HotSongTaiwaneseNew.cs @@ -7,9 +7,7 @@ namespace DualScreenDemo // 重置其他按钮背景 UpdateHotSongButtons(taiYuNewSongButtonHotSong, taiYuNewSongHotSongActiveBackground); - int songLimit = ReadHotSongLimit(); - - string query = $"SELECT * FROM song_library_cache WHERE language_name = '台語' ORDER BY `add_date` DESC, `song_counts` DESC LIMIT {songLimit};"; + string query = $"SELECT * FROM song_library_cache WHERE language_name = '台語' ORDER BY `add_date` DESC, `song_counts` DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};"; var selectedSongs = SearchSongs_Mysql(query); currentPage = 0; diff --git a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlert.cs b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlert.cs index b6ef384..910e9ee 100644 --- a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlert.cs +++ b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlert.cs @@ -221,40 +221,8 @@ namespace DualScreenDemo this.Controls.Add(hanYuButtonNewSong); } - public static int ReadNewSongLimit() - { - string filePath = Path.Combine(Application.StartupPath, "txt", "SongLimitsSettings.txt"); - try - { - - var lines = File.ReadAllLines(filePath); - foreach (var line in lines) - { - - if (line.StartsWith("NewSongLimit:")) - { - string valuePart = line.Split(':')[1].Trim(); - int limit; - if (int.TryParse(valuePart, out limit)) - { - return limit; - } - break; - } - } - } - catch (Exception ex) - { - Console.WriteLine("Failed to read song limits from file: " + ex.Message); - return 100; - } - - return 100; - } private string setQueryforNewSong(string category){ - string query = $"SELECT * FROM song_library_cache WHERE language_name = '{category}' ORDER BY add_date DESC LIMIT {ReadNewSongLimit()};"; - - return query; + return $"SELECT * FROM song_library_cache WHERE language_name = '{category}' ORDER BY add_date DESC LIMIT {Utils.Env.GetInt("NewSongLimit", 100)};"; } } } \ No newline at end of file diff --git a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertCantonese.cs b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertCantonese.cs index af31407..fdb89b1 100644 --- a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertCantonese.cs +++ b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertCantonese.cs @@ -11,21 +11,13 @@ namespace DualScreenDemo riYuButtonNewSong.BackgroundImage = riYuNewSongNormalBackground; hanYuButtonNewSong.BackgroundImage = hanYuNewSongNormalBackground; - int songLimit = ReadNewSongLimit(); - - /*yueYuSongs2 = allSongs.Where(song => song.Category == "粵語") - .OrderByDescending(song => song.AddedTime) - .Take(songLimit) - .ToList();*/ - string query = setQueryforNewSong("粵語"); - var yueYuSongs2 = SearchSongs_Mysql(query); + var yueYuSongs2 = SearchSongs_Mysql(setQueryforNewSong("粵語")); currentPage = 0; - currentSongList = yueYuSongs2; totalPages = (int)Math.Ceiling((double)yueYuSongs2.Count / itemsPerPage); multiPagePanel.currentPageIndex = 0; - multiPagePanel.LoadSongs(currentSongList); + multiPagePanel.LoadSongs(yueYuSongs2); } } } \ No newline at end of file diff --git a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertChinese.cs b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertChinese.cs index 1c6b556..0a09c82 100644 --- a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertChinese.cs +++ b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertChinese.cs @@ -11,21 +11,13 @@ namespace DualScreenDemo riYuButtonNewSong.BackgroundImage = riYuNewSongNormalBackground; hanYuButtonNewSong.BackgroundImage = hanYuNewSongNormalBackground; - int songLimit = ReadNewSongLimit(); - - /*guoYuSongs2 = allSongs.Where(song => song.Category == "國語") - .OrderByDescending(song => song.AddedTime) - .Take(songLimit) - .ToList();*/ - string query = setQueryforNewSong("國語"); - var guoYuSongs2 = SearchSongs_Mysql(query); + var guoYuSongs2 = SearchSongs_Mysql(setQueryforNewSong("國語")); currentPage = 0; - currentSongList = guoYuSongs2; totalPages = (int)Math.Ceiling((double)guoYuSongs2.Count / itemsPerPage); multiPagePanel.currentPageIndex = 0; - multiPagePanel.LoadSongs(currentSongList); + multiPagePanel.LoadSongs(guoYuSongs2); } } } \ No newline at end of file diff --git a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertEnglish.cs b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertEnglish.cs index 7126385..187e33b 100644 --- a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertEnglish.cs +++ b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertEnglish.cs @@ -11,22 +11,14 @@ namespace DualScreenDemo riYuButtonNewSong.BackgroundImage = riYuNewSongNormalBackground; hanYuButtonNewSong.BackgroundImage = hanYuNewSongNormalBackground; - int songLimit = ReadNewSongLimit(); - - /*yingWenSongs2 = allSongs.Where(song => song.Category == "英語") - .OrderByDescending(song => song.AddedTime) - .Take(songLimit) - .ToList();*/ - string query = setQueryforNewSong("英語"); - var yingWenSongs2 = SearchSongs_Mysql(query); + var yingWenSongs2 = SearchSongs_Mysql(setQueryforNewSong("英語")); currentPage = 0; - currentSongList = yingWenSongs2; totalPages = (int)Math.Ceiling((double)yingWenSongs2.Count / itemsPerPage); multiPagePanel.currentPageIndex = 0; - multiPagePanel.LoadSongs(currentSongList); + multiPagePanel.LoadSongs(yingWenSongs2); } } } \ No newline at end of file diff --git a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertJapanese.cs b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertJapanese.cs index 9c8ba3d..edc7e5b 100644 --- a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertJapanese.cs +++ b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertJapanese.cs @@ -11,21 +11,13 @@ namespace DualScreenDemo riYuButtonNewSong.BackgroundImage = riYuNewSongActiveBackground; hanYuButtonNewSong.BackgroundImage = hanYuNewSongNormalBackground; - int songLimit = ReadNewSongLimit(); - - /*riYuSongs2 = allSongs.Where(song => song.Category == "日語") - .OrderByDescending(song => song.AddedTime) - .Take(songLimit) - .ToList();*/ - string query = setQueryforNewSong("日語"); - var riYuSongs2 = SearchSongs_Mysql(query); + var riYuSongs2 = SearchSongs_Mysql(setQueryforNewSong("日語")); currentPage = 0; - currentSongList = riYuSongs2; totalPages = (int)Math.Ceiling((double)riYuSongs2.Count / itemsPerPage); multiPagePanel.currentPageIndex = 0; - multiPagePanel.LoadSongs(currentSongList); + multiPagePanel.LoadSongs(riYuSongs2); } } } \ No newline at end of file diff --git a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertTaiwanese.cs b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertTaiwanese.cs index 0785c2b..b9259c1 100644 --- a/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertTaiwanese.cs +++ b/PrimaryFormParts/NewSongAlert/PrimaryForm.NewSongAlertTaiwanese.cs @@ -11,21 +11,13 @@ namespace DualScreenDemo riYuButtonNewSong.BackgroundImage = riYuNewSongNormalBackground; hanYuButtonNewSong.BackgroundImage = hanYuNewSongNormalBackground; - int songLimit = ReadNewSongLimit(); - - /*taiYuSongs2 = allSongs.Where(song => song.Category == "台語") - .OrderByDescending(song => song.AddedTime) - .Take(songLimit) - .ToList();*/ - string query = setQueryforNewSong("台語"); - var taiYuSongs2 = SearchSongs_Mysql(query); + var taiYuSongs2 = SearchSongs_Mysql(setQueryforNewSong("台語")); currentPage = 0; - currentSongList = taiYuSongs2; totalPages = (int)Math.Ceiling((double)taiYuSongs2.Count / itemsPerPage); multiPagePanel.currentPageIndex = 0; - multiPagePanel.LoadSongs(currentSongList); + multiPagePanel.LoadSongs(taiYuSongs2); } } } \ No newline at end of file diff --git a/PrimaryFormParts/PrimaryForm.Promotions.cs b/PrimaryFormParts/PrimaryForm.Promotions.cs index 1ae60c4..5896bb6 100644 --- a/PrimaryFormParts/PrimaryForm.Promotions.cs +++ b/PrimaryFormParts/PrimaryForm.Promotions.cs @@ -74,28 +74,6 @@ namespace DualScreenDemo } } - private List LoadPromotionsImages() - { - List images = new List(); - string newsFolderPath = Path.Combine(Application.StartupPath, "news"); - - string[] imageFiles = Directory.GetFiles(newsFolderPath, "*.jpg"); - - foreach (string filePath in imageFiles) - { - try - { - images.Add(Image.FromFile(filePath)); - } - catch (Exception ex) - { - Console.WriteLine("Error loading image: " + filePath + ". Exception: " + ex.Message); - } - } - - return images; - } - private void promotionsButton_Click(object sender, EventArgs e) { promotionsAndMenuPanel.currentPageIndex=0; @@ -137,27 +115,16 @@ namespace DualScreenDemo private void PreviousPromotionButton_Click(object sender, EventArgs e) { - - - - - promotionsAndMenuPanel.LoadPreviousPage(); } private void NextPromotionButton_Click(object sender, EventArgs e) { - - - - - promotionsAndMenuPanel.LoadNextPage(); } private void ClosePromotionsButton_Click(object sender, EventArgs e) { - promotionsAndMenuPanel.Visible = false; previousPromotionButton.Visible = false; nextPromotionButton.Visible = false; diff --git a/PrimaryFormParts/PrimaryForm.PromotionsAndMenuPanel.cs b/PrimaryFormParts/PrimaryForm.PromotionsAndMenuPanel.cs index 3316c48..2fcc501 100644 --- a/PrimaryFormParts/PrimaryForm.PromotionsAndMenuPanel.cs +++ b/PrimaryFormParts/PrimaryForm.PromotionsAndMenuPanel.cs @@ -1,4 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Drawing; using System.IO; + namespace DualScreenDemo { public partial class PrimaryForm @@ -11,32 +15,50 @@ namespace DualScreenDemo ResizeAndPositionControl(promotionsAndMenuPanel, 0, 0, 1440, 900); this.Controls.Add(promotionsAndMenuPanel); - promotions = LoadPromotionsImages(); - menu = LoadMenuImages(); - - + promotions = LoadImagesFromFolder("news"); + menu = LoadImagesFromFolder("foods"); } - - private List LoadMenuImages() - { - List images = new List(); - string foodsFolderPath = Path.Combine(Application.StartupPath, "foods"); - string[] imageFiles = Directory.GetFiles(foodsFolderPath, "*.jpg"); + /// + /// 從指定資料夾載入所有 .jpg 圖片 + /// + private List LoadImagesFromFolder(string folderName) + { + List images = new(); + string folderPath = Path.Combine(Utils.Env.KtvPath, folderName); + + if (!Directory.Exists(folderPath)) + { + Console.WriteLine($" 找不到遠端資料夾:{folderPath}"); + return images; + } + + string[] imageFiles = Directory.GetFiles(folderPath, "*.jpg"); foreach (string filePath in imageFiles) { try { - images.Add(Image.FromFile(filePath)); + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); + images.Add(Image.FromStream(new MemoryStream(ReadFully(fs)))); } catch (Exception ex) { - Console.WriteLine("Error loading image: " + filePath + ". Exception: " + ex.Message); + Console.WriteLine($"載入圖片失敗:{filePath},原因:{ex.Message}"); } } return images; } + + /// + /// 將 Stream 轉為 byte[],用於避免 Image 檔案鎖定 + /// + private byte[] ReadFully(Stream input) + { + using MemoryStream ms = new(); + input.CopyTo(ms); + return ms.ToArray(); + } } -} \ No newline at end of file +} diff --git a/PrimaryFormParts/PrimaryForm.SQLSearch.cs b/PrimaryFormParts/PrimaryForm.SQLSearch.cs index 1fc8f1c..b70044d 100644 --- a/PrimaryFormParts/PrimaryForm.SQLSearch.cs +++ b/PrimaryFormParts/PrimaryForm.SQLSearch.cs @@ -6,40 +6,9 @@ using System.Diagnostics; namespace DualScreenDemo{ public partial class PrimaryForm { - private static string connectionStringfortest = ""; - public static void LoadConnectionStringFromFile(string filePath) - { - filePath = Path.Combine(Application.StartupPath, "txt", filePath); - try - { - if (File.Exists(filePath)) - { - string fileContent = File.ReadAllText(filePath).Trim(); - - if (!string.IsNullOrWhiteSpace(fileContent)) - { - connectionStringfortest = fileContent; - Console.WriteLine("連線字串載入成功。"); - } - else - { - Console.WriteLine("檔案內容為空。"); - } - } - else - { - Console.WriteLine("找不到指定的檔案:" + filePath); - } - } - catch (Exception ex) - { - Console.WriteLine("讀取檔案時發生錯誤:" + ex.Message); - } - } - private static string GetConnectionString() { - return connectionStringfortest; + return $"Server={Utils.Env.Get("DBServer", "localhost")};Port={Utils.Env.Get("DBPort", "3306")};Database={Utils.Env.Get("Database", "test")};User={Utils.Env.Get("DBUser", "root")};Password={Utils.Env.Get("DBPassword", "")};"; } public bool isLoggedIn = false; @@ -55,7 +24,7 @@ namespace DualScreenDemo{ Stopwatch stopwatch = new Stopwatch(); connection.Open(); - + stopwatch.Start(); Console.WriteLine("MyDB 連線成功!"); @@ -72,15 +41,15 @@ namespace DualScreenDemo{ string artistA = reader["artistA"].ToString(); string artistB = reader["artistB"].ToString(); string fileName = reader["song_filename"].ToString(); - string songFilePathHost1 = Path.Combine(@"\\SVR01\", fileName); - string songFilePathHost2 = Path.Combine(@"\\SVR02\", fileName); - string artistASimplified = reader["artistA_simplified"].ToString(); + string songFilePathHost1 = Path.Combine(@"\\SVR01\e\", fileName); + string songFilePathHost2 = Path.Combine(@"\\SVR02\e\", fileName); + string artistASimplified = reader["artistA_simplified"].ToString(); string artistBSimplified = reader["artistB_simplified"].ToString(); string songSimplified = reader["song_simplified"].ToString(); int humanVoice = Convert.ToInt32(reader["vocal"]); searchResults.Add(new SongData( - songNumber, song, artistA, artistB,fileName, + songNumber, song, artistA, artistB, fileName, songFilePathHost1, songFilePathHost2, artistASimplified, artistBSimplified, songSimplified, humanVoice @@ -118,8 +87,8 @@ namespace DualScreenDemo{ while (reader.Read()) { string artist = reader["name"].ToString(); - string artistSimplified = reader ["simplified"].ToString(); - searchResults.Add(new Artist(artist,artistSimplified)); + string artistSimplified = reader["simplified"].ToString(); + searchResults.Add(new Artist(artist, artistSimplified)); } } } @@ -140,7 +109,7 @@ namespace DualScreenDemo{ string connectionString = GetConnectionString(); using (var connection = new MySqlConnection(connectionString)) { - + connection.Open(); Console.WriteLine("MyDB 連線成功!"); @@ -168,7 +137,7 @@ namespace DualScreenDemo{ string connectionString = GetConnectionString(); using (var connection = new MySqlConnection(connectionString)) { - + connection.Open(); Console.WriteLine("MyDB 連線成功!"); @@ -254,7 +223,7 @@ namespace DualScreenDemo{ string connectionString = GetConnectionString(); using (var connection = new MySqlConnection(connectionString)) { - + connection.Open(); Console.WriteLine("MyDB 連線成功!"); diff --git a/PrimaryFormParts/PrimaryForm.SoundEffects.cs b/PrimaryFormParts/PrimaryForm.SoundEffects.cs index e38ba0e..db942c9 100644 --- a/PrimaryFormParts/PrimaryForm.SoundEffects.cs +++ b/PrimaryFormParts/PrimaryForm.SoundEffects.cs @@ -28,14 +28,32 @@ namespace DualScreenDemo private void ConfigureImageButton(Button button, int posX, int posY, int width, int height, string imagePath, EventHandler clickEventHandler) { - Bitmap image = new Bitmap(imagePath); - button.SetBounds(posX, posY, image.Width, image.Height); + // 你的基準解析度(設計時以這個為標準) + const float baseWidth = 1920f; + const float baseHeight = 1080f; + + // 實際螢幕解析度 + float actualWidth = Screen.PrimaryScreen.Bounds.Width; + float actualHeight = Screen.PrimaryScreen.Bounds.Height; + + // 計算縮放比例 + float scaleX = actualWidth / baseWidth; + float scaleY = actualHeight / baseHeight; + + // 套用縮放比例到位置與大小 + int scaledX = (int)(posX * scaleX); + int scaledY = (int)(posY * scaleY); + int scaledWidth = (int)(width * scaleX); + int scaledHeight = (int)(height * scaleY); + + // 載入圖片並調整按鈕尺寸 + Bitmap image = new Bitmap(imagePath); + button.SetBounds(scaledX, scaledY, scaledWidth, scaledHeight); - // 載入圖片 button.BackgroundImage = image; button.BackgroundImageLayout = ImageLayout.Stretch; - // 按鈕樣式設定 + // 按鈕樣式 button.FlatStyle = FlatStyle.Flat; button.FlatAppearance.BorderSize = 0; button.FlatAppearance.MouseDownBackColor = Color.Transparent; @@ -165,20 +183,28 @@ namespace DualScreenDemo if (File.Exists(imagePath)) { - // 直接載入完整圖 - Bitmap image = new Bitmap(imagePath); + try + { + // 使用 Image.FromFile 載入後 clone,避免檔案 lock & GDI 錯誤 + using (Image original = Image.FromFile(imagePath)) + { + Bitmap image = new Bitmap(original); + pictureBoxSceneSoundEffects.Image = image; + } - // 顯示在 PictureBox 上 - pictureBoxSceneSoundEffects.Image = image; + ResizeAndPositionPictureBox(pictureBoxSceneSoundEffects, 850, 450, + pictureBoxSceneSoundEffects.Image.Width, pictureBoxSceneSoundEffects.Image.Height); - // 設定 PictureBox 的大小與位置(依你的需要調整) - ResizeAndPositionPictureBox(pictureBoxSceneSoundEffects, 850, 450, image.Width , image.Height); - - pictureBoxSceneSoundEffects.Visible = true; + pictureBoxSceneSoundEffects.Visible = true; + } + catch (Exception ex) + { + Console.WriteLine("圖片載入失敗:" + ex.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } else { - Console.WriteLine("圖片檔案不存在:" + imagePath); + Console.WriteLine("圖片檔案不存在:" + imagePath, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } diff --git a/PrimaryFormParts/PrimaryForm.cs b/PrimaryFormParts/PrimaryForm.cs index 4e0a6e2..78ce004 100644 --- a/PrimaryFormParts/PrimaryForm.cs +++ b/PrimaryFormParts/PrimaryForm.cs @@ -239,7 +239,6 @@ namespace DualScreenDemo multiPagePanel.PageIndexChanged += HandlePageChanged; // 添加 Load 事件處理 this.Load += PrimaryForm_Load; - LoadConnectionStringFromFile("test.env"); } public bool IsAppResponsive() @@ -504,7 +503,7 @@ namespace DualScreenDemo string selectedTheme = ReadSelectedThemePath(); if (!string.IsNullOrEmpty(selectedTheme)) { - string backgroundImagePath = Path.Combine(Application.StartupPath, "themes\\superstar\\555009.jpg"); + string backgroundImagePath = Path.Combine(Utils.Env.KtvPath, "themes","superstar","555009.jpg"); try { using (Image originalImage = Image.FromFile(backgroundImagePath)) @@ -1554,23 +1553,10 @@ namespace DualScreenDemo try { // 1. 檢查是否能連接到 SVR01 - string serverVideoPath = @"\\SVR01\video"; - string serverVideoPath2 = @"\\SVR02\video"; - string selectedServerPath = null; - + string serverVideoPath = Path.Combine(Utils.Env.KtvPath, "video"); string localVideoPath = @"D:\video"; - if (Directory.Exists(serverVideoPath)) - { - selectedServerPath = serverVideoPath; - Console.WriteLine("已連接到 SVR01"); - } - else if (Directory.Exists(serverVideoPath2)) - { - selectedServerPath = serverVideoPath2; - Console.WriteLine("已連接到 SVR02"); - } - else + if (!Directory.Exists(serverVideoPath)) { Console.WriteLine("未連接到 SVR,使用本地影片"); LoadLocalVideoFiles(); @@ -1584,7 +1570,7 @@ namespace DualScreenDemo } // 獲取服務器和本地的所有文件 - var serverFiles = Directory.GetFiles(selectedServerPath, "*.mpg") + var serverFiles = Directory.GetFiles(serverVideoPath, "*.mpg") .Select(f => new FileInfo(f)) .ToDictionary(f => f.Name, f => f); @@ -2351,13 +2337,14 @@ namespace DualScreenDemo SendCommandThroughSerialPort("a2 53 a4"); // 显示提示信息 - OverlayForm.MainForm.ShowServiceBellLabel(); + OverlayForm.MainForm.HideAllLabels(); + OverlayForm.MainForm.ShowServiceBell(); // 延迟3秒 await Task.Delay(3000); // 隐藏提示信息 - OverlayForm.MainForm.HideServiceBellLabel(); + //OverlayForm.MainForm.HideServiceBellLabel(); isWaiting = false; } @@ -2565,46 +2552,14 @@ namespace DualScreenDemo { HotPlayButton_Click(null, EventArgs.Empty); } - try - { - string stateFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "txt", "states.txt"); - string initialState = ReadStateFile(stateFilePath); - - if (initialState.Equals("CLOSE", StringComparison.OrdinalIgnoreCase)) - { - /* - foreach (Control ctrl in this.Controls) - { - ctrl.Enabled = false; - } - */ - ShowSendOffScreen(); - } - } - catch (Exception ex) - { - Console.WriteLine($"[PrimaryForm_Load] 初始化狀態錯誤: {ex.Message}"); - } + if (Program.RoomState.Equals("CLOSE")) + { + ShowSendOffScreen(); + } // 確保所有控件都已初始化完成後,再觸發熱門排行按鈕點擊 } - private string ReadStateFile(string filePath) - { - try - { - if (File.Exists(filePath)) - { - return File.ReadAllText(filePath).Trim(); - } - } - catch (Exception ex) - { - Console.WriteLine("讀取 states.txt 時發生錯誤: " + ex.Message); - } - return ""; - } - private void AutoRefreshTimer_Tick(object sender, EventArgs e) { if (isOnOrderedSongsPage) diff --git a/Program.cs b/Program.cs index 425a2e1..413594a 100644 --- a/Program.cs +++ b/Program.cs @@ -2,8 +2,7 @@ using System.IO; using Microsoft.Win32; using System.Diagnostics; using DBObj; -using DataCheck; - +using HeartbeatSender; namespace DualScreenDemo { public static class Program @@ -13,59 +12,30 @@ namespace DualScreenDemo //internal static ArtistManager artistManager; internal static SerialPortManager serialPortManager; private static PrimaryForm primaryForm; // 儲存實例的參考 + public static string RoomState = Utils.Env.Get("RoomStates", "CLOSE"); [STAThread] static void Main() { - - - Console.WriteLine("隱藏滑鼠游標"); - Cursor.Hide(); + Console.WriteLine("Server V.1.1.0 20250701"); + if(Utils.Env.GetBool("IsCursor", true))Cursor.Hide(); AppDomain.CurrentDomain.ProcessExit += (s, e) => { Cursor.Show(); }; - Console.WriteLine("正在喚醒SVR裝置(每3分鐘呼叫一次)..."); - _ = Task.Run(async () => - { - while (true) - { - _ = Directory.Exists(@"\\svr01\video"); - _ = Directory.Exists(@"\\svr02\video"); - await Task.Delay(180000); // 每3min送一次 - } - }); - + //Console.WriteLine("正在喚醒SVR裝置(每3分鐘呼叫一次)..."); + //_ = Task.Run(async () => + // { + // while (true) + // { + // _ = Directory.Exists(@"\\svr01\e\video"); + // _ = Directory.Exists(@"\\svr02\e\video"); + // await Task.Delay(180000); // 每3min送一次 + // } + // }); + // Console.WriteLine("正在與中控取得聯繫..."); - var sender = new HeartbeatSender.heartbeatSender(); - - // 同步呼叫非同步登入取得 token - bool loginSuccess = sender.LoginAndGetTokenAsync().GetAwaiter().GetResult(); - - if (loginSuccess) - { - // 先送一次心跳 (同步呼叫) - sender.SendHeartbeatAsync().GetAwaiter().GetResult(); - - // 背景持續每5分鐘送心跳 - _ = Task.Run(async () => - { - while (true) - { - await sender.SendHeartbeatAsync(); - await Task.Delay(300000); // 每5min送一次 - } - }); - Console.WriteLine("正在發送心跳中..."); - } - else - { - Console.WriteLine("登入失敗,無法送出心跳"); - } - //之後需要做添加同步菜單+酒單+背景圖(若圖規格有做正規化) - // DataCheck.cs 有預寫好相關流程函式 - Console.WriteLine("更新菜單和酒單..."); - dataCheck Checkprocess = new dataCheck(); + var sender = new heartbeatSender(); try { @@ -102,27 +72,13 @@ namespace DualScreenDemo // 創建主窗體 primaryForm = new PrimaryForm(); - //primaryForm.allSongs = songListManager.AllSongs; - //primaryForm.allArtists = artistManager.AllArtists; primaryForm.StartPosition = FormStartPosition.Manual; primaryForm.Location = new Point(0, 0); primaryForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // 在完整初始化後檢查狀態 - string stateFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "txt", "states.txt"); - bool isClosedState = File.Exists(stateFilePath) && - File.ReadAllText(stateFilePath).Trim().Equals("CLOSE", StringComparison.OrdinalIgnoreCase); - InitializeSecondaryScreen(); - - // 使用 Shown 事件來確保窗體完全加載後再顯示送客畫面 - if (isClosedState) - { - primaryForm.Shown += (s, e) => - { - primaryForm.ShowSendOffScreen(); - }; - } + WatchDog _watchDog = new WatchDog( () => VideoPlayerForm.Instance.GetCurrentVideoStatus(), () => primaryForm.IsAppResponsive() @@ -133,7 +89,6 @@ namespace DualScreenDemo { _watchDog.Stop(); }; - primaryForm.Show(); Application.Run(primaryForm); @@ -148,7 +103,7 @@ namespace DualScreenDemo { SystemEvents.DisplaySettingsChanged -= OnDisplaySettingsChanged; } -} + } private static bool IsUrlAclExists(string url) diff --git a/TCPServer.cs b/TCPServer.cs index 0379029..86c78ce 100644 --- a/TCPServer.cs +++ b/TCPServer.cs @@ -89,28 +89,6 @@ namespace DualScreenDemo try { - string stateFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "txt", "states.txt"); - string initialState = ReadStateFile(stateFilePath); - /* - if (initialState.Equals("CLOSE", StringComparison.OrdinalIgnoreCase)) - { - _ = SafeInvoke(PrimaryForm.Instance, () => - { - try { - foreach (Control ctrl in PrimaryForm.Instance.Controls) - { - ctrl.Enabled = false; - } - PrimaryForm.Instance.ShowSendOffScreen(); - } - catch (Exception ex) { - Console.WriteLine($"顯示送客畫面時發生錯誤: {ex.Message}"); - } - }); - } */ - - - while (true) { Console.WriteLine("Waiting for connections..."); @@ -201,7 +179,7 @@ namespace DualScreenDemo } }); - UpdateStateFile(stateFilePath, "CLOSE"); + Program.RoomState = "CLOSE"; byte[] okResponse = Encoding.UTF8.GetBytes("OK\n"); stream.Write(okResponse, 0, okResponse.Length); @@ -217,7 +195,7 @@ namespace DualScreenDemo VideoPlayerForm.Instance.PlayPublicPlaylist(); PrimaryForm.currentSongIndexInHistory = -1; PrimaryForm.Instance.HotPlayButton_Click(null, EventArgs.Empty); - UpdateStateFile(stateFilePath, "OPEN"); + Program.RoomState = "OPEN"; PrimaryForm.Instance.HideSendOffScreen(); @@ -236,7 +214,7 @@ namespace DualScreenDemo }); // 更新狀態檔案(可選,若你要記錄狀態) - UpdateStateFile(stateFilePath, "PAUSE"); + Program.RoomState = "PAUSE"; byte[] okResponse = Encoding.UTF8.GetBytes("OK\n"); stream.Write(okResponse, 0, okResponse.Length); @@ -266,12 +244,18 @@ namespace DualScreenDemo OverlayForm.MainForm.UpdateMarqueeTextSecondLine(marqueeMessage); } }); + byte[] okResponse = Encoding.UTF8.GetBytes("OK\n"); + stream.Write(okResponse, 0, okResponse.Length); + continue; } + + /* if (request.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase)) { break; } + */ } Console.WriteLine("Connection closed."); @@ -312,40 +296,5 @@ namespace DualScreenDemo string hostName = Dns.GetHostName(); return hostName.Length > 3 ? hostName.Substring(hostName.Length - 3) : hostName; } - private string ReadStateFile(string filePath) - { - try - { - if (File.Exists(filePath)) - { - string state = File.ReadAllText(filePath).Trim(); - Console.WriteLine($"✅ State file read: {filePath} -> {state}"); - return state; - } - else - { - Console.WriteLine("⚠️ State file not found. Creating new file with default state: OPEN"); - UpdateStateFile(filePath, "OPEN"); - return "OPEN"; - } - } - catch (Exception ex) - { - Console.WriteLine($"❌ Failed to read state file: {ex.Message}"); - return "OPEN"; // 默認為 OPEN - } - } - private void UpdateStateFile(string filePath, string state) - { - try - { - File.WriteAllText(filePath, state); - Console.WriteLine($"✅ State file updated: {filePath} -> {state}"); - } - catch (Exception ex) - { - Console.WriteLine($"❌ Failed to update state file: {ex.Message}"); - } - } } } \ No newline at end of file diff --git a/VideoPlayerForm.cs b/VideoPlayerForm.cs index 9d3f713..0085ccf 100644 --- a/VideoPlayerForm.cs +++ b/VideoPlayerForm.cs @@ -1596,14 +1596,15 @@ namespace DualScreenDemo { streamSelect.Enable(audioTrack1, AMStreamSelectEnableFlags.Enable); isVocalRemoved = false; - } - //OverlayForm.MainForm.ShowOriginalSongLabel(); + } string labelText = isVocalRemoved ? "無人聲" : "有人聲"; // 显示标签 - OverlayForm.MainForm.ShowOriginalSongLabel(labelText); - await Task.Delay(3000); + // 修改成新標籤 + OverlayForm.MainForm.HideAllLabels(); + OverlayForm.MainForm.ShowOriginalLabel(labelText); + // await Task.Delay(3000); // 隐藏标签 - OverlayForm.MainForm.HideOriginalSongLabel(); + // OverlayForm.MainForm.HideOriginalSongLabel(); } } } diff --git a/superstar_1.0.0.csproj b/superstar_1.0.0.csproj index 91169b1..14ee5db 100644 --- a/superstar_1.0.0.csproj +++ b/superstar_1.0.0.csproj @@ -71,16 +71,6 @@ - - - PreserveNewest - - - - - PreserveNewest - - PreserveNewest @@ -90,11 +80,6 @@ PreserveNewest - - - PreserveNewest - - PreserveNewest