開關台自動刷新QRCODE亂碼
This commit is contained in:
parent
d5b7623dd8
commit
424ef89dbc
103
HttpServer.cs
103
HttpServer.cs
@ -35,8 +35,14 @@ namespace DualScreenDemo
|
||||
private static readonly ConcurrentDictionary<string, byte[]> _fileCache = new ConcurrentDictionary<string, byte[]>();
|
||||
private static readonly SemaphoreSlim _requestThrottle = new SemaphoreSlim(20); // 限制并发请求数
|
||||
private static readonly CancellationTokenSource _serverCts = new CancellationTokenSource();
|
||||
private static HttpListener _listener;
|
||||
private static CancellationTokenSource _cts;
|
||||
private static Task _serverTask;
|
||||
private static string _baseDirectory = @"themes\superstar\_www"; // 根據實際情況設定
|
||||
private static SongListManager _songListManager;
|
||||
private static TaskCompletionSource<string> _qrReadyTcs;
|
||||
|
||||
|
||||
/*
|
||||
public static async Task StartServer(string baseDirectory, int port, SongListManager manager)
|
||||
{
|
||||
songListManager = manager; // 保存传递的SongListManager实例
|
||||
@ -130,6 +136,101 @@ namespace DualScreenDemo
|
||||
await ProcessRequestAsync(context, baseDirectory, randomFolderName);
|
||||
}
|
||||
}
|
||||
*/
|
||||
public static async Task StartServer(string baseDirectory, int port, SongListManager manager, CancellationToken token)
|
||||
{
|
||||
_songListManager = manager;
|
||||
string randomFolderName = CreateRandomFolderAndRedirectHTML(baseDirectory);
|
||||
randomFolderPath = randomFolderName;
|
||||
Console.WriteLine("測試" + randomFolderPath);
|
||||
string localAddress = GetLocalIPAddress();
|
||||
string externalAddress = File.Exists(@"\\SVR01\superstarb\txt\ip.txt")
|
||||
? File.ReadAllText(@"\\SVR01\superstarb\txt\ip.txt").Trim()
|
||||
: "";
|
||||
|
||||
_listener = new HttpListener();
|
||||
_listener.Prefixes.Add($"http://{localAddress}:{port}/");
|
||||
string hostName = System.Net.Dns.GetHostName();
|
||||
string externalPort = '1' + hostName.Substring(Math.Max(2, hostName.Length - 20));
|
||||
if (!string.IsNullOrEmpty(externalAddress))
|
||||
{
|
||||
string host = externalAddress.Split(':')[0];
|
||||
externalPort = '1' + System.Net.Dns.GetHostName().Substring(Math.Max(2, System.Net.Dns.GetHostName().Length - 20));
|
||||
_listener.Prefixes.Add($"http://{host}:{externalPort}/");
|
||||
}
|
||||
string localQrContent = String.Format("http://{0}:{1}/{2}/windows.html", localAddress, port, randomFolderName);
|
||||
|
||||
|
||||
// 修改外网二维码内容生成
|
||||
|
||||
string externalQrContent = !string.IsNullOrEmpty(externalAddress) ?
|
||||
String.Format("http://{0}:{1}/{2}/windows.html", externalAddress, externalPort, randomFolderName) :
|
||||
localQrContent;
|
||||
|
||||
/*string qrContent = !string.IsNullOrEmpty(externalAddress)
|
||||
? $"http://{externalAddress}:{port}/{randomFolderName}/windows.html"
|
||||
: $"http://{localAddress}:{port}/{randomFolderName}/windows.html";*/
|
||||
Console.WriteLine("qrcode 測試內容 " + externalQrContent);
|
||||
GenerateQRCode(externalQrContent, Path.Combine(baseDirectory, randomFolderName, "qrcode.png"));
|
||||
|
||||
_qrReadyTcs?.TrySetResult(randomFolderName); // safe call,null-safe
|
||||
try
|
||||
{
|
||||
_listener.Start();
|
||||
Console.WriteLine("Server started.");
|
||||
}
|
||||
catch (HttpListenerException ex)
|
||||
{
|
||||
Console.WriteLine("Error starting server: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpListenerContext context = await _listener.GetContextAsync();
|
||||
await ProcessRequestAsync(context, baseDirectory, randomFolderName);
|
||||
}
|
||||
catch (HttpListenerException)
|
||||
{
|
||||
// 可能是 Stop() 引起,不處理
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_listener.Close();
|
||||
Console.WriteLine("Server stopped.");
|
||||
}
|
||||
|
||||
public static async Task RestartServer()
|
||||
{
|
||||
Console.WriteLine("Restarting server...");
|
||||
|
||||
_cts?.Cancel();
|
||||
_listener?.Stop();
|
||||
|
||||
if (_serverTask != null)
|
||||
{
|
||||
try { await _serverTask; }
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
DeleteRandomFolder(_baseDirectory);
|
||||
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
|
||||
// ✅ 等 QR code 跑完
|
||||
_qrReadyTcs = new TaskCompletionSource<string>();
|
||||
_serverTask = StartServer(_baseDirectory, _port, _songListManager, _cts.Token);
|
||||
string readyFolder = await _qrReadyTcs.Task;
|
||||
|
||||
// ✅ 等 QR Code 圖片準備好之後再處理 UI 更新
|
||||
Console.WriteLine("restart : " + readyFolder);
|
||||
PrimaryForm.Instance.OverlayQRCodeOnImage(readyFolder);
|
||||
OverlayForm.Instance.DisplayQRCodeOnOverlay(readyFolder);
|
||||
}
|
||||
|
||||
private static async Task ProcessRequestWithTimeout(HttpListenerContext context, string baseDirectory, string randomFolderName)
|
||||
{
|
||||
|
@ -1,18 +1,21 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using System.Threading;
|
||||
namespace DualScreenDemo
|
||||
{
|
||||
public static class HttpServerManager
|
||||
{
|
||||
private static CancellationTokenSource _cts;
|
||||
public static async void StartServer()
|
||||
{
|
||||
int httpPort = 9090; // 你可以修改此端口
|
||||
string baseDirectory = Path.Combine(Application.StartupPath, @"themes\superstar\_www");
|
||||
|
||||
CleanUpDirectory(baseDirectory);
|
||||
await HttpServer.StartServer(baseDirectory, httpPort, Program.songListManager);
|
||||
// await HttpServer.StartServer(baseDirectory, httpPort, Program.songListManager);
|
||||
_cts = new CancellationTokenSource();
|
||||
await HttpServer.StartServer(baseDirectory, httpPort, Program.songListManager, _cts.Token);
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,11 +74,12 @@ namespace OverlayFormObj
|
||||
get { return _mainForm; }
|
||||
private set { _mainForm = value; }
|
||||
}
|
||||
|
||||
public static OverlayForm Instance { get; private set; }
|
||||
public OverlayForm()
|
||||
{
|
||||
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
|
||||
MainForm = this;
|
||||
MainForm = this;
|
||||
Instance = this;
|
||||
InitializeFormSettings();
|
||||
ConfigureTimers();
|
||||
|
||||
|
@ -7,10 +7,10 @@ namespace DualScreenDemo
|
||||
{
|
||||
public partial class PrimaryForm : Form
|
||||
{
|
||||
private PictureBox pictureBoxQRCode;
|
||||
private Button closeQRCodeButton;
|
||||
public PictureBox pictureBoxQRCode;
|
||||
public Button closeQRCodeButton;
|
||||
|
||||
private void OverlayQRCodeOnImage(string randomFolderPath)
|
||||
public void OverlayQRCodeOnImage(string randomFolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -48,13 +48,15 @@ namespace DualScreenDemo
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string tempPath = Path.GetTempFileName();
|
||||
File.Copy(qrImagePath, tempPath, true); // 複製一份再讀,避開快取
|
||||
|
||||
Image qrCodeImage = null;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(qrImagePath, FileMode.Open, FileAccess.Read))
|
||||
using (var fs = new FileStream(tempPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
qrCodeImage = Image.FromStream(fs);
|
||||
}
|
||||
@ -66,7 +68,7 @@ namespace DualScreenDemo
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
File.Delete(tempPath); // 用完記得刪除
|
||||
if (qrCodeImage == null)
|
||||
{
|
||||
Console.WriteLine("Failed to load QR code image after multiple attempts.");
|
||||
|
24
TCPServer.cs
24
TCPServer.cs
@ -149,11 +149,13 @@ namespace DualScreenDemo
|
||||
// 指令為 "X":播放 CLOSE.MPG,並顯示送客畫面
|
||||
if (command.Trim().Equals("X", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
PrimaryForm.Instance.pictureBoxQRCode.Visible = false;
|
||||
PrimaryForm.Instance.closeQRCodeButton.Visible = false;
|
||||
_ = SafeInvoke(VideoPlayerForm.Instance, async () =>
|
||||
{
|
||||
if (IsFormReady(PrimaryForm.Instance))
|
||||
{
|
||||
await SafeInvoke(PrimaryForm.Instance, () =>
|
||||
await SafeInvoke(PrimaryForm.Instance, async () =>
|
||||
{
|
||||
PrimaryForm.Instance.ShowSendOffScreen();
|
||||
PrimaryForm.Instance.HideFireScreen();
|
||||
@ -167,13 +169,13 @@ namespace DualScreenDemo
|
||||
{
|
||||
// 建立結束播放用的 SongData 實例
|
||||
SongData closeSong = new SongData(
|
||||
"", "", "結束播放", 0, "", "", "", "",
|
||||
DateTime.Now, closePath, "", "", "", "",
|
||||
"", "", "結束播放", 0, "", "", "", "",
|
||||
DateTime.Now, closePath, "", "", "", "",
|
||||
"", "", "", "", "", "", "", 1
|
||||
);
|
||||
|
||||
// 建立新的播放清單
|
||||
|
||||
|
||||
VideoPlayerForm.publicPlaylist = new List<SongData>();
|
||||
VideoPlayerForm.playingSongList = new List<SongData>();
|
||||
PrimaryForm.playedSongsHistory = new List<SongData>();
|
||||
@ -182,8 +184,8 @@ namespace DualScreenDemo
|
||||
{
|
||||
VideoPlayerForm.playingSongList.Add(VideoPlayerForm.Instance.currentPlayingSong);
|
||||
}
|
||||
|
||||
VideoPlayerForm.publicPlaylist.Add(closeSong);
|
||||
|
||||
VideoPlayerForm.publicPlaylist.Add(closeSong);
|
||||
// 將 CLOSE.MPG 加入播放清單
|
||||
VideoPlayerForm.playingSongList.Add(closeSong);
|
||||
|
||||
@ -195,8 +197,16 @@ namespace DualScreenDemo
|
||||
{
|
||||
OverlayForm.MainForm.nextSongLabel.Visible = false;
|
||||
}
|
||||
VideoPlayerForm.Instance.PlayNextSong();
|
||||
VideoPlayerForm.Instance.PlayNextSong();
|
||||
Console.WriteLine("已設置新的播放列表,包含當前歌曲和 CLOSE.MPG");
|
||||
try
|
||||
{
|
||||
await HttpServer.RestartServer();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("RestartServer 發生錯誤: " + ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -14,5 +14,5 @@ Filter: LAV Splitter
|
||||
Pin: Input
|
||||
Pin: Video
|
||||
Pin: Audio
|
||||
Filter: C:\video\BGM01.mpg
|
||||
Filter: C:\video\welcome.mpg
|
||||
Pin: Output
|
||||
|
Reference in New Issue
Block a user