Compare commits
2 Commits
107639f4c9
...
3f272cbdf4
Author | SHA1 | Date | |
---|---|---|---|
3f272cbdf4 | |||
8046eb5a35 |
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
140
DataCheck.cs
140
DataCheck.cs
@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
61
Env.cs
Normal file
61
Env.cs
Normal 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 ... 視需要
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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<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
|
||||
{
|
||||
|
@ -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);
|
||||
@ -215,7 +213,8 @@ namespace DualScreenDemo
|
||||
Image activeBackground, out Bitmap activeBackgroundOut,
|
||||
EventHandler clickEventHandler)
|
||||
{
|
||||
button = new Button {
|
||||
button = new Button
|
||||
{
|
||||
Text = "", // 移除文字
|
||||
Visible = false
|
||||
};
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)};";
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -74,28 +74,6 @@ 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)
|
||||
{
|
||||
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;
|
||||
|
@ -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<Image> LoadMenuImages()
|
||||
/// <summary>
|
||||
/// 從指定資料夾載入所有 .jpg 圖片
|
||||
/// </summary>
|
||||
private List<Image> LoadImagesFromFolder(string folderName)
|
||||
{
|
||||
List<Image> images = new List<Image>();
|
||||
string foodsFolderPath = Path.Combine(Application.StartupPath, "foods");
|
||||
List<Image> images = new();
|
||||
string folderPath = Path.Combine(Utils.Env.KtvPath, folderName);
|
||||
|
||||
string[] imageFiles = Directory.GetFiles(foodsFolderPath, "*.jpg");
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
@ -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 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
77
Program.cs
77
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()
|
||||
@ -134,7 +90,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)
|
||||
|
69
TCPServer.cs
69
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1597,13 +1597,14 @@ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,16 +71,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- 複製資料夾 foods -->
|
||||
<Content Include="foods\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
||||
<!-- 複製資料夾 db -->
|
||||
<Content Include="db\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
||||
<!-- 複製資料夾 txt -->
|
||||
<Content Include="txt\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
@ -90,11 +80,6 @@
|
||||
<Content Include="themes\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<!-- 複製資料夾 news -->
|
||||
<Content Include="news\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
||||
<!-- 複製資料夾 sounds -->
|
||||
<Content Include="sounds\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
Loading…
x
Reference in New Issue
Block a user