2025-07-09 21:35:58 -07:00

289 lines
11 KiB
C#

using NAudio.Wave;
using System;
using System.Windows.Forms;
using YoutubeExplode;
using YoutubeExplode.Videos;
using YoutubeExplode.Videos.Streams;
namespace Projector
{
public partial class FrmMain : Form
{
private Video? _video = null;
private StreamManifest? _streamManifest = null;
FourChannelToStereoSampleProvider? mixer = null;
string musicPath = "C:\\Hymnal\\Music";
string editsPath = "C:\\Hymnal\\Edits";
string LyricsPath = "C:\\Hymnal\\Lyrics";
FrmPreview frmPreview = new FrmPreview();
public FrmMain()
{
InitializeComponent();
DgvHymns.CellContentClick += DgvHymns_CellContentClick;
}
private void FrmMain_Load(object sender, EventArgs e)
{
FrmMain_Resize(null, null);
if (!System.IO.Directory.Exists(musicPath))
{
MessageBox.Show("Hymns directory does not exist: " + musicPath);
return;
}
var hymns = System.IO.Directory.GetFiles(musicPath, "*.m4a");
foreach (var hymn in hymns)
{
var fileName = System.IO.Path.GetFileNameWithoutExtension(hymn);
DgvHymns.Rows.Add(fileName, "");
}
}
private void DgvHymns_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (DgvHymns.Columns[e.ColumnIndex].Name == "CnPlay" && e.RowIndex >= 0)
{
e.Paint(e.CellBounds, DataGridViewPaintParts.All);
var icon = Properties.Resources.Play; // Assuming you have a play icon in resources
var iconRect = new Rectangle(e.CellBounds.X + 2, e.CellBounds.Y + 2, e.CellBounds.Height - 4, e.CellBounds.Height - 4);
e.Graphics?.DrawImage(icon, iconRect);
e.Handled = true; // Prevent default painting
}
}
// 3. Handle the Play button click:
private void DgvHymns_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Check if PlayButton column and not header row
if (e.RowIndex >= 0 && DgvHymns.Columns[e.ColumnIndex].Name == "CnPlay")
{
var hymnName = DgvHymns.Rows[e.RowIndex].Cells["CnHymn"].Value?.ToString();
if (!string.IsNullOrEmpty(hymnName))
{
PlayHymn(hymnName);
}
}
}
private void PlayHymn(string name)
{
string audioFilePath = Path.Combine(editsPath, name + ".m4a");
if (!File.Exists(audioFilePath))
{
audioFilePath = Path.Combine(musicPath, name + ".m4a");
}
string number = name.Substring(0, 3).Trim(); // Extract the first 3 characters
try
{
// Open the audio file
var reader = new MediaFoundationReader(audioFilePath);
// Check for 4 channels
if (reader.WaveFormat.Channels != 4)
{
MessageBox.Show("Audio file does not have 4 channels.");
reader.Dispose();
return;
}
// Create a custom sample provider to mix channels 0+2 to left, 1+3 to right
mixer = new FourChannelToStereoSampleProvider(reader.ToSampleProvider());
// Search the folder in LyricsPath that starts with the hymn number
string lyricsFilePath = Directory.GetDirectories(LyricsPath).ToList().ConvertAll(d => Path.GetFileName(d))
.FirstOrDefault(dir => dir.StartsWith(number, StringComparison.OrdinalIgnoreCase));
// Get all the jpg files in the lyrics folder
if (lyricsFilePath != null)
{
string lyricsFolderPath = Path.Combine(LyricsPath, lyricsFilePath);
var jpgFiles = Directory.GetFiles(lyricsFolderPath, "*.jpg");
// Order the jpg files by name
Array.Sort(jpgFiles, StringComparer.OrdinalIgnoreCase);
// Display the first jpg file in a PictureBox or similar control
if (jpgFiles.Length > 0)
{
// Assuming you have a PictureBox named pictureBoxLyrics
frmPreview.SetImages(jpgFiles, mixer);
}
}
var waveOut = new WaveOutEvent();
waveOut.Init(mixer);
waveOut.Play();
frmPreview.ShowDialog(this);
TbFilter.SelectAll();
TbFilter.Focus();
// Crate a task to handle the transition
Task.Run(() =>
{
mixer.SetOff();
while (!mixer.IsOff)
{
Thread.Sleep(100); // Check every 100ms
}
waveOut.Stop();
});
// Optionally, store waveOut and reader as fields to stop/dispose later
}
catch (Exception ex)
{
MessageBox.Show("Error playing audio: " + ex.Message);
}
}
private void TbFilter_TextChanged(object sender, EventArgs e)
{
// Filter the DataGridView based on the text in the filter TextBox
string filterText = TbFilter.Text.ToLower();
foreach (DataGridViewRow row in DgvHymns.Rows)
{
if (row.Cells["CnHymn"].Value != null)
{
row.Visible = row.Cells["CnHymn"].Value.ToString().ToLower().Contains(filterText);
}
}
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
int firstVisibleRowIndex = visibleRows[0].Index;
DgvHymns.Rows[firstVisibleRowIndex].Selected = true;
DgvHymns.FirstDisplayedScrollingRowIndex = firstVisibleRowIndex;
}
}
private void FrmMain_Resize(object sender, EventArgs e)
{
DgvHymns.Columns["CnHymn"].Width = Width - 80;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Down)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
int selectedRowIndex = visibleRows.FindIndex(row => row.Selected);
selectedRowIndex++;
if (selectedRowIndex < visibleRows.Count)
{
visibleRows[selectedRowIndex].Selected = true;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
int lastDisplayed = firstDisplayed + displayedCount - 1;
if (selectedRowIndex >= lastDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex - displayedCount + 1].Index;
}
}
}
return true;
}
else if (keyData == Keys.Up)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
int selectedRowIndex = visibleRows.FindIndex(row => row.Selected);
selectedRowIndex--;
if (selectedRowIndex >= 0)
{
visibleRows[selectedRowIndex].Selected = true;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
if (selectedRowIndex < firstDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex].Index;
}
}
}
return true;
}
else if (keyData == Keys.Enter)
{
// Handle Enter key to simulate Play button click
var selectedRow = DgvHymns.SelectedRows.Cast<DataGridViewRow>().FirstOrDefault();
if (selectedRow != null && selectedRow.Cells["CnPlay"].Value != null)
{
DgvHymns_CellContentClick(sender: null, e: new DataGridViewCellEventArgs(1, selectedRow.Index));
return true; // Indicate that the key press has been handled
}
}
else if (keyData == Keys.Home)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
visibleRows.First().Selected = true;
int selectedRowIndex = visibleRows.First().Index;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
if (selectedRowIndex < firstDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex].Index;
}
}
return true; // Indicate that the key press has been handled
}
else if (keyData == Keys.End)
{
var visibleRows = DgvHymns.Rows
.Cast<DataGridViewRow>()
.Where(row => row.Visible)
.ToList();
if (visibleRows.Count > 0)
{
visibleRows.Last().Selected = true;
int selectedRowIndex = visibleRows.Last().Index;
int firstDisplayed = DgvHymns.FirstDisplayedScrollingRowIndex;
int displayedCount = DgvHymns.DisplayedRowCount(false); // false = only fully visible rows
int lastDisplayed = firstDisplayed + displayedCount - 1;
if (selectedRowIndex >= lastDisplayed)
{
DgvHymns.FirstDisplayedScrollingRowIndex = visibleRows[selectedRowIndex - displayedCount + 1].Index;
}
}
return true; // Indicate that the key press has been handled
}
return base.ProcessCmdKey(ref msg, keyData); // Allow default processing if not an arrow key
}
}
}