PublicSongChecker 完成
還原 點歌流 20250704
This commit is contained in:
parent
8f456c347d
commit
c1437a02d9
@ -7,8 +7,6 @@ namespace DBObj
|
|||||||
public string ArtistA { get; set; }
|
public string ArtistA { get; set; }
|
||||||
public string ArtistB { get; set; }
|
public string ArtistB { get; set; }
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
public string SongFilePathHost1 { get; set; }
|
|
||||||
public string SongFilePathHost2 { get; set; }
|
|
||||||
public string ArtistASimplified { get; set; }
|
public string ArtistASimplified { get; set; }
|
||||||
public string ArtistBSimplified { get; set; }
|
public string ArtistBSimplified { get; set; }
|
||||||
public string SongSimplified { get; set; }
|
public string SongSimplified { get; set; }
|
||||||
@ -42,15 +40,20 @@ namespace DBObj
|
|||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
public SongData(string songNumber, string song, string artistA, string artistB, string filename, string songFilePathHost1, string songFilePathHost2, string artistASimplified, string artistBSimplified, string songSimplified, int humanVoice)
|
public SongData(string songNumber, string song, string filename, int humanVoice)
|
||||||
|
{
|
||||||
|
SongNumber = songNumber;
|
||||||
|
Song = song;
|
||||||
|
FileName = filename;
|
||||||
|
HumanVoice = humanVoice;
|
||||||
|
}
|
||||||
|
public SongData(string songNumber, string song, string artistA, string artistB, string filename, string artistASimplified, string artistBSimplified, string songSimplified, int humanVoice)
|
||||||
{
|
{
|
||||||
SongNumber = songNumber;
|
SongNumber = songNumber;
|
||||||
Song = song;
|
Song = song;
|
||||||
ArtistA = artistA;
|
ArtistA = artistA;
|
||||||
ArtistB = artistB;
|
ArtistB = artistB;
|
||||||
FileName = filename;
|
FileName = filename;
|
||||||
SongFilePathHost1 = songFilePathHost1;
|
|
||||||
SongFilePathHost2 = songFilePathHost2;
|
|
||||||
ArtistASimplified = artistASimplified;
|
ArtistASimplified = artistASimplified;
|
||||||
ArtistBSimplified = artistBSimplified;
|
ArtistBSimplified = artistBSimplified;
|
||||||
SongSimplified = songSimplified;
|
SongSimplified = songSimplified;
|
||||||
|
80
DataCheck.cs
80
DataCheck.cs
@ -1,80 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace DataCheck
|
|
||||||
{
|
|
||||||
public class DataChecker
|
|
||||||
{
|
|
||||||
public DataChecker()
|
|
||||||
{
|
|
||||||
// 加入你要同步的資料夾
|
|
||||||
SyncFolder(Utils.Env.GetPath("video", ""), @"D:\video", "video", new[] { ".mpg" });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SyncFolder(string serverPath, string localPath, string label, string[] extensions)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!Directory.Exists(localPath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(localPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(serverPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"找不到伺服器資料夾:{serverPath}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var serverFiles = Directory.GetFiles(serverPath)
|
|
||||||
.Where(f => extensions.Contains(Path.GetExtension(f), StringComparer.OrdinalIgnoreCase))
|
|
||||||
.Select(f => new FileInfo(f))
|
|
||||||
.ToDictionary(f => f.Name, f => f);
|
|
||||||
|
|
||||||
var localFiles = Directory.GetFiles(localPath)
|
|
||||||
.Where(f => extensions.Contains(Path.GetExtension(f), StringComparer.OrdinalIgnoreCase))
|
|
||||||
.Select(f => new FileInfo(f))
|
|
||||||
.ToDictionary(f => f.Name, f => f);
|
|
||||||
|
|
||||||
// 1. 複製或更新檔案
|
|
||||||
foreach (var serverFile in serverFiles)
|
|
||||||
{
|
|
||||||
bool needsCopy = !localFiles.ContainsKey(serverFile.Key) ||
|
|
||||||
serverFile.Value.LastWriteTime > localFiles[serverFile.Key].LastWriteTime;
|
|
||||||
|
|
||||||
if (needsCopy)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string dest = Path.Combine(localPath, serverFile.Key);
|
|
||||||
File.Copy(serverFile.Value.FullName, dest, true);
|
|
||||||
Console.WriteLine($"更新{label}: {serverFile.Key}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"複製{label}失敗 {serverFile.Key}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 刪除多餘的本地檔案
|
|
||||||
foreach (var localFile in localFiles)
|
|
||||||
{
|
|
||||||
if (!serverFiles.ContainsKey(localFile.Key))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(localFile.Value.FullName);
|
|
||||||
Console.WriteLine($"刪除多餘{label}: {localFile.Key}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"刪除{label}失敗 {localFile.Key}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -786,8 +786,7 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
song.Song,
|
song.Song,
|
||||||
song.ArtistA,
|
song.ArtistA,
|
||||||
song.SongFilePathHost1,
|
song.FileName,
|
||||||
song.SongFilePathHost2,
|
|
||||||
PlayState = playState.HasValue ? (playState.Value == PlayState.Playing ? "播放中" : "播放完畢") : null // 如果状态为 null,不返回状态信息
|
PlayState = playState.HasValue ? (playState.Value == PlayState.Playing ? "播放中" : "播放完畢") : null // 如果状态为 null,不返回状态信息
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1118,21 +1117,11 @@ namespace DualScreenDemo
|
|||||||
song.Song,
|
song.Song,
|
||||||
song.ArtistA,
|
song.ArtistA,
|
||||||
song.SongNumber,
|
song.SongNumber,
|
||||||
//song.Category,
|
|
||||||
//song.PhoneticNotation,
|
|
||||||
//song.PinyinNotation,
|
|
||||||
//song.ArtistAPhonetic,
|
|
||||||
//song.ArtistBPhonetic,
|
|
||||||
song.ArtistASimplified,
|
song.ArtistASimplified,
|
||||||
song.ArtistBSimplified,
|
song.ArtistBSimplified,
|
||||||
song.SongSimplified,
|
song.SongSimplified,
|
||||||
//song.SongGenre,
|
|
||||||
//song.ArtistAPinyin,
|
|
||||||
//song.ArtistBPinyin,
|
|
||||||
song.HumanVoice,
|
song.HumanVoice,
|
||||||
//song.AddedTime,
|
song.FileName
|
||||||
song.SongFilePathHost1,
|
|
||||||
song.SongFilePathHost2 // 例如语言类别等信息
|
|
||||||
})
|
})
|
||||||
.ToList(),
|
.ToList(),
|
||||||
status = "success",
|
status = "success",
|
||||||
|
@ -1004,7 +1004,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
|
|||||||
if (songIndex >= 0 && songIndex < totalSongs)
|
if (songIndex >= 0 && songIndex < totalSongs)
|
||||||
{
|
{
|
||||||
selectedSong = LanguageSongList[songIndex];
|
selectedSong = LanguageSongList[songIndex];
|
||||||
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].Song + " " + selectedSong.SongFilePathHost1);
|
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].Song + " " + selectedSong.FileName);
|
||||||
|
|
||||||
|
|
||||||
// DisplayActionWithSong(currentPage, songIndex, "點播");
|
// DisplayActionWithSong(currentPage, songIndex, "點播");
|
||||||
@ -1036,7 +1036,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
|
|||||||
if (songIndex < totalSongs)
|
if (songIndex < totalSongs)
|
||||||
{
|
{
|
||||||
selectedSong = LanguageSongList[songIndex];
|
selectedSong = LanguageSongList[songIndex];
|
||||||
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].Song + " " + selectedSong.SongFilePathHost1 );
|
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].Song + " " + selectedSong.FileName );
|
||||||
|
|
||||||
|
|
||||||
// DisplayActionWithSong(currentPage, songIndex, "插播");
|
// DisplayActionWithSong(currentPage, songIndex, "插播");
|
||||||
@ -1120,7 +1120,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
|
|||||||
if (songIndex < totalSongs)
|
if (songIndex < totalSongs)
|
||||||
{
|
{
|
||||||
selectedSong = LanguageSongList[songIndex];
|
selectedSong = LanguageSongList[songIndex];
|
||||||
Console.WriteLine("Adding song to playlist C: " + LanguageSongList[songIndex].Song + " " + selectedSong.SongFilePathHost1);
|
Console.WriteLine("Adding song to playlist C: " + LanguageSongList[songIndex].Song + " " + selectedSong.FileName);
|
||||||
|
|
||||||
|
|
||||||
DisplaySongsWithArrows(currentPage, songIndex);
|
DisplaySongsWithArrows(currentPage, songIndex);
|
||||||
@ -1531,40 +1531,12 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var filePath1 = songData.SongFilePathHost1;
|
//var filePath1 = songData.SongFilePathHost1;
|
||||||
var filePath2 = songData.SongFilePathHost2;
|
//var filePath2 = songData.SongFilePathHost2;
|
||||||
// 之後還要設計成本地的資料夾位置
|
// 之後還要設計成本地的資料夾位置
|
||||||
var filename = songData.FileName;
|
string pathToPlay = songData.FileName;
|
||||||
bool checkpath = false;
|
if (File.Exists(pathToPlay))
|
||||||
string pathToPlay = "";
|
|
||||||
if (File.Exists(filename))
|
|
||||||
{
|
{
|
||||||
pathToPlay = filename;
|
|
||||||
checkpath = true;
|
|
||||||
PrimaryForm.WriteLog(String.Format("{0} Using local file: {1}", songData.Song,filename));
|
|
||||||
}
|
|
||||||
else if (File.Exists(filePath1))
|
|
||||||
{
|
|
||||||
pathToPlay = filePath1;
|
|
||||||
checkpath = true;
|
|
||||||
PrimaryForm.WriteLog(String.Format("{0} Using Host1 file: {1}", songData.Song, filePath1));
|
|
||||||
}
|
|
||||||
else if (File.Exists(filePath2))
|
|
||||||
{
|
|
||||||
pathToPlay = filePath2;
|
|
||||||
checkpath = true;
|
|
||||||
PrimaryForm.WriteLog(String.Format("{0} Using Host2 file: {1}", songData.Song, filePath2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PrimaryForm.WriteLog(String.Format("File not found on hosts: {0}, {1} and {2}", filename, filePath1, filePath2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkpath)
|
|
||||||
{
|
|
||||||
//做判定 決定pathToPlay值
|
|
||||||
//pathToPlay = File.Exists(filePath1) ? filePath1 : filePath2;
|
|
||||||
|
|
||||||
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
|
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
|
||||||
|
|
||||||
PrimaryForm.userRequestedSongs.Add(songData);
|
PrimaryForm.userRequestedSongs.Add(songData);
|
||||||
@ -1599,19 +1571,13 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 從 songData 中取得兩個可能的檔案路徑(主機1與主機2)
|
// 從 songData 中取得兩個可能的檔案路徑(主機1與主機2)
|
||||||
var filePath1 = songData.SongFilePathHost1;
|
var pathToPlay = songData.FileName;
|
||||||
var filePath2 = songData.SongFilePathHost2;
|
|
||||||
|
|
||||||
// 檢查兩個主機上的檔案是否皆不存在
|
// 檢查兩個主機上的檔案是否皆不存在
|
||||||
if (!File.Exists(filePath1) && !File.Exists(filePath2))
|
if (File.Exists(pathToPlay))
|
||||||
{
|
|
||||||
// 若兩個都找不到,寫入 Log 並不加入歌單
|
|
||||||
PrimaryForm.WriteLog(String.Format("File not found on both hosts: {0} and {1}", filePath1, filePath2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// 若其中一個存在,就用第一個存在的那個檔案
|
// 若其中一個存在,就用第一個存在的那個檔案
|
||||||
var pathToPlay = File.Exists(filePath1) ? filePath1 : filePath2;
|
|
||||||
Console.WriteLine("path to play" + pathToPlay);
|
Console.WriteLine("path to play" + pathToPlay);
|
||||||
|
|
||||||
// 檢查目前使用者歌單是否為空
|
// 檢查目前使用者歌單是否為空
|
||||||
|
@ -37,23 +37,16 @@ namespace DualScreenDemo{
|
|||||||
{
|
{
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
string songNumber = reader["song_id"].ToString();
|
|
||||||
string song = reader["song_name"].ToString();
|
|
||||||
string artistA = reader["artistA"].ToString();
|
|
||||||
string artistB = reader["artistB"].ToString();
|
|
||||||
string fileName = reader["song_filename"].ToString();
|
|
||||||
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(
|
searchResults.Add(new SongData(
|
||||||
songNumber, song, artistA, artistB,fileName,
|
reader["song_id"].ToString(),
|
||||||
songFilePathHost1, songFilePathHost2,
|
reader["song_name"].ToString(),
|
||||||
artistASimplified, artistBSimplified,
|
reader["artistA"].ToString(),
|
||||||
songSimplified, humanVoice
|
reader["artistB"].ToString(),
|
||||||
|
reader["song_filename"].ToString(),
|
||||||
|
reader["artistA_simplified"].ToString(),
|
||||||
|
reader["artistB_simplified"].ToString(),
|
||||||
|
reader["song_simplified"].ToString(),
|
||||||
|
Convert.ToInt32(reader["vocal"])
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,6 @@ namespace DualScreenDemo
|
|||||||
public VideoPlayerForm videoPlayerForm;
|
public VideoPlayerForm videoPlayerForm;
|
||||||
public List<SongData> currentSongList;
|
public List<SongData> currentSongList;
|
||||||
public List<Artist> currentArtistList;
|
public List<Artist> currentArtistList;
|
||||||
public List<SongData> publicSongList;
|
|
||||||
public static List<SongData> userRequestedSongs;
|
public static List<SongData> userRequestedSongs;
|
||||||
public static List<SongData> playedSongsHistory;
|
public static List<SongData> playedSongsHistory;
|
||||||
public static List<PlayState> playStates;
|
public static List<PlayState> playStates;
|
||||||
@ -1546,50 +1545,9 @@ namespace DualScreenDemo
|
|||||||
private void LoadSongData()
|
private void LoadSongData()
|
||||||
{
|
{
|
||||||
userRequestedSongs = new List<SongData>();
|
userRequestedSongs = new List<SongData>();
|
||||||
publicSongList = new List<SongData>();
|
|
||||||
playedSongsHistory = new List<SongData>();
|
playedSongsHistory = new List<SongData>();
|
||||||
playStates = new List<PlayState>();
|
playStates = new List<PlayState>();
|
||||||
LoadLocalVideoFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 將原本的本地文件載入邏輯抽取為單獨的方法
|
|
||||||
private void LoadLocalVideoFiles()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string[] videoFiles = Directory.GetFiles(@"D:\video\", "*.mpg");
|
|
||||||
string pattern = @"^(?<songNumber>\d+)-.*?-(?<songName>[^-]+)-";
|
|
||||||
|
|
||||||
foreach (var songPath in videoFiles)
|
|
||||||
{
|
|
||||||
string fileName = Path.GetFileNameWithoutExtension(songPath);
|
|
||||||
Match match = Regex.Match(fileName, pattern);
|
|
||||||
string songNumber = "";
|
|
||||||
string songName = "";
|
|
||||||
if (match.Success){
|
|
||||||
songNumber = match.Groups["songNumber"].Value;
|
|
||||||
songName = match.Groups["songName"].Value;
|
|
||||||
}
|
|
||||||
SongData song = new SongData(
|
|
||||||
songNumber, // songNumber
|
|
||||||
songName, // song
|
|
||||||
"", // artistA
|
|
||||||
"", // artistB
|
|
||||||
"", // filename
|
|
||||||
songPath, // songFilePathHost1
|
|
||||||
"", // songFilePathHost2
|
|
||||||
"", // songFilePathHost3
|
|
||||||
"", // songFilePathHost4
|
|
||||||
"", // songFilePathHost5
|
|
||||||
1 // priority
|
|
||||||
);
|
|
||||||
publicSongList.Add(song);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
MessageBox.Show($"Failed to read video files: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap ResizeImage(Image image, int width, int height)
|
private Bitmap ResizeImage(Image image, int width, int height)
|
||||||
|
21
Program.cs
21
Program.cs
@ -13,6 +13,7 @@ namespace DualScreenDemo
|
|||||||
internal static SerialPortManager serialPortManager;
|
internal static SerialPortManager serialPortManager;
|
||||||
private static PrimaryForm primaryForm; // 儲存實例的參考
|
private static PrimaryForm primaryForm; // 儲存實例的參考
|
||||||
public static string RoomState = Utils.Env.Get("RoomStates", "CLOSE");
|
public static string RoomState = Utils.Env.Get("RoomStates", "CLOSE");
|
||||||
|
public static DataCheck.PublicSongChecker cherker;
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
@ -36,7 +37,7 @@ namespace DualScreenDemo
|
|||||||
|
|
||||||
//Console.WriteLine("正在與中控取得聯繫...");
|
//Console.WriteLine("正在與中控取得聯繫...");
|
||||||
var sender = new heartbeatSender();
|
var sender = new heartbeatSender();
|
||||||
var cherker =new DataCheck.DataChecker();
|
cherker =new DataCheck.PublicSongChecker();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -64,8 +65,8 @@ namespace DualScreenDemo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 啟動服務器
|
// 啟動服務器
|
||||||
|
var TCP = new TCPServer();
|
||||||
Task.Run(() => HttpServerManager.StartServer());
|
Task.Run(() => HttpServerManager.StartServer());
|
||||||
Task.Run(() => TCPServerManager.StartServer());
|
|
||||||
|
|
||||||
// 註冊事件
|
// 註冊事件
|
||||||
Application.ApplicationExit += (sender, e) => SerialPortManager.CloseSerialPortSafely();
|
Application.ApplicationExit += (sender, e) => SerialPortManager.CloseSerialPortSafely();
|
||||||
@ -82,18 +83,6 @@ namespace DualScreenDemo
|
|||||||
// 在完整初始化後檢查狀態
|
// 在完整初始化後檢查狀態
|
||||||
InitializeSecondaryScreen();
|
InitializeSecondaryScreen();
|
||||||
|
|
||||||
WatchDog _watchDog = new WatchDog(
|
|
||||||
() => VideoPlayerForm.Instance.GetCurrentVideoStatus(),
|
|
||||||
() => primaryForm.IsAppResponsive()
|
|
||||||
);
|
|
||||||
_watchDog.Start();
|
|
||||||
Console.WriteLine("啟動WatchDog進行監聽");
|
|
||||||
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
|
|
||||||
{
|
|
||||||
_watchDog.Stop();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
primaryForm.Show();
|
primaryForm.Show();
|
||||||
Application.Run(primaryForm);
|
Application.Run(primaryForm);
|
||||||
|
|
||||||
@ -161,7 +150,7 @@ namespace DualScreenDemo
|
|||||||
primaryForm.videoPlayerForm.Show();
|
primaryForm.videoPlayerForm.Show();
|
||||||
|
|
||||||
// 初始化公共播放列表
|
// 初始化公共播放列表
|
||||||
primaryForm.videoPlayerForm.InitializePublicPlaylist(primaryForm.publicSongList);
|
primaryForm.videoPlayerForm.InitializePublicPlaylist(cherker.GetSongs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,7 +174,7 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
primaryForm.videoPlayerForm = new VideoPlayerForm();
|
primaryForm.videoPlayerForm = new VideoPlayerForm();
|
||||||
// primaryForm.primaryMediaPlayerForm = new PrimaryMediaPlayerForm(primaryForm, primaryForm.secondaryMediaPlayerForm);
|
// primaryForm.primaryMediaPlayerForm = new PrimaryMediaPlayerForm(primaryForm, primaryForm.secondaryMediaPlayerForm);
|
||||||
primaryForm.videoPlayerForm.InitializePublicPlaylist(primaryForm.publicSongList);
|
primaryForm.videoPlayerForm.InitializePublicPlaylist(cherker.GetSongs());
|
||||||
primaryForm.videoPlayerForm.Show();
|
primaryForm.videoPlayerForm.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
84
PublicSongChecker.cs
Normal file
84
PublicSongChecker.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using DBObj;
|
||||||
|
|
||||||
|
namespace DataCheck
|
||||||
|
{
|
||||||
|
public class PublicSongChecker
|
||||||
|
{
|
||||||
|
|
||||||
|
private List<SongData> publicSongList = new();
|
||||||
|
public PublicSongChecker()
|
||||||
|
{
|
||||||
|
string serverPath = Utils.Env.GetPath("video", "");
|
||||||
|
string localPath = @"D:\video";
|
||||||
|
// 加入你要同步的資料夾
|
||||||
|
SyncFolder(serverPath, localPath, "video", new[] { ".mpg" });
|
||||||
|
}
|
||||||
|
public List<SongData> GetSongs()
|
||||||
|
{
|
||||||
|
return publicSongList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncFolder(string serverPath, string localPath, string label, string[] extensions)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath);
|
||||||
|
if (!Directory.Exists(serverPath)) {
|
||||||
|
Console.WriteLine($"找不到伺服器資料夾:{serverPath}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var serverFiles = Directory.GetFiles(serverPath)
|
||||||
|
.Where(f => extensions.Contains(Path.GetExtension(f), StringComparer.OrdinalIgnoreCase))
|
||||||
|
.Select(f => new FileInfo(f))
|
||||||
|
.ToDictionary(f => f.Name, f => f);
|
||||||
|
|
||||||
|
var localFiles = Directory.GetFiles(localPath)
|
||||||
|
.Where(f => extensions.Contains(Path.GetExtension(f), StringComparer.OrdinalIgnoreCase))
|
||||||
|
.Select(f => new FileInfo(f))
|
||||||
|
.ToDictionary(f => f.Name, f => f);
|
||||||
|
|
||||||
|
// 1. 複製或更新檔案
|
||||||
|
foreach (var serverFile in serverFiles) {
|
||||||
|
string dest = Path.Combine(localPath, serverFile.Key);
|
||||||
|
bool needsCopy = !localFiles.ContainsKey(serverFile.Key) ||
|
||||||
|
serverFile.Value.LastWriteTime > localFiles[serverFile.Key].LastWriteTime;
|
||||||
|
if (needsCopy) {
|
||||||
|
try {
|
||||||
|
File.Copy(serverFile.Value.FullName, dest, true);
|
||||||
|
Console.WriteLine($"✅ 更新 {label}: {serverFile.Key}");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine($"❌ 複製 {label} 失敗 {serverFile.Key}: {ex.Message}");
|
||||||
|
continue; // 如果複製失敗就不加入 SongData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string fileName = Path.GetFileNameWithoutExtension(serverFile.Key);
|
||||||
|
Match match = Regex.Match(fileName, @"^(?<songNumber>\d+)-.*?-(?<songName>[^-]+)-");
|
||||||
|
if (match.Success) {
|
||||||
|
publicSongList.Add(new SongData(
|
||||||
|
match.Groups["songNumber"].Value, // songNumber
|
||||||
|
match.Groups["songName"].Value, // song
|
||||||
|
Path.Combine(localPath, serverFile.Key), // songFilePathHost1
|
||||||
|
1 // priority
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 刪除多餘的本地檔案
|
||||||
|
foreach (var localFile in localFiles) {
|
||||||
|
if (!serverFiles.ContainsKey(localFile.Key)) {
|
||||||
|
try {
|
||||||
|
File.Delete(localFile.Value.FullName);
|
||||||
|
Console.WriteLine($"刪除多餘{label}: {localFile.Key}");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine($"刪除{label}失敗 {localFile.Key}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,8 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
listener = new TcpListener(IPAddress.Any, Port);
|
listener = new TcpListener(IPAddress.Any, Port);
|
||||||
hostNameSuffix = GetHostNameSuffix();
|
hostNameSuffix = GetHostNameSuffix();
|
||||||
|
|
||||||
|
_ = Task.Run(() => Start());
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsFormReady(Form form)
|
private bool IsFormReady(Form form)
|
||||||
@ -136,11 +138,7 @@ namespace DualScreenDemo
|
|||||||
string closePath = @"D:\video\CLOSE.MPG";
|
string closePath = @"D:\video\CLOSE.MPG";
|
||||||
if (File.Exists(closePath))
|
if (File.Exists(closePath))
|
||||||
{
|
{
|
||||||
SongData closeSong = new SongData(
|
SongData closeSong = new SongData("0", "結束播放",closePath, 1);
|
||||||
"0", "結束播放", "", "", "",
|
|
||||||
closePath, "", "", "", "",
|
|
||||||
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>();
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
namespace DualScreenDemo
|
|
||||||
{
|
|
||||||
public static class TCPServerManager
|
|
||||||
{
|
|
||||||
public static void StartServer()
|
|
||||||
{
|
|
||||||
TCPServer server = new TCPServer();
|
|
||||||
server.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -612,8 +612,7 @@ namespace DualScreenDemo
|
|||||||
if (File.Exists(welcomePath))
|
if (File.Exists(welcomePath))
|
||||||
{
|
{
|
||||||
publicPlaylist.Add(new SongData(
|
publicPlaylist.Add(new SongData(
|
||||||
"0", "歡迎光臨", "", "", "", welcomePath,
|
"0", "歡迎光臨", welcomePath, 1
|
||||||
"", "", "", "", 1
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,8 +623,7 @@ namespace DualScreenDemo
|
|||||||
if (File.Exists(bgmPath))
|
if (File.Exists(bgmPath))
|
||||||
{
|
{
|
||||||
publicPlaylist.Add(new SongData(
|
publicPlaylist.Add(new SongData(
|
||||||
i.ToString(), $"背景音樂{i:D2}",
|
i.ToString(), $"背景音樂{i:D2}", bgmPath, 1
|
||||||
"", "", "", bgmPath, "", "", "", "", 1
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,11 +636,7 @@ namespace DualScreenDemo
|
|||||||
foreach (var songPath in videoFiles)
|
foreach (var songPath in videoFiles)
|
||||||
{
|
{
|
||||||
string fileName = Path.GetFileNameWithoutExtension(songPath);
|
string fileName = Path.GetFileNameWithoutExtension(songPath);
|
||||||
publicPlaylist.Add(new SongData(
|
publicPlaylist.Add(new SongData("0", fileName,songPath,1));
|
||||||
"0", fileName, "", "", "",
|
|
||||||
songPath, "", "", "", "",
|
|
||||||
1
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,7 +763,7 @@ namespace DualScreenDemo
|
|||||||
var songToPlay = currentPlaylist[currentSongIndex];
|
var songToPlay = currentPlaylist[currentSongIndex];
|
||||||
|
|
||||||
// pathToPlay 需要調整
|
// pathToPlay 需要調整
|
||||||
var pathToPlay = File.Exists(songToPlay.SongFilePathHost1) ? songToPlay.SongFilePathHost1 : songToPlay.SongFilePathHost2;
|
var pathToPlay = songToPlay.FileName;
|
||||||
|
|
||||||
// 若兩個 host 上都找不到檔案就直接結束
|
// 若兩個 host 上都找不到檔案就直接結束
|
||||||
if (!File.Exists(pathToPlay))
|
if (!File.Exists(pathToPlay))
|
||||||
@ -966,9 +960,7 @@ namespace DualScreenDemo
|
|||||||
string welcomePath = @"D:\video\welcome.mpg";
|
string welcomePath = @"D:\video\welcome.mpg";
|
||||||
if (File.Exists(welcomePath))
|
if (File.Exists(welcomePath))
|
||||||
{
|
{
|
||||||
publicPlaylist.Add(new SongData(
|
publicPlaylist.Add(new SongData("0", "歡迎光臨", welcomePath, 1));
|
||||||
"0", "歡迎光臨", "", "", "", welcomePath, "", "", "", "", 1
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加 BGM 序列
|
// 添加 BGM 序列
|
||||||
@ -977,10 +969,7 @@ namespace DualScreenDemo
|
|||||||
string bgmPath = $@"D:\video\BGM{i:D2}.mpg";
|
string bgmPath = $@"D:\video\BGM{i:D2}.mpg";
|
||||||
if (File.Exists(bgmPath))
|
if (File.Exists(bgmPath))
|
||||||
{
|
{
|
||||||
publicPlaylist.Add(new SongData(
|
publicPlaylist.Add(new SongData(i.ToString(), $"背景音樂{i:D2}", bgmPath, 1));
|
||||||
i.ToString(), $"背景音樂{i:D2}", "", "", "", bgmPath,
|
|
||||||
"", "", "", "", 1
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,7 +989,7 @@ namespace DualScreenDemo
|
|||||||
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
|
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
|
||||||
if (!currentPlaylist.Any()) return;
|
if (!currentPlaylist.Any()) return;
|
||||||
var songToPlay = currentPlaylist[currentSongIndex];
|
var songToPlay = currentPlaylist[currentSongIndex];
|
||||||
var pathToPlay = File.Exists(songToPlay.SongFilePathHost1) ? songToPlay.SongFilePathHost1 : songToPlay.SongFilePathHost2;
|
var pathToPlay = songToPlay.FileName;
|
||||||
if (!File.Exists(pathToPlay))
|
if (!File.Exists(pathToPlay))
|
||||||
{
|
{
|
||||||
MessageBox.Show("File does not exist on both hosts.");
|
MessageBox.Show("File does not exist on both hosts.");
|
||||||
@ -1570,9 +1559,7 @@ namespace DualScreenDemo
|
|||||||
if (audioTrack1 == -1)
|
if (audioTrack1 == -1)
|
||||||
{
|
{
|
||||||
audioTrack1 = i;
|
audioTrack1 = i;
|
||||||
}
|
} else if (audioTrack2 == -1) {
|
||||||
else if (audioTrack2 == -1)
|
|
||||||
{
|
|
||||||
audioTrack2 = i;
|
audioTrack2 = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1663,19 +1650,8 @@ namespace DualScreenDemo
|
|||||||
|
|
||||||
public void AddSongToPlaylist(SongData songData)
|
public void AddSongToPlaylist(SongData songData)
|
||||||
{
|
{
|
||||||
try
|
try{
|
||||||
{
|
|
||||||
var filePath1 = songData.SongFilePathHost1;
|
|
||||||
var filePath2 = songData.SongFilePathHost2;
|
|
||||||
|
|
||||||
if (!File.Exists(filePath1) && !File.Exists(filePath2))
|
|
||||||
{
|
|
||||||
PrimaryForm.WriteLog(String.Format("File not found on both hosts: {0} and {1}", filePath1, filePath2));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
|
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
|
||||||
|
|
||||||
// 查找所有相同歌曲的索引
|
// 查找所有相同歌曲的索引
|
||||||
var sameNameIndices = new List<int>();
|
var sameNameIndices = new List<int>();
|
||||||
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
|
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
|
||||||
@ -1745,19 +1721,8 @@ namespace DualScreenDemo
|
|||||||
|
|
||||||
public void InsertSongToPlaylist(SongData songData)
|
public void InsertSongToPlaylist(SongData songData)
|
||||||
{
|
{
|
||||||
try
|
try{
|
||||||
{
|
|
||||||
var filePath1 = songData.SongFilePathHost1;
|
|
||||||
var filePath2 = songData.SongFilePathHost2;
|
|
||||||
|
|
||||||
if (!File.Exists(filePath1) && !File.Exists(filePath2))
|
|
||||||
{
|
|
||||||
PrimaryForm.WriteLog(String.Format("File not found on both hosts: {0} and {1}", filePath1, filePath2));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
|
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
|
||||||
|
|
||||||
// 查找所有相同歌曲的索引
|
// 查找所有相同歌曲的索引
|
||||||
var sameNameIndices = new List<int>();
|
var sameNameIndices = new List<int>();
|
||||||
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
|
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
|
||||||
|
84
WatchDog.cs
84
WatchDog.cs
@ -1,84 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using DualScreenDemo.Shared;
|
|
||||||
public class WatchDog
|
|
||||||
{
|
|
||||||
|
|
||||||
private Func<VideoStatus> getVideoStatus;
|
|
||||||
private Func<bool> isApplicationResponsive;
|
|
||||||
private Thread watchdogThread;
|
|
||||||
private bool running = false;
|
|
||||||
private double lastPosition = -1;
|
|
||||||
private int freezeCounter = 0;
|
|
||||||
|
|
||||||
public WatchDog(Func<VideoStatus> getVideoPositionFunc, Func<bool> isAppResponsiveFunc)
|
|
||||||
{
|
|
||||||
getVideoStatus = getVideoPositionFunc;
|
|
||||||
isApplicationResponsive = isAppResponsiveFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
running = true;
|
|
||||||
watchdogThread = new Thread(Run);
|
|
||||||
watchdogThread.IsBackground = true;
|
|
||||||
watchdogThread.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
running = false;
|
|
||||||
watchdogThread?.Join();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Run()
|
|
||||||
{
|
|
||||||
while (running)
|
|
||||||
{
|
|
||||||
var status = getVideoStatus(); // 改用 getVideoStatus 取得完整狀態
|
|
||||||
bool responsive = isApplicationResponsive();
|
|
||||||
|
|
||||||
if (!status.IsGraphOk)
|
|
||||||
{
|
|
||||||
Log($"影片圖表異常: {status.LastError}");
|
|
||||||
}
|
|
||||||
else if(status.PlayState != "Paused")
|
|
||||||
{
|
|
||||||
double currentPosition = status.PositionSeconds;
|
|
||||||
|
|
||||||
if (Math.Abs(currentPosition - lastPosition) < 0.001)
|
|
||||||
{
|
|
||||||
freezeCounter++;
|
|
||||||
if (freezeCounter >= 3)
|
|
||||||
{
|
|
||||||
Log($"影片疑似卡死(3次位置沒變):位置={currentPosition:F2}秒,播放狀態={status.PlayState}");
|
|
||||||
freezeCounter = 0; // 記得 reset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
freezeCounter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPosition = currentPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!responsive)
|
|
||||||
{
|
|
||||||
Log("UI 疑似卡死(Invoke 失敗)");
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void Log(string message)
|
|
||||||
{
|
|
||||||
string logFilePath = Path.Combine("txt", "watchdog_log.txt");
|
|
||||||
File.AppendAllText(logFilePath, $"{DateTime.Now}: {message}{Environment.NewLine}");
|
|
||||||
}
|
|
||||||
}
|
|
@ -71,11 +71,6 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- 複製資料夾 foods -->
|
|
||||||
<Content Include="foods\**\*.*">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
|
|
||||||
<!-- 複製資料夾 db -->
|
<!-- 複製資料夾 db -->
|
||||||
<Content Include="db\**\*.*">
|
<Content Include="db\**\*.*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@ -90,11 +85,6 @@
|
|||||||
<Content Include="themes\**\*.*">
|
<Content Include="themes\**\*.*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<!-- 複製資料夾 news -->
|
|
||||||
<Content Include="news\**\*.*">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
|
|
||||||
<!-- 複製資料夾 sounds -->
|
<!-- 複製資料夾 sounds -->
|
||||||
<Content Include="sounds\**\*.*">
|
<Content Include="sounds\**\*.*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user