2509031254

server與歌曲路徑使用ftp
This commit is contained in:
jasonchenwork 2025-09-03 12:56:34 +08:00
parent 237e9f6c49
commit 4ca6594561
7 changed files with 210 additions and 98 deletions

View File

@ -1,6 +1,7 @@
using DualScreenDemo; using DualScreenDemo;
using System; using System;
using System.IO; using System.IO;
using System.Net;
using System.Windows.Markup; using System.Windows.Markup;
namespace DBObj namespace DBObj
{ {
@ -31,7 +32,8 @@ namespace DBObj
B = !artistB.Equals("") ? new Artist(artistB, artistBSimplified) : null; B = !artistB.Equals("") ? new Artist(artistB, artistBSimplified) : null;
isPublicSong = false; isPublicSong = false;
} }
public SongData(SongData value,PlayState s){ public SongData(SongData value, PlayState s)
{
basic = value.getBasic(); basic = value.getBasic();
A = value.getA(); A = value.getA();
B = value.getB(); B = value.getB();
@ -73,12 +75,13 @@ namespace DBObj
{ {
try try
{ {
string fullPath = Path.Combine(server, basic.getFileName()); // string fullPath = Path.Combine(server, basic.getFileName());
if (File.Exists(fullPath)) Uri fullUri = new Uri(new Uri(server), basic.getFileName());
{ // if (File.Exists(fullPath))
Console.WriteLine($"找到檔案: {fullPath}"); // {
// Console.WriteLine($"找到檔案: {fullPath}");
return true; return true;
} // }
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -103,6 +106,27 @@ namespace DBObj
} }
return null; // 找不到就回原本的 filename不加路徑 return null; // 找不到就回原本的 filename不加路徑
} }
public Uri getFileUrl()
{
return GetUri(basic.getFileName());
}
private Uri GetUri(string filename)
{
foreach (var server in Utils.Env.GetSongServers())
{
var check = IsFtpUriReachable(new Uri(server).ToString());
if (!string.IsNullOrWhiteSpace(server) && check != false)
{
return new Uri(new Uri(server), filename);
}
}
// throw new InvalidOperationException("No valid server found.");
Console.WriteLine("No valid server found.");
return null;
}
public Color GetStateColor() => state switch public Color GetStateColor() => state switch
{ {
PlayState.Played => Color.Gray, PlayState.Played => Color.Gray,
@ -122,5 +146,36 @@ namespace DBObj
{ {
return String.Format("{0} {1}", basic.getName(), state.GetDescription()); return String.Format("{0} {1}", basic.getName(), state.GetDescription());
} }
public static bool IsFtpUriReachable(string ftpUri)
{
try
{
#pragma warning disable SYSLIB0014 // 類型或成員已經過時
var request = (FtpWebRequest)WebRequest.Create(ftpUri);
#pragma warning restore SYSLIB0014 // 類型或成員已經過時
request.Method = WebRequestMethods.Ftp.ListDirectory; // Lightweight check
// request.Credentials = new NetworkCredential("svr", "svr"); // Replace with actual username/password
request.Timeout = 5000;
using var response = (FtpWebResponse)request.GetResponse();
return response.StatusCode == FtpStatusCode.OpeningData || response.StatusCode == FtpStatusCode.DataAlreadyOpen;
}
catch (WebException ex)
{
if (ex.Response is FtpWebResponse ftpResponse)
{
Console.WriteLine($"FTP error: {ftpResponse.StatusDescription}");
return false;
}
Console.WriteLine($"Connection error: {ex.Message}");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
return false;
}
}
} }
} }

2
Env.cs
View File

@ -60,7 +60,7 @@ namespace Utils
// .Select(s => s.Trim('\'', '"').TrimEnd('\\')) // 清理 // .Select(s => s.Trim('\'', '"').TrimEnd('\\')) // 清理
// .ToArray(); // .ToArray();
return new string[] { @"\\svr01", @"\\svr02" }; return new string[] { @"ftp://svr:svr@svr",@"ftp://song1:song1@svr01", @"ftp://song2:song2@svr02",@"ftp://song3:song3@svr03" };
} }

View File

@ -321,6 +321,28 @@ namespace DualScreenDemo
{ {
try try
{ {
var request = context.Request;
var user = context.User;
Console.WriteLine("Headers:");
foreach (string key in request.Headers.AllKeys)
{
Console.WriteLine($" {key}: {request.Headers[key]}");
}
Console.WriteLine("Query String:");
foreach (string key in request.QueryString.AllKeys)
{
Console.WriteLine($" {key}: {request.QueryString[key]}");
}
Console.WriteLine("Body:");
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
string body = reader.ReadToEnd();
Console.WriteLine(body);
}
context.Response.Close(); context.Response.Close();
} }
catch { } catch { }
@ -528,7 +550,8 @@ namespace DualScreenDemo
break; break;
case "service": case "service":
// 执行服务操作 // 执行服务操作
OverlayForm.MainForm.Invoke(new System.Action(() => { OverlayForm.MainForm.Invoke(new System.Action(() =>
{
OverlayForm.MainForm.ShowTopRightLabel("服務鈴", "a2 53 a4"); OverlayForm.MainForm.ShowTopRightLabel("服務鈴", "a2 53 a4");
})); }));
break; break;
@ -706,7 +729,8 @@ namespace DualScreenDemo
var json = JObject.Parse(requestBody); var json = JObject.Parse(requestBody);
SongData song = songListManager.SearchSongByNumber(json["SongNumber"]?.ToString()); SongData song = songListManager.SearchSongByNumber(json["SongNumber"]?.ToString());
if (song != null) { if (song != null)
{
Console.WriteLine($"Ordering Song: {song.getName()} by {song.getArtist_A()}"); Console.WriteLine($"Ordering Song: {song.getName()} by {song.getArtist_A()}");
// 这里可以添加处理逻辑,例如将歌曲加入到播放列表或数据库中 // 这里可以添加处理逻辑,例如将歌曲加入到播放列表或数据库中
@ -716,7 +740,9 @@ namespace DualScreenDemo
var response = new { status = "success", message = "Song ordered successfully" }; var response = new { status = "success", message = "Song ordered successfully" };
string jsonResponse = JsonConvert.SerializeObject(response); string jsonResponse = JsonConvert.SerializeObject(response);
await SendResponseAsync(context, jsonResponse); await SendResponseAsync(context, jsonResponse);
} else { }
else
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"Invalid song data\"}"); await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"Invalid song data\"}");
} }
@ -745,7 +771,8 @@ namespace DualScreenDemo
var json = JObject.Parse(requestBody); var json = JObject.Parse(requestBody);
SongData song = songListManager.SearchSongByNumber(json["SongNumber"]?.ToString()); SongData song = songListManager.SearchSongByNumber(json["SongNumber"]?.ToString());
if (song != null){ if (song != null)
{
Console.WriteLine($"Inserting Song: {song.getName()} by {song.getArtist_A()}"); Console.WriteLine($"Inserting Song: {song.getName()} by {song.getArtist_A()}");
// 这里可以添加插播歌曲的处理逻辑 // 这里可以添加插播歌曲的处理逻辑
song.getBasic().setNameTest("*"); song.getBasic().setNameTest("*");
@ -753,7 +780,9 @@ namespace DualScreenDemo
var response = new { status = "success", message = "Song inserted successfully" }; var response = new { status = "success", message = "Song inserted successfully" };
string jsonResponse = JsonConvert.SerializeObject(response); string jsonResponse = JsonConvert.SerializeObject(response);
await SendResponseAsync(context, jsonResponse); await SendResponseAsync(context, jsonResponse);
} else { }
else
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"Invalid song data\"}"); await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"Invalid song data\"}");
} }
@ -822,11 +851,13 @@ namespace DualScreenDemo
} }
// 封装响应代码以避免重复 // 封装响应代码以避免重复
async static Task SendResponseAsync(HttpListenerContext context, string jsonResponse) { async static Task SendResponseAsync(HttpListenerContext context, string jsonResponse)
{
context.Response.ContentType = "application/json"; context.Response.ContentType = "application/json";
context.Response.ContentLength64 = Encoding.UTF8.GetByteCount(jsonResponse); context.Response.ContentLength64 = Encoding.UTF8.GetByteCount(jsonResponse);
context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.StatusCode = (int)HttpStatusCode.OK;
using (var streamWriter = new StreamWriter(context.Response.OutputStream)) { using (var streamWriter = new StreamWriter(context.Response.OutputStream))
{
await streamWriter.WriteAsync(jsonResponse); await streamWriter.WriteAsync(jsonResponse);
await streamWriter.FlushAsync(); await streamWriter.FlushAsync();
} }

View File

@ -2,7 +2,7 @@ namespace DualScreenDemo
{ {
public partial class PrimaryForm public partial class PrimaryForm
{ {
private Button orderedSongsButton; public Button orderedSongsButton;
private Bitmap orderedSongsNormalBackground; private Bitmap orderedSongsNormalBackground;
private Bitmap orderedSongsActiveBackground; private Bitmap orderedSongsActiveBackground;
} }

View File

@ -14,7 +14,7 @@ namespace DualScreenDemo
private static PrimaryForm primaryForm; // 儲存實例的參考 private static PrimaryForm primaryForm; // 儲存實例的參考
public static Room room = new Room(); public static Room room = new Room();
public static string verSion = "Server V2.10 202509010938"; public static string verSion = "Server V2.10 202509031254";
[STAThread] [STAThread]
static void Main() static void Main()

View File

@ -94,6 +94,7 @@ namespace DualScreenDemo.Services
_mediaPlayer.Play(); _mediaPlayer.Play();
// } // }
}; };
_mediaPlayer.Fullscreen = true; _mediaPlayer.Fullscreen = true;
_mediaPlayer.Mute = false; _mediaPlayer.Mute = false;
} }
@ -103,7 +104,27 @@ namespace DualScreenDemo.Services
Program.WriteLog(ex.ToString()); Program.WriteLog(ex.ToString());
} }
} }
public void LoadMedia(Uri url, int audioTrackIndex = 0)
{
try
{
_mediaPlayer.Pause();
_media?.Dispose();
_media = new Media(url);
_mediaPlayer.Media = addMediaOption(_media, audioTrackIndex);
_mediaPlayer.Play();
_mediaPlayer.Fullscreen = true;
_mediaPlayer.Mute = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Program.WriteLog(ex.ToString());
}
}
private Media addMediaOption(Media media, int audioTrackIndex) private Media addMediaOption(Media media, int audioTrackIndex)
{ {
media.AddOption(":avcodec-hw=dxva2"); media.AddOption(":avcodec-hw=dxva2");

View File

@ -347,12 +347,15 @@ namespace DualScreenDemo
try try
{ {
string pathToPlay = song.getFile(); string pathToPlay = song.getFile();
Uri url = song.getFileUrl();
if (pathToPlay == null) _mediaService0.LoadMedia(url, 0);
//同步畫面播放器載入media設置參數 //同步畫面播放器載入media設置參數
_mediaService0.LoadMedia(pathToPlay, 0); else _mediaService0.LoadMedia(pathToPlay, 0);
// _mediaService0.Player.Media.AddOption(":no-audio"); // _mediaService0.Player.Media.AddOption(":no-audio");
_mediaService0.Player.AspectRatio = "8:5"; _mediaService0.Player.AspectRatio = "8:5";
if(pathToPlay==null)_mediaService1.LoadMedia(url, song.isPublicSong ? 0 : 1);
//影片畫面播放器載入media設置聲道 //影片畫面播放器載入media設置聲道
_mediaService1.LoadMedia(pathToPlay, song.isPublicSong ? 0 : 1); else _mediaService1.LoadMedia(pathToPlay, song.isPublicSong ? 0 : 1);
isVocalRemoved = true; isVocalRemoved = true;
if (isMuted) { Mute(true); } if (isMuted) { Mute(true); }
@ -361,6 +364,7 @@ namespace DualScreenDemo
SetVolume(100 + song.getBasic().getDbChange()); SetVolume(100 + song.getBasic().getDbChange());
Task.Run(() => Thread.Sleep(100)); Task.Run(() => Thread.Sleep(100));
if (isSyncToPrimaryMonitor) SyncToPrimaryMonitor(); if (isSyncToPrimaryMonitor) SyncToPrimaryMonitor();
if (url == null&&!song.isPublicSong) PlayNextSong();
return Task.CompletedTask; return Task.CompletedTask;
} }
catch (Exception ex) catch (Exception ex)
@ -403,6 +407,7 @@ namespace DualScreenDemo
BeginInvoke(new Action(async () => BeginInvoke(new Action(async () =>
{ {
await PlayNextSong(); await PlayNextSong();
if (PrimaryForm.Instance.isOnOrderedSongsPage) PrimaryForm.Instance.orderedSongsButton.PerformClick();
})); }));
} }
} }