開關台自動刷新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 ConcurrentDictionary<string, byte[]> _fileCache = new ConcurrentDictionary<string, byte[]>();
|
||||||
private static readonly SemaphoreSlim _requestThrottle = new SemaphoreSlim(20); // 限制并发请求数
|
private static readonly SemaphoreSlim _requestThrottle = new SemaphoreSlim(20); // 限制并发请求数
|
||||||
private static readonly CancellationTokenSource _serverCts = new CancellationTokenSource();
|
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)
|
public static async Task StartServer(string baseDirectory, int port, SongListManager manager)
|
||||||
{
|
{
|
||||||
songListManager = manager; // 保存传递的SongListManager实例
|
songListManager = manager; // 保存传递的SongListManager实例
|
||||||
@ -130,6 +136,101 @@ namespace DualScreenDemo
|
|||||||
await ProcessRequestAsync(context, baseDirectory, randomFolderName);
|
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)
|
private static async Task ProcessRequestWithTimeout(HttpListenerContext context, string baseDirectory, string randomFolderName)
|
||||||
{
|
{
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using System.Threading;
|
||||||
namespace DualScreenDemo
|
namespace DualScreenDemo
|
||||||
{
|
{
|
||||||
public static class HttpServerManager
|
public static class HttpServerManager
|
||||||
{
|
{
|
||||||
|
private static CancellationTokenSource _cts;
|
||||||
public static async void StartServer()
|
public static async void StartServer()
|
||||||
{
|
{
|
||||||
int httpPort = 9090; // 你可以修改此端口
|
int httpPort = 9090; // 你可以修改此端口
|
||||||
string baseDirectory = Path.Combine(Application.StartupPath, @"themes\superstar\_www");
|
string baseDirectory = Path.Combine(Application.StartupPath, @"themes\superstar\_www");
|
||||||
|
|
||||||
CleanUpDirectory(baseDirectory);
|
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; }
|
get { return _mainForm; }
|
||||||
private set { _mainForm = value; }
|
private set { _mainForm = value; }
|
||||||
}
|
}
|
||||||
|
public static OverlayForm Instance { get; private set; }
|
||||||
public OverlayForm()
|
public OverlayForm()
|
||||||
{
|
{
|
||||||
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
|
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
|
||||||
MainForm = this;
|
MainForm = this;
|
||||||
|
Instance = this;
|
||||||
InitializeFormSettings();
|
InitializeFormSettings();
|
||||||
ConfigureTimers();
|
ConfigureTimers();
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
public partial class PrimaryForm : Form
|
public partial class PrimaryForm : Form
|
||||||
{
|
{
|
||||||
private PictureBox pictureBoxQRCode;
|
public PictureBox pictureBoxQRCode;
|
||||||
private Button closeQRCodeButton;
|
public Button closeQRCodeButton;
|
||||||
|
|
||||||
private void OverlayQRCodeOnImage(string randomFolderPath)
|
public void OverlayQRCodeOnImage(string randomFolderPath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -48,13 +48,15 @@ namespace DualScreenDemo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string tempPath = Path.GetTempFileName();
|
||||||
|
File.Copy(qrImagePath, tempPath, true); // 複製一份再讀,避開快取
|
||||||
|
|
||||||
Image qrCodeImage = null;
|
Image qrCodeImage = null;
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
try
|
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);
|
qrCodeImage = Image.FromStream(fs);
|
||||||
}
|
}
|
||||||
@ -66,7 +68,7 @@ namespace DualScreenDemo
|
|||||||
System.Threading.Thread.Sleep(100);
|
System.Threading.Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File.Delete(tempPath); // 用完記得刪除
|
||||||
if (qrCodeImage == null)
|
if (qrCodeImage == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to load QR code image after multiple attempts.");
|
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,並顯示送客畫面
|
// 指令為 "X":播放 CLOSE.MPG,並顯示送客畫面
|
||||||
if (command.Trim().Equals("X", StringComparison.OrdinalIgnoreCase))
|
if (command.Trim().Equals("X", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
PrimaryForm.Instance.pictureBoxQRCode.Visible = false;
|
||||||
|
PrimaryForm.Instance.closeQRCodeButton.Visible = false;
|
||||||
_ = SafeInvoke(VideoPlayerForm.Instance, async () =>
|
_ = SafeInvoke(VideoPlayerForm.Instance, async () =>
|
||||||
{
|
{
|
||||||
if (IsFormReady(PrimaryForm.Instance))
|
if (IsFormReady(PrimaryForm.Instance))
|
||||||
{
|
{
|
||||||
await SafeInvoke(PrimaryForm.Instance, () =>
|
await SafeInvoke(PrimaryForm.Instance, async () =>
|
||||||
{
|
{
|
||||||
PrimaryForm.Instance.ShowSendOffScreen();
|
PrimaryForm.Instance.ShowSendOffScreen();
|
||||||
PrimaryForm.Instance.HideFireScreen();
|
PrimaryForm.Instance.HideFireScreen();
|
||||||
@ -167,13 +169,13 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
// 建立結束播放用的 SongData 實例
|
// 建立結束播放用的 SongData 實例
|
||||||
SongData closeSong = new SongData(
|
SongData closeSong = new SongData(
|
||||||
"", "", "結束播放", 0, "", "", "", "",
|
"", "", "結束播放", 0, "", "", "", "",
|
||||||
DateTime.Now, closePath, "", "", "", "",
|
DateTime.Now, closePath, "", "", "", "",
|
||||||
"", "", "", "", "", "", "", 1
|
"", "", "", "", "", "", "", 1
|
||||||
);
|
);
|
||||||
|
|
||||||
// 建立新的播放清單
|
// 建立新的播放清單
|
||||||
|
|
||||||
VideoPlayerForm.publicPlaylist = new List<SongData>();
|
VideoPlayerForm.publicPlaylist = new List<SongData>();
|
||||||
VideoPlayerForm.playingSongList = new List<SongData>();
|
VideoPlayerForm.playingSongList = new List<SongData>();
|
||||||
PrimaryForm.playedSongsHistory = new List<SongData>();
|
PrimaryForm.playedSongsHistory = new List<SongData>();
|
||||||
@ -182,8 +184,8 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
VideoPlayerForm.playingSongList.Add(VideoPlayerForm.Instance.currentPlayingSong);
|
VideoPlayerForm.playingSongList.Add(VideoPlayerForm.Instance.currentPlayingSong);
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoPlayerForm.publicPlaylist.Add(closeSong);
|
VideoPlayerForm.publicPlaylist.Add(closeSong);
|
||||||
// 將 CLOSE.MPG 加入播放清單
|
// 將 CLOSE.MPG 加入播放清單
|
||||||
VideoPlayerForm.playingSongList.Add(closeSong);
|
VideoPlayerForm.playingSongList.Add(closeSong);
|
||||||
|
|
||||||
@ -195,8 +197,16 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
OverlayForm.MainForm.nextSongLabel.Visible = false;
|
OverlayForm.MainForm.nextSongLabel.Visible = false;
|
||||||
}
|
}
|
||||||
VideoPlayerForm.Instance.PlayNextSong();
|
VideoPlayerForm.Instance.PlayNextSong();
|
||||||
Console.WriteLine("已設置新的播放列表,包含當前歌曲和 CLOSE.MPG");
|
Console.WriteLine("已設置新的播放列表,包含當前歌曲和 CLOSE.MPG");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await HttpServer.RestartServer();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("RestartServer 發生錯誤: " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -14,5 +14,5 @@ Filter: LAV Splitter
|
|||||||
Pin: Input
|
Pin: Input
|
||||||
Pin: Video
|
Pin: Video
|
||||||
Pin: Audio
|
Pin: Audio
|
||||||
Filter: C:\video\BGM01.mpg
|
Filter: C:\video\welcome.mpg
|
||||||
Pin: Output
|
Pin: Output
|
||||||
|
Reference in New Issue
Block a user