調整 DB 物件

調整 Room states 改讀DB
修正 字體統一 20
20250728
This commit is contained in:
jasonchenwork 2025-07-28 16:22:24 +08:00
parent 36ab52bac1
commit 4808f02501
10 changed files with 258 additions and 106 deletions

View File

@ -16,9 +16,9 @@ namespace DualScreenDemo
private int _wrongInputCountfor62 = 0; // 錯誤輸入計數器
private int _wrongInputCountfor61 = 0; // 錯誤輸入計數器
private const int MaxWrongLimit = 3; // 錯誤輸入限制次數
private readonly SongListManager songListManager;
private readonly SQLManager songListManager;
public CommandHandler(SongListManager songListManager)
public CommandHandler(SQLManager songListManager)
{
this.songListManager = songListManager;
}

View File

@ -6,27 +6,35 @@ namespace DBObj
{
public class MyDB : IDisposable
{
private readonly string connectionString = Utils.Env.GetDBConnection();
private MySqlConnection conn;
private DataTable table = new DataTable();
private int cursor = 0;
public MyDB()
{
conn = new MySqlConnection(connectionString);
conn.Open();
Console.WriteLine("MyDB 連線成功!");
//Console.WriteLine("MyDB 連線成功!");
}
public void Dispose()
{
if (conn != null)
{
conn.Close();
Console.WriteLine("MyDB 連線已關閉!");
conn.Dispose(); // 包含 Close + 資源釋放
conn = null;
//Console.WriteLine("MyDB 連線已釋放!");
}
}
// SELECT 方法
public DataTable Select(string query, MySqlParameter[] parameters)
public bool open(string query, MySqlParameter[] parameters, bool showError = true)
{
table.Clear();
cursor = 0;
try
{
using (var cmd = new MySqlCommand(query, conn))
{
@ -36,12 +44,128 @@ namespace DBObj
}
using (var adapter = new MySqlDataAdapter(cmd))
{
DataTable result = new DataTable();
adapter.Fill(result);
return result;
adapter.Fill(table);
}
}
}
catch (Exception ex)
{
if (showError)
Console.WriteLine($"DB Error: {ex.Message}");
return false;
}
return true;
}
public T Field<T>(string name)
{
if (cursor < 0 || cursor >= table.Rows.Count || !table.Columns.Contains(name))
return default;
object value = table.Rows[cursor][name];
if (value == DBNull.Value)
return default;
return (T)Convert.ChangeType(value, typeof(T));
}
public List<T> ToList<T>() where T : new()
{
var list = new List<T>();
foreach (DataRow row in table.Rows)
{
T obj = new T();
foreach (DataColumn col in table.Columns)
{
var prop = typeof(T).GetProperty(col.ColumnName,
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.IgnoreCase);
if (prop != null && prop.CanWrite)
{
object value = row[col];
if (value == DBNull.Value)
{
value = null;
}
try
{
if (value != null && prop.PropertyType != value.GetType())
{
value = Convert.ChangeType(value, prop.PropertyType);
}
prop.SetValue(obj, value);
}
catch
{
// 可以視情況加入錯誤處理
}
}
}
list.Add(obj);
}
return list;
}
public Dictionary<string, object> CurrentRowAsDictionary()
{
if (cursor < 0 || cursor >= table.Rows.Count)
return null;
var dict = new Dictionary<string, object>();
foreach (DataColumn col in table.Columns)
{
dict[col.ColumnName] = table.Rows[cursor][col];
}
return dict;
}
public void moveNext()
{
cursor++;
}
public void movePrevious()
{
cursor--;
}
public void move(int index)
{
cursor = index;
}
public void moveFirst()
{
cursor = 0;
}
public void moveEnd()
{
cursor = table.Rows.Count - 1;
}
public bool bof()
{
return (cursor < 0) || (table.Rows.Count == 0);
}
public bool eof()
{
return cursor > table.Rows.Count - 1;
}
public bool Read()
{
if (eof()) return false;
moveNext();
return !eof();
}
public int recordCount()
{
return table.Rows.Count;
}
public bool found()
{
return table.Rows.Count > 0;
}
public void clear()
{
table.Clear();
}
// INSERT / UPDATE / DELETE 方法
public int ExecuteNonQuery(string query, MySqlParameter[] parameters)
@ -55,5 +179,12 @@ namespace DBObj
return cmd.ExecuteNonQuery();
}
}
public long LastInsertId()
{
using (var cmd = new MySqlCommand("SELECT LAST_INSERT_ID()", conn))
{
return Convert.ToInt64(cmd.ExecuteScalar());
}
}
}
}

View File

@ -2,13 +2,13 @@ using System.Data;
using DualScreenDemo;
namespace DBObj
{
public class SongListManager
public class SQLManager
{
private MyDB db = new MyDB();
public List<SongData> FavoriteSongs { get; private set; }
//public bool IsUserLoggedIn { get; set; }
//public string UserPhoneNumber { get; set; }
public SongListManager()
public SQLManager()
{
FavoriteSongs = new List<SongData>();
}
@ -52,53 +52,55 @@ namespace DBObj
}
}
*/
public List<SongData> SearchNewSongs(){
public List<SongData> SearchNewSongs()
{
string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY add_date DESC LIMIT {Utils.Env.GetInt("NewSongLimit", 100)};";
return PrimaryForm.Instance.SearchSongs_Mysql(query);
return select_Mysql(query);
}
public List<SongData> SearchHotSongs(){
string query= $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY song_counts DESC LIMIT {Utils.Env.GetInt("HotSongLimit", 100)};";
return PrimaryForm.Instance.SearchSongs_Mysql(query);
return select_Mysql(query);
}
public List<SongData> SearchSongsBySinger(string keyword)
{
Console.WriteLine("keyword : " + keyword);
var keywordLower = keyword.ToLower();
string query = $"SELECT * FROM song_library_cache WHERE artistA LIKE '%{keywordLower}%' OR artistB LIKE'%{keywordLower}%'ORDER BY song_counts DESC;";
return PrimaryForm.Instance.SearchSongs_Mysql(query);
return select_Mysql(query);
}
public List<SongData> SearchSongsByName(string keyword)
{
string query = $"SELECT * FROM song_library_cache WHERE LOWER(song_name) LIKE CONCAT('%', LOWER('{keyword}'), '%');";
return PrimaryForm.Instance.SearchSongs_Mysql(query);
return select_Mysql(query);
}
public SongData SearchSongByNumber(string songNumber)
{
string query = $"SELECT * FROM song_library_cache WHERE song_id = '{songNumber}';";
var searchResults =PrimaryForm.Instance.SearchSongs_Mysql(query);
var searchResults =select_Mysql(query);
return searchResults.FirstOrDefault();
}
private List<SongData> select_Mysql(string query)
{
List<SongData> searchResults = new List<SongData>();
Console.WriteLine(query);
using (db)
{
DataTable result = db.Select(query, null);
foreach (DataRow row in result.Rows)
using (var db = new MyDB())
{
if (db.open(query, null)) {
while (db.Read()){
searchResults.Add(new SongData(
row["song_id"].ToString(),
row["song_name"].ToString(),
row["artistA"].ToString(),
row["artistB"].ToString(),
row["song_filename"].ToString(),
row["artistA_simplified"].ToString(),
row["artistB_simplified"].ToString(),
row["song_simplified"].ToString(),
Convert.ToInt32(row["vocal"])
db.Field<string>("song_id"),
db.Field<string>("song_name"),
db.Field<string>("artistA"),
db.Field<string>("artistB"),
db.Field<string>("song_filename"),
db.Field<string>("artistA_simplified"),
db.Field<string>("artistB_simplified"),
db.Field<string>("song_simplified"),
db.Field<int>("vocal")
));
}
}
Console.WriteLine($"查詢到 {searchResults.Count} 筆資料。");
}

View File

@ -44,9 +44,9 @@ namespace DBObj
}
private static SongData NextPublicSong()
{
if (Room.IsClose()) {
if (Program.room.IsClose()) {
publicPlaying = close;
} else if(Room.IsOpen() && isWelcome){
} else if(Program.room.IsOpen() && isWelcome){
isWelcome = false;
publicPlaying = welcome;
} else {

View File

@ -19,7 +19,7 @@ namespace DualScreenDemo
private static string _localIP = GetLocalIPAddress();
private static int _port = 9090; // 或其他方式設置
// 服务器类变量
private static SongListManager songListManager;
private static SQLManager songListManager;
// 使用完整命名空间来避免歧义
public static event ActionString OnDisplayBarrage;
private static DateTime lastClickTime = DateTime.MinValue;
@ -35,7 +35,7 @@ namespace DualScreenDemo
private static TaskCompletionSource<string> _qrReadyTcs;
public static async Task StartServer(string baseDirectory, int port, SongListManager manager, CancellationToken token)
public static async Task StartServer(string baseDirectory, int port, SQLManager manager, CancellationToken token)
{
songListManager = manager;
string randomFolderName = CreateRandomFolderAndRedirectHTML(baseDirectory);

View File

@ -264,26 +264,10 @@ namespace DualScreenDemo
artist.Name;
artistLabel.Text = artistText;
artistLabel.Tag = artist;
artistLabel.AutoSize = false;
artistLabel.AutoSize = true;
// 計算文字寬度
Font normalFont = new Font("微軟正黑體", 24, FontStyle.Bold);
Font mediumFont = new Font("微軟正黑體", 18, FontStyle.Bold);
Font smallFont = new Font("微軟正黑體", 14, FontStyle.Bold);
// 根據文字長度設置字體大小
if (artistLabel.Text.Length > 18)
{
artistLabel.Font = smallFont;
}
else if (artistLabel.Text.Length > 13)
{
artistLabel.Font = mediumFont;
}
else
{
artistLabel.Font = normalFont;
}
artistLabel.Font = new Font("微軟正黑體", 20, FontStyle.Bold);
Screen screen = Screen.PrimaryScreen;
int screenWidth = screen.Bounds.Width;
int screenHeight = screen.Bounds.Height;
@ -400,25 +384,10 @@ namespace DualScreenDemo
int textLength = fullText.Length;
// 計算文字寬度
Font normalFont = new Font("微軟正黑體", 20, FontStyle.Bold);
Font mediumFont = new Font("微軟正黑體", 14, FontStyle.Bold);
Font smallFont = new Font("微軟正黑體", 12, FontStyle.Bold);
// 根據文字長度設置字體大小
if (textLength > 18)
{
songLabel.Font = smallFont;
}
else if (textLength > 8)
{
songLabel.Font = mediumFont;
}
else
{
songLabel.Font = normalFont;
}
songLabel.Font = new Font("微軟正黑體", 20, FontStyle.Bold);
songLabel.Text = fullText;
songLabel.Tag = song;
songLabel.AutoSize = false;
songLabel.AutoSize = true;
// 創建歌手標籤
Label artistLabel = new Label();
artistLabel.Text = artistText;
@ -457,7 +426,7 @@ namespace DualScreenDemo
{
Image = Image.FromFile(Path.Combine(Application.StartupPath, @"themes\superstar\其他符號_人聲\其他符號_人聲.png")),
SizeMode = PictureBoxSizeMode.Zoom,
Size = new Size(32, 32),
Size = new Size(30, 30),
Location = new Point(songX + 5, y + 8)
};
this.Controls.Add(icon);

View File

@ -2235,7 +2235,7 @@ namespace DualScreenDemo
{
HotPlayButton_Click(null, EventArgs.Empty);
}
if (Room.IsClose())
if (Program.room.IsClose())
{
ShowSendOffScreen();
}

View File

@ -7,7 +7,7 @@ namespace DualScreenDemo
public static class Program
{
// 定义全局变量
internal static DBObj.SongListManager songListManager;
internal static DBObj.SQLManager songListManager;
//internal static ArtistManager artistManager;
internal static SerialPortManager serialPortManager;
private static PrimaryForm primaryForm; // 儲存實例的參考
@ -17,7 +17,7 @@ namespace DualScreenDemo
[STAThread]
static void Main()
{
Console.WriteLine("Server V.1.2.3 202507211828");
Console.WriteLine("Server V.1.2.4 202507281600");
if (Utils.Env.GetBool("IsCursor", true)) Cursor.Hide();
AppDomain.CurrentDomain.ProcessExit += (s, e) => Cursor.Show();
//Console.WriteLine("正在與中控取得聯繫...");
@ -34,7 +34,7 @@ namespace DualScreenDemo
}
// 初始化管理器
songListManager = new DBObj.SongListManager(); // 使用单例
songListManager = new DBObj.SQLManager(); // 使用单例
//artistManager = new ArtistManager();
var commandHandler = new CommandHandler(songListManager);
@ -49,7 +49,7 @@ namespace DualScreenDemo
}
// 啟動服務器
var TCP = new TCPServer();
var TCP = new TCPServer(room);
Task.Run(() => HttpServerManager.StartServer());
// 註冊事件

74
Room.cs
View File

@ -1,24 +1,76 @@
using OverlayFormObj;
using DBObj;
using MySqlConnector;
using System.Data;
namespace DualScreenDemo
{
public class Room
{
private static string State=Utils.Env.Get("RoomStates", "CLOSE");
public Room(){}
public static void set(string value)
public int branch_id =0;
public string hostName;
private string State = "error";
public Room()
{
hostName = System.Net.Dns.GetHostName();
branch_id =getBranchId();
State =getDB();
Console.WriteLine($"hostname status: {hostName},{State}");
}
private int getBranchId()
{
using (var db = new MyDB())
{
string sql = "SELECT id FROM branches LIMIT 1";
if (db.open(sql, null) && db.found())return db.Field<int>("id");
return 0;
}
}
private string getDB()
{
using (var db = new MyDB())
{
string query = @"SELECT * FROM rooms WHERE branch_id = @branch_id AND CONCAT(type, name) = @hostName";
MySqlParameter[] parameters = {
new MySqlParameter("@branch_id", branch_id),
new MySqlParameter("@hostName", hostName)
};
if (db.open(query, parameters) && db.found())
{
State = db.Field<string>("status");
return State;
}
}
return "error";
}
private void setDB(string value)
{
using (var db = new MyDB())
{
string query = @"UPDATE rooms SET status = @status WHERE branch_id = @branch_id AND CONCAT(type, name) = @hostName;";
MySqlParameter[] parameters = {
new MySqlParameter("@status", value),
new MySqlParameter("@branch_id", branch_id),
new MySqlParameter("@hostName", hostName)
};
db.ExecuteNonQuery(query, parameters);
}
}
public void set(string value)
{
string marqueeMessage = "歡迎使用超級巨星歡唱,與你共度美好時光。";
Color c = Color.White;
State = value;
if (value.Equals("PAUSE"))
setDB(value);
if (value.Equals("fire"))
{
PrimaryForm.Instance.ShowSendOffScreen();
VideoPlayerForm.Instance.Pause();
marqueeMessage = "發生火災,請跟隨引導至逃生出口!!!";
c = Color.Red;
}
else if (value.Equals("OPEN"))
else if (value.Equals("active"))
{
DBObj.SongList.clearSong();
PrimaryForm.Instance.HotPlayButton_Click(null, EventArgs.Empty);
@ -38,17 +90,17 @@ namespace DualScreenDemo
PrimaryForm.Instance.logout();
}
State =getDB();
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, c);
}
public static bool IsClose()
public bool IsClose()
{
return State.Equals("CLOSE");
return State.Equals("closed");
}
public static bool IsOpen()
public bool IsOpen()
{
return State.Equals("OPEN");
return State.Equals("active");
}
}

View File

@ -12,11 +12,13 @@ namespace DualScreenDemo
private TcpListener listener;
private const int Port = 1000;
private readonly string hostNameSuffix;
private Room _room;
//private bool isProcessingCommand = false;
public TCPServer()
public TCPServer(Room room)
{
_room = room;
listener = new TcpListener(IPAddress.Any, Port);
hostNameSuffix = GetHostNameSuffix();
@ -83,10 +85,6 @@ namespace DualScreenDemo
{
listener.Start();
Console.WriteLine("Server started on port " + Port + ".");
// 心跳封包
//heartbeatSender sender = new heartbeatSender("127.0.0.1", 8888);
//sender.Start();
// Console.WriteLine($"heart beat for server{sender.RemoteEndPoint.Address}:{sender.RemoteEndPoint.Port}");
try {
@ -124,7 +122,7 @@ namespace DualScreenDemo
{
_ = SafeInvoke(VideoPlayerForm.Instance, async () =>
{
Room.set("CLOSE");
_room.set("closed");
try{
await HttpServer.RestartServer();
} catch (Exception ex) {
@ -142,7 +140,7 @@ namespace DualScreenDemo
if (command.Trim().Equals("O", StringComparison.OrdinalIgnoreCase))
{
// 開台時跳至首頁
Room.set("OPEN");
_room.set("active");
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);
continue;
@ -151,7 +149,7 @@ namespace DualScreenDemo
{
_ = SafeInvoke(PrimaryForm.Instance, () =>
{
Room.set("PAUSE");
_room.set("fire");
});
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);