Compare commits

..

8 Commits

66 changed files with 1125 additions and 3644 deletions

View File

@ -1,12 +0,0 @@
namespace DualScreenDemo
{
public enum ClickSequenceState
{
Initial,
FirstClicked,
SecondClicked,
ThirdClicked,
Completed
}
}

View File

@ -25,8 +25,9 @@ namespace DualScreenDemo
/// <summary>
/// 遙控器接收資料
/// </summary>
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<SongData> history= SongList.GetHistory();
List<SongData> historySongs = new List<SongData>();
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<SongData> historySongs = new List<SongData>();
List<PlayState> playStates = new List<PlayState>();
// 錨點 遙控器
// 從播放紀錄中取出當前頁面應顯示的歌曲與狀態
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();
}
}
}

View File

@ -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()
{

59
DBObj/MyDB.cs Normal file
View File

@ -0,0 +1,59 @@
using System;
using System.Data;
using MySqlConnector;
namespace DBObj
{
public class MyDB : IDisposable
{
private readonly string connectionString = Utils.Env.GetDBConnection();
private MySqlConnection conn;
public MyDB()
{
conn = new MySqlConnection(connectionString);
conn.Open();
Console.WriteLine("MyDB 連線成功!");
}
public void Dispose()
{
if (conn != null)
{
conn.Close();
Console.WriteLine("MyDB 連線已關閉!");
}
}
// SELECT 方法
public DataTable Select(string query, MySqlParameter[] parameters)
{
using (var cmd = new MySqlCommand(query, conn))
{
if (parameters != null)
{
cmd.Parameters.AddRange(parameters);
}
using (var adapter = new MySqlDataAdapter(cmd))
{
DataTable result = new DataTable();
adapter.Fill(result);
return result;
}
}
}
// 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();
}
}
}
}

26
DBObj/Song.cs Normal file
View File

@ -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;}
}
}

View File

@ -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());
}
}
}

107
DBObj/SongList.cs Normal file
View File

@ -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<SongData> publicSong = new();
private static SongData playing=null;
private static List<SongData> not_played = new List<SongData>();
private static List<SongData> played = new List<SongData>();
public static List<SongData> 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 (Room.IsClose()) {
publicPlaying = close;
} else if(Room.IsOpen() && isWelcome){
isWelcome = false;
publicPlaying = welcome;
} else {
publicPlaying = publicSong[0];
publicSong.RemoveAt(0);
publicSong.Add(publicPlaying);
}
return publicPlaying;
}
public static List<SongData> GetHistory()
{
List<SongData> 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();
}
}
}

View File

@ -1,9 +1,11 @@
using System.Data;
using DualScreenDemo;
namespace DBObj
{
public class SongListManager
{
public List<SongData> FavoriteSongs { get; private set; }
private MyDB db = new MyDB();
public List<SongData> FavoriteSongs { get; private set; }
//public bool IsUserLoggedIn { get; set; }
//public string UserPhoneNumber { get; set; }
public SongListManager()
@ -76,6 +78,32 @@ namespace DBObj
var searchResults =PrimaryForm.Instance.SearchSongs_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)
{
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"])
));
}
Console.WriteLine($"查詢到 {searchResults.Count} 筆資料。");
}
return searchResults;
}
}
}

View File

@ -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; }
}
}

19
EnumExtensions.cs Normal file
View File

@ -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<LocalizedDescriptionAttribute>();
if (attr != null)
return isSimplified ? attr.Simplified : attr.Traditional;
return value.ToString();
}
}
}

7
Env.cs
View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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");
}
}

View File

@ -10,6 +10,7 @@ using ActionString = System.Action<string>; // 现在可以在代码中使用 Ac
using System.Collections.Concurrent;
using DBObj;
using OverlayFormObj;
using Newtonsoft.Json.Linq;
namespace DualScreenDemo
{
@ -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<SongData>();
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<PlayState?> DeterminePlayStates(List<SongData> playedSongsHistory)
{
var playStates = new List<PlayState?>();
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<SongData>(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<SongData>(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",

View File

@ -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;
}
}
}

View File

@ -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");
}

View File

@ -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");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -29,16 +29,6 @@ namespace OverlayFormObj
public static System.Timers.Timer unifiedTimer;
private System.Windows.Forms.Timer stickerTimer1 = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer stickerTimer2 = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer keyUpTimer = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer keyDownTimer = new System.Windows.Forms.Timer();
public Label standardKeyLabel;
private System.Windows.Forms.Timer standardKeyTimer = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer messageTimer = new System.Windows.Forms.Timer();
public Label maleKeyLabel;
public Label messageLabel;
private System.Windows.Forms.Timer maleKeyTimer;
public Label femaleKeyLabel;
private System.Windows.Forms.Timer femaleKeyTimer;
private System.Windows.Forms.Timer secondLineTimer;
private DateTime secondLineStartTime;
private const int secondLineDuration = 20000;
@ -109,182 +99,159 @@ namespace OverlayFormObj
currentSegmentIndex = 0;
}
private void InitializeMaleKeyTimer()
private void AddCenteredPicture(Bitmap bitmap, int y)
{
maleKeyTimer = new System.Windows.Forms.Timer();
maleKeyTimer.Interval = 3000;
maleKeyTimer.Tick += (s, e) =>
{
HideAllLabels();
};
int x = (this.Width - bitmap.Width) / 2;
AddPicture(bitmap, x, y);
}
private void InitializeFemaleKeyTimer()
private void AddPicture(Bitmap bitmap, int x, int y)
{
femaleKeyTimer = new System.Windows.Forms.Timer();
femaleKeyTimer.Interval = 3000;
femaleKeyTimer.Tick += (s, e) =>
PictureBox pictureBox = new PictureBox
{
HideAllLabels();
Image = bitmap,
Size = bitmap.Size,
BackColor = Color.Transparent,
Location = new Point(x, y)
};
this.Controls.Add(pictureBox);
pictureBox.BringToFront();
}
private void AddCenteredPicture(Bitmap bitmap, int y)
{
int x = (this.Width - bitmap.Width) / 2;
AddPicture(bitmap, x, y);
}
private void AddPicture(Bitmap bitmap, int x, int y)
{
PictureBox pictureBox = new PictureBox
{
Image = bitmap,
Size = bitmap.Size,
BackColor = Color.Transparent,
Location = new Point(x, y)
};
this.Controls.Add(pictureBox);
pictureBox.BringToFront();
}
private Bitmap GenerateTextImage(string text, Font font, Color textColor, Color backgroundColor)
{
SizeF textSize;
using (Bitmap tempBitmap = new Bitmap(1, 1))
using (Graphics tempGraphics = Graphics.FromImage(tempBitmap))
{
textSize = tempGraphics.MeasureString(text, font);
}
// 創建一個稍大的位圖尺寸,以容納描邊
int padding = 4; // 描邊寬度
Bitmap bitmap = new Bitmap((int)textSize.Width + padding * 2, (int)textSize.Height + padding * 2);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(backgroundColor);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// 先繪製黑色描邊
using (Brush outlineBrush = new SolidBrush(Color.Black))
private Bitmap GenerateTextImage(string text, Font font, Color textColor, Color backgroundColor)
{
for (int x = -2; x <= 2; x++)
SizeF textSize;
using (Bitmap tempBitmap = new Bitmap(1, 1))
using (Graphics tempGraphics = Graphics.FromImage(tempBitmap))
{
for (int y = -2; y <= 2; y++)
textSize = tempGraphics.MeasureString(text, font);
}
// 創建一個稍大的位圖尺寸,以容納描邊
int padding = 4; // 描邊寬度
Bitmap bitmap = new Bitmap((int)textSize.Width + padding * 2, (int)textSize.Height + padding * 2);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(backgroundColor);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// 先繪製黑色描邊
using (Brush outlineBrush = new SolidBrush(Color.Black))
{
if (x != 0 || y != 0)
for (int x = -2; x <= 2; x++)
{
graphics.DrawString(text, font, outlineBrush,
new PointF(padding + x, padding + y));
for (int y = -2; y <= 2; y++)
{
if (x != 0 || y != 0)
{
graphics.DrawString(text, font, outlineBrush,
new PointF(padding + x, padding + y));
}
}
}
}
// 繪製中心文字
using (Brush textBrush = new SolidBrush(textColor))
{
graphics.DrawString(text, font, textBrush,
new PointF(padding, padding));
}
}
// 修剪圖片邊緣空白
return TrimBitmap(bitmap);
}
// 繪製中心文字
using (Brush textBrush = new SolidBrush(textColor))
private Bitmap TrimBitmap(Bitmap source)
{
graphics.DrawString(text, font, textBrush,
new PointF(padding, padding));
}
}
Rectangle rect = FindContentBounds(source);
// 修剪圖片邊緣空白
return TrimBitmap(bitmap);
}
if (rect.Width == 0 || rect.Height == 0)
return source; // 防止圖片完全空白時崩潰
private Bitmap TrimBitmap(Bitmap source)
{
Rectangle rect = FindContentBounds(source);
if (rect.Width == 0 || rect.Height == 0)
return source; // 防止圖片完全空白時崩潰
Bitmap trimmedBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(trimmedBitmap))
{
g.DrawImage(source, 0, 0, rect, GraphicsUnit.Pixel);
}
return trimmedBitmap;
}
private Rectangle FindContentBounds(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
int top = 0, left = 0, bottom = height - 1, right = width - 1;
bool found = false;
// 找到頂邊界
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (bmp.GetPixel(x, y).A > 0)
Bitmap trimmedBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(trimmedBitmap))
{
top = y;
found = true;
break;
g.DrawImage(source, 0, 0, rect, GraphicsUnit.Pixel);
}
}
if (found) break;
}
found = false;
// 找到底邊界
for (int y = height - 1; y >= 0; y--)
{
for (int x = 0; x < width; x++)
return trimmedBitmap;
}
private Rectangle FindContentBounds(Bitmap bmp)
{
if (bmp.GetPixel(x, y).A > 0)
{
bottom = y;
found = true;
break;
}
}
if (found) break;
}
int width = bmp.Width;
int height = bmp.Height;
found = false;
// 找到左邊界
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (bmp.GetPixel(x, y).A > 0)
{
left = x;
found = true;
break;
}
}
if (found) break;
}
int top = 0, left = 0, bottom = height - 1, right = width - 1;
found = false;
// 找到右邊界
for (int x = width - 1; x >= 0; x--)
{
for (int y = 0; y < height; y++)
{
if (bmp.GetPixel(x, y).A > 0)
{
right = x;
found = true;
break;
}
}
if (found) break;
}
bool found = false;
return Rectangle.FromLTRB(left, top, right + 1, bottom + 1);
}
// 找到頂邊界
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (bmp.GetPixel(x, y).A > 0)
{
top = y;
found = true;
break;
}
}
if (found) break;
}
found = false;
// 找到底邊界
for (int y = height - 1; y >= 0; y--)
{
for (int x = 0; x < width; x++)
{
if (bmp.GetPixel(x, y).A > 0)
{
bottom = y;
found = true;
break;
}
}
if (found) break;
}
found = false;
// 找到左邊界
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (bmp.GetPixel(x, y).A > 0)
{
left = x;
found = true;
break;
}
}
if (found) break;
}
found = false;
// 找到右邊界
for (int x = width - 1; x >= 0; x--)
{
for (int y = 0; y < height; y++)
{
if (bmp.GetPixel(x, y).A > 0)
{
right = x;
found = true;
break;
}
}
if (found) break;
}
return Rectangle.FromLTRB(left, top, right + 1, bottom + 1);
}
@ -296,7 +263,7 @@ private Rectangle FindContentBounds(Bitmap bmp)
{
string currentText = MainForm.displayLabel.Text;
MainForm.nextSongLabel.Visible = false;
MainForm.topLeftLabel.Visible = false;
string combinedText = currentText + newText;
@ -308,7 +275,7 @@ private Rectangle FindContentBounds(Bitmap bmp)
MainForm.displayLabel.Text = combinedText;
MainForm.nextSongLabel.Visible = false;
MainForm.topLeftLabel.Visible = false;
displayTimer.Stop();
@ -356,7 +323,6 @@ private Rectangle FindContentBounds(Bitmap bmp)
secondLineTimer = new System.Windows.Forms.Timer();
secondLineTimer.Interval = 100;
secondLineTimer.Tick += SecondLineTimer_Tick;
try
{
@ -370,12 +336,6 @@ private Rectangle FindContentBounds(Bitmap bmp)
Console.WriteLine("Error reading marquee text from file: " + ex.Message);
marqueeText = "這是跑馬燈文字示例 - 歡迎使用MediaPlayerForm!";
}
this.DoubleBuffered = true;
}
@ -422,54 +382,51 @@ private Rectangle FindContentBounds(Bitmap bmp)
};
}
private static void DisplayTimer_Tick(object sender, EventArgs e)
{
if (MainForm.InvokeRequired)
{
MainForm.Invoke(new System.Action(() =>
private static void DisplayTimer_Tick(object sender, EventArgs e)
{
MainForm.displayLabel.Text = "";
MainForm.nextSongLabel.Visible = true; // 显示 nextSongLabel
}));
}
else
{
MainForm.displayLabel.Text = "";
MainForm.nextSongLabel.Visible = true; // 显示 nextSongLabel
}
if (MainForm.InvokeRequired)
{
MainForm.Invoke(new System.Action(() =>
{
MainForm.displayLabel.Text = "";
MainForm.topLeftLabel.Visible = true; // 显示 topLeftLabel
}));
}
else
{
MainForm.displayLabel.Text = "";
MainForm.topLeftLabel.Visible = true; // 显示 topLeftLabel
}
displayTimer.Stop(); // 停止计时器
}
displayTimer.Stop(); // 停止计时器
}
// 當 songDisplayTimer 計時完成時會呼叫此函式
private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
{
// 檢查是否需要跨執行緒操作 UI 控制項
if (MainForm.InvokeRequired)
{
// 如果目前不在 UI 執行緒上,必須透過 Invoke 安全執行 UI 更新邏輯
Console.WriteLine("SongDisplayTimer_Tick invoked on UI thread.");
MainForm.BeginInvoke(new Action(() =>
// 當 songDisplayTimer 計時完成時會呼叫此函式
private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
{
if (MainForm.songDisplayLabel != null)
MainForm.songDisplayLabel.Text = "";
// 檢查是否需要跨執行緒操作 UI 控制項
if (MainForm.InvokeRequired)
{
// 如果目前不在 UI 執行緒上,必須透過 Invoke 安全執行 UI 更新邏輯
Console.WriteLine("SongDisplayTimer_Tick invoked on UI thread.");
if (MainForm.nextSongLabel != null)
MainForm.nextSongLabel.Visible = true;
}));
}
else
{
// 如果已經在 UI 執行緒,就直接更新 UI 控制項
Console.WriteLine("SongDisplayTimer_Tick invoked on background thread.");
MainForm.songDisplayLabel.Text = "";
MainForm.nextSongLabel.Visible = true;
}
MainForm.BeginInvoke(new Action(() =>
{
if (MainForm.topLeftLabel != null)
MainForm.topLeftLabel.Visible = true;
}));
}
else
{
// 如果已經在 UI 執行緒,就直接更新 UI 控制項
Console.WriteLine("SongDisplayTimer_Tick invoked on background thread.");
//MainForm.songDisplayLabel.Text = "";
MainForm.topLeftLabel.Visible = true;
}
// 停止計時器,避免重複觸發
songDisplayTimer.Stop();
}
// 停止計時器,避免重複觸發
songDisplayTimer.Stop();
}
@ -521,7 +478,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
private void DisplayMessage(string message, int duration)
{
MainForm.nextSongLabel.Visible = false;
MainForm.topLeftLabel.Visible = false;
displayLabel.Text = message;
unifiedTimer.Interval = duration;
unifiedTimer.Start();
@ -561,27 +518,6 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
}
}
public void UpdateSongDisplayLabel(string newText)
{
songDisplayLabel.Text = newText;
songDisplayLabel.Font = new Font("Arial", 125);
songDisplayLabel.ForeColor = Color.White;
songDisplayTimer.Stop();
songDisplayTimer.Start();
this.Invalidate();
}
private void SecondLineTimer_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - secondLineStartTime).TotalMilliseconds >= secondLineDuration)
@ -591,19 +527,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
}
}
public void ResetMarqueeTextToWelcomeMessage()
{
try
{
string filePath = Path.Combine(Application.StartupPath,"txt","WelcomeMessage.txt");
string welcomeMessage = File.ReadAllText(filePath);
this.UpdateMarqueeText(welcomeMessage, MarqueeStartPosition.Right, Color.White);
}
catch (Exception ex)
{
Console.WriteLine("Error reading marquee text from file: " + ex.Message);
}
}
protected override void OnPaint(PaintEventArgs e)
{
@ -682,69 +606,6 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
}
public void DisplayBarrage(string text)
{
if (this.InvokeRequired)
{
this.Invoke(new System.Action(() => DisplayBarrage(text)));
return;
}
Random rnd = new Random();
for (int i = 0; i < 30; i++)
{
Label lblBarrage = new Label
{
Text = text,
AutoSize = true,
ForeColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256)),
Font = new Font("Arial", rnd.Next(10, 50)),
Location = new Point(rnd.Next(0, this.Width), rnd.Next(0, this.Height))
};
this.Controls.Add(lblBarrage);
lblBarrage.BringToFront();
System.Windows.Forms.Timer moveTimer = new System.Windows.Forms.Timer { Interval = 50 };
moveTimer.Tick += (sender, e) =>
{
lblBarrage.Left -= 5;
if (lblBarrage.Right < 0)
{
lblBarrage.Dispose();
moveTimer.Dispose();
}
};
moveTimer.Start();
int duration = rnd.Next(3000, 7000);
System.Windows.Forms.Timer durationTimer = new System.Windows.Forms.Timer { Interval = duration };
durationTimer.Tick += (sender, e) =>
{
if (moveTimer.Enabled)
{
moveTimer.Stop();
moveTimer.Dispose();
}
this.Controls.Remove(lblBarrage);
lblBarrage.Dispose();
durationTimer.Stop();
durationTimer.Dispose();
};
durationTimer.Start();
}
}
public void DisplaySticker(string stickerId)
{
//Console.WriteLine("Attempting to display sticker.");
@ -800,7 +661,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
public static string ReadSongNumber()
{
string songNumber = MainForm.displayLabel.Text;
MainForm.nextSongLabel.Visible = false;
MainForm.topLeftLabel.Visible = false;
return songNumber;
}
@ -851,27 +712,9 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
if (control != MainForm.displayLabel &&
control != MainForm.pauseLabel &&
control != MainForm.muteLabel &&
control != MainForm.volumeUpLabel &&
control != MainForm.volumeDownLabel &&
control != MainForm.micUpLabel &&
control != MainForm.micDownLabel &&
control != MainForm.standardKeyLabel &&
control != MainForm.keyUpLabel &&
control != MainForm.keyDownLabel &&
control != MainForm.maleKeyLabel &&
control != MainForm.femaleKeyLabel &&
control != MainForm.squareLabel &&
control != MainForm.professionalLabel &&
control != MainForm.standardLabel &&
control != MainForm.singDownLabel &&
control != MainForm.brightLabel &&
control != MainForm.softLabel &&
control != MainForm.autoLabel &&
control != MainForm.romanticLabel &&
control != MainForm.dynamicLabel &&
control != MainForm.tintLabel &&
control != MainForm.topRightLabel &&
control != MainForm.blackBackgroundPanel &&
control != MainForm.nextSongLabel)
control != MainForm.topLeftLabel)
{
MainForm.Controls.Remove(control);
// control.Dispose();
@ -1004,13 +847,8 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
if (songIndex >= 0 && songIndex < totalSongs)
{
selectedSong = LanguageSongList[songIndex];
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].Name + " " + selectedSong.FileName);
// DisplayActionWithSong(currentPage, songIndex, "點播");
AddSongToPlaylist(selectedSong);
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].getName() + " " + selectedSong.getFileName());
SongList.Add(selectedSong);
}
else
{
@ -1036,13 +874,8 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
if (songIndex < totalSongs)
{
selectedSong = LanguageSongList[songIndex];
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].Name + " " + selectedSong.FileName );
// DisplayActionWithSong(currentPage, songIndex, "插播");
InsertSongToPlaylist(selectedSong);
Console.WriteLine("Adding song to playlist: " + LanguageSongList[songIndex].getName() + " " + selectedSong.getFileName() );
SongList.Insert(selectedSong);
}
else
{
@ -1120,7 +953,7 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
if (songIndex < totalSongs)
{
selectedSong = LanguageSongList[songIndex];
Console.WriteLine("Adding song to playlist C: " + LanguageSongList[songIndex].Name + " " + selectedSong.FileName);
Console.WriteLine("Adding song to playlist C: " + LanguageSongList[songIndex].getName() + " " + selectedSong.getFileName());
DisplaySongsWithArrows(currentPage, songIndex);
@ -1173,34 +1006,16 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
if (control != displayLabel &&
control != pauseLabel &&
control != muteLabel &&
control != volumeUpLabel &&
control != volumeDownLabel &&
control != micUpLabel &&
control != micDownLabel &&
control != standardKeyLabel &&
control != keyUpLabel &&
control != keyDownLabel &&
control != maleKeyLabel &&
control != femaleKeyLabel &&
control != squareLabel &&
control != professionalLabel &&
control != standardLabel &&
control != singDownLabel &&
control != brightLabel &&
control != softLabel &&
control != autoLabel &&
control != romanticLabel &&
control != dynamicLabel &&
control != tintLabel &&
control != topRightLabel &&
control != blackBackgroundPanel &&
control != nextSongLabel)
control != topLeftLabel)
{
this.Controls.Remove(control);
control.Dispose();
}
}
}
public void UpdateHistoryLabel(List<SongData> historySongs, List<PlayState> playStates, int currentPage, int totalPages)
public void UpdateHistoryLabel(List<SongData> historySongs, int currentPage, int totalPages)
{
// 移除畫面上所有現有的 PictureBox用於刷新內容
@ -1227,37 +1042,15 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
int rightMargin = this.Width - 100;
// 逐一繪製歷史歌曲列表
for (int i = 0; i < historySongs.Count; i++)
{
var song = historySongs[i]; // 歌曲資料
var state = playStates[i]; // 對應的播放狀態
string status; // 播放狀態文字(如「播放中」)
Color textColor; // 對應的顏色
// 根據播放狀態決定狀態文字與顏色
switch (state)
{
case PlayState.Played:
status = "(播畢)";
textColor = Color.FromArgb(200, 75, 125); // 播畢顏色:紫紅色
break;
case PlayState.Playing:
status = "(播放中)";
textColor = Color.LimeGreen; // 播放中顏色:亮綠
break;
case PlayState.NotPlayed:
status = "";
textColor = Color.White; // 尚未播放:白色
break;
default:
status = "";
textColor = Color.White;
break;
}
var song = historySongs[i]; // 歌曲資料
string status=song.GetStateTxt(false); // 播放狀態文字(如「播放中」)
Color textColor=song.GetStateColor(); // 對應的顏色
// 建立顯示的歌曲文字,例如 "1. 我的歌"
string songText = $"{i + 1}. {song.Name}";
string songText = $"{i + 1}. {song.getName()}";
Font songFont = new Font("Microsoft JhengHei", 50, FontStyle.Bold);
// 將歌名轉成圖片
@ -1526,100 +1319,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
ClearDisplay();
DisplaySongs(currentPage);
}
// 歌庫路徑調整
public void AddSongToPlaylist(SongData songData)
{
try
{
// 之後還要設計成本地的資料夾位置
string pathToPlay = songData.getFile();
if (!string.IsNullOrEmpty(pathToPlay))
{
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
PrimaryForm.userRequestedSongs.Add(songData);
PrimaryForm.playedSongsHistory.Add(songData);
PrimaryForm.playStates.Add(wasEmpty ? PlayState.Playing : PlayState.NotPlayed);
// 刷新頁面
if (PrimaryForm.Instance.multiPagePanel.get_currentSongList() == PrimaryForm.playedSongsHistory)
PrimaryForm.Instance.multiPagePanel.LoadSongs(PrimaryForm.Instance.currentSongList);
if (wasEmpty)
{
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs);
PrimaryForm.currentSongIndexInHistory += 1;
}
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
PrimaryForm.PrintPlayingSongList();
// 點播次數+1
PrimaryForm.Instance.AddSongCount(songData.Number);
}
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
public void InsertSongToPlaylist(SongData songData)
{
try
{
// 從 songData 中取得兩個可能的檔案路徑主機1與主機2
var pathToPlay = songData.getFile();
// 檢查兩個主機上的檔案是否皆不存在
if (!string.IsNullOrEmpty(pathToPlay))
{
// 若其中一個存在,就用第一個存在的那個檔案
Console.WriteLine("path to play" + pathToPlay);
// 檢查目前使用者歌單是否為空
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
if (wasEmpty)
{
// 若是空的,代表是第一首歌,直接加入並設為正在播放
PrimaryForm.userRequestedSongs.Add(songData); // 加入播放清單
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs); // 傳給播放器
PrimaryForm.playedSongsHistory.Add(songData); // 加入播放歷史
PrimaryForm.playStates.Add(PlayState.Playing); // 設定狀態為正在播放
PrimaryForm.currentSongIndexInHistory += 1; // 歷史索引 +1
}
else if (PrimaryForm.userRequestedSongs.Count == 1)
{
// 若清單中已有一首,插入新歌在 index 1 (即目前播放之後的位置)
PrimaryForm.userRequestedSongs.Insert(1, songData);
PrimaryForm.playedSongsHistory.Insert(PrimaryForm.currentSongIndexInHistory + 1, songData);
PrimaryForm.playStates.Insert(PrimaryForm.currentSongIndexInHistory + 1, PlayState.NotPlayed); // 尚未播放
}
else
{
// 若清單中超過一首,同樣插入在 index 1也是在當前歌曲之後的位置
PrimaryForm.userRequestedSongs.Insert(1, songData);
PrimaryForm.playedSongsHistory.Insert(PrimaryForm.currentSongIndexInHistory + 1, songData);
PrimaryForm.playStates.Insert(PrimaryForm.currentSongIndexInHistory + 1, PlayState.NotPlayed);
}
// 更新下一首即將播放的資訊(畫面或播放器邏輯用)
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
// 印出目前播放清單資訊到畫面或 console
PrimaryForm.PrintPlayingSongList();
}
}
catch (Exception ex)
{
// 捕捉所有例外並印出錯誤訊息(避免整個流程當掉)
Console.WriteLine("Error occurred: " + ex.Message);
}
}
// 測試
public int currentPage = 1;
public int songsPerPage = 5;
@ -1681,7 +1381,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Name}";
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].getName(false)}";
string artistText = LanguageSongList[i].artist_text();
maxSongLength = Math.Max(maxSongLength, songText.Length);
@ -1701,7 +1401,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
// 計算行高
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Name}";
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].getName(false)}";
string artistText = LanguageSongList[i].artist_text();
Font songFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
@ -1718,7 +1418,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
{
int songNumber = i - startIndex + 1;
string songText = $"{songNumber}. {LanguageSongList[i].Name}";
string songText = $"{songNumber}. {LanguageSongList[i].getName(false)}";
string artistText = LanguageSongList[i].artist_text();
Font songFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
@ -1791,7 +1491,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
int maxArtistLength = 0;
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Name}";
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].getName()}";
string artistText = LanguageSongList[i].artist_text();
maxSongLength = Math.Max(maxSongLength, songText.Length);
@ -1807,7 +1507,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
int rowHeight = 0;
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Name}";
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].getName(false)}";
string artistText = LanguageSongList[i].artist_text();
Font tempSongFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
@ -1824,7 +1524,7 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
{
int songNumber = i - startIndex + 1;
string songText = $"{songNumber}. {LanguageSongList[i].Name}";
string songText = $"{songNumber}. {LanguageSongList[i].getName(false)}";
string artistText = LanguageSongList[i].artist_text();
// 設定顏色,選中的索引顯示為亮綠色
@ -1847,67 +1547,6 @@ private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後
}
}
public void DisplayActionWithSong(int page, int songIndex, string actionType)
{
// try
// {
// if (LanguageSongList == null || LanguageSongList.Count == 0)
// {
// Console.WriteLine("Error: LanguageSongList is null or empty.");
// return;
// }
// SongData song = LanguageSongList[songIndex];
// this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
// int songsPerColumn = 5;
// int startIndex = (page - 1) * songsPerPage;
// int endIndex = Math.Min(startIndex + songsPerPage, LanguageSongList.Count);
// int totalPages = (int)Math.Ceiling((double)LanguageSongList.Count / songsPerPage);
// string headerText = $"{actionType}: {song.ArtistA} - {song.Song} ({page} / {totalPages})";
// Font headerFont = new Font("Microsoft JhengHei", 40, FontStyle.Bold);
// Color headerColor = actionType == "點播" ? Color.LimeGreen : Color.Yellow;
// Bitmap headerBitmap = GenerateTextImage(headerText, headerFont, headerColor, Color.Transparent);
// AddCenteredPicture(headerBitmap, 150);
// int startY = 250;
// int verticalSpacing = 10;
// int leftColumnX = 200;
// int rightColumnX = this.Width / 2 + 150;
// for (int i = startIndex; i < endIndex; i++)
// {
// int songNumber = i - startIndex + 1;
// string songText = $"{songNumber}. {LanguageSongList[i].Song}";
// string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
// ? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
// : LanguageSongList[i].ArtistA;
// Font songFont = new Font("Microsoft JhengHei", 40, FontStyle.Bold);
// Bitmap songBitmap = GenerateTextImage(songText, songFont, Color.White, Color.Transparent);
// Font artistFont = new Font("Microsoft JhengHei", 30, FontStyle.Bold);
// Bitmap artistBitmap = GenerateTextImage(artistText, artistFont, Color.White, Color.Transparent);
// int x = (i - startIndex) < songsPerColumn ? leftColumnX : rightColumnX;
// int y = startY + ((i - startIndex) % songsPerColumn) * (songBitmap.Height + verticalSpacing);
// AddPicture(songBitmap, x, y);
// AddPicture(artistBitmap, x + songBitmap.Width + 20, y);
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Error in DisplayActionWithSong: {ex.Message}");
// Console.WriteLine(ex.StackTrace);
// }
}
public void NextPage()
{

View File

@ -1,11 +1,26 @@
using System.ComponentModel;
namespace DualScreenDemo
{
public enum PlayState
{
Playing,
Played,
NotPlayed,
Skipped
[LocalizedDescription("", "")]//未播放
NotPlayed,
[LocalizedDescription("播放中", "播放中")]
Playing,
[LocalizedDescription("播畢", "播毕")]
Played,
[LocalizedDescription("插播", "插播")]
InsertPlayback,
[LocalizedDescription("無文件", "无文件")]
NoFile,
[LocalizedDescription("已跳過", "已跳过")]
Skipped
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("F1"); // Set the query for SQL to filter by genre "F1"
var chinaSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = chinaSongs;
totalPages = (int)Math.Ceiling((double)chinaSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(chinaSongs);
}
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("A1"); // Set the query for SQL to filter by genre "F1"
var loveDuetSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = loveDuetSongs;
totalPages = (int)Math.Ceiling((double)loveDuetSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(loveDuetSongs);
}
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("C1"); // Set the query for SQL to filter by genre "F1"
var medleyDanceSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = medleyDanceSongs;
totalPages = (int)Math.Ceiling((double)medleyDanceSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(medleyDanceSongs);
}
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("D1"); // Set the query for SQL to filter by genre "F1"
var ninetiesSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = ninetiesSongs;
totalPages = (int)Math.Ceiling((double)ninetiesSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(ninetiesSongs);
}
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("E1"); // Set the query for SQL to filter by genre "F1"
var nostalgicSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = nostalgicSongs;
totalPages = (int)Math.Ceiling((double)nostalgicSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(nostalgicSongs);
}
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("B1"); // Set the query for SQL to filter by genre "F1"
var talentShowSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = talentShowSongs;
totalPages = (int)Math.Ceiling((double)talentShowSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(talentShowSongs);
}
}
}

View File

@ -18,11 +18,10 @@ namespace DualScreenDemo
string query = SetQueryforSQL("G1"); // Set the query for SQL to filter by genre "F1"
var vietnameseSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = vietnameseSongs;
totalPages = (int)Math.Ceiling((double)vietnameseSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(vietnameseSongs);
}
}
}

View File

@ -185,12 +185,11 @@ namespace DualScreenDemo
string query = SetQueryforSQL("A1");
var loveDuetSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = loveDuetSongs;
totalPages = (int)Math.Ceiling((double)loveDuetSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(loveDuetSongs);
SetHotSongButtonsVisibility(false);

View File

@ -17,12 +17,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '國語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var guoYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = guoYuSongs;
totalPages = (int)Math.Ceiling((double)guoYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(guoYuSongs);
}
}
}

View File

@ -17,12 +17,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '韓語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var hanYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = hanYuSongs;
totalPages = (int)Math.Ceiling((double)hanYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(hanYuSongs);
}
}
}

View File

@ -18,12 +18,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '日語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var riYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = riYuSongs;
totalPages = (int)Math.Ceiling((double)riYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(riYuSongs);
}
}
}

View File

@ -17,12 +17,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '台語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var taiYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = taiYuSongs;
totalPages = (int)Math.Ceiling((double)taiYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(taiYuSongs);
}
}
}

View File

@ -17,12 +17,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '英語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var yingWenSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = yingWenSongs;
totalPages = (int)Math.Ceiling((double)yingWenSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(yingWenSongs);
}
}
}

View File

@ -18,12 +18,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '粵語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var yueYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = yueYuSongs;
totalPages = (int)Math.Ceiling((double)yueYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(yueYuSongs);
}
}
}

View File

@ -136,12 +136,11 @@ namespace DualScreenDemo
string query = "SELECT * FROM song_library_cache WHERE language_name = '國語' AND (`artistA_category` = '團' OR `artistB_category` = '團') ORDER BY song_counts DESC;";
var guoYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = guoYuSongs;
totalPages = (int)Math.Ceiling((double)guoYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(guoYuSongs);
SetHotSongButtonsVisibility(false);

View File

@ -112,12 +112,11 @@ namespace DualScreenDemo
private void UpdateSongList(List<SongData> songs)
{
currentPage = 0;
currentSongList = songs;
totalPages = (int)Math.Ceiling((double)songs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(songs);
}
private void SetButtonsVisibility()

View File

@ -11,11 +11,10 @@ namespace DualScreenDemo
var selectedSongs = PrimaryForm.Instance.SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = selectedSongs;
totalPages = (int)Math.Ceiling((double)selectedSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(selectedSongs);
}
}
}

View File

@ -11,11 +11,10 @@ namespace DualScreenDemo
var selectedSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = selectedSongs;
totalPages = (int)Math.Ceiling((double)selectedSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(selectedSongs);
}
}
}

View File

@ -78,13 +78,10 @@ namespace DualScreenDemo
string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' ORDER BY song_counts DESC LIMIT 100";
var guoYuSongs = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = guoYuSongs;
totalPages = (int)Math.Ceiling((double)guoYuSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(guoYuSongs);
SetHotSongButtonsVisibility(false);
SetNewSongButtonsVisibility(false);
@ -125,16 +122,12 @@ namespace DualScreenDemo
activeButton.BackgroundImage = activeBackground;
string query = $"SELECT * FROM song_library_cache WHERE language_name = '{category}' ORDER BY song_counts DESC LIMIT 100";
var selectedSongs = SearchSongs_Mysql(query);
/*var selectedSongs = allSongs.Where(song => song.Category == category)
.OrderByDescending(song => song.Plays)
.ToList();*/
currentPage = 0;
currentSongList = selectedSongs;
totalPages = (int)Math.Ceiling((double)selectedSongs.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(selectedSongs);
}
private void SetPictureBoxLanguageButtonsVisibility(bool isVisible)

View File

@ -89,14 +89,11 @@ namespace DualScreenDemo
string query = setQueryforNewSong("國語");
var guoYuSongs2 = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = guoYuSongs2;
totalPages = (int)Math.Ceiling((double)guoYuSongs2.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(guoYuSongs2);
SetHotSongButtonsVisibility(false);
SetSingerSearchButtonsVisibility(false);
SetSongSearchButtonsVisibility(false);

View File

@ -221,11 +221,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(SearchFavoriteSongs_Mysql());
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
ToggleFavoritePictureBoxButtonsVisibility();
}
@ -257,11 +256,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(SearchFavoriteSongs_Mysql());
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
ToggleFavoritePictureBoxButtonsVisibility();
}
@ -274,11 +272,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(SearchFavoriteSongs_Mysql());
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
ToggleFavoritePictureBoxButtonsVisibility();
}

View File

@ -194,7 +194,7 @@ namespace DualScreenDemo
RefreshDisplayBase_Singer();
}
public void LoadPlayedSongs(List<SongData> songs, List<PlayState> states)
public void LoadPlayedSongs(List<SongData> songs)
{
_isShowingSinger = false;
currentSongList = songs;
@ -376,76 +376,20 @@ namespace DualScreenDemo
{
// 創建歌曲標籤
Label songLabel = new Label();
string statusText = ""; // 狀態文字
bool isCurrentlyPlaying = false; // 是否正在播放
bool hasBeenPlayed = false; // 是否已播放完成
bool isLatestInstance = true; // 是否是最新的歌曲
// 僅在 "已點歌曲" 頁面顯示播放狀態
string statusText;
Color color;
if (PrimaryForm.Instance.isOnOrderedSongsPage)
{
// 判斷是否正在播放公播歌單 (若用戶點播歌單為空,則播放公播歌單)
bool isPlayingPublicList = userRequestedSongs.Count == 0 ||
(currentSongIndexInHistory >= userRequestedSongs.Count - 1 && PrimaryForm.Instance.videoPlayerForm.IsPlayingPublicSong);
if (isPlayingPublicList)
{
// 若播放公播歌單,代表已點歌曲皆已播放完畢
hasBeenPlayed = true;
songLabel.ForeColor = Color.Gray;
statusText = IsSimplified ? "(播毕)" : "(播畢)";
}
else
{
// 計算已完成播放的歌曲數量
int completedCount = currentSongIndexInHistory;
//Console.WriteLine("currentSongIndexInHistory:" + currentSongIndexInHistory);
// 遍歷已點歌曲歷史
/*for (int i = 0; i <= currentSongIndexInHistory && i < playedSongsHistory.Count; i++) {
if (i == currentSongIndexInHistory) {
completedCount = i + 1; // 当前播放的歌曲
break;
}
// 检查播放状态
if (i < playStates.Count) {
if (playStates[i] == PlayState.Played || playStates[i] == PlayState.Playing) {
completedCount++;
}
// 如果是切歌状态,不增加计数
}
}*/
// 計算歌曲在歷史中的位置
int songPosition = pageOffset + index;
// 判斷歌曲狀態
if (songPosition < completedCount)
{
// 已播放完成
hasBeenPlayed = true;
songLabel.ForeColor = Color.Gray;
statusText = IsSimplified ? "(播毕)" : "(播畢)";
}
else if (songPosition == completedCount)
{
// 正在播放
isCurrentlyPlaying = true;
songLabel.ForeColor = Color.LimeGreen;
statusText = IsSimplified ? "(播放中)" : "(播放中)";
}
else
{
// 未播放
songLabel.ForeColor = Color.White;
statusText = string.Empty;
}
}
statusText = song.GetStateTxt(IsSimplified); // 狀態文字
color = song.GetStateColor();
}
else
{
// 未在 "已點歌曲" 頁面顯示白色
songLabel.ForeColor = Color.White;
color = Color.White;
statusText = string.Empty;
}
songLabel.ForeColor = color;
// 根據簡繁體設置選擇要顯示的文字
string songText = song.getName(IsSimplified);
@ -507,7 +451,7 @@ namespace DualScreenDemo
int artistWidth = (int)(this.Width * ArtistWidth);
int artistX = songX + songWidth + 10;
// 添加人聲標籤
if (song.HumanVoice == 1)
if (song.getHumanVoice() == 1)
{
PictureBox icon = new PictureBox()
{
@ -542,20 +486,12 @@ namespace DualScreenDemo
};
// 根據文字長度設置字體大小
int fold = 14;
if (artistText.Length > 6)
{
artistLabel.Font = new Font("微軟正黑體", 10, FontStyle.Bold);
}
else if (artistText.Length > 3)
{
artistLabel.Font = new Font("微軟正黑體", 12, FontStyle.Bold);
}
else
{
artistLabel.Font = new Font("微軟正黑體", 14, FontStyle.Bold);
}
//artistLabel.Font = new Font("微軟正黑體", 16, FontStyle.Bold);
fold = 10;
else if (artistText.Length > 3)
fold = 12;
artistLabel.Font = new Font("微軟正黑體", fold, FontStyle.Bold);
artistLabel.ForeColor = Color.FromArgb(30,144,255);
songLabel.TextAlign = ContentAlignment.MiddleLeft;
@ -565,48 +501,15 @@ namespace DualScreenDemo
artistLabel.BackColor = Color.Transparent;
// 定義滑鼠進入 (MouseEnter) 事件的處理程序
EventHandler mouseEnter = (sender, e) => {
// 當不在「已點歌曲」頁面,或者該歌曲不是當前正在播放的歌曲,
// 且(該歌曲未播放過或不是該歌曲的最新實例)時,改變顯示樣式
if (!PrimaryForm.Instance.isOnOrderedSongsPage ||
(!isCurrentlyPlaying && (!hasBeenPlayed || !isLatestInstance)))
{
// 當滑鼠移到歌曲上時,變更歌曲名稱為黃色
songLabel.ForeColor = Color.Yellow;
// 變更歌手名稱為黃色
artistLabel.ForeColor = Color.Yellow;
// 增強分隔線的亮度,使其更明顯
separatorPanel.BackColor = Color.FromArgb(120, 255, 255, 255);
}
songLabel.ForeColor = Color.Yellow;
artistLabel.ForeColor = Color.Yellow;
separatorPanel.BackColor = Color.FromArgb(120, 255, 255, 255);
};
// 定義滑鼠離開 (MouseLeave) 事件的處理程序
EventHandler mouseLeave = (sender, e) => {
// 判斷是否處於「已點歌曲」頁面
if (PrimaryForm.Instance.isOnOrderedSongsPage)
{
// 如果當前歌曲正在播放,則維持綠色顯示
if (isCurrentlyPlaying)
{
songLabel.ForeColor = Color.LimeGreen;
}
// 如果該歌曲已播放完成,且是該歌曲的最新實例,則變為灰色
else if (hasBeenPlayed && isLatestInstance)
{
songLabel.ForeColor = Color.Gray;
}
// 其他情況,則維持白色
else
{
songLabel.ForeColor = Color.White;
}
}
else
{
// 若不在「已點歌曲」頁面,則默認為白色
songLabel.ForeColor = Color.White;
}
// 恢復歌手名稱的顏色為預設的藍色
songLabel.ForeColor = color;
artistLabel.ForeColor = Color.FromArgb(30, 144, 255);
// 恢復分隔線的顏色為半透明白色
separatorPanel.BackColor = Color.FromArgb(80, 255, 255, 255);
};
// 添加事件处理

View File

@ -20,23 +20,6 @@ namespace DualScreenDemo
using (Image baseImage = Image.FromFile(imagePath))
{
string serverAddressFilePath = Path.Combine(Application.StartupPath, "txt", "ip.txt");
if (!File.Exists(serverAddressFilePath))
{
Console.WriteLine("Server address file not found: " + serverAddressFilePath);
return;
}
string serverAddress = File.ReadAllText(serverAddressFilePath).Trim();
// 根据地址格式生成不同的URL
string qrContent = serverAddress.Contains(":") ?
String.Format("http://{0}/{1}/windows.html", serverAddress, randomFolderPath) :
String.Format("http://{0}:{1}/{2}/windows.html", serverAddress, 9090, randomFolderPath);
// Console.WriteLine("QR Content: " + qrContent);
string qrImagePath = Path.Combine(Application.StartupPath, "themes/superstar/_www", randomFolderPath, "qrcode.png");
if (!File.Exists(qrImagePath))
{

View File

@ -34,77 +34,36 @@ namespace DualScreenDemo
this.syncCloseButton = new System.Windows.Forms.Button();
this.SuspendLayout();
ResizeAndPositionControl(this.primaryScreenPanel, 0, 0, 1440, 900);
this.primaryScreenPanel.TabIndex = 0;
this.primaryScreenPanel.BorderStyle = BorderStyle.FixedSingle;
this.primaryScreenPanel.BackColor = System.Drawing.Color.Black;
// 同步畫面 服務鈴
ConfigureButton(this.syncServiceBellButton, 1240, 17, 161, 161,
resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen,
//(sender, e) => SendCommandThroughSerialPort("a2 53 a4"));
(sender,e)=>OnServiceBellButtonClick(sender,e));
ConfigureButton(this.syncCutSongButton, 1218, 195, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, (sender, e) => videoPlayerForm.SkipToNextSong());
ConfigureButton(this.syncCutSongButton, 1218, 195, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, (sender, e) => videoPlayerForm.PlayNextSong());
ConfigureButton(this.syncReplayButton, 1218, 265, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, ReplayButton_Click);
// 有人聲入口位置
ConfigureButton(this.syncOriginalSongButton, 1218, 335, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, (sender,e) => videoPlayerForm.ToggleVocalRemoval());
ConfigureButton(this.syncMuteButton, 1218, 406, 205, 55, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, MuteUnmuteButton_Click);
ConfigureButton(this.syncPauseButton, 1218, 475, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, SyncPauseButton_Click);
ConfigureButton(this.syncPlayButton, 1218, 475, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, SyncPlayButton_Click);
ConfigureButton(this.syncVolumeUpButton, 1218, 546, 205, 55, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, null);
this.syncVolumeUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowVolumeUpLabel(); volumeUpTimer.Start(); };
this.syncVolumeUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); volumeUpTimer.Stop(); };
this.syncVolumeUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("音量 ↑ ","a2 b3 a4"); };
this.syncVolumeUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };
ConfigureButton(this.syncVolumeDownButton, 1218, 616, 205, 55, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, null);
this.syncVolumeDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowVolumeDownLabel(); volumeDownTimer.Start(); };
this.syncVolumeDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); volumeDownTimer.Stop(); };
this.syncVolumeDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("音量 ↓ ","a2 b4 a4");};
this.syncVolumeDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel();};
ConfigureButton(this.syncMicUpButton, 1218, 686, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, null);
this.syncMicUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowMicUpLabel(); micControlTimer.Tag = "a2 b5 a4"; micControlTimer.Start(); };
this.syncMicUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); micControlTimer.Stop(); };
this.syncMicUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("麥克風 ↑ ","a2 b5 a4");};
this.syncMicUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };
ConfigureButton(this.syncMicDownButton, 1218, 756, 205, 56, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, resizedNormalStateImageForSyncScreen, null);
this.syncMicDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowMicDownLabel(); micControlTimer.Tag = "a2 b6 a4"; micControlTimer.Start(); };
this.syncMicDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); micControlTimer.Stop(); };
this.syncMicDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("麥克風 ↓ ","a2 b6 a4");};
this.syncMicDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };

View File

@ -1,6 +1,6 @@
using System.IO;
using DBObj;
using OverlayFormObj;
namespace DualScreenDemo
{
public partial class PrimaryForm
@ -114,26 +114,21 @@ namespace DualScreenDemo
this.Controls.Add(favoriteButton);
this.Controls.Add(vodScreenCloseButton);
}
private async void VodButton_Click(object sender, EventArgs e)
private void VodButton_Click(object sender, EventArgs e)
{
SetVodScreenPictureBoxAndButtonsVisibility(false);
await Task.Delay(1000);
OverlayForm.MainForm.AddSongToPlaylist(currentSelectedSong);
SongList.Add(currentSelectedSong);
}
private void InsertButton_Click(object sender, EventArgs e)
{
SetVodScreenPictureBoxAndButtonsVisibility(false);
OverlayForm.MainForm.InsertSongToPlaylist(currentSelectedSong);
SongList.Insert(currentSelectedSong);
}
private void AlbumButton_Click(object sender, EventArgs e)
{
string name = currentSelectedSong.Artist_A;
string name = currentSelectedSong.getArtist_A(false);
string query = $"SELECT * FROM song_library_cache WHERE artistA = '{name}' ORDER BY add_date DESC;";
var selectedSongs = SearchSongs_Mysql(query);
/*var selectedSongs = allSongs.Where(song => song.ArtistA == currentSelectedSong.ArtistA)
@ -146,24 +141,21 @@ namespace DualScreenDemo
private void FavoriteButton_Click(object sender, EventArgs e)
{
Console.WriteLine("Favorite Button Clicked");
InsertNewFavoriteSong(currentSelectedSong.Number);
InsertNewFavoriteSong(currentSelectedSong.getNumber());
var searchResults = SearchSongs_Mysql(SearchFavoriteSongs_Mysql());
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
SetVodScreenPictureBoxAndButtonsVisibility(false);
}
private void VodScreenCloseButton_Click(object sender, EventArgs e)
{
SetVodScreenPictureBoxAndButtonsVisibility(false);
}
@ -171,38 +163,23 @@ namespace DualScreenDemo
private void SetVodScreenPictureBoxAndButtonsVisibility(bool isVisible)
{
overlayPanel.Visible = isVisible;
VodScreenPictureBox.Visible = isVisible;
vodButton.Visible = isVisible;
insertButton.Visible = isVisible;
albumButton.Visible = isVisible;
favoriteButton.Visible = isVisible;
vodScreenCloseButton.Visible = isVisible;
if (isVisible)
{
if (isLoggedIn)
{
if (isVisible){
if (isLoggedIn){
favoriteButton.Enabled = true;
favoriteButton.Controls.Remove(disabledPanel);
}
else
{
} else {
favoriteButton.Enabled = false;
}
overlayPanel.BringToFront();
VodScreenPictureBox.BringToFront();
vodButton.BringToFront();
insertButton.BringToFront();
albumButton.BringToFront();

View File

@ -118,12 +118,7 @@ namespace DualScreenDemo
private static Bitmap normalStateImageForLightControl;
private static Bitmap resizedNormalStateImageForLightControl;
public VideoPlayerForm videoPlayerForm;
public List<SongData> currentSongList;
public List<Artist> currentArtistList;
public static List<SongData> userRequestedSongs;
public static List<SongData> playedSongsHistory;
public static List<PlayState> playStates;
public static int currentSongIndexInHistory = -1;
public MultiPagePanel multiPagePanel;
private List<Label> songLabels = new List<Label>();
private int _currentPage { get; set; }= 0;
@ -155,10 +150,7 @@ namespace DualScreenDemo
private const int PanelEndTop = 739; // 修改為實際需要的下邊界
private Timer lightControlTimer;
public Timer volumeUpTimer;
public Timer volumeDownTimer;
public Timer micControlTimer;
private SequenceManager sequenceManager = new SequenceManager();
private PictureBox buttonMiddle;
private PictureBox buttonTopRight;
@ -206,19 +198,9 @@ namespace DualScreenDemo
lightControlTimer = new Timer();
lightControlTimer.Interval = 5;
lightControlTimer.Tick += LightControlTimer_Tick;
volumeUpTimer = new Timer();
volumeUpTimer.Interval = 100;
volumeUpTimer.Tick += VolumeUpTimer_Tick;
volumeDownTimer = new Timer();
volumeDownTimer.Interval = 100;
volumeDownTimer.Tick += VolumeDownTimer_Tick;
micControlTimer = new Timer();
micControlTimer.Interval = 100;
micControlTimer.Tick += MicControlTimer_Tick;
InitializeRecording();
InitializeMediaPlayer();
LoadSongData();
LoadImages();
InitializeFormAndControls();
InitializeMultiPagePanel();
@ -240,23 +222,6 @@ namespace DualScreenDemo
this.Load += PrimaryForm_Load;
}
public bool IsAppResponsive()
{
try
{
var form = this;
if (form != null)
{
bool dummy = form.InvokeRequired; // 如果 Invoke 卡死,會丟錯
return true;
}
}
catch
{
return false;
}
return true;
}
// 添加 DPI 感知支持
[DllImport("user32.dll")]
@ -885,7 +850,7 @@ namespace DualScreenDemo
}
}
}
private void LightControlTimer_Tick(object sender, EventArgs e)
{
if(lightControlTimer.Tag != null)
@ -894,56 +859,6 @@ namespace DualScreenDemo
}
}
private void VolumeUpTimer_Tick(object sender, EventArgs e)
{
Task.Run(() =>
{
try
{
SendCommandThroughSerialPort("a2 b3 a4");
}
catch (Exception ex)
{
Console.WriteLine("Failed to send command: " + ex.Message);
}
});
}
private void VolumeDownTimer_Tick(object sender, EventArgs e)
{
Task.Run(() =>
{
try
{
SendCommandThroughSerialPort("a2 b4 a4");
}
catch (Exception ex)
{
Console.WriteLine("Failed to send command: " + ex.Message);
}
});
}
private void MicControlTimer_Tick(object sender, EventArgs e)
{
Task.Run(() =>
{
try
{
if(micControlTimer.Tag != null)
{
SendCommandThroughSerialPort(micControlTimer.Tag.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine("Failed to send command: " + ex.Message);
}
});
}
public static void SendCommandThroughSerialPort(string command)
{
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
@ -989,10 +904,6 @@ namespace DualScreenDemo
if (status == RecognitionStatus.NoError)
{
List<string> candidates = new List<string>();
foreach (RecognitionAlternate alternate in result.GetAlternatesFromSelection())
{
@ -1102,7 +1013,7 @@ namespace DualScreenDemo
qieGeButton.Name = "qieGeButton";
ConfigureButton(qieGeButton, 28, 755, 92, 132,
resizedNormalStateImage, resizedNormalStateImage, resizedNormalStateImage,
(sender, e) => videoPlayerForm.SkipToNextSong());
(sender, e) => videoPlayerForm.PlayNextSong());
this.Controls.Add(qieGeButton);
@ -1114,8 +1025,8 @@ namespace DualScreenDemo
musicUpButton.BackgroundImageLayout = ImageLayout.Stretch;
musicUpButton.FlatStyle = FlatStyle.Flat;
musicUpButton.FlatAppearance.BorderSize = 0;
musicUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowVolumeUpLabel(); volumeUpTimer.Start(); };
musicUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); volumeUpTimer.Stop(); };
musicUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("音量 ↑","a2 b3 a4"); };
musicUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };
this.Controls.Add(musicUpButton);
@ -1127,8 +1038,8 @@ namespace DualScreenDemo
musicDownButton.BackgroundImageLayout = ImageLayout.Stretch;
musicDownButton.FlatStyle = FlatStyle.Flat;
musicDownButton.FlatAppearance.BorderSize = 0;
musicDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowVolumeDownLabel(); volumeDownTimer.Start(); };
musicDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); volumeDownTimer.Stop(); };
musicDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("音量 ↓","a2 b4 a4"); };
musicDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };
this.Controls.Add(musicDownButton);
@ -1140,8 +1051,8 @@ namespace DualScreenDemo
micUpButton.BackgroundImageLayout = ImageLayout.Stretch;
micUpButton.FlatStyle = FlatStyle.Flat;
micUpButton.FlatAppearance.BorderSize = 0;
micUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowMicUpLabel(); micControlTimer.Tag = "a2 b5 a4"; micControlTimer.Start(); };
micUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); micControlTimer.Stop(); };
micUpButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowTopRightLabel("麥克風 ↑","a2 b5 a4"); };
micUpButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };
this.Controls.Add(micUpButton);
@ -1153,8 +1064,8 @@ namespace DualScreenDemo
micDownButton.BackgroundImageLayout = ImageLayout.Stretch;
micDownButton.FlatStyle = FlatStyle.Flat;
micDownButton.FlatAppearance.BorderSize = 0;
micDownButton.MouseDown += (sender, e) => { OverlayForm.MainForm.ShowMicDownLabel(); micControlTimer.Tag = "a2 b6 a4"; micControlTimer.Start(); };
micDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.HideAllLabels(); micControlTimer.Stop(); };
micDownButton.MouseDown += (sender, e) =>{ OverlayForm.MainForm.ShowTopRightLabel("麥克風 ↓","a2 b6 a4"); };
micDownButton.MouseUp += (sender, e) => { OverlayForm.MainForm.RedisplayTopRigthLabel(); };
this.Controls.Add(micDownButton);
@ -1438,8 +1349,6 @@ namespace DualScreenDemo
}
this.Controls.Add(button);
}
private void InitializeMultiPagePanel()
{
// 獲取螢幕尺寸
@ -1496,15 +1405,6 @@ namespace DualScreenDemo
}
}
public static void PrintPlayingSongList()
{
Console.WriteLine("當前播放列表:");
foreach (var song in userRequestedSongs)
{
Console.WriteLine(song.name_text());
}
}
private void NextPageButton_Click(object sender, EventArgs e)
{
multiPagePanel.LoadNextPage();
@ -1536,14 +1436,6 @@ namespace DualScreenDemo
{
multiPagePanel.LoadPreviousPage();
}
private void LoadSongData()
{
userRequestedSongs = new List<SongData>();
playedSongsHistory = new List<SongData>();
playStates = new List<PlayState>();
}
private Bitmap ResizeImage(Image image, int width, int height)
{
@ -1701,7 +1593,7 @@ namespace DualScreenDemo
return bmp;
}
private void DrawTextOnVodScreenPictureBox(string imagePath, SongData songData)
private void DrawTextOnVodScreenPictureBox(string imagePath, SongData SongDetail)
{
Bitmap originalImage = new Bitmap(imagePath);
@ -1724,11 +1616,11 @@ namespace DualScreenDemo
Font font = new Font("微軟正黑體", points, FontStyle.Bold);
// 根據文字長度設置字體大小
if (songData.getNameLength() > 18)
if (SongDetail.getNameLength() > 18)
{
font = new Font("微軟正黑體", 17, FontStyle.Bold);
}
else if (songData.getNameLength() > 13)
else if (SongDetail.getNameLength() > 13)
{
font = new Font("微軟正黑體", 21, FontStyle.Bold);
}
@ -1741,7 +1633,7 @@ namespace DualScreenDemo
Brush textBrush = Brushes.Black;
string songInfo = songData.Name ?? "未提供歌曲信息";
string songInfo = SongDetail.getName() ?? "未提供歌曲信息";
g.DrawString(songInfo, font, textBrush, new PointF(201, 29));
@ -1935,7 +1827,7 @@ namespace DualScreenDemo
foreach(var song in userRequestedSongs){
Console.WriteLine(song.ToString());
}*/
if( multiPagePanel.get_currentSongList() == playedSongsHistory)
if( multiPagePanel.get_currentSongList() == SongList.GetHistory())
return;
autoRefreshTimer.Stop(); // 停止自动刷新
FindFirstNonEmptyText(inputBoxZhuYinSingers
@ -2046,65 +1938,45 @@ namespace DualScreenDemo
private void MaleKeyButton_Click(object sender, EventArgs e)
{
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
byte[] commandBytesIncreasePitch1 = new byte[] { 0xA2, 0x7F, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length);
OverlayForm.MainForm.HideAllLabels();
byte[] commandBytesDecreasePitch = new byte[] { 0xA2, 0xB2, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesDecreasePitch, 0, commandBytesDecreasePitch.Length);
OverlayForm.MainForm.HideAllLabels();
SerialPortManager.mySerialPort.Write(commandBytesDecreasePitch, 0, commandBytesDecreasePitch.Length);
OverlayForm.MainForm.HideAllLabels();
}
else
{
MessageBox.Show("串口未開啟,無法發送降調指令。");
}
OverlayForm.MainForm.ShowMaleKeyLabel();
}
private void FemaleKeyButton_Click(object sender, EventArgs e)
{
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
byte[] commandBytesIncreasePitch1 = new byte[] { 0xA2, 0x7F, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length);
OverlayForm.MainForm.HideAllLabels();
byte[] commandBytesIncreasePitch = new byte[] { 0xA2, 0xB1, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch, 0, commandBytesIncreasePitch.Length);
OverlayForm.MainForm.HideAllLabels();
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch, 0, commandBytesIncreasePitch.Length);
OverlayForm.MainForm.HideAllLabels();
}
else
{
MessageBox.Show("串口未開啟,無法發送升調指令。");
}
OverlayForm.MainForm.ShowFemaleKeyLabel();
}
private void StandardKeyButton_Click(object sender, EventArgs e)
{
OverlayForm.MainForm.ShowStandardKeyLabel();
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
byte[] commandBytesIncreasePitch = new byte[] { 0xA2, 0x7F, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch, 0, commandBytesIncreasePitch.Length);
}
else
{
@ -2114,15 +1986,10 @@ namespace DualScreenDemo
private void PitchUpButton_Click(object sender, EventArgs e)
{
OverlayForm.MainForm.ShowKeyUpLabel();
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
{
byte[] commandBytesIncreasePitch = new byte[] { 0xA2, 0xB1, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch, 0, commandBytesIncreasePitch.Length);
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch, 0, commandBytesIncreasePitch.Length);
}
else
{
@ -2132,15 +1999,10 @@ namespace DualScreenDemo
private void PitchDownButton_Click(object sender, EventArgs e)
{
OverlayForm.MainForm.ShowKeyDownLabel();
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
byte[] commandBytesDecreasePitch = new byte[] { 0xA2, 0xB2, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesDecreasePitch, 0, commandBytesDecreasePitch.Length);
SerialPortManager.mySerialPort.Write(commandBytesDecreasePitch, 0, commandBytesDecreasePitch.Length);
}
else
{
@ -2160,18 +2022,12 @@ namespace DualScreenDemo
if (isWaiting) return;
isWaiting = true;
// 发送串口命令
SendCommandThroughSerialPort("a2 53 a4");
// 显示提示信息
OverlayForm.MainForm.HideAllLabels();
OverlayForm.MainForm.ShowServiceBell();
//OverlayForm.MainForm.HideAllLabels();
OverlayForm.MainForm.ShowTopRightLabel("服務鈴","a2 53 a4");
// 延迟3秒
await Task.Delay(3000);
// 隐藏提示信息
//OverlayForm.MainForm.HideServiceBellLabel();
isWaiting = false;
}
@ -2379,7 +2235,7 @@ namespace DualScreenDemo
{
HotPlayButton_Click(null, EventArgs.Empty);
}
if (Program.RoomState.Equals("CLOSE"))
if (Room.IsClose())
{
ShowSendOffScreen();
}
@ -2412,8 +2268,8 @@ namespace DualScreenDemo
isOnOrderedSongsPage = true;
autoRefreshTimer.Start(); // 开始自动刷新
// 已點歌曲錨點
currentSongList = playedSongsHistory;
totalPages = (int)Math.Ceiling((double)playedSongsHistory.Count / itemsPerPage);
var List = SongList.GetHistory();
totalPages = (int)Math.Ceiling((double)List.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
SetHotSongButtonsVisibility(false);
@ -2438,7 +2294,7 @@ namespace DualScreenDemo
closeQRCodeButton.Visible = false;
}
multiPagePanel.LoadPlayedSongs(playedSongsHistory, playStates);
multiPagePanel.LoadPlayedSongs(List);
}
}
}

View File

@ -317,11 +317,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
}

View File

@ -236,11 +236,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
}

View File

@ -294,11 +294,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
}

View File

@ -557,11 +557,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
}

View File

@ -271,11 +271,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
}
/// <summary>
/// 初始化拼音輸入框 (RichTextBox),並從 config.ini 讀取相關設定。

View File

@ -490,11 +490,10 @@ namespace DualScreenDemo
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResults);
}

View File

@ -52,12 +52,11 @@ namespace DualScreenDemo
string query = $"SELECT * FROM song_library_cache WHERE language_name = '國語' LIMIT 100;";
var searchResult = SearchSongs_Mysql(query);
currentPage = 0;
currentSongList = searchResult;
totalPages = (int)Math.Ceiling((double)searchResult.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
multiPagePanel.LoadSongs(searchResult);
// 隱藏其他 UI
SetHotSongButtonsVisibility(false);

View File

@ -1,44 +1,28 @@
using System.IO;
using Microsoft.Win32;
using System.Diagnostics;
using DBObj;
using HeartbeatSender;
namespace DualScreenDemo
{
public static class Program
{
// 定义全局变量
internal static SongListManager songListManager;
internal static DBObj.SongListManager songListManager;
//internal static ArtistManager artistManager;
internal static SerialPortManager serialPortManager;
private static PrimaryForm primaryForm; // 儲存實例的參考
public static string RoomState = Utils.Env.Get("RoomStates", "CLOSE");
public static DataCheck.PublicSongChecker cherker;
public static Room room = new Room();
[STAThread]
static void Main()
{
Console.WriteLine("Server V.1.2.0 20250703");
if(Utils.Env.GetBool("IsCursor", true))Cursor.Hide();
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
Cursor.Show();
};
//Console.WriteLine("正在喚醒SVR裝置(每3分鐘呼叫一次)...");
//_ = Task.Run(async () =>
// {
// while (true)
// {
// _ = Directory.Exists(@"\\svr01\video");
// _ = Directory.Exists(@"\\svr02\video");
// await Task.Delay(180000); // 每3min送一次
// }
// });
Console.WriteLine("Server V.1.2.3 202507211828");
if (Utils.Env.GetBool("IsCursor", true)) Cursor.Hide();
AppDomain.CurrentDomain.ProcessExit += (s, e) => Cursor.Show();
//Console.WriteLine("正在與中控取得聯繫...");
var sender = new heartbeatSender();
cherker =new DataCheck.PublicSongChecker();
var cherker=new DataCheck.PublicSongChecker(DBObj.SongList.PublicSong());
try
{
// COM 初始化
@ -50,7 +34,7 @@ namespace DualScreenDemo
}
// 初始化管理器
songListManager = new SongListManager(); // 使用单例
songListManager = new DBObj.SongListManager(); // 使用单例
//artistManager = new ArtistManager();
var commandHandler = new CommandHandler(songListManager);
@ -74,86 +58,46 @@ namespace DualScreenDemo
// 創建主窗體
primaryForm = new PrimaryForm();
//primaryForm.allSongs = songListManager.AllSongs;
//primaryForm.allArtists = artistManager.AllArtists;
primaryForm.StartPosition = FormStartPosition.Manual;
primaryForm.Location = new Point(0, 0);
primaryForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
// 在完整初始化後檢查狀態
InitializeSecondaryScreen();
if (Screen.AllScreens.Length > 1)
{
var secondaryScreen = Screen.AllScreens.FirstOrDefault(s => !s.Primary);
if (secondaryScreen != null)
{
// 确保 primaryForm 和 videoPlayerForm 已经正确初始化
if (primaryForm.videoPlayerForm == null)
{
primaryForm.videoPlayerForm = new VideoPlayerForm();
}
// 设置 videoPlayerForm 的位置和大小
// primaryForm.videoPlayerForm.StartPosition = FormStartPosition.Manual;
// primaryForm.videoPlayerForm.Location = secondaryScreen.WorkingArea.Location;
// primaryForm.videoPlayerForm.Size = secondaryScreen.WorkingArea.Size;
// 显示 videoPlayerForm 在第二显示器
primaryForm.videoPlayerForm.Show();
// 初始化公共播放列表
primaryForm.videoPlayerForm.PlayNextSong();
}
}
primaryForm.Show();
Application.Run(primaryForm);
}
catch (Exception ex)
{
WriteLog(ex.ToString());
}
finally
{
SystemEvents.DisplaySettingsChanged -= OnDisplaySettingsChanged;
}
}
private static bool IsUrlAclExists(string url)
{
try
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "netsh",
Arguments = "http show urlacl",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (Process process = Process.Start(startInfo))
{
using (StreamReader reader = process.StandardOutput)
{
string output = reader.ReadToEnd();
return output.Contains(url); // 检查是否包含指定 URL
}
}
}
catch (Exception ex)
{
Console.WriteLine("检查 URL ACL 时出错: " + ex.Message);
return false;
//} finally {
//SystemEvents.DisplaySettingsChanged -= OnDisplaySettingsChanged;
}
}
private static void InitializeSecondaryScreen()
{
if (Screen.AllScreens.Length > 1)
{
var secondaryScreen = Screen.AllScreens.FirstOrDefault(s => !s.Primary);
if (secondaryScreen != null)
{
// 确保 primaryForm 和 videoPlayerForm 已经正确初始化
if (primaryForm.videoPlayerForm == null)
{
primaryForm.videoPlayerForm = new VideoPlayerForm();
}
// 设置 videoPlayerForm 的位置和大小
// primaryForm.videoPlayerForm.StartPosition = FormStartPosition.Manual;
// primaryForm.videoPlayerForm.Location = secondaryScreen.WorkingArea.Location;
// primaryForm.videoPlayerForm.Size = secondaryScreen.WorkingArea.Size;
// 显示 videoPlayerForm 在第二显示器
primaryForm.videoPlayerForm.Show();
// 初始化公共播放列表
primaryForm.videoPlayerForm.InitializePublicPlaylist(cherker.GetSongs());
}
}
}
private static void OnDisplaySettingsChanged(object sender, EventArgs e)
{
@ -174,7 +118,7 @@ namespace DualScreenDemo
{
primaryForm.videoPlayerForm = new VideoPlayerForm();
// primaryForm.primaryMediaPlayerForm = new PrimaryMediaPlayerForm(primaryForm, primaryForm.secondaryMediaPlayerForm);
primaryForm.videoPlayerForm.InitializePublicPlaylist(cherker.GetSongs());
//primaryForm.videoPlayerForm.PlayNextSong();
primaryForm.videoPlayerForm.Show();
}
}
@ -213,26 +157,6 @@ namespace DualScreenDemo
Console.WriteLine(String.Format("Error writing to log file: {0}", ex.Message));
}
}
private static Form CreatePrimaryForm()
{
return new Form
{
WindowState = FormWindowState.Maximized,
FormBorderStyle = FormBorderStyle.None
};
}
private static Form CreateSecondaryForm(Screen screen)
{
return new Form
{
Text = "Secondary Screen Form",
StartPosition = FormStartPosition.Manual,
Bounds = screen.Bounds,
WindowState = FormWindowState.Maximized,
FormBorderStyle = FormBorderStyle.None
};
}
}
}

View File

@ -10,22 +10,19 @@ namespace DataCheck
public class PublicSongChecker
{
private List<SongData> publicSongList = new();
public PublicSongChecker()
private List<SongData> publicList;
public PublicSongChecker(List<SongData> publicSongList)
{
publicList = publicSongList;
string serverPath = Utils.Env.GetPath("video", "");
string localPath = @"D:\video";
// 加入你要同步的資料夾
SyncFolder(serverPath, localPath, "video", new[] { ".mpg" });
}
public List<SongData> GetSongs()
{
return publicSongList;
Console.WriteLine($"publicList:{publicList.Count}");
}
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}");
@ -57,11 +54,15 @@ namespace DataCheck
}
}
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
if (fileName == "welcome") {
DBObj.SongList.welcome=new SongData("0", "歡迎光臨", @"D:\video\welcome.mpg", 1 ,true);
} else if (fileName == "CLOSE") {
DBObj.SongList.close =new SongData("0", "結束播放", @"D:\video\CLOSE.MPG", 1 ,true);
} else {
//Console.WriteLine($"{fileName} {Path.Combine(localPath, serverFile.Key)}");
publicList.Add(new SongData(
publicList.Count.ToString(), // songNumber
fileName, // song
Path.Combine(localPath, serverFile.Key), // songFilePathHost1
1, // priority
true

View File

@ -1,12 +0,0 @@
namespace DualScreenDemo
{
public enum RemoteCommand
{
NextPage,
PreviousPage,
Play,
Pause,
Stop
}
}

View File

@ -1,7 +0,0 @@
namespace DualScreenDemo
{
public class RemoteControlEventArgs : EventArgs
{
public RemoteCommand Command { get; set; }
}
}

View File

@ -1,8 +0,0 @@
namespace DualScreenDemo
{
public class RequestData
{
public string buttonId { get; set; }
public string text { get; set; }
}
}

60
Room.cs Normal file
View File

@ -0,0 +1,60 @@
using OverlayFormObj;
namespace DualScreenDemo
{
public class Room
{
private static string State=Utils.Env.Get("RoomStates", "CLOSE");
public Room(){}
public static void set(string value)
{
string marqueeMessage = "歡迎使用超級巨星歡唱,與你共度美好時光。";
Color c = Color.White;
State = value;
if (value.Equals("PAUSE"))
{
PrimaryForm.Instance.ShowSendOffScreen();
VideoPlayerForm.Instance.Pause();
marqueeMessage = "發生火災,請跟隨引導至逃生出口!!!";
c = Color.Red;
}
else if (value.Equals("OPEN"))
{
DBObj.SongList.clearSong();
PrimaryForm.Instance.HotPlayButton_Click(null, EventArgs.Empty);
PrimaryForm.Instance.HideSendOffScreen();
}
else
{
DBObj.SongList.clearSong();
PrimaryForm.Instance.pictureBoxQRCode.Visible = false;
PrimaryForm.Instance.closeQRCodeButton.Visible = false;
PrimaryForm.Instance.ShowSendOffScreen();
OverlayForm.MainForm.topLeftLabel.Visible = false;
VideoPlayerForm.Instance.PlayNextSong();
PrimaryForm.Instance.logout();
}
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, c);
}
public static bool IsClose()
{
return State.Equals("CLOSE");
}
public static bool IsOpen()
{
return State.Equals("OPEN");
}
}
}

View File

@ -1,26 +0,0 @@
using DirectShowLib;
namespace DualScreenDemo
{
public class SampleGrabberCallback : ISampleGrabberCB
{
private VideoPlayerForm form;
public SampleGrabberCallback(VideoPlayerForm form)
{
this.form = form;
}
public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
return 0;
}
public int SampleCB(double SampleTime, IMediaSample pSample)
{
return 0;
}
}
}

View File

@ -1,127 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System.Linq;
using DBObj;
namespace DataCheck
{
public class SongChecker
{
private static List<SongData> playingSongList= new();
//public static List<PlayState> playStates;
private static List<SongData> publicSongList = new();
private SongData welcome = new SongData("0", "歡迎光臨", @"D:\video\welcome.mpg", 1 ,true);
private SongData close = new SongData("0", "結束播放", @"D:\video\CLOSE.MPG", 1 ,true);
public SongChecker()
{
string serverPath = Utils.Env.GetPath("video", "");
string localPath = @"D:\video";
// 加入你要同步的資料夾
SyncFolder(serverPath, localPath, "video", new[] { ".mpg" });
}
public static bool AddSongToPlayList(SongData song)
{
playingSongList.Add(song);
return true;
}
public static bool isPlayingUserSong()
{
return playingSongList.Count == 0;
}
public static SongData GetCurrentSong()
{
SongData song = null;
int count = playingSongList.Count;
if (count == 0)
{
song = publicSongList[0];
publicSongList.RemoveAt(0);
publicSongList.Add(song);
}
else
{
song = playingSongList[0];
playingSongList.RemoveAt(0);
}
return song;
}
public static SongData GetNextSong()
{
return playingSongList.Count > 1 ? playingSongList[1] : null;
}
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
true
));
}
}
// 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}");
}
}
}
}
}
}

View File

@ -5,7 +5,6 @@ using System.Text.RegularExpressions;
using System.IO; // 為 Path 和 File 提供支持
using DBObj;
using OverlayFormObj;
using HeartbeatSender;
namespace DualScreenDemo
{
public class TCPServer
@ -123,62 +122,17 @@ namespace DualScreenDemo
if (command.Trim().Equals("X", StringComparison.OrdinalIgnoreCase))
{
PrimaryForm.Instance.pictureBoxQRCode.Visible = false;
PrimaryForm.Instance.closeQRCodeButton.Visible = false;
_ = SafeInvoke(VideoPlayerForm.Instance, async () =>
{
if (IsFormReady(PrimaryForm.Instance))
{
await SafeInvoke(PrimaryForm.Instance, async () =>
{
PrimaryForm.Instance.ShowSendOffScreen();
Console.WriteLine("開始設置新的播放列表");
string closePath = @"D:\video\CLOSE.MPG";
if (File.Exists(closePath))
{
SongData closeSong = new SongData("0", "結束播放",closePath, 1,true);
VideoPlayerForm.publicPlaylist = new List<SongData>();
VideoPlayerForm.playingSongList = new List<SongData>();
PrimaryForm.playedSongsHistory = new List<SongData>();
if (VideoPlayerForm.Instance.currentPlayingSong != null)
{
VideoPlayerForm.playingSongList.Add(VideoPlayerForm.Instance.currentPlayingSong);
}
VideoPlayerForm.playingSongList.Add(closeSong);
VideoPlayerForm.publicPlaylist.Add(closeSong);
PrimaryForm.userRequestedSongs = new List<SongData>();
if (IsFormReady(OverlayForm.MainForm))
{
OverlayForm.MainForm.nextSongLabel.Visible = false;
}
VideoPlayerForm.Instance.PlayNextSong();
PrimaryForm.Instance.logout();
Console.WriteLine("已設置新的播放列表,包含當前歌曲和 CLOSE.MPG");
try
{
await HttpServer.RestartServer();
}
catch (Exception ex)
{
Console.WriteLine("RestartServer 發生錯誤: " + ex.Message);
}
}
else
{
Console.WriteLine($"錯誤: 找不到檔案 {closePath}");
}
OverlayForm.Instance.ResetMarqueeTextToWelcomeMessage();
});
Room.set("CLOSE");
try{
await HttpServer.RestartServer();
} catch (Exception ex) {
Console.WriteLine("RestartServer 發生錯誤: " + ex.Message);
}
});
Program.RoomState = "CLOSE";
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);
@ -188,17 +142,7 @@ namespace DualScreenDemo
if (command.Trim().Equals("O", StringComparison.OrdinalIgnoreCase))
{
// 開台時跳至首頁
VideoPlayerForm.publicPlaylist = new List<SongData>();
VideoPlayerForm.playingSongList = new List<SongData>();
VideoPlayerForm.Instance.PlayPublicPlaylist();
PrimaryForm.currentSongIndexInHistory = -1;
PrimaryForm.Instance.HotPlayButton_Click(null, EventArgs.Empty);
Program.RoomState = "OPEN";
PrimaryForm.Instance.HideSendOffScreen();
OverlayForm.Instance.ResetMarqueeTextToWelcomeMessage();
Room.set("OPEN");
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);
continue;
@ -207,17 +151,10 @@ namespace DualScreenDemo
{
_ = SafeInvoke(PrimaryForm.Instance, () =>
{
PrimaryForm.Instance.ShowSendOffScreen();
VideoPlayerForm.Instance.Pause();
string marqueeMessage = "發生火災,請跟隨引導至逃生出口!!!";
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, Color.Red);
Room.set("PAUSE");
});
// 更新狀態檔案(可選,若你要記錄狀態)
Program.RoomState = "PAUSE";
byte[] okResponse = Encoding.UTF8.GetBytes("OK\n");
stream.Write(okResponse, 0, okResponse.Length);
continue;
}
@ -255,7 +192,7 @@ namespace DualScreenDemo
*/
}
Console.WriteLine("Connection closed.");
//Console.WriteLine("Connection closed.");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +0,0 @@
namespace DualScreenDemo
{
public static class WindowStyles
{
public const int WS_CHILD = 0x40000000;
public const int WS_CLIPSIBLINGS = 0x04000000;
}
}

View File

@ -4,7 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<ApplicationIcon>Images/superstar.ico</ApplicationIcon>
<RootNamespace>superstar</RootNamespace>
<RootNamespace>superstar_1.2</RootNamespace>
<AssemblyName>superstar</AssemblyName>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

View File

@ -389,8 +389,6 @@
Song: row.cells[0].textContent,
ArtistA: row.cells[1].textContent,
SongNumber: row.cells[2].textContent,
SongFilePathHost1: row.cells[3].textContent,
SongFilePathHost2: row.cells[4].textContent
};
window.selectedSong = song;
@ -543,8 +541,6 @@
<td>${song.Song}</td>
<td>${song.ArtistA}</td>
<td>${song.SongNumber}</td>
<td style="display:none;">${song.SongFilePathHost1}</td>
<td style="display:none;">${song.SongFilePathHost2}</td>
`;
row.addEventListener('click', function(e) {
e.preventDefault();