diff --git a/ClickSequenceState.cs b/ClickSequenceState.cs deleted file mode 100644 index 212e055..0000000 --- a/ClickSequenceState.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace DualScreenDemo -{ - - public enum ClickSequenceState - { - Initial, - FirstClicked, - SecondClicked, - ThirdClicked, - Completed - } -} \ No newline at end of file diff --git a/CommandHandler.cs b/CommandHandler.cs index 1e54917..3caadfe 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -16,17 +16,18 @@ 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; } /// /// 遙控器接收資料 /// - public async Task ProcessData(string indata) - { AddToHistory(indata); + public Task ProcessData(string indata) + { + AddToHistory(indata); // 遙控器測試 // Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 遙控器: {indata}"); switch (indata) @@ -86,102 +87,73 @@ namespace DualScreenDemo HandleArtistAnnouncements(); break; case "A2B3A4": - SafeInvokeAction("A2B3A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2B3A4",() => OverlayForm.MainForm.ShowVolumeUpLabel()); + SafeInvokeAction("A2B3A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("音量 ↑ ")); break; case "A2B4A4": - SafeInvokeAction("A2B4A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2B4A4",() => OverlayForm.MainForm.ShowVolumeDownLabel()); + SafeInvokeAction("A2B4A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("音量 ↓ ")); break; case "A2B5A4": - SafeInvokeAction("A2B5A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2B5A4",() => OverlayForm.MainForm.ShowMicUpLabel()); + SafeInvokeAction("A2B5A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("麥克風 ↑ ")); break; case "A2B6A4": - SafeInvokeAction("A2B6A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2B6A4",() => OverlayForm.MainForm.ShowMicDownLabel()); + SafeInvokeAction("A2B6A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("麥克風 ↓ ")); break; case "A2C2A4": - SafeInvokeAction("A2C2A4",() => OverlayForm.MainForm.HidemicLabels()); - SafeInvokeAction("A2C2A4",() => OverlayForm.MainForm.ShowStandardLabel()); + SafeInvokeAction("A2C2A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("標準迴音")); break; case "A2C3A4": - SafeInvokeAction("A2C3A4",() => OverlayForm.MainForm.HidemicLabels()); - SafeInvokeAction("A2C3A4",() => OverlayForm.MainForm.ShowProfessionalLabel()); + SafeInvokeAction("A2C3A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("專業迴音")); break; case "A2C4A4": - SafeInvokeAction("A2C4A4",() => OverlayForm.MainForm.HidemicLabels()); - SafeInvokeAction("A2C4A4",() => OverlayForm.MainForm.ShowSquareLabel()); + SafeInvokeAction("A2C4A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("廣場迴音")); break; case "A2C1A4": - SafeInvokeAction("A2C1A4",() => OverlayForm.MainForm.HidemicLabels()); - SafeInvokeAction("A2C1A4",() => OverlayForm.MainForm.ShowSingDownLabel()); + SafeInvokeAction("A2C1A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("唱將迴音")); break; case "A2D5A4": - SafeInvokeAction("A2D5A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2D5A4",() => OverlayForm.MainForm.ShowBrightLabel()); + SafeInvokeAction("A2D5A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 明亮 ")); break; case "A2D7A4": - SafeInvokeAction("A2D7A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2D7A4",() => OverlayForm.MainForm.ShowRomanticLabel()); + SafeInvokeAction("A2D7A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 浪漫 ")); break; - /* case "A27CA4": - InvokeAction(() => OverlayForm.MainForm.ShowMaleKeyLabel()); - break; - case "A282A4": - InvokeAction(() => OverlayForm.MainForm.ShowFemaleKeyLabel()); - break;*/ case "A2D6A4": - SafeInvokeAction("A2D6A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2D6A4",() => OverlayForm.MainForm.ShowSoftLabel()); + SafeInvokeAction("A2D6A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 柔和 ")); break; case "A2D8A4": - SafeInvokeAction("A2D8A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A2D8A4",() => OverlayForm.MainForm.ShowDynamicLabel()); + SafeInvokeAction("A2D8A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 動感 ")); break; case "A275A4": - SafeInvokeAction("A275A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A275A4",() => OverlayForm.MainForm.ShowTintLabel()); + SafeInvokeAction("A275A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 調色 ")); break; case "A283A4": - SafeInvokeAction("A283A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A283A4",() => OverlayForm.MainForm.ShowKeyUpLabel("↑升4調")); + SafeInvokeAction("A283A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升4調 ")); break; case "A282A4": - SafeInvokeAction("A282A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A282A4",() => OverlayForm.MainForm.ShowKeyUpLabel("↑升3調")); + SafeInvokeAction("A282A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升3調 ")); break; case "A281A4": - SafeInvokeAction("A281A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A281A4",() => OverlayForm.MainForm.ShowKeyUpLabel("↑升2調")); + SafeInvokeAction("A281A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升2調 ")); break; case "A280A4": - SafeInvokeAction("A280A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A280A4",() => OverlayForm.MainForm.ShowKeyUpLabel("↑升1調")); + SafeInvokeAction("A280A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升1調 ")); break; case "A27FA4": - SafeInvokeAction("A27FA4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A27FA4",() => OverlayForm.MainForm.ShowStandardKeyLabel()); + SafeInvokeAction("A27FA4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 標準調 ")); break; case "A27EA4": - SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.ShowKeyDownLabel("↓降1調")); + SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降1調 ")); break; case "A27DA4": - SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.ShowKeyDownLabel("↓降2調")); + SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降2調 ")); break; case "A27CA4": - SafeInvokeAction("A27CA4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A27CA4",() => OverlayForm.MainForm.ShowKeyDownLabel("↓降3調")); + SafeInvokeAction("A27CA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降3調 ")); break; case "A27BA4": - SafeInvokeAction("A27BA4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A27BA4",() => OverlayForm.MainForm.ShowKeyDownLabel("↓降4調")); + SafeInvokeAction("A27BA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降4調 ")); break; case "A266A4": - SafeInvokeAction("A266A4",() => OverlayForm.MainForm.HideAllLabels()); - SafeInvokeAction("A266A4",() => OverlayForm.MainForm.ShowServiceBell()); + SafeInvokeAction("A266A4",() => OverlayForm.MainForm.ShowTopRightLabel("服務鈴")); break; default: if (Regex.IsMatch(indata, @"^A23\d+A4$")) @@ -190,7 +162,8 @@ namespace DualScreenDemo } break; } - + + return Task.CompletedTask; } private void SafeInvokeAction(string commandKey, Action action) { @@ -243,18 +216,11 @@ namespace DualScreenDemo private static void SkipToNextSong() { if (PrimaryForm.Instance.InvokeRequired) - { - PrimaryForm.Instance.Invoke(new System.Action(() => PrimaryForm.Instance.videoPlayerForm.SkipToNextSong())); - } + PrimaryForm.Instance.Invoke(new System.Action(() => PrimaryForm.Instance.videoPlayerForm.PlayNextSong())); else - { - PrimaryForm.Instance.videoPlayerForm.SkipToNextSong(); - } - - OverlayForm.MainForm.Invoke(new System.Action(() => - { - OverlayForm.MainForm.ShowStandardLabel(); - })); + PrimaryForm.Instance.videoPlayerForm.PlayNextSong(); + + OverlayForm.MainForm.Invoke(new System.Action(() => { OverlayForm.MainForm.ShowTopRightEchoLabel("標準迴音"); } ) ); } @@ -352,8 +318,8 @@ namespace DualScreenDemo { ClearDisplay(); OverlayForm.MainForm.displayLabel.Text = String.Format("已點歌曲:{0}", song); - OverlayForm.MainForm.AddSongToPlaylist(song); - OverlayForm.MainForm.nextSongLabel.Visible = false; + SongList.Add(song); + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } else @@ -371,7 +337,7 @@ namespace DualScreenDemo _indataHistory.Clear(); // 清空歷史紀錄 _wrongInputCountfor61 = 0; // 重置計數器 } - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } })); @@ -382,8 +348,8 @@ namespace DualScreenDemo { ClearDisplay(); OverlayForm.MainForm.displayLabel.Text = String.Format("{0}", song); - OverlayForm.MainForm.AddSongToPlaylist(song); - OverlayForm.MainForm.nextSongLabel.Visible = false; + SongList.Add(song); + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } else @@ -401,7 +367,7 @@ namespace DualScreenDemo _indataHistory.Clear(); // 清空歷史紀錄 _wrongInputCountfor61 = 0; // 重置計數器 } - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } } @@ -409,12 +375,12 @@ namespace DualScreenDemo } private string check_control(string old){ foreach(string item in _indataHistory) - { - if(item == "A261A4") - old += "#"; - else if(item == "A262A4") - old += "*"; - } + { + if(item == "A261A4") + old += "#"; + else if(item == "A262A4") + old += "*"; + } return old; } @@ -458,8 +424,8 @@ namespace DualScreenDemo { ClearDisplay(); OverlayForm.MainForm.displayLabel.Text = String.Format("插播歌曲{0}", song); - OverlayForm.MainForm.InsertSongToPlaylist(song); - OverlayForm.MainForm.nextSongLabel.Visible = false; + SongList.Insert(song); + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } else @@ -477,7 +443,7 @@ namespace DualScreenDemo _indataHistory.Clear(); // 清空歷史紀錄 _wrongInputCountfor62 = 0; // 重置計數器 } - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } })); @@ -488,7 +454,7 @@ namespace DualScreenDemo { ClearDisplay(); OverlayForm.MainForm.displayLabel.Text = String.Format("已點歌曲:{0}", song); - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.topLeftLabel.Visible = false; } else { @@ -505,7 +471,7 @@ namespace DualScreenDemo _indataHistory.Clear(); // 清空歷史紀錄 _wrongInputCountfor62 = 0; // 重置計數器 } - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); } } @@ -542,27 +508,9 @@ namespace DualScreenDemo OverlayForm.MainForm.displayLabel, OverlayForm.MainForm.pauseLabel, OverlayForm.MainForm.muteLabel, - OverlayForm.MainForm.volumeUpLabel, - OverlayForm.MainForm.volumeDownLabel, - OverlayForm.MainForm.micUpLabel, - OverlayForm.MainForm.micDownLabel, - OverlayForm.MainForm.standardKeyLabel, - OverlayForm.MainForm.keyUpLabel, - OverlayForm.MainForm.keyDownLabel, - OverlayForm.MainForm.maleKeyLabel, - OverlayForm.MainForm.femaleKeyLabel, - OverlayForm.MainForm.squareLabel, - OverlayForm.MainForm.professionalLabel, - OverlayForm.MainForm.standardLabel, - OverlayForm.MainForm.singDownLabel, - OverlayForm.MainForm.brightLabel, - OverlayForm.MainForm.softLabel, - OverlayForm.MainForm.autoLabel, - OverlayForm.MainForm.romanticLabel, - OverlayForm.MainForm.dynamicLabel, - OverlayForm.MainForm.tintLabel, + OverlayForm.MainForm.topRightLabel, OverlayForm.MainForm.blackBackgroundPanel, - OverlayForm.MainForm.nextSongLabel + OverlayForm.MainForm.topLeftLabel }; // 將所有不在保留清單內的控制項移除並釋放資源 @@ -592,7 +540,9 @@ namespace DualScreenDemo ClearDisplay(); // 設定歌曲總數為已播放歌曲的數量 - OverlayForm.MainForm.totalSongs = PrimaryForm.playedSongsHistory.Count; + List history= SongList.GetHistory(); + List historySongs = new List(); + OverlayForm.MainForm.totalSongs = SongList.GetHistory().Count; // 若無任何播放紀錄,直接顯示訊息並返回,不執行後續動作 if (OverlayForm.MainForm.totalSongs == 0) @@ -609,45 +559,11 @@ namespace DualScreenDemo int endIndex = Math.Min(startIndex + OverlayForm.MainForm.songsPerPage, OverlayForm.MainForm.totalSongs); // 準備要傳給 UpdateHistoryLabel 的兩個清單:歌曲資料與播放狀態 - List historySongs = new List(); - List playStates = new List(); - // 錨點 遙控器 - // 從播放紀錄中取出當前頁面應顯示的歌曲與狀態 - int completedCount = PrimaryForm.currentSongIndexInHistory; - // 判斷是否正在播放公播歌單 (若用戶點播歌單為空,則播放公播歌單) - bool isPlayingPublicList = PrimaryForm.userRequestedSongs.Count == 0 || - (PrimaryForm.currentSongIndexInHistory >= PrimaryForm.userRequestedSongs.Count - 1 && PrimaryForm.Instance.videoPlayerForm.IsPlayingPublicSong); - if (isPlayingPublicList) - { - for (int i = startIndex; i < endIndex; i++) - { - historySongs.Add(PrimaryForm.playedSongsHistory[i]); // 加入歌曲 - playStates.Add(PlayState.Played); - } + for (int i = startIndex; i < endIndex; i++) { + historySongs.Add(history[i]); } - else - { - for (int i = startIndex; i < endIndex; i++) - { - - historySongs.Add(PrimaryForm.playedSongsHistory[i]); // 加入歌曲 - if (i < completedCount) - { - playStates.Add(PlayState.Played); - } - else if (i == completedCount) - { - playStates.Add(PlayState.Playing); - } - else - { - playStates.Add(PlayState.NotPlayed); - } - } - } - - - + + // 錨點 遙控器 // 安全更新 UI:若非 UI 執行緒則使用 Invoke 切換 if (OverlayForm.MainForm.InvokeRequired) @@ -655,17 +571,17 @@ namespace DualScreenDemo OverlayForm.MainForm.Invoke(new System.Action(() => { // 更新主畫面的歷史播放顯示區 - OverlayForm.MainForm.UpdateHistoryLabel(historySongs, playStates, OverlayForm.MainForm.currentPage, totalPages); + OverlayForm.MainForm.UpdateHistoryLabel(historySongs, OverlayForm.MainForm.currentPage, totalPages); // 隱藏下一首提示 - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.topLeftLabel.Visible = false; })); } else { // 若已在 UI 執行緒,直接操作 - OverlayForm.MainForm.UpdateHistoryLabel(historySongs, playStates, OverlayForm.MainForm.currentPage, totalPages); - OverlayForm.MainForm.nextSongLabel.Visible = false; + OverlayForm.MainForm.UpdateHistoryLabel(historySongs, OverlayForm.MainForm.currentPage, totalPages); + OverlayForm.MainForm.topLeftLabel.Visible = false; } // 切換 UI 狀態為播放歷史模式(可做為內部狀態管理用途) @@ -897,27 +813,9 @@ namespace DualScreenDemo if (control != OverlayForm.MainForm.displayLabel && control != OverlayForm.MainForm.pauseLabel && control != OverlayForm.MainForm.muteLabel && - control != OverlayForm.MainForm.volumeUpLabel && - control != OverlayForm.MainForm.volumeDownLabel && - control != OverlayForm.MainForm.micUpLabel && - control != OverlayForm.MainForm.micDownLabel && - control != OverlayForm.MainForm.standardKeyLabel && - control != OverlayForm.MainForm.keyUpLabel && - control != OverlayForm.MainForm.keyDownLabel && - control != OverlayForm.MainForm.maleKeyLabel && - control != OverlayForm.MainForm.femaleKeyLabel && - control != OverlayForm.MainForm.squareLabel && - control != OverlayForm.MainForm.professionalLabel && - control != OverlayForm.MainForm.standardLabel && - control != OverlayForm.MainForm.singDownLabel && - control != OverlayForm.MainForm.brightLabel && - control != OverlayForm.MainForm.softLabel && - control != OverlayForm.MainForm.autoLabel && - control != OverlayForm.MainForm.romanticLabel && - control != OverlayForm.MainForm.dynamicLabel && - control != OverlayForm.MainForm.tintLabel && + control != OverlayForm.MainForm.topRightLabel && control != OverlayForm.MainForm.blackBackgroundPanel && - control != OverlayForm.MainForm.nextSongLabel) + control != OverlayForm.MainForm.topLeftLabel) { OverlayForm.MainForm.Controls.Remove(control); control.Dispose(); @@ -934,27 +832,9 @@ namespace DualScreenDemo if (control != OverlayForm.MainForm.displayLabel && control != OverlayForm.MainForm.pauseLabel && control != OverlayForm.MainForm.muteLabel && - control != OverlayForm.MainForm.volumeUpLabel && - control != OverlayForm.MainForm.volumeDownLabel && - control != OverlayForm.MainForm.micUpLabel && - control != OverlayForm.MainForm.micDownLabel && - control != OverlayForm.MainForm.standardKeyLabel && - control != OverlayForm.MainForm.keyUpLabel && - control != OverlayForm.MainForm.keyDownLabel && - control != OverlayForm.MainForm.maleKeyLabel && - control != OverlayForm.MainForm.femaleKeyLabel && - control != OverlayForm.MainForm.squareLabel && - control != OverlayForm.MainForm.professionalLabel && - control != OverlayForm.MainForm.standardLabel && - control != OverlayForm.MainForm.singDownLabel && - control != OverlayForm.MainForm.brightLabel && - control != OverlayForm.MainForm.softLabel && - control != OverlayForm.MainForm.autoLabel && - control != OverlayForm.MainForm.romanticLabel && - control != OverlayForm.MainForm.dynamicLabel && - control != OverlayForm.MainForm.tintLabel && + control != OverlayForm.MainForm.topRightLabel && control != OverlayForm.MainForm.blackBackgroundPanel && - control != OverlayForm.MainForm.nextSongLabel) + control != OverlayForm.MainForm.topLeftLabel) { OverlayForm.MainForm.Controls.Remove(control); control.Dispose(); @@ -1004,14 +884,14 @@ namespace DualScreenDemo { OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.DisplayNumberAtTopLeft(number); - OverlayForm.MainForm.HideAllLabels(); + OverlayForm.MainForm.HideTopRightLabels(); + OverlayForm.DisplayNumberAtTopLeft(number); })); } else { + OverlayForm.MainForm.HideTopRightLabels(); OverlayForm.DisplayNumberAtTopLeft(number); - OverlayForm.MainForm.HideAllLabels(); } } } diff --git a/DBObj/Artist.cs b/DBObj/Artist.cs index 8a5138c..bc7f5f9 100644 --- a/DBObj/Artist.cs +++ b/DBObj/Artist.cs @@ -3,8 +3,8 @@ namespace DBObj // artist OOP test public class Artist { - public string Name { get; set; } - public string NameSimplified{get;set;} + public string Name ; + public string NameSimplified ; //public string Phonetic { get; set; } //public string Category { get; set; } //public int Strokes { get; set; } @@ -14,6 +14,8 @@ namespace DBObj Name = name; NameSimplified=nameSimplified; } + public string getName(bool IsSimplified=false) { return IsSimplified ? NameSimplified : Name; } + public string getName() {return Name;} public override string ToString() { diff --git a/DBObj/MyDB.cs b/DBObj/MyDB.cs new file mode 100644 index 0000000..49dc846 --- /dev/null +++ b/DBObj/MyDB.cs @@ -0,0 +1,190 @@ +using System; +using System.Data; +using MySqlConnector; + +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 連線成功!"); + } + + public void Dispose() + { + if (conn != null) + { + conn.Dispose(); // 包含 Close + 資源釋放 + conn = null; + //Console.WriteLine("MyDB 連線已釋放!"); + } + } + + // SELECT 方法 + public bool open(string query, MySqlParameter[] parameters, bool showError = true) + { + table.Clear(); + cursor = 0; + try + { + using (var cmd = new MySqlCommand(query, conn)) + { + if (parameters != null) + { + cmd.Parameters.AddRange(parameters); + } + using (var adapter = new MySqlDataAdapter(cmd)) + { + adapter.Fill(table); + } + } + } + catch (Exception ex) + { + if (showError) + Console.WriteLine($"DB Error: {ex.Message}"); + return false; + } + return true; + } + public T Field(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 ToList() where T : new() + { + var list = new List(); + + 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 CurrentRowAsDictionary() + { + if (cursor < 0 || cursor >= table.Rows.Count) + return null; + + var dict = new Dictionary(); + 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) + { + using (var cmd = new MySqlCommand(query, conn)) + { + if (parameters != null) + { + cmd.Parameters.AddRange(parameters); + } + return cmd.ExecuteNonQuery(); + } + } + public long LastInsertId() + { + using (var cmd = new MySqlCommand("SELECT LAST_INSERT_ID()", conn)) + { + return Convert.ToInt64(cmd.ExecuteScalar()); + } + } + } +} diff --git a/DBObj/SongListManager.cs b/DBObj/SQLManager.cs similarity index 64% rename from DBObj/SongListManager.cs rename to DBObj/SQLManager.cs index e7f97c1..a25f0b0 100644 --- a/DBObj/SongListManager.cs +++ b/DBObj/SQLManager.cs @@ -1,12 +1,14 @@ +using System.Data; using DualScreenDemo; namespace DBObj { - public class SongListManager + public class SQLManager { - public List FavoriteSongs { get; private set; } + private MyDB db = new MyDB(); + public List FavoriteSongs { get; private set; } //public bool IsUserLoggedIn { get; set; } //public string UserPhoneNumber { get; set; } - public SongListManager() + public SQLManager() { FavoriteSongs = new List(); } @@ -50,32 +52,60 @@ namespace DBObj } } */ - public List 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); + public List SearchNewSongs() + { + string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY add_date DESC LIMIT {Utils.Env.GetInt("NewSongLimit", 100)};"; + return select_Mysql(query); } public List 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 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 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 select_Mysql(string query) + { + List searchResults = new List(); + Console.WriteLine(query); + using (var db = new MyDB()) + { + if (db.open(query, null)) { + while (db.Read()){ + searchResults.Add(new SongData( + db.Field("song_id"), + db.Field("song_name"), + db.Field("artistA"), + db.Field("artistB"), + db.Field("song_filename"), + db.Field("artistA_simplified"), + db.Field("artistB_simplified"), + db.Field("song_simplified"), + db.Field("vocal") + )); + } + } + + Console.WriteLine($"查詢到 {searchResults.Count} 筆資料。"); + } + + return searchResults; + } } } \ No newline at end of file diff --git a/DBObj/Song.cs b/DBObj/Song.cs new file mode 100644 index 0000000..507666e --- /dev/null +++ b/DBObj/Song.cs @@ -0,0 +1,26 @@ +namespace DBObj +{ + // song OOP test + public class Song + { + private string Number; + private string Name; + private string Name_Simplified; + private string FileName; + private int HumanVoice; + + + public Song(string num,string name,string name_s,string filename,int humanVoice) { + Number=num; + Name=name; + Name_Simplified=name_s; + FileName=filename; + HumanVoice =humanVoice; + } + public string getNumber() {return Number;} + public string getName(bool IsSimplified) {return IsSimplified ? Name_Simplified : Name;} + public string getName() { return Name;} + public string getFileName() { return FileName;} + public int getHumanVoice() { return HumanVoice;} + } +} \ No newline at end of file diff --git a/DBObj/SongData.cs b/DBObj/SongData.cs index 606fbdb..bb9bc94 100644 --- a/DBObj/SongData.cs +++ b/DBObj/SongData.cs @@ -1,120 +1,96 @@ using DualScreenDemo; using System; using System.IO; +using System.Windows.Markup; namespace DBObj { public class SongData { - public string Number { get; set; } - public string Name { get; set; } - public string Artist_A { get; set; } - private string Artist_B { get; set; } - public string FileName { get; set; } - public string Artist_A_Simplified { get; set; } - public string Artist_B_Simplified { get; set; } - public string Name_Simplified { get; set; } - public int HumanVoice { get; set; } + private Song basic; + private Artist A ; + private Artist B ; public bool isPublicSong { get; set; } public PlayState state; - - /* - public SongData(string songNumber, string category, string song, double plays, string artistA, string artistB, string artistACategory, string artistBCategory, DateTime addedTime, string songFilePathHost1, string songFilePathHost2, string phoneticNotation, string pinyinNotation, string artistAPhonetic, string artistBPhonetic, string artistASimplified, string artistBSimplified, string songSimplified, string songGenre, string artistAPinyin, string artistBPinyin, int humanVoice) - { - SongNumber = songNumber; - // Category = category; - Song = song; - // Plays = plays; - ArtistA = artistA; - ArtistB = artistB; - //ArtistACategory = artistACategory; - //ArtistBCategory = artistBCategory; - //AddedTime = addedTime; - SongFilePathHost1 = songFilePathHost1; - SongFilePathHost2 = songFilePathHost2; - //PhoneticNotation = phoneticNotation; - //PinyinNotation = pinyinNotation; - //ArtistAPhonetic = artistAPhonetic; - //ArtistBPhonetic = artistBPhonetic; - ArtistASimplified = artistASimplified; - ArtistBSimplified = artistBSimplified; - SongSimplified = songSimplified; - //SongGenre = songGenre; - //ArtistAPinyin = artistAPinyin; - //ArtistBPinyin = artistBPinyin; - HumanVoice = humanVoice; - } - - */ public SongData(string songNumber, string song, string filename, int humanVoice, bool isPublic) { - Number = songNumber; - Name = song; - FileName = filename; - HumanVoice = humanVoice; + basic=new(songNumber,song,"",filename,humanVoice); isPublicSong = isPublic; } public SongData(string songNumber, string song, string artistA, string artistB, string filename, string artistASimplified, string artistBSimplified, string songSimplified, int humanVoice) { - Number = songNumber; - Name = song; - Artist_A = artistA; - Artist_B = artistB; - FileName = filename; - Artist_A_Simplified = artistASimplified; - Artist_B_Simplified = artistBSimplified; - Name_Simplified = songSimplified; - HumanVoice = humanVoice; + basic=new(songNumber,song,songSimplified,filename,humanVoice); + A= new Artist(artistA, artistASimplified); + if(artistB!=null){ + B = new Artist(artistB, artistBSimplified); + } isPublicSong = false; } - public string getName(bool IsSimplified=false) - { - return IsSimplified ? Name_Simplified : Name; + public SongData(SongData value,PlayState s){ + basic = value.getBasic(); + A = value.getA(); + B = value.getB(); + state =s; } - public int getNameLength() + public Song getBasic() => basic; + public Artist getA() => A; + public Artist getB() => B; + + public string getNumber() {return basic.getNumber();} + public string getName(bool IsSimplified=false) { return basic.getName(IsSimplified); } + public string getName() { return basic.getName();} + public string getArtist_A(bool IsSimplified) { return A.getName(IsSimplified); } + public string getArtist_A() { return A.getName();} + public string getArtist_B(bool IsSimplified) { return B.getName(IsSimplified); } + public string getArtist_B() { return B.getName();} + public int getNameLength() { return basic.getName().Length; } + public string getFileName() {return basic.getFileName();} + public string next_song_text() { - return Name.Length; - } - public string next_artist_text() - { - return !string.IsNullOrWhiteSpace(Artist_B) - ? String.Format("下一首:{0} {1} {2}", Artist_A, Artist_B, Name) - : String.Format("下一首:{0} {1}", Artist_A, Name); + var str = (state == PlayState.InsertPlayback) ? GetStateTxt(false) : ""; + return String.Format("下一首:{0} {1}", basic.getName(false),str); } public string artist_text() { - return !string.IsNullOrWhiteSpace(Artist_B) - ? $"{Artist_A} - {Artist_B}" - : Artist_A; + return B!=null + ? $"{A.getName(false)} - {B.getName(false)}" + : A.getName(false); } public string name_text() { - return !string.IsNullOrWhiteSpace(Artist_B) - ? String.Format("{0} - {1} - {2}", Artist_A, Artist_B, Name) - : String.Format("{0} - {1}", Artist_A, Name); - } - public string getArtist_A(bool IsSimplified) - { - return IsSimplified ? Artist_A_Simplified : Artist_A; - } - public string getArtist_B(bool IsSimplified) - { - return IsSimplified ? Artist_B_Simplified : Artist_B; + return B!=null + ? String.Format("{0} - {1} - {2}", A.getName(false), B.getName(false), basic.getName(false)) + : String.Format("{0} - {1}", A.getName(false), basic.getName(false)); } + public string getFile() { - return FindExistingPath(FileName); + return FindExistingPath(basic.getFileName()); } private string FindExistingPath(string filename) { - var servers = new[] { @"\\svr01\", @"\\svr02\", @"\\svr01\e", @"\\svr02\e" }; - foreach (var server in servers) + foreach (var server in Utils.Env.GetSongServers()) { + Console.WriteLine($"伺服器路徑: '{server}'"); string fullPath = Path.Combine(server, filename); if (File.Exists(fullPath)) return fullPath; } return null; // 找不到就回原本的 filename,不加路徑 } + public Color GetStateColor(){ + Color c = Color.White; + if (state == PlayState.Played){ + c = Color.Gray;//Color.FromArgb(200, 75, 125); // 播畢顏色:紫紅色 + }else if (state == PlayState.Playing){ + c = Color.LimeGreen; + }else if (state == PlayState.InsertPlayback){ + c = Color.Gold; + } + return c; + } + public string GetStateTxt(bool IsSimplified){ + return (state==PlayState.NotPlayed)?"":$"({state.GetDescription(IsSimplified)})"; + } public void SetState(PlayState s) => state = s; public PlayState GetState() @@ -122,13 +98,13 @@ namespace DBObj return state; } - + public int getHumanVoice() { return basic.getHumanVoice(); } public override string ToString() { - return !string.IsNullOrWhiteSpace(Artist_B) - ? String.Format("{0} - {1} - {2}", Artist_A, Artist_B, Name) - : String.Format("{0} - {1}", Artist_A, Name); + return B!=null + ? String.Format("{0} - {1} - {2} - {3}", state, A.getName(), B.getName(), basic.getName()) + : String.Format("{0} - {1} - {2}", state, A.getName(), basic.getName()); } } } \ No newline at end of file diff --git a/DBObj/SongList.cs b/DBObj/SongList.cs new file mode 100644 index 0000000..29f23f2 --- /dev/null +++ b/DBObj/SongList.cs @@ -0,0 +1,107 @@ +using DualScreenDemo; +using System; +using System.IO; +using System.Windows.Navigation; +namespace DBObj +{ + public class SongList + { + private static bool isWelcome = true; + public static SongData welcome; + public static SongData close ; + private static SongData publicPlaying=null; + private static List publicSong = new(); + private static SongData playing=null; + private static List not_played = new List(); + private static List played = new List(); + public static List PublicSong() => publicSong; + + public static SongData Current() + { + Console.WriteLine(not_played.Count + " Current " + playing); + return (playing ==null) ? publicPlaying : playing; + } + public static SongData Next() + { + if (playing != null) + { + playing.SetState(PlayState.Played); + played.Add(playing); + playing = null; + } + if (not_played.Count <= 0) + return NextPublicSong(); + else + return NextUserSong(); + } + private static SongData NextUserSong() + { + playing = not_played[0]; + not_played.RemoveAt(0); + playing.SetState(PlayState.Playing); + UpdateNextSongLabel(); + return playing; + } + private static SongData NextPublicSong() + { + if (Program.room.IsClose()) { + publicPlaying = close; + } else if(Program.room.IsOpen() && isWelcome){ + isWelcome = false; + publicPlaying = welcome; + } else { + publicPlaying = publicSong[0]; + publicSong.RemoveAt(0); + publicSong.Add(publicPlaying); + } + + return publicPlaying; + } + + public static List GetHistory() + { + List History = [.. played]; + if (playing != null) History.Add(playing); + History.AddRange(not_played); + return History; + } + + public static void Add(SongData song) + { + not_played.Add(new SongData(song,PlayState.NotPlayed)); + // PrimaryForm.Instance.AddSongCount(songData.Number); + chkCut(); + } + public static void Insert(SongData song) + { + not_played.Insert(0, new SongData(song,PlayState.InsertPlayback)); + chkCut(); + } + private static void chkCut() + { + if (playing == null) + { + if (PrimaryForm.Instance.InvokeRequired) + PrimaryForm.Instance.Invoke(new System.Action(() => PrimaryForm.Instance.videoPlayerForm.PlayNextSong())); + else + PrimaryForm.Instance.videoPlayerForm.PlayNextSong(); + } else { + UpdateNextSongLabel(); + } + } + + public static void UpdateNextSongLabel() + { + VideoPlayerForm.overlayForm.UpdateTopLeftLabel( + (not_played.Count > 0) ? not_played[0].next_song_text() : "目前沒有下一首,請踴躍點歌!!!" + ); + } + public static void clearSong() + { + + isWelcome = true; + not_played.Clear(); + played.Clear(); + } + } +} diff --git a/DualScreenDemo.Shared.cs b/DualScreenDemo.Shared.cs deleted file mode 100644 index 5c3810d..0000000 --- a/DualScreenDemo.Shared.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace DualScreenDemo.Shared -{ - public class VideoStatus - { - public bool IsGraphOk { get; set; } - public string LastError { get; set; } - public double PositionSeconds { get; set; } - public string PlayState { get; set; } - } -} diff --git a/EnumExtensions.cs b/EnumExtensions.cs new file mode 100644 index 0000000..4ffd274 --- /dev/null +++ b/EnumExtensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Reflection; + +namespace DualScreenDemo +{ + public static class EnumExtensions + { + public static string GetDescription(this Enum value, bool isSimplified = false) + { + var field = value.GetType().GetField(value.ToString()); + + var attr = field?.GetCustomAttribute(); + if (attr != null) + return isSimplified ? attr.Simplified : attr.Traditional; + + return value.ToString(); + } + } +} diff --git a/Env.cs b/Env.cs index 22936eb..f280a94 100644 --- a/Env.cs +++ b/Env.cs @@ -49,6 +49,13 @@ namespace Utils Console.WriteLine("所有指定目錄都找不到 config.ini"); } + public static string[] GetSongServers() + { + return Get("songServer", "") + .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .Select(s => s.Trim('\'', '"').TrimEnd('\\')) // 清理 + .ToArray(); + } public static string Get(string key, string fallback = "") => _values.TryGetValue(key, out var value) ? value : fallback; diff --git a/FilterEnumerator.cs b/FilterEnumerator.cs deleted file mode 100644 index 8ab416f..0000000 --- a/FilterEnumerator.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using DirectShowLib; - -namespace DualScreenDemo -{ - public class FilterEnumerator - { - private static readonly Guid IID_IPropertyBag = new Guid("55272A00-42CB-11CE-8135-00AA004BB851"); - - public void EnumerateFilters() - { - ICreateDevEnum createDevEnum = (ICreateDevEnum)new CreateDevEnum(); - IEnumMoniker enumMoniker; - int hr = createDevEnum.CreateClassEnumerator(FilterCategory.LegacyAmFilterCategory, out enumMoniker, 0); - if (hr != 0 || enumMoniker == null) - { - Console.WriteLine("No filters found."); - return; - } - - IMoniker[] monikers = new IMoniker[1]; - IntPtr fetched = Marshal.AllocHGlobal(sizeof(int)); - while (enumMoniker.Next(1, monikers, fetched) == 0) - { - int fetchedCount = Marshal.ReadInt32(fetched); - if (fetchedCount > 0) - { - object objPropBag; - Guid tempGuid = IID_IPropertyBag; - monikers[0].BindToStorage(null, null, ref tempGuid, out objPropBag); - IPropertyBag propBag = objPropBag as IPropertyBag; - - object filterName = null; - if (propBag != null) - { - propBag.Read("FriendlyName", out filterName, null); - } - - if (filterName != null) - { - Console.WriteLine("Filter: " + filterName.ToString()); - } - - Marshal.ReleaseComObject(monikers[0]); - } - } - Marshal.ReleaseComObject(enumMoniker); - Marshal.FreeHGlobal(fetched); - } - } -} \ No newline at end of file diff --git a/FormatTypes.cs b/FormatTypes.cs deleted file mode 100644 index 99202c0..0000000 --- a/FormatTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace DualScreenDemo -{ - public static class FormatTypes - { - public static readonly Guid VideoInfo = new Guid("05589F80-C356-11CE-BF01-00AA0055595A"); - public static readonly Guid WaveEx = new Guid("05589f81-c356-11ce-bf01-00aa0055595a"); - } -} \ No newline at end of file diff --git a/HttpServer.cs b/HttpServer.cs index 40e95b5..8595ec9 100644 --- a/HttpServer.cs +++ b/HttpServer.cs @@ -10,6 +10,7 @@ using ActionString = System.Action; // 现在可以在代码中使用 Ac using System.Collections.Concurrent; using DBObj; using OverlayFormObj; +using Newtonsoft.Json.Linq; namespace DualScreenDemo { @@ -18,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; @@ -34,7 +35,7 @@ namespace DualScreenDemo private static TaskCompletionSource _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); @@ -271,7 +272,7 @@ namespace DualScreenDemo await HandleOrderSongListRequest(context); break; case "/message": - await HandlemessageRequest(context); + await HandleMessageRequest(context); break; case "/favorite": await HandleFavoriteRequest(context); @@ -369,8 +370,16 @@ namespace DualScreenDemo searchResults = new List(); break; } + var response = searchResults + .Select(song => new + { + Song = song.getName(), + ArtistA =song.getArtist_A(), + SongNumber = song.getNumber(), + }) + .ToList(); - await SendJsonResponseAsync(context, searchResults); + await SendJsonResponseAsync(context, response); } catch (Exception ex) { @@ -451,24 +460,16 @@ namespace DualScreenDemo break; case "volume_up": // 执行音量增大操作 - PrimaryForm.SendCommandThroughSerialPort("a2 b3 a4"); OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowVolumeUpLabel(); - PrimaryForm.Instance.volumeUpTimer.Start(); - OverlayForm.MainForm.HideAllLabels(); - PrimaryForm.Instance.volumeUpTimer.Stop(); + OverlayForm.MainForm.ShowTopRightLabelTime("音量 ↑","a2 b3 a4"); })); break; case "mic_up": // 执行麦克风增大操作 - PrimaryForm.SendCommandThroughSerialPort("a2 b5 a4"); OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowMicUpLabel(); - PrimaryForm.Instance.micControlTimer.Start(); - OverlayForm.MainForm.HideAllLabels(); - PrimaryForm.Instance.micControlTimer.Stop(); + OverlayForm.MainForm.ShowTopRightLabelTime("麥克風 ↑","a2 b5 a4"); })); break; case "mute": @@ -496,24 +497,16 @@ namespace DualScreenDemo break; case "volume_down": // 执行音量减小操作 - PrimaryForm.SendCommandThroughSerialPort("a2 b4 a4"); OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowVolumeDownLabel(); - PrimaryForm.Instance.volumeDownTimer.Start(); - OverlayForm.MainForm.HideAllLabels(); - PrimaryForm.Instance.volumeDownTimer.Stop(); + OverlayForm.MainForm.ShowTopRightLabelTime("音量 ↓","a2 b4 a4"); })); break; case "mic_down": // 执行麦克风减小操作 - PrimaryForm.SendCommandThroughSerialPort("a2 b6 a4"); OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowMicDownLabel(); - PrimaryForm.Instance.micControlTimer.Start(); - OverlayForm.MainForm.HideAllLabels(); - PrimaryForm.Instance.micControlTimer.Stop(); + OverlayForm.MainForm.ShowTopRightLabelTime("麥克風 ↓","a2 b6 a4"); })); break; case "original_song": @@ -533,12 +526,9 @@ namespace DualScreenDemo break; case "service": // 执行服务操作 - PrimaryForm.SendCommandThroughSerialPort("a2 53 a4"); OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowServiceBell(); + OverlayForm.MainForm.ShowTopRightLabel("服務鈴","a2 53 a4"); })); - // 异步处理等待和隐藏标签 - await HttpServer.HandleServiceBellAsync(); break; case "replay": // 执行重唱操作 @@ -551,9 +541,6 @@ namespace DualScreenDemo break; case "male_key": // 执行男调操作 - OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowMaleKeyLabel(); - })); if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen) { // 假設 0xA2, 0xC1, 0xA4 是升調的指令 @@ -571,9 +558,6 @@ namespace DualScreenDemo break; case "female_key": // 执行女调操作 - OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowFemaleKeyLabel(); - })); if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen) { // 假設 0xA2, 0xC1, 0xA4 是升調的指令 @@ -592,24 +576,12 @@ namespace DualScreenDemo case "cut": // 执行切歌操作 if (PrimaryForm.Instance.InvokeRequired) - { - PrimaryForm.Instance.Invoke(new System.Action(() => - { - PrimaryForm.Instance.videoPlayerForm.SkipToNextSong(); - })); - } + PrimaryForm.Instance.Invoke(new System.Action(() => { PrimaryForm.Instance.videoPlayerForm.PlayNextSong();})); else - { - PrimaryForm.Instance.videoPlayerForm.SkipToNextSong(); - } + PrimaryForm.Instance.videoPlayerForm.PlayNextSong(); break; case "lower_key": // 执行降调操作 - OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowKeyDownLabel(); - })); - - // MessageBox.Show("降調功能啟動"); if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen) { // 假設 0xA2, 0xC2, 0xA4 是降調的指令 @@ -624,9 +596,6 @@ namespace DualScreenDemo break; case "standard_key": // 执行标准调操作 - OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowStandardKeyLabel(); - })); if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen) { // 假設 0xA2, 0xC1, 0xA4 是升調的指令 @@ -641,11 +610,6 @@ namespace DualScreenDemo break; case "raise_key": // 执行升调操作 - OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowKeyUpLabel(); - })); - - // MessageBox.Show("升調功能啟動"); if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen) { // 假設 0xA2, 0xC1, 0xA4 是升調的指令 @@ -682,15 +646,9 @@ namespace DualScreenDemo await context.Response.OutputStream.WriteAsync(new byte[0], 0, 0); } } - private static async Task HandleServiceBellAsync() - { - await Task.Delay(3000); // 等待 3 秒 - OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.HideServiceBellLabel(); - })); - } private static async Task HandleOrderSongListRequest(HttpListenerContext context) { + string jsonResponse = "{\"status\": \"error\", \"message\": \"An error occurred\"}"; try { // 读取请求的内容 @@ -701,94 +659,32 @@ namespace DualScreenDemo } Console.WriteLine("Received order song request: " + requestBody); - // 检查 playedSongsHistory 是否存在且不为空 - if (PrimaryForm.playedSongsHistory != null && PrimaryForm.playedSongsHistory.Count > 0) + // 创建响应数据 + var response = new { - Console.WriteLine("Played Songs History Count: " + PrimaryForm.playedSongsHistory.Count); - foreach (var song in PrimaryForm.playedSongsHistory) - { - Console.WriteLine($"Song: {song.Name}, ArtistA: {song.Artist_A}"); - } - - // 根据播放历史确定每首歌的播放状态 - var playStates = DeterminePlayStates(PrimaryForm.playedSongsHistory); - - // 创建响应数据 - var response = new - { - playingSongList = PrimaryForm.playedSongsHistory - .Select((song, index) => CreateSongResponse(song, playStates[index])) // 使用新的播放状态 - .ToList(), - // 生成播放历史 - currentSongIndexInHistory = PrimaryForm.currentSongIndexInHistory - }; - - string jsonResponse = JsonConvert.SerializeObject(response); - Console.WriteLine("Serialized JSON Response: " + jsonResponse); - - context.Response.ContentType = "application/json"; - context.Response.StatusCode = (int)HttpStatusCode.OK; - await SendResponseAsync(context, jsonResponse); - } - else - { - // 如果播放历史为空,回传一条消息 - var response = new { status = "info", message = "No songs in the played history" }; - string jsonResponse = JsonConvert.SerializeObject(response); - Console.WriteLine("Sending empty response: " + jsonResponse); - - context.Response.ContentType = "application/json"; - context.Response.StatusCode = (int)HttpStatusCode.OK; - await SendResponseAsync(context, jsonResponse); - } + playingSongList = SongList.GetHistory() + .Select((song, index) => new + { + Song=song.getName(), + ArtistA=song.getArtist_A(), + PlayState = song.GetState().GetDescription() + }) + .ToList() + }; + + jsonResponse = JsonConvert.SerializeObject(response); + context.Response.StatusCode = (int)HttpStatusCode.OK; + } catch (Exception ex) { Console.WriteLine("Error handling order song request: " + ex.Message); - context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"An error occurred\"}"); + } - } - - // 确定每首歌的播放状态 - private static List DeterminePlayStates(List playedSongsHistory) - { - var playStates = new List(); - bool foundPlaying = false; // 标记是否已找到正在播放的歌曲 - - for (int i = 0; i < playedSongsHistory.Count; i++) - { - // 这里可以根据您的业务逻辑来确定每首歌的播放状态 - if (i == PrimaryForm.currentSongIndexInHistory) - { - playStates.Add(PlayState.Playing); - foundPlaying = true; // 找到正在播放的歌曲 - } - else if (foundPlaying) - { - playStates.Add(null); // 找到播放中的歌曲后,后面的状态设置为 null - } - else - { - playStates.Add(PlayState.NotPlayed); // 未播放状态 - } - } - - return playStates; - } - - // 用于创建歌曲响应对象,包括播放状态 - private static object CreateSongResponse(SongData song, PlayState? playState) - { - return new - { - song.Name, - song.Artist_A, - song.FileName, - PlayState = playState.HasValue ? (playState.Value == PlayState.Playing ? "播放中" : "播放完畢") : null // 如果状态为 null,不返回状态信息 - }; + context.Response.ContentType = "application/json"; + await SendResponseAsync(context, jsonResponse); } // 生成播放状态 @@ -804,22 +700,20 @@ namespace DualScreenDemo } Console.WriteLine("Received order song request: " + requestBody); - // 解析 JSON 为 Song 对象 - var song = JsonConvert.DeserializeObject(requestBody); + var json = JObject.Parse(requestBody); + SongData song =songListManager.SearchSongByNumber(json["SongNumber"]?.ToString()); - if (song != null) - { - Console.WriteLine($"Ordering Song: {song.Name} by {song.Artist_A}"); + if (song != null) { + Console.WriteLine($"Ordering Song: {song.getName()} by {song.getArtist_A()}"); + // 这里可以添加处理逻辑,例如将歌曲加入到播放列表或数据库中 - OverlayForm.MainForm.AddSongToPlaylist(song); + SongList.Add(song); var response = new { status = "success", message = "Song ordered successfully" }; string jsonResponse = JsonConvert.SerializeObject(response); await SendResponseAsync(context, jsonResponse); - } - else - { + } else { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"Invalid song data\"}"); } @@ -845,20 +739,17 @@ namespace DualScreenDemo Console.WriteLine("Received insert song request: " + requestBody); // 解析 JSON 为 Song 对象 - var song = JsonConvert.DeserializeObject(requestBody); + var json = JObject.Parse(requestBody); + SongData song =songListManager.SearchSongByNumber(json["SongNumber"]?.ToString()); - if (song != null) - { - Console.WriteLine($"Inserting Song: {song.Name} by {song.Artist_A}"); + if (song != null){ + Console.WriteLine($"Inserting Song: {song.getName()} by {song.getArtist_A()}"); // 这里可以添加插播歌曲的处理逻辑 - OverlayForm.MainForm.InsertSongToPlaylist(song); - + SongList.Insert(song); var response = new { status = "success", message = "Song inserted successfully" }; string jsonResponse = JsonConvert.SerializeObject(response); await SendResponseAsync(context, jsonResponse); - } - else - { + } else { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; await SendResponseAsync(context, "{\"status\": \"error\", \"message\": \"Invalid song data\"}"); } @@ -947,7 +838,37 @@ namespace DualScreenDemo action(); } } - private static async Task HandlemessageRequest(HttpListenerContext context) + private static async Task HandleMessageRequest(HttpListenerContext context) + { + try + { + using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding)) + { + string json = await reader.ReadToEndAsync(); + if (!string.IsNullOrEmpty(json)) + { + context.Response.StatusCode = 200; + context.Response.ContentType = "application/json"; + int startIndex = json.IndexOf("\"message\":\"") + 11; + int endIndex = json.IndexOf("\"", startIndex); + if (startIndex >= 0 && endIndex >= 0) + OnDisplayBarrage?.Invoke( json.Substring(startIndex, endIndex - startIndex) ); + } + else + { + // 如果没有有效的 JSON 数据,返回错误响应 + context.Response.StatusCode = 400; // Bad Request + context.Response.StatusDescription = "Invalid JSON data."; + } + } + } + finally + { + context.Response.Close(); + } + } + /* + private static async Task HandleMessageRequest2(HttpListenerContext context) { try { @@ -967,17 +888,18 @@ namespace DualScreenDemo context.Response.ContentType = "application/json"; // 确保返回 JSON 格式 int startIndex = json.IndexOf("\"message\":\"") + 11; // 11 是 "message\":\"" 的长度 int endIndex = json.IndexOf("\"", startIndex); - string Messagefist ="藏鏡人:"; + string Messagefist = "藏鏡人:"; // 如果找到了 "message" 字段 if (startIndex >= 0 && endIndex >= 0) { // 提取 "message" 字段的值 string message = json.Substring(startIndex, endIndex - startIndex); - for(int i=0;i<3;i++) + for (int i = 0; i < 3; i++) { - string Messagelast=""; - for(int j=0;j < message.Length;j++){ + string Messagelast = ""; + for (int j = 0; j < message.Length; j++) + { Messagelast += message[j]; await Task.Delay(10); // 将读取到的 "message" 字段传递给 UI 控件显示 @@ -985,17 +907,17 @@ namespace DualScreenDemo { OverlayForm.MainForm.Invoke(new System.Action(() => { - OverlayForm.MainForm.ShowmessageLabel(Messagefist + Messagelast + '_'); + OverlayForm.MainForm.ShowMessageLabel(Messagefist + Messagelast + '_'); })); } else { - OverlayForm.MainForm.ShowmessageLabel(Messagefist + Messagelast + '_'); + OverlayForm.MainForm.ShowMessageLabel(Messagefist + Messagelast + '_'); } } // 真情告白顯示秒數 await Task.Delay(3000); - } + } } } else @@ -1020,21 +942,9 @@ namespace DualScreenDemo { context.Response.Close(); } - } + }*/ - private static async Task OutputMessageAsync(string message, Label messageLabel) - { - messageLabel.Text = ""; // 清空现有的文本 - - foreach (char c in message) - { - messageLabel.Text += c; // 逐字显示消息 - await Task.Delay(500); // 每个字符间隔 0.5 秒 - } - - // 模拟等待 5 秒后继续其他操作 - await Task.Delay(5000); - } + private static string GetMimeType(string filePath) { @@ -1114,14 +1024,14 @@ namespace DualScreenDemo favoriteSongList = searchResults .Select(song => new { - song.Name, - song.Artist_A, - song.Number, - song.Artist_A_Simplified, - song.Artist_B_Simplified, - song.Name_Simplified, - song.HumanVoice, - song.FileName + Name = song.getName(), + ArtistA =song.getArtist_A(), + Number = song.getNumber(), + ArtistAFull = song.getArtist_A(true), + ArtistBFull = song.getArtist_B(true), + NameFull = song.getName(true), + HumanVoice =song.getHumanVoice(), + FileName = song.getFileName() }) .ToList(), status = "success", diff --git a/LocalizedDescriptionAttribute.cs b/LocalizedDescriptionAttribute.cs new file mode 100644 index 0000000..9b56e30 --- /dev/null +++ b/LocalizedDescriptionAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace DualScreenDemo +{ + [AttributeUsage(AttributeTargets.Field)] + public class LocalizedDescriptionAttribute : Attribute + { + public string Traditional { get; } + public string Simplified { get; } + + public LocalizedDescriptionAttribute(string traditional, string simplified) + { + Traditional = traditional; + Simplified = simplified; + } + } +} diff --git a/MediaSubTypes.cs b/MediaSubTypes.cs deleted file mode 100644 index 8e1944a..0000000 --- a/MediaSubTypes.cs +++ /dev/null @@ -1,5 +0,0 @@ -public static class MediaSubTypes -{ - public static readonly Guid YUY2 = new Guid("32595559-0000-0010-8000-00AA00389B71"); - public static readonly Guid IEEE_FLOAT = new Guid("00000003-0000-0010-8000-00AA00389B71"); -} \ No newline at end of file diff --git a/MediaTypes.cs b/MediaTypes.cs deleted file mode 100644 index 767b478..0000000 --- a/MediaTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace DualScreenDemo -{ - public static class MediaTypes - { - public static readonly Guid Video = new Guid("73646976-0000-0010-8000-00AA00389B71"); - public static readonly Guid Audio = new Guid("73647561-0000-0010-8000-00AA00389B71"); - } -} \ No newline at end of file diff --git a/OverlayFormObj/OverlayForm.Labels.cs b/OverlayFormObj/OverlayForm.Labels.cs index fbc1bdb..b14e314 100644 --- a/OverlayFormObj/OverlayForm.Labels.cs +++ b/OverlayFormObj/OverlayForm.Labels.cs @@ -7,149 +7,35 @@ namespace OverlayFormObj public partial class OverlayForm { public Label displayLabel; - public Label songDisplayLabel; + //public Label songDisplayLabel; private List