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$"))
@ -191,6 +163,7 @@ 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();
}
PrimaryForm.Instance.videoPlayerForm.PlayNextSong();
OverlayForm.MainForm.Invoke(new System.Action(() =>
{
OverlayForm.MainForm.ShowStandardLabel();
}));
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();
}
}
@ -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>();
for (int i = startIndex; i < endIndex; i++) {
historySongs.Add(history[i]);
}
// 錨點 遙控器
// 從播放紀錄中取出當前頁面應顯示的歌曲與狀態
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);
}
}
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.MainForm.HideTopRightLabels();
OverlayForm.DisplayNumberAtTopLeft(number);
OverlayForm.MainForm.HideAllLabels();
}));
}
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,8 +1,10 @@
using System.Data;
using DualScreenDemo;
namespace DBObj
{
public class SongListManager
{
private MyDB db = new MyDB();
public List<SongData> FavoriteSongs { get; private set; }
//public bool IsUserLoggedIn { get; set; }
//public string UserPhoneNumber { get; set; }
@ -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)
{
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
playingSongList = SongList.GetHistory()
.Select((song, index) => new
{
Song=song.getName(),
ArtistA=song.getArtist_A(),
PlayState = song.GetState().GetDescription()
})
.ToList()
};
string jsonResponse = JsonConvert.SerializeObject(response);
Console.WriteLine("Serialized JSON Response: " + jsonResponse);
context.Response.ContentType = "application/json";
jsonResponse = JsonConvert.SerializeObject(response);
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);
}
}
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.getName()} by {song.getArtist_A()}");
if (song != null)
{
Console.WriteLine($"Ordering Song: {song.Name} by {song.Artist_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
{
@ -977,7 +898,8 @@ namespace DualScreenDemo
for (int i = 0; i < 3; i++)
{
string Messagelast = "";
for(int j=0;j < message.Length;j++){
for (int j = 0; j < message.Length; j++)
{
Messagelast += message[j];
await Task.Delay(10);
// 将读取到的 "message" 字段传递给 UI 控件显示
@ -985,12 +907,12 @@ 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 + '_');
}
}
// 真情告白顯示秒數
@ -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,29 +99,6 @@ namespace OverlayFormObj
currentSegmentIndex = 0;
}
private void InitializeMaleKeyTimer()
{
maleKeyTimer = new System.Windows.Forms.Timer();
maleKeyTimer.Interval = 3000;
maleKeyTimer.Tick += (s, e) =>
{
HideAllLabels();
};
}
private void InitializeFemaleKeyTimer()
{
femaleKeyTimer = new System.Windows.Forms.Timer();
femaleKeyTimer.Interval = 3000;
femaleKeyTimer.Tick += (s, e) =>
{
HideAllLabels();
};
}
private void AddCenteredPicture(Bitmap bitmap, int y)
{
int x = (this.Width - bitmap.Width) / 2;
@ -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();
@ -357,7 +324,6 @@ private Rectangle FindContentBounds(Bitmap bmp)
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;
}
@ -429,13 +389,13 @@ private static void DisplayTimer_Tick(object sender, EventArgs e)
MainForm.Invoke(new System.Action(() =>
{
MainForm.displayLabel.Text = "";
MainForm.nextSongLabel.Visible = true; // 显示 nextSongLabel
MainForm.topLeftLabel.Visible = true; // 显示 topLeftLabel
}));
}
else
{
MainForm.displayLabel.Text = "";
MainForm.nextSongLabel.Visible = true; // 显示 nextSongLabel
MainForm.topLeftLabel.Visible = true; // 显示 topLeftLabel
}
displayTimer.Stop(); // 停止计时器
@ -452,19 +412,16 @@ private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
MainForm.BeginInvoke(new Action(() =>
{
if (MainForm.songDisplayLabel != null)
MainForm.songDisplayLabel.Text = "";
if (MainForm.nextSongLabel != null)
MainForm.nextSongLabel.Visible = true;
if (MainForm.topLeftLabel != null)
MainForm.topLeftLabel.Visible = true;
}));
}
else
{
// 如果已經在 UI 執行緒,就直接更新 UI 控制項
Console.WriteLine("SongDisplayTimer_Tick invoked on background thread.");
MainForm.songDisplayLabel.Text = "";
MainForm.nextSongLabel.Visible = true;
//MainForm.songDisplayLabel.Text = "";
MainForm.topLeftLabel.Visible = true;
}
// 停止計時器,避免重複觸發
@ -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;
}
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,99 +1319,6 @@ 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;
@ -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,
[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,13 +89,10 @@ 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);

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 ? "(播毕)" : "(播畢)";
statusText = song.GetStateTxt(IsSimplified); // 狀態文字
color = song.GetStateColor();
}
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;
}
}
}
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);
}
fold = 10;
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 = 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);
}
};
// 定義滑鼠離開 (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,9 +150,6 @@ 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;
@ -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")]
@ -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();
@ -1537,14 +1437,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)
{
var destRect = new Rectangle(0, 0, width, 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);
}
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);
}
else
{
@ -2161,18 +2023,12 @@ namespace DualScreenDemo
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");
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("正在喚醒SVR裝置(每3分鐘呼叫一次)...");
//_ = Task.Run(async () =>
// {
// while (true)
// {
// _ = Directory.Exists(@"\\svr01\video");
// _ = Directory.Exists(@"\\svr02\video");
// await Task.Delay(180000); // 每3min送一次
// }
// });
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,62 +58,11 @@ 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();
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;
}
}
private static void InitializeSecondaryScreen()
{
if (Screen.AllScreens.Length > 1)
{
var secondaryScreen = Screen.AllScreens.FirstOrDefault(s => !s.Primary);
@ -150,10 +83,21 @@ namespace DualScreenDemo
primaryForm.videoPlayerForm.Show();
// 初始化公共播放列表
primaryForm.videoPlayerForm.InitializePublicPlaylist(cherker.GetSongs());
primaryForm.videoPlayerForm.PlayNextSong();
}
}
primaryForm.Show();
Application.Run(primaryForm);
}
catch (Exception ex)
{
WriteLog(ex.ToString());
//} finally {
//SystemEvents.DisplaySettingsChanged -= OnDisplaySettingsChanged;
}
}
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();
}
}
@ -214,25 +158,5 @@ namespace DualScreenDemo
}
}
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
{
Room.set("CLOSE");
try{
await HttpServer.RestartServer();
}
catch (Exception ex)
{
} catch (Exception ex) {
Console.WriteLine("RestartServer 發生錯誤: " + ex.Message);
}
}
else
{
Console.WriteLine($"錯誤: 找不到檔案 {closePath}");
}
OverlayForm.Instance.ResetMarqueeTextToWelcomeMessage();
});
}
});
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.");
}
}
}

View File

@ -3,14 +3,12 @@ using System.Runtime.InteropServices;
using DirectShowLib;
using DBObj;
using OverlayFormObj;
using DualScreenDemo.Shared;
namespace DualScreenDemo
{
public class VideoPlayerForm : Form
{
#region
public SongData currentPlayingSong;
public bool IsPlayingPublicSong { get; private set; } = false;
protected override CreateParams CreateParams
{
get
@ -92,10 +90,6 @@ namespace DualScreenDemo
private static bool isInitializationComplete = false;
public static OverlayForm overlayForm;
public static List<SongData> playingSongList;
public static List<SongData> publicPlaylist;
public static int currentSongIndex = 0;
private static bool isUserPlaylistPlaying = false;
public bool isMuted = false;
public int previousVolume = -1000;
public bool isPaused = false;
@ -113,8 +107,6 @@ namespace DualScreenDemo
{
Instance = this;
// this.DoubleBuffered = true;
InitializeComponent();
this.Load += VideoPlayerForm_Load;
this.Shown += VideoPlayerForm_Shown;
this.FormClosing += VideoPlayerForm_FormClosing;
@ -125,11 +117,6 @@ namespace DualScreenDemo
MonitorMediaEvents();
}
private void InitializeComponent()
{
}
private void VideoPlayerForm_Load(object sender, EventArgs e)
{
secondMonitor = ScreenHelper.GetSecondMonitor();
@ -144,38 +131,16 @@ namespace DualScreenDemo
CheckMonitor();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
try
{
if (secondMonitor != null)
{
SetWindowPos(this.Handle, IntPtr.Zero, secondMonitor.Bounds.X, secondMonitor.Bounds.Y,
secondMonitor.Bounds.Width, secondMonitor.Bounds.Height, 0);
}
IntPtr exStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
SetWindowLong(this.Handle, GWL_EXSTYLE, (IntPtr)(exStyle.ToInt32()));
}
catch (Exception ex)
{
Console.WriteLine("An error occurred in OnShown: " + ex.Message);
}
}
private void VideoPlayerForm_Shown(object sender, EventArgs e)
{
int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED);
if (hr < 0)
{
if (hr < 0) {
Console.WriteLine("Failed to initialize COM library.");
return;
}
InitializeGraphBuilderPrimary();
InitializeGraphBuilderSecondary();
Task.Run(() => MonitorMediaEvents());
}
private void VideoPlayerForm_FormClosing(object sender, FormClosingEventArgs e)
@ -299,23 +264,6 @@ namespace DualScreenDemo
}
}
private void ConfigureSampleGrabber(IBaseFilter sampleGrabberFilter)
{
ISampleGrabber sampleGrabber = (ISampleGrabber)sampleGrabberFilter;
AMMediaType mediaType = new AMMediaType
{
majorType = MediaType.Video,
subType = MediaSubType.RGB24,
formatType = FormatType.VideoInfo
};
sampleGrabber.SetMediaType(mediaType);
DsUtils.FreeAMMediaType(mediaType);
sampleGrabber.SetBufferSamples(false);
sampleGrabber.SetOneShot(false);
sampleGrabber.SetCallback(new SampleGrabberCallback(this), 1);
}
private int ConnectFilters(IGraphBuilder graphBuilder, IBaseFilter sourceFilter, string sourcePinName, IBaseFilter destFilter, string destPinName)
{
IPin outPin = FindPin(sourceFilter, sourcePinName);
@ -527,200 +475,10 @@ namespace DualScreenDemo
private void DisplayBarrageOnOverlay(string text)
{
if (overlayForm.InvokeRequired)
{
overlayForm.Invoke(new System.Action(() => overlayForm.DisplayBarrage(text)));
}
else
{
overlayForm.DisplayBarrage(text);
}
}
public async void InitializePublicPlaylist(List<SongData> initialPlaylist)
{
publicPlaylist = initialPlaylist;
await PlayPublicPlaylist(); // 开始播放公播歌单
}
public async Task SetPlayingSongList(List<SongData> songList)
{
// [1] 輸出 debug 訊息,方便開發時追蹤是否有呼叫此方法
Console.WriteLine("SetPlayingSongList called");
// [2] 停止當前播放,釋放資源(例如關閉影片播放器、清除緩衝)
StopAndReleaseResources();
// [3] 將新的播放清單指派給 `playingSongList`
playingSongList = songList;
// [4] 根據是否有歌,設定旗標為是否播放使用者點播清單
isUserPlaylistPlaying = playingSongList != null && playingSongList.Any();
// [5] 強制關閉公播狀態(意即現在進入點歌模式)
IsPlayingPublicSong = false;
// [6] 若使用者點播清單有歌,就開始播放
if (isUserPlaylistPlaying)
{
// [6.1] 設定當前歌曲索引為 -1意味著即將播放第一首從 `PlayNextSong` 開始)
currentSongIndex = -1;
// [6.2] 播放下一首歌(實際會遞增 index 為 0並播放該首歌
await PlayNextSong();
}
else
{
await InitializeAndPlayPublicPlaylist();
}
}
public async Task PlayPublicPlaylist()
{
Console.WriteLine("開始播放公播清單...");
// 在切换到公播之前,确保最后一首用户歌曲状态正确
if (PrimaryForm.currentSongIndexInHistory >= 0 &&
PrimaryForm.currentSongIndexInHistory < PrimaryForm.playStates.Count)
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
Console.WriteLine($"切換到公播前更新最後一首歌曲狀態為已播放,索引:{PrimaryForm.currentSongIndexInHistory}");
// 强制刷新显示
if (PrimaryForm.Instance.multiPagePanel != null)
{
PrimaryForm.Instance.multiPagePanel.LoadPlayedSongs(
PrimaryForm.playedSongsHistory,
PrimaryForm.playStates
);
}
}
isUserPlaylistPlaying = false;
IsPlayingPublicSong = true; // 设置为正在播放公播
currentSongIndex = -1;
try
{
// 重新整理公播清單
publicPlaylist = new List<SongData>();
// 首先添加 welcome.mpg
string welcomePath = @"D:\video\welcome.mpg";
if (File.Exists(welcomePath))
{
publicPlaylist.Add(new SongData(
"0", "歡迎光臨", welcomePath, 1,true
));
}
// 添加 BGM 序列
for (int i = 1; i <= 99; i++)
{
string bgmPath = $@"D:\video\BGM{i:D2}.mpg";
if (File.Exists(bgmPath))
{
publicPlaylist.Add(new SongData(
i.ToString(), $"背景音樂{i:D2}", bgmPath, 1,true
));
}
}
// 如果公播清單為空,使用原有的歌曲
if (publicPlaylist.Count == 0)
{
string videoDirectory = @"D:\video\";
string[] videoFiles = Directory.GetFiles(videoDirectory, "*.mpg");
foreach (var songPath in videoFiles)
{
string fileName = Path.GetFileNameWithoutExtension(songPath);
publicPlaylist.Add(new SongData("0", fileName,songPath,1,true));
}
}
await Task.Delay(100); // 添加短暂延迟
await PlayNextSong();
}
catch (Exception ex)
{
Console.WriteLine($"播放公播清單時發生錯誤: {ex.Message}");
// 可以在这里添加重试逻辑
await Task.Delay(1000);
await PlayNextSong();
}
}
// private static async Task UpdateMarqueeTextForCurrentSong(SongData song)
// {
// string text;
// if (string.IsNullOrEmpty(song?.Song))
// {
// text = string.Empty;
// }
// else
// {
// text = String.Format("正在播放:{0} ", song.Song);
// }
// overlayForm.UpdateSongDisplayLabel(text);
// await Task.Delay(5000);
// }
public static async Task UpdateMarqueeTextForNextSong(SongData song)
{
string nextSongText = String.Format("下一首3{0}", song.Name);
if (overlayForm.InvokeRequired)
{
overlayForm.Invoke(new MethodInvoker(() =>
{
overlayForm.UpdateMarqueeText(nextSongText, OverlayForm.MarqueeStartPosition.Middle, Color.White);
}));
}
else
{
overlayForm.UpdateMarqueeText(nextSongText, OverlayForm.MarqueeStartPosition.Middle, Color.White);
}
await Task.Delay(5000);
// 重置跑马灯文本
if (overlayForm.InvokeRequired)
{
overlayForm.Invoke(new MethodInvoker(() =>
{
overlayForm.ResetMarqueeTextToWelcomeMessage();
}));
}
else
{
overlayForm.ResetMarqueeTextToWelcomeMessage();
}
}
public void UpdateNextSongFromPlaylist()
{
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
if (currentPlaylist == null || currentPlaylist.Count == 0)
{
overlayForm?.UpdateNextSongLabelFromPlaylist(isUserPlaylistPlaying, null);
return;
}
int currentSongIndex = currentPlaylist.IndexOf(currentPlayingSong);
if (currentSongIndex == -1 || currentSongIndex + 1 >= currentPlaylist.Count)
{
overlayForm?.UpdateNextSongLabelFromPlaylist(isUserPlaylistPlaying, null);
}
else
{
SongData nextSong = currentPlaylist[currentSongIndex + 1];
overlayForm?.UpdateNextSongLabelFromPlaylist(isUserPlaylistPlaying, currentPlayingSong);
}
}
public async Task PlayNextSong()
{
@ -729,54 +487,24 @@ namespace DualScreenDemo
{
await Task.Delay(100);
}
StopAndReleaseResources();
await Task.Delay(100);
Console.WriteLine("開始播放下一首歌曲...");
// 根據目前播放模式(點歌 or 公播)決定要播放的清單
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
// 若播放清單是空的,直接返回(不執行播放)
if (!currentPlaylist.Any()) return;
if (!isUserPlaylistPlaying)
{
// 公播模式下,正常循環播放(用 % 保證不會超出陣列界限)
currentSongIndex = (currentSongIndex + 1) % currentPlaylist.Count;
Console.WriteLine($"順序播放: currentSongIndex = {currentSongIndex}, currentPlaylist.Count = {currentPlaylist.Count}");
}
else
{
var songToPlay = SongList.Next();
if (!songToPlay.isPublicSong) {
// 若是使用者點播模式先送出升Key的串口指令
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
byte[] commandBytesIncreasePitch1 = new byte[] { 0xA2, 0x7F, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length);
}
// 同樣遞增 index 來播放下一首
currentSongIndex = (currentSongIndex + 1) % currentPlaylist.Count;
}
// 可以取得 燈控/聲控 的位置
var songToPlay = currentPlaylist[currentSongIndex];
// pathToPlay 需要調整
var pathToPlay = songToPlay.getFile();
// 若兩個 host 上都找不到檔案就直接結束
if (string.IsNullOrEmpty(pathToPlay))
{
Console.WriteLine($"文件不存在:{songToPlay.Name}");
return;
}
// 更新目前正在播放的歌曲
currentPlayingSong = songToPlay;
// 更新畫面上顯示的下一首歌資訊
UpdateNextSongFromPlaylist();
SongList.UpdateNextSongLabel();
// 顯示 QRCode可能是點歌頁用
overlayForm.DisplayQRCodeOnOverlay(HttpServer.randomFolderPath);
@ -789,17 +517,10 @@ namespace DualScreenDemo
{
// 確保在UI線程上執行COM對象操作
if (this.InvokeRequired)
{
this.Invoke(new Action(async () =>
{
await InitializeAndPlayMedia(pathToPlay);
}));
}
this.Invoke(new Action(async () => { await InitializeAndPlayMedia(pathToPlay); }));
else
{
await InitializeAndPlayMedia(pathToPlay);
}
}
catch (Exception ex)
{
Console.WriteLine($"播放時發生錯誤: {ex.Message}");
@ -829,15 +550,8 @@ namespace DualScreenDemo
private async Task InitializeAndPlayMedia(string pathToPlay)
{
if (videoWindowPrimary != null)
{
videoWindowPrimary.put_Visible(OABool.False);
}
if (videoWindowSecondary != null)
{
videoWindowSecondary.put_Visible(OABool.False);
}
if (videoWindowPrimary != null) videoWindowPrimary.put_Visible(OABool.False);
if (videoWindowSecondary != null) videoWindowSecondary.put_Visible(OABool.False);
// 清理並初始化 DirectShow 圖表
RemoveAllFilters(graphBuilderPrimary);
@ -867,156 +581,21 @@ namespace DualScreenDemo
if (mediaControlPrimary != null) mediaControlPrimary.Run();
if (mediaControlSecondary != null) mediaControlSecondary.Run();
if (isSyncToPrimaryMonitor)
{
SyncToPrimaryMonitor();
}
}
/// <summary>
/// 跳至下一首歌曲的方法,會根據目前播放清單(使用者清單或公播清單)做切換與播放邏輯控制。
/// </summary>
public async Task SkipToNextSong()
{
try
{
// 停止當前播放並釋放資源(如播放器、影片檔等)
StopAndReleaseResources();
// 稍作延遲,確保資源已被釋放
await Task.Delay(100);
// 如果目前正在播放使用者點播清單,且清單還有歌曲
if (isUserPlaylistPlaying && playingSongList != null && playingSongList.Count > 0)
{
// 移除目前播放的第一首歌(已經播放過的)
playingSongList.RemoveAt(0);
if (playingSongList.Count == 0)
{
// 使用者點播清單播完了,切換回公播清單
Console.WriteLine("用戶播放列表已清空,切換至公播清單");
isUserPlaylistPlaying = false;
lastPlayedIndex = -1;
currentSongIndex = -1;
// 初始化並開始播放公播清單
await InitializeAndPlayPublicPlaylist();
}
else
{
// 還有歌曲可播,繼續播放下一首使用者歌曲
currentSongIndex = -1;
await PlayNextSong();
}
}
else
{
// 如果不是在播放使用者清單(或清單為空),直接初始化並播放公播清單
await InitializeAndPlayPublicPlaylist();
}
// 如果目前歌曲在播放歷史列表的索引是合法的(防呆)
if (PrimaryForm.currentSongIndexInHistory >= 0 && PrimaryForm.currentSongIndexInHistory < PrimaryForm.playedSongsHistory.Count)
{
var currentSong = PrimaryForm.playedSongsHistory[PrimaryForm.currentSongIndexInHistory];
// 如果新的播放清單還有歌曲,並且當前歷史記錄中的歌曲與播放清單的第一首一致,則標記為已播畢
if (playingSongList.Count > 0 && currentSong == playingSongList[0])
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
}
}
/*如果當前為公播,不可以+1*/
bool isPlayingPublicList = PrimaryForm.userRequestedSongs.Count == 0 ||
(PrimaryForm.currentSongIndexInHistory >= PrimaryForm.userRequestedSongs.Count - 1 && PrimaryForm.Instance.videoPlayerForm.IsPlayingPublicSong);
if (!isPlayingPublicList)
{
PrimaryForm.currentSongIndexInHistory += 1;
}
Console.WriteLine("currentSongIndexInHistory : " + PrimaryForm.currentSongIndexInHistory);
}
catch (Exception ex)
{
// 若有例外錯誤,列印錯誤訊息並切回公播模式
Console.WriteLine($"切換歌曲時發生錯誤: {ex.Message}");
await InitializeAndPlayPublicPlaylist();
}
}
// 新增一个方法来处理公播列表的初始化和播放
private async Task InitializeAndPlayPublicPlaylist()
{
try
{
isUserPlaylistPlaying = false;
currentSongIndex = -1;
// 重新初始化公播列表
publicPlaylist = new List<SongData>();
// 添加 welcome.mpg
string welcomePath = @"D:\video\welcome.mpg";
if (File.Exists(welcomePath))
{
publicPlaylist.Add(new SongData("0", "歡迎光臨", welcomePath, 1,true));
}
// 添加 BGM 序列
for (int i = 1; i <= 99; i++)
{
string bgmPath = $@"D:\video\BGM{i:D2}.mpg";
if (File.Exists(bgmPath))
{
publicPlaylist.Add(new SongData(i.ToString(), $"背景音樂{i:D2}", bgmPath, 1,true));
}
}
if (publicPlaylist.Count > 0)
{
await PlayNextSong();
}
}
catch (Exception ex)
{
Console.WriteLine($"初始化公播清單時發生錯誤: {ex.Message}");
}
if (isSyncToPrimaryMonitor) SyncToPrimaryMonitor();
}
public void ReplayCurrentSong()
{
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
if (!currentPlaylist.Any()) return;
var songToPlay = currentPlaylist[currentSongIndex];
var songToPlay = SongList.Current();
var pathToPlay = songToPlay.getFile();
if (string.IsNullOrEmpty(pathToPlay))
{
MessageBox.Show("File does not exist on both hosts.");
return;
}
// UpdateMarqueeTextForCurrentSong(songToPlay);
try
{
if (mediaControlPrimary != null)
{
mediaControlPrimary.Stop();
}
if (mediaControlSecondary != null)
{
mediaControlSecondary.Stop();
}
if (videoWindowPrimary != null)
{
videoWindowPrimary.put_Visible(OABool.False); // 隐藏主屏幕窗口,避免干扰
}
if (videoWindowSecondary != null)
{
videoWindowSecondary.put_Visible(OABool.False); // 隐藏副屏幕窗口,避免闪烁
}
if (mediaControlPrimary != null) mediaControlPrimary.Stop();
if (mediaControlSecondary != null) mediaControlSecondary.Stop();
if (videoWindowPrimary != null) videoWindowPrimary.put_Visible(OABool.False); // 隐藏主屏幕窗口,避免干扰
if (videoWindowSecondary != null) videoWindowSecondary.put_Visible(OABool.False); // 隐藏副屏幕窗口,避免闪烁
// 清理并初始化 DirectShow 图表
RemoveAllFilters(graphBuilderPrimary);
@ -1039,19 +618,13 @@ namespace DualScreenDemo
}
// 音量处理
if (isMuted)
{
SetVolume(-10000); // 静音
}
if (isMuted) SetVolume(-10000); // 静音
// 开始播放
mediaControlPrimary?.Run();
mediaControlSecondary?.Run();
if (isSyncToPrimaryMonitor)
{
SyncToPrimaryMonitor();
}
if (isSyncToPrimaryMonitor) SyncToPrimaryMonitor();
}
catch (Exception ex)
{
@ -1122,10 +695,8 @@ namespace DualScreenDemo
public void RenderMediaFilePrimary(string filePath)
{
try {
int hr;
try
{
IBaseFilter sourceFilter;
hr = graphBuilderPrimary.AddSourceFilter(filePath, "Source", out sourceFilter);
DsError.ThrowExceptionForHR(hr);
@ -1144,18 +715,9 @@ namespace DualScreenDemo
//Task.Delay(100).Wait();
videoWindowPrimary.put_Visible(OABool.True);
SaveGraphFile(graphBuilderPrimary, "primary_graph.grf");
Console.WriteLine("主檔案 " + ((hr == 0) ? "成功" : "失敗"));
if (hr == 0)
{
Console.WriteLine("主檔案 成功");
}
else
{
Console.WriteLine("檔案失敗");
}
}
catch (Exception ex)
{
} catch (Exception ex) {
Console.WriteLine("主檔案失敗2: " + ex.Message);
}
}
@ -1244,7 +806,6 @@ namespace DualScreenDemo
}
private bool isPlayingNext = false;
private int lastPlayedIndex = -1; // 追蹤上一首播放的索引
public void MonitorMediaEvents()
{
@ -1256,7 +817,7 @@ namespace DualScreenDemo
{
try
{
if (mediaControlSecondary == null || isPlayingNext)
if (mediaControlSecondary == null)
{
await Task.Delay(500);
continue;
@ -1284,126 +845,14 @@ namespace DualScreenDemo
{
Console.WriteLine($"檢測到歌曲結束 - 當前位置: {currentSeconds:F2}秒, 總時長: {durationSeconds:F2}秒");
if (!isPlayingNext)
{
isPlayingNext = true;
// 添加额外的保护:确保在切换前停止当前播放
if (mediaControlSecondary != null)
BeginInvoke(new Action(async () =>
{
mediaControlSecondary.Stop();
}
this.BeginInvoke(new Action(async () =>
{
try
{
// 在切换前释放资源
StopAndReleaseResources();
await Task.Delay(100); // 给予足够的时间释放资源
if (isUserPlaylistPlaying && playingSongList != null)
{
if (playingSongList.Count > 0)
{
try
{
// 移除當前播放的歌曲
playingSongList.RemoveAt(0);
// 更新播放状态逻辑
if (PrimaryForm.currentSongIndexInHistory >= 0)
{
// 将当前播放的歌曲标记为已播放
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
// 如果还有下一首歌
if (playingSongList.Count > 0)
{
PrimaryForm.currentSongIndexInHistory++;
// 将下一首歌标记为正在播放
if (PrimaryForm.currentSongIndexInHistory < PrimaryForm.playStates.Count)
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Playing;
}
}
}
if (playingSongList.Count == 0)
{
Console.WriteLine("用戶播放列表已播放完畢,切換到公共播放列表");
// 确保当前歌曲状态更新为已播放
if (PrimaryForm.currentSongIndexInHistory >= 0 &&
PrimaryForm.currentSongIndexInHistory < PrimaryForm.playStates.Count)
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
Console.WriteLine($"已將最後一首歌曲狀態更新為已播放,索引:{PrimaryForm.currentSongIndexInHistory}");
// 强制刷新显示
if (PrimaryForm.Instance.multiPagePanel != null)
{
PrimaryForm.Instance.multiPagePanel.LoadPlayedSongs(
PrimaryForm.playedSongsHistory,
PrimaryForm.playStates
);
}
}
// 重置播放状态但保留历史记录
isUserPlaylistPlaying = false;
currentSongIndex = -1;
// 确保所有未播放的歌曲状态被清除
for (int i = PrimaryForm.currentSongIndexInHistory + 1;
i < PrimaryForm.playStates.Count; i++)
{
if (PrimaryForm.playStates[i] == PlayState.Playing)
{
PrimaryForm.playStates[i] = PlayState.NotPlayed;
}
}
// 添加延迟以确保状态更新完成
await Task.Delay(200);
await InitializeAndPlayPublicPlaylist();
}
else
{
currentSongIndex = -1;
await PlayNextSong();
}
}
catch (Exception ex)
{
Console.WriteLine($"處理播放列表時發生錯誤: {ex.Message}");
lastPlayedIndex = -1;
isUserPlaylistPlaying = false;
currentSongIndex = -1;
await InitializeAndPlayPublicPlaylist();
}
}
}
else if (!isUserPlaylistPlaying && publicPlaylist != null)
{
await PlayNextSong();
}
}
catch (Exception ex)
{
Console.WriteLine($"切換歌曲時發生錯誤: {ex.Message}");
// 发生错误时重置状态并切换到公播
lastPlayedIndex = -1;
isUserPlaylistPlaying = false;
currentSongIndex = -1;
await InitializeAndPlayPublicPlaylist();
}
finally
{
isPlayingNext = false;
}
}));
}
}
}
}
@ -1413,13 +862,6 @@ namespace DualScreenDemo
Console.WriteLine($"監控媒體事件時發生錯誤: {ex.Message}");
isPlayingNext = false;
// 添加重试机制
if (!isUserPlaylistPlaying && publicPlaylist != null)
{
await Task.Delay(1000);
await PlayNextSong();
}
await Task.Delay(1000);
}
@ -1528,7 +970,7 @@ namespace DualScreenDemo
return -10000;
}
private bool isVocalRemoved = false;
public async void ToggleVocalRemoval()
public void ToggleVocalRemoval()
{
try
{
@ -1587,8 +1029,7 @@ namespace DualScreenDemo
string labelText = isVocalRemoved ? "無人聲" : "有人聲";
// 显示标签
// 修改成新標籤
OverlayForm.MainForm.HideAllLabels();
OverlayForm.MainForm.ShowOriginalSongLabel(labelText);
OverlayForm.MainForm.ShowTopRightLabel(labelText);
//await Task.Delay(3000);
// 隐藏标签
//OverlayForm.MainForm.HideOriginalSongLabel();
@ -1648,211 +1089,6 @@ namespace DualScreenDemo
}
}
public void AddSongToPlaylist(SongData songData)
{
try{
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
// 查找所有相同歌曲的索引
var sameNameIndices = new List<int>();
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
{
if (PrimaryForm.playedSongsHistory[i].Name == songData.Name)
{
sameNameIndices.Add(i);
}
}
// 添加新歌到播放列表
PrimaryForm.userRequestedSongs.Add(songData);
PrimaryForm.playedSongsHistory.Add(songData);
// 更新状态
if (wasEmpty)
{
// 如果是空列表,设置为正在播放
PrimaryForm.playStates.Add(PlayState.Playing);
PrimaryForm.currentSongIndexInHistory = PrimaryForm.playedSongsHistory.Count - 1;
// 确保之前相同歌曲的状态为已播放
foreach (int index in sameNameIndices)
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
PrimaryForm.playStates[index] = PlayState.Played;
}
}
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs);
}
else
{
// 如果不是空列表,设置为未播放
PrimaryForm.playStates.Add(PlayState.NotPlayed);
// 更新所有相同歌曲的状态
foreach (int index in sameNameIndices.Where(i => i < PrimaryForm.playedSongsHistory.Count - 1))
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
// 之前的相同歌曲标记为已播放
PrimaryForm.playStates[index] = PlayState.Played;
}
else if (index == PrimaryForm.currentSongIndexInHistory)
{
// 当前播放的歌曲保持Playing状态
PrimaryForm.playStates[index] = PlayState.Playing;
}
else
{
// 后面的相同歌曲标记为未播放
PrimaryForm.playStates[index] = PlayState.NotPlayed;
}
}
}
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
PrimaryForm.PrintPlayingSongList();
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
public void InsertSongToPlaylist(SongData songData)
{
try{
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
// 查找所有相同歌曲的索引
var sameNameIndices = new List<int>();
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
{
if (PrimaryForm.playedSongsHistory[i].Name == songData.Name)
{
sameNameIndices.Add(i);
}
}
if (wasEmpty)
{
// 如果列表为空,直接添加
PrimaryForm.userRequestedSongs.Add(songData);
PrimaryForm.playedSongsHistory.Add(songData);
PrimaryForm.playStates.Add(PlayState.Playing);
PrimaryForm.currentSongIndexInHistory = PrimaryForm.playedSongsHistory.Count - 1;
// 更新之前相同歌曲的状态
foreach (int index in sameNameIndices)
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
PrimaryForm.playStates[index] = PlayState.Played;
}
}
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs);
}
else
{
// 插入到当前播放歌曲之后
int insertIndex = PrimaryForm.currentSongIndexInHistory + 1;
PrimaryForm.userRequestedSongs.Insert(1, songData);
PrimaryForm.playedSongsHistory.Insert(insertIndex, songData);
PrimaryForm.playStates.Insert(insertIndex, PlayState.NotPlayed);
// 更新所有相同歌曲的状态
foreach (int index in sameNameIndices)
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
// 之前的相同歌曲标记为已播放
PrimaryForm.playStates[index] = PlayState.Played;
}
else if (index == PrimaryForm.currentSongIndexInHistory)
{
// 当前播放的歌曲保持Playing状态
PrimaryForm.playStates[index] = PlayState.Playing;
}
else if (index > insertIndex)
{
// 后面的相同歌曲标记为未播放
PrimaryForm.playStates[index] = PlayState.NotPlayed;
}
}
}
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
PrimaryForm.PrintPlayingSongList();
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
public VideoStatus GetCurrentVideoStatus()
{
var status = new VideoStatus();
try
{
IMediaSeeking mediaSeekingSecondary = graphBuilderSecondary as IMediaSeeking;
if (mediaSeekingSecondary != null)
{
long position;
if (mediaSeekingSecondary.GetCurrentPosition(out position) >= 0)
{
status.PositionSeconds = position / 10000000.0;
}
else
{
status.LastError = "無法取得影片播放位置";
status.PositionSeconds = -1;
}
}
else
{
status.LastError = "mediaSeekingSecondary 物件為 null";
status.PositionSeconds = -1;
}
if (mediaControlSecondary != null)
{
FilterState stateCode;
int hr = mediaControlSecondary.GetState(100, out stateCode);
if (hr >= 0)
{
var state = (FilterState)stateCode;
status.PlayState = state.ToString();
status.LastError = state.ToString();
status.IsGraphOk = true;
}
else
{
status.PlayState = "無法取得播放狀態";
status.LastError = "無法取得播放狀態";
status.IsGraphOk = false;
}
}
else
{
status.PlayState = "mediaControlSecondary 物件為 null";
status.LastError = "mediaControlSecondary 物件為 null";
status.IsGraphOk = false;
}
}
catch (Exception ex)
{
status.LastError = "取得影片狀態時發生例外:" + ex.Message;
status.PositionSeconds = -1;
status.PlayState = "Error";
status.IsGraphOk = false;
}
return status;
}
}
}

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