調整 video 開啓先比對
新增 env 多個遠端路徑 新増 env 能比對檔案路徑 20250704
This commit is contained in:
parent
d041ff1f80
commit
8f456c347d
80
DataCheck.cs
Normal file
80
DataCheck.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
Env.cs
105
Env.cs
@ -6,56 +6,87 @@ namespace Utils
|
|||||||
{
|
{
|
||||||
public static class Env
|
public static class Env
|
||||||
{
|
{
|
||||||
public static readonly string KtvPath = @"\\pc101\KTVData";
|
private static string KtvPath = "";
|
||||||
private static readonly Dictionary<string, string> _values;
|
private static readonly List<string> KtvPaths = new()
|
||||||
|
{
|
||||||
|
@"\\sshost\KTVSuperstar",
|
||||||
|
@"\\pc101\KTVSuperstar"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> _values = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
static Env()
|
static Env()
|
||||||
{
|
{
|
||||||
var path = Path.Combine(KtvPath, "config.ini");
|
foreach (var path in KtvPaths)
|
||||||
_values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine($"❌ 找不到環境檔案:{path}");
|
var configPath = Path.Combine(path, "config.ini");
|
||||||
return;
|
|
||||||
|
if (File.Exists(configPath))
|
||||||
|
{
|
||||||
|
KtvPath = path;
|
||||||
|
Console.WriteLine("✅ 找到設定檔:" + configPath);
|
||||||
|
|
||||||
|
foreach (var line in File.ReadAllLines(configPath))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return; // 找到一份 config 就跳出
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var line in File.ReadAllLines(path))
|
Console.WriteLine("❌ 所有指定目錄都找不到 config.ini");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Get(string key, string fallback = "") =>
|
||||||
|
_values.TryGetValue(key, out var value) ? value : fallback;
|
||||||
|
|
||||||
|
public static bool GetBool(string key, bool fallback = false) =>
|
||||||
|
_values.TryGetValue(key, out var value) && bool.TryParse(value, out var result)
|
||||||
|
? result : fallback;
|
||||||
|
|
||||||
|
public static int GetInt(string key, int fallback = 0) =>
|
||||||
|
_values.TryGetValue(key, out var value) && int.TryParse(value, out var result)
|
||||||
|
? result : fallback;
|
||||||
|
|
||||||
|
public static string GetPath(string key, string fallback = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(KtvPath))
|
||||||
{
|
{
|
||||||
var trimmed = line.Trim();
|
Console.WriteLine("⚠️ KtvPath 尚未設定,將使用 fallback。");
|
||||||
if (string.IsNullOrWhiteSpace(trimmed) || trimmed.StartsWith("#")) continue;
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
var index = trimmed.IndexOf('=');
|
var path = Path.Combine(KtvPath, key);
|
||||||
if (index < 0) continue;
|
|
||||||
|
|
||||||
var key = trimmed[..index].Trim();
|
if (Directory.Exists(path))
|
||||||
var value = trimmed[(index + 1)..].Trim();
|
{
|
||||||
|
return path;
|
||||||
if (value.StartsWith("\"") && value.EndsWith("\""))
|
}
|
||||||
value = value[1..^1]; // 去除引號
|
else
|
||||||
|
{
|
||||||
_values[key] = value;
|
Console.WriteLine($"⚠️ 找不到目錄:{path},使用 fallback:{fallback}");
|
||||||
|
return fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static string GetDBConnection()
|
||||||
public static string Get(string key, string fallback = "")
|
|
||||||
{
|
{
|
||||||
return _values.TryGetValue(key, out var value) ? value : fallback;
|
return $"Server={Get("DBServer", "localhost")};Port={Get("DBPort", "3306")};Database={Get("Database", "test")};User={Get("DBUser", "root")};Password={Get("DBPassword", "")};";
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
// 如需支援更多型別可自行擴充:GetFloat, GetDouble, GetDateTime 等
|
||||||
{
|
|
||||||
return _values.TryGetValue(key, out var value) && int.TryParse(value, out var result)
|
|
||||||
? result
|
|
||||||
: fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 可加上 GetFloat、GetDouble、GetTimeSpan ... 視需要
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,9 @@ namespace DualScreenDemo
|
|||||||
private List<Image> LoadImagesFromFolder(string folderName)
|
private List<Image> LoadImagesFromFolder(string folderName)
|
||||||
{
|
{
|
||||||
List<Image> images = new();
|
List<Image> images = new();
|
||||||
string folderPath = Path.Combine(Utils.Env.KtvPath, folderName);
|
string folderPath = Utils.Env.GetPath(folderName, "");
|
||||||
|
|
||||||
if (!Directory.Exists(folderPath))
|
if (folderPath.Equals("")) return images;
|
||||||
{
|
|
||||||
Console.WriteLine($" 找不到遠端資料夾:{folderPath}");
|
|
||||||
return images;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] imageFiles = Directory.GetFiles(folderPath, "*.jpg");
|
string[] imageFiles = Directory.GetFiles(folderPath, "*.jpg");
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ namespace DualScreenDemo{
|
|||||||
|
|
||||||
private static string GetConnectionString()
|
private static string GetConnectionString()
|
||||||
{
|
{
|
||||||
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", "")};";
|
return Utils.Env.GetDBConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isLoggedIn = false;
|
public bool isLoggedIn = false;
|
||||||
|
@ -1549,92 +1549,7 @@ namespace DualScreenDemo
|
|||||||
publicSongList = new List<SongData>();
|
publicSongList = new List<SongData>();
|
||||||
playedSongsHistory = new List<SongData>();
|
playedSongsHistory = new List<SongData>();
|
||||||
playStates = new List<PlayState>();
|
playStates = new List<PlayState>();
|
||||||
|
LoadLocalVideoFiles();
|
||||||
try
|
|
||||||
{
|
|
||||||
// 1. 檢查是否能連接到 SVR01
|
|
||||||
string serverVideoPath = Path.Combine(Utils.Env.KtvPath, "video");
|
|
||||||
|
|
||||||
string localVideoPath = @"D:\video";
|
|
||||||
|
|
||||||
if (!Directory.Exists(serverVideoPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine("未連接到 SVR,使用本地影片");
|
|
||||||
LoadLocalVideoFiles();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 確認本地文件夾是否存在(不存在則創立)
|
|
||||||
if (!Directory.Exists(localVideoPath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(localVideoPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 獲取服務器和本地的所有文件
|
|
||||||
var serverFiles = Directory.GetFiles(serverVideoPath, "*.mpg")
|
|
||||||
.Select(f => new FileInfo(f))
|
|
||||||
.ToDictionary(f => f.Name, f => f);
|
|
||||||
|
|
||||||
var localFiles = Directory.GetFiles(localVideoPath, "*.mpg")
|
|
||||||
.Select(f => new FileInfo(f))
|
|
||||||
.ToDictionary(f => f.Name, f => f);
|
|
||||||
|
|
||||||
// 3-1. 檢查並更新文件
|
|
||||||
foreach (var serverFile in serverFiles)
|
|
||||||
{
|
|
||||||
bool needsCopy = false;
|
|
||||||
string localFilePath = Path.Combine(localVideoPath, 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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 4. 載入更新後的本地文件
|
|
||||||
LoadLocalVideoFiles();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"更新影片失敗:{ex.Message}");
|
|
||||||
LoadLocalVideoFiles(); // 出錯時使用本地文件
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 將原本的本地文件載入邏輯抽取為單獨的方法
|
// 將原本的本地文件載入邏輯抽取為單獨的方法
|
||||||
@ -1642,74 +1557,33 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string videoDirectory = @"D:\video\";
|
string[] videoFiles = Directory.GetFiles(@"D:\video\", "*.mpg");
|
||||||
string[] videoFiles = Directory.GetFiles(videoDirectory, "*.mpg");
|
|
||||||
string pattern = @"^(?<songNumber>\d+)-.*?-(?<songName>[^-]+)-";
|
string pattern = @"^(?<songNumber>\d+)-.*?-(?<songName>[^-]+)-";
|
||||||
|
|
||||||
foreach (var songPath in videoFiles)
|
foreach (var songPath in videoFiles)
|
||||||
{
|
{
|
||||||
string fileName = Path.GetFileNameWithoutExtension(songPath);
|
string fileName = Path.GetFileNameWithoutExtension(songPath);
|
||||||
Match match = Regex.Match(fileName, pattern);
|
Match match = Regex.Match(fileName, pattern);
|
||||||
|
string songNumber = "";
|
||||||
if (match.Success)
|
string songName = "";
|
||||||
{
|
if (match.Success){
|
||||||
string songNumber = match.Groups["songNumber"].Value;
|
songNumber = match.Groups["songNumber"].Value;
|
||||||
string songName = match.Groups["songName"].Value;
|
songName = match.Groups["songName"].Value;
|
||||||
|
|
||||||
SongData song = new SongData(
|
|
||||||
songNumber, // songNumber
|
|
||||||
//"", // songNumberB
|
|
||||||
songName, // song
|
|
||||||
//0, // songLength
|
|
||||||
"", // artistA
|
|
||||||
"", // artistB
|
|
||||||
"", // filename
|
|
||||||
//"", // category
|
|
||||||
//DateTime.Now, // dateAdded
|
|
||||||
songPath, // songFilePathHost1
|
|
||||||
"", // songFilePathHost2
|
|
||||||
"", // songFilePathHost3
|
|
||||||
"", // songFilePathHost4
|
|
||||||
"", // songFilePathHost5
|
|
||||||
//"", // songFilePathHost6
|
|
||||||
//"", // songFilePathHost7
|
|
||||||
//"", // songFilePathHost8
|
|
||||||
//"", // songFilePathHost9
|
|
||||||
//"", // songFilePathHost10
|
|
||||||
//"", // humanVoice
|
|
||||||
//"", // songType
|
|
||||||
1 // priority
|
|
||||||
);
|
|
||||||
publicSongList.Add(song);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SongData song = new SongData(
|
|
||||||
"", // songNumber
|
|
||||||
//"", // songNumberB
|
|
||||||
"", // song
|
|
||||||
//0, // songLength
|
|
||||||
"", // artistA
|
|
||||||
"", // artistB
|
|
||||||
"", // filename
|
|
||||||
//"", // category
|
|
||||||
//DateTime.Now, // dateAdded
|
|
||||||
songPath, // songFilePathHost1
|
|
||||||
"", // songFilePathHost2
|
|
||||||
"", // songFilePathHost3
|
|
||||||
"", // songFilePathHost4
|
|
||||||
"", // songFilePathHost5
|
|
||||||
//"", // songFilePathHost6
|
|
||||||
//"", // songFilePathHost7
|
|
||||||
//"", // songFilePathHost8
|
|
||||||
//"", // songFilePathHost9
|
|
||||||
//"", // songFilePathHost10
|
|
||||||
//"", // humanVoice
|
|
||||||
//"", // songType
|
|
||||||
1 // priority
|
|
||||||
);
|
|
||||||
publicSongList.Add(song);
|
|
||||||
}
|
}
|
||||||
|
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)
|
catch (Exception ex)
|
||||||
|
@ -36,6 +36,7 @@ namespace DualScreenDemo
|
|||||||
|
|
||||||
//Console.WriteLine("正在與中控取得聯繫...");
|
//Console.WriteLine("正在與中控取得聯繫...");
|
||||||
var sender = new heartbeatSender();
|
var sender = new heartbeatSender();
|
||||||
|
var cherker =new DataCheck.DataChecker();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -80,7 +81,7 @@ namespace DualScreenDemo
|
|||||||
|
|
||||||
// 在完整初始化後檢查狀態
|
// 在完整初始化後檢查狀態
|
||||||
InitializeSecondaryScreen();
|
InitializeSecondaryScreen();
|
||||||
|
|
||||||
WatchDog _watchDog = new WatchDog(
|
WatchDog _watchDog = new WatchDog(
|
||||||
() => VideoPlayerForm.Instance.GetCurrentVideoStatus(),
|
() => VideoPlayerForm.Instance.GetCurrentVideoStatus(),
|
||||||
() => primaryForm.IsAppResponsive()
|
() => primaryForm.IsAppResponsive()
|
||||||
@ -91,7 +92,7 @@ namespace DualScreenDemo
|
|||||||
{
|
{
|
||||||
_watchDog.Stop();
|
_watchDog.Stop();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
primaryForm.Show();
|
primaryForm.Show();
|
||||||
Application.Run(primaryForm);
|
Application.Run(primaryForm);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user