新增 設定檔

調整 心跳功能
修正 藏鏡人
修正 服務鈴
20250703
This commit is contained in:
jasonchenwork 2025-07-03 18:15:21 +08:00
parent b3261306eb
commit d041ff1f80
26 changed files with 413 additions and 723 deletions

View File

@ -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<string, DateTime> _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)
{

View File

@ -51,11 +51,11 @@ namespace DBObj
}
*/
public List<SongData> 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<SongData> 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<SongData> SearchSongsBySinger(string keyword)

View File

@ -1,140 +0,0 @@
using System.IO;
namespace DataCheck
{
public class dataCheck
{
public dataCheck()
{
menu_check();
news_check();
}
private void menu_check()
{
string menuPath = @"\\svr01\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 = @"\\svr01\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}");
}
}
}
}
}
}

61
Env.cs Normal file
View File

@ -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<string, string> _values;
static Env()
{
var path = Path.Combine(KtvPath, "config.ini");
_values = new Dictionary<string, string>(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 ... 視需要
}
}

View File

@ -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");
}
/// <summary>
/// 讀取URL
/// </summary>
/// <param name="filePath">路徑</param>
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<bool> 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<bool> LoginAndGetTokenAsync()
{
var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/receiveRegister";
var loginPayload = new
{
email = "MachineKTV@gmail.com",
password = "aa147258-"
};
var result = await SendPostAsync<JsonElement>(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<JsonElement>(url, heartbeatPayload, token);
Console.WriteLine($"心跳送出成功: {DateTime.Now:HH:mm:ss}");
}
private async Task<T?> SendPostAsync<T>(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<T>(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);
}
}

View File

@ -42,10 +42,7 @@ namespace DualScreenDemo
// 安裝包更新
string localAddress = GetLocalIPAddress();
string externalAddress = File.Exists(@"\\svr01\txt\ip.txt")
? File.ReadAllText(@"\\svr01\txt\ip.txt").Trim()
: "";
string externalAddress = Utils.Env.Get("PhoneIP", "").Trim();
_listener = new HttpListener();
_listener.Prefixes.Add($"http://{localAddress}:{port}/");
string hostName = System.Net.Dns.GetHostName();
@ -538,7 +535,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 +980,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);

View File

@ -56,10 +56,45 @@ namespace OverlayFormObj
this.Invalidate();
blackBackgroundPanel.Invalidate();
// StartMarquee();
}
private System.Windows.Forms.Timer marqueeTimer_detection;
private int scrollSpeed = 2; // 每次移動的像素
public void StartMarquee()
{
if (marqueeTimer_detection != null)
{
marqueeTimer_detection.Stop();
marqueeTimer_detection.Dispose();
}
marqueeTimer_detection = new System.Windows.Forms.Timer();
marqueeTimer_detection.Interval = 30; // 約每 30ms 更新一次
marqueeTimer_detection.Tick += (s, e) =>
{
marqueeXPos -= scrollSpeed;
int textWidth = TextRenderer.MeasureText(marqueeText, new Font("Arial", 25, FontStyle.Bold)).Width;
if (marqueeXPos + textWidth < 0) // 跑出畫面左側
{
marqueeTimer_detection.Stop();
marqueeTimer_detection.Dispose();
marqueeTimer_detection = null;
Console.WriteLine("Marquee 跑完了!");
}
this.Invalidate();
blackBackgroundPanel.Invalidate();
};
marqueeTimer_detection.Start();
}
public void UpdateMarqueeTextSecondLine(string newText)
{
Console.WriteLine(InvokeRequired);
if (InvokeRequired)
{
Invoke(new MethodInvoker(() => UpdateMarqueeTextSecondLine(newText)));

View File

@ -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,24 +856,19 @@ 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();
}
*/
}
// 显示标准标签
@ -1029,6 +1072,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()
{

View File

@ -613,7 +613,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
using (Font largeFont = new Font("微軟正黑體", 34, FontStyle.Bold))
using (Brush whiteBrush = new SolidBrush(Color.White))
using (Brush limeGreenBrush = new SolidBrush(Color.LimeGreen))
using (Brush LimeGreen = new SolidBrush(Color.LimeGreen))
using (Brush marqueeBrush = new SolidBrush(marqueeTextColor))
using (Brush backgroundBrush = new SolidBrush(Color.FromArgb(255, 0, 0, 0)))
{
@ -631,9 +631,9 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
SizeF textSizeSecondLine = e.Graphics.MeasureString(marqueeTextSecondLine, largeFont);
float centeredXPos = (this.Width - textSizeSecondLine.Width) / 2;
e.Graphics.FillRectangle(backgroundBrush, centeredXPos, yPosition2, textSizeSecondLine.Width, textSizeSecondLine.Height);
e.Graphics.DrawString(marqueeTextSecondLine, largeFont, limeGreenBrush, new PointF(centeredXPos, yPosition2));
e.Graphics.DrawString(marqueeTextSecondLine, largeFont, LimeGreen, new PointF(centeredXPos, yPosition2));
e.Graphics.Clip = originalClip;
@ -1495,11 +1495,11 @@ private void DisplayArtists(List<Artist> 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
{

View File

@ -62,8 +62,7 @@ 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);
@ -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);
@ -235,35 +233,5 @@ namespace DualScreenDemo
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;
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -221,38 +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()};";
string query = $"SELECT * FROM song_library_cache WHERE language_name = '{category}' ORDER BY add_date DESC LIMIT {Utils.Env.GetInt("NewSongLimit", 100)};";
return query;
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -11,21 +11,13 @@ namespace DualScreenDemo
riYuButtonNewSong.BackgroundImage = riYuNewSongNormalBackground;
hanYuButtonNewSong.BackgroundImage = hanYuNewSongActiveBackground;
int songLimit = ReadNewSongLimit();
/*hanYuSongs2 = allSongs.Where(song => song.Category == "韓語")
.OrderByDescending(song => song.AddedTime)
.Take(songLimit)
.ToList();*/
string query = setQueryforNewSong("韓語");
var hanYuSongs2 = SearchSongs_Mysql(query);
var hanYuSongs2 = SearchSongs_Mysql(setQueryforNewSong("韓語"));
currentPage = 0;
currentSongList = hanYuSongs2;
totalPages = (int)Math.Ceiling((double)hanYuSongs2.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(hanYuSongs2);
}
}
}

View File

@ -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);
}
}
}

View File

@ -74,27 +74,7 @@ namespace DualScreenDemo
}
}
private List<Image> LoadPromotionsImages()
{
List<Image> images = new List<Image>();
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)
{
@ -137,21 +117,11 @@ namespace DualScreenDemo
private void PreviousPromotionButton_Click(object sender, EventArgs e)
{
promotionsAndMenuPanel.LoadPreviousPage();
}
private void NextPromotionButton_Click(object sender, EventArgs e)
{
promotionsAndMenuPanel.LoadNextPage();
}

View File

@ -11,32 +11,52 @@ namespace DualScreenDemo
ResizeAndPositionControl(promotionsAndMenuPanel, 0, 0, 1440, 900);
this.Controls.Add(promotionsAndMenuPanel);
promotions = LoadPromotionsImages();
menu = LoadMenuImages();
promotions = LoadImagesFromFolder("news");
menu = LoadImagesFromFolder("foods");
}
private List<Image> LoadMenuImages()
{
List<Image> images = new List<Image>();
string foodsFolderPath = Path.Combine(Application.StartupPath, "foods");
string[] imageFiles = Directory.GetFiles(foodsFolderPath, "*.jpg");
/// <summary>
/// 從指定資料夾載入所有 .jpg 圖片
/// </summary>
private List<Image> LoadImagesFromFolder(string folderName)
{
List<Image> 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;
}
/// <summary>
/// 將 Stream 轉為 byte[],用於避免 Image 檔案鎖定
/// </summary>
private byte[] ReadFully(Stream input)
{
using MemoryStream ms = new();
input.CopyTo(ms);
return ms.ToArray();
}
}
}

View File

@ -6,40 +6,10 @@ 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;
@ -72,8 +42,8 @@ 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 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();

View File

@ -239,7 +239,6 @@ namespace DualScreenDemo
multiPagePanel.PageIndexChanged += HandlePageChanged;
// 添加 Load 事件處理
this.Load += PrimaryForm_Load;
LoadConnectionStringFromFile("test.env");
}
public bool IsAppResponsive()
@ -1554,23 +1553,11 @@ 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 +1571,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 +2338,13 @@ 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)

View File

@ -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,60 +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.2.0 20250703");
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\video");
// _ = Directory.Exists(@"\\svr02\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();
//Console.WriteLine("正在與中控取得聯繫...");
var sender = new heartbeatSender();
try
{
@ -110,20 +79,8 @@ namespace DualScreenDemo
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()
@ -149,7 +106,7 @@ namespace DualScreenDemo
{
SystemEvents.DisplaySettingsChanged -= OnDisplaySettingsChanged;
}
}
}
private static bool IsUrlAclExists(string url)

View File

@ -88,29 +88,7 @@ namespace DualScreenDemo
// Console.WriteLine($"heart beat for server{sender.RemoteEndPoint.Address}:{sender.RemoteEndPoint.Port}");
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...");
@ -202,7 +180,7 @@ namespace DualScreenDemo
}
});
UpdateStateFile(stateFilePath, "CLOSE");
Program.RoomState = "CLOSE";
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);
@ -218,7 +196,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();
OverlayForm.Instance.ResetMarqueeTextToWelcomeMessage();
@ -238,7 +216,7 @@ namespace DualScreenDemo
});
// 更新狀態檔案(可選,若你要記錄狀態)
UpdateStateFile(stateFilePath, "PAUSE");
Program.RoomState = "PAUSE";
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);
@ -271,10 +249,12 @@ namespace DualScreenDemo
stream.Write(okResponse, 0, okResponse.Length);
}
/*
if (request.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
*/
}
Console.WriteLine("Connection closed.");
@ -315,40 +295,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}");
}
}
}
}

View File

@ -812,9 +812,9 @@ namespace DualScreenDemo
// 嘗試重新初始化並重播
try
{
await Task.Delay(1000);
await Task.Delay(100);
StopAndReleaseResources();
await Task.Delay(1000);
await Task.Delay(100);
// 重新初始化 COM
int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED);
@ -1599,10 +1599,12 @@ namespace DualScreenDemo
//OverlayForm.MainForm.ShowOriginalSongLabel();
string labelText = isVocalRemoved ? "無人聲" : "有人聲";
// 显示标签
// 修改成新標籤
OverlayForm.MainForm.HideAllLabels();
OverlayForm.MainForm.ShowOriginalSongLabel(labelText);
await Task.Delay(3000);
//await Task.Delay(3000);
// 隐藏标签
OverlayForm.MainForm.HideOriginalSongLabel();
//OverlayForm.MainForm.HideOriginalSongLabel();
}
}
}