using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;
namespace AudioPlayerApp
{
public partial class MainWindow : Window
{
private DispatcherTimer _subtitleTimer;
private List<Subtitle> _subtitles;
private List<Subtitle> _subtitlesEn;
private TextRange _textRange;
private TextRange _textRangeEn;
private HashSet<string> _outputtedSubtitles; // 用于存储已输出的字幕文本
private HashSet<string> _outputtedSubtitlesEn; // 用于存储已输出的字幕文本
public MainWindow()
{
InitializeComponent();
InitializeApp(); // 初始化应用程序
}
private void InitializeApp()
{
_subtitles = LoadSubtitles("test_cn.srt");
_subtitlesEn = LoadSubtitles("test_en.srt");
SetRichTextBoxContent(_subtitles, ref _textRange, TextDisplay);
SetRichTextBoxContent(_subtitlesEn, ref _textRangeEn, TextDisplayEn);
InitializeTimer();
InitializeOutputtedSubtitles();
}
private List<Subtitle> LoadSubtitles(string filePath)
{
var subtitles = new List<Subtitle>();
var lines = File.ReadAllLines(filePath);
for (int i = 0; i < lines.Length; i++)
{
if (int.TryParse(lines[i], out _)) // Skip index line
{
i++;
var timeLine = lines[i].Split(new[] { " --> " }, StringSplitOptions.None);
var startTime = TimeSpan.Parse(timeLine[0].Replace(',', '.'));
var endTime = TimeSpan.Parse(timeLine[1].Replace(',', '.'));
i++;
var text = lines[i]; // Add subtitle text
subtitles.Add(new Subtitle { StartTime = startTime, EndTime = endTime, Text = text });
}
}
return subtitles;
}
private void SetRichTextBoxContent(List<Subtitle> subtitles, ref TextRange textRange, RichTextBox richTextBox)
{
string content = string.Join("\r", subtitles.Select(x => x.Text).ToArray());
textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
textRange.Text = content;
}
private void InitializeTimer()
{
_subtitleTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(100)
};
_subtitleTimer.Tick += SubtitleTimer_Tick;
}
private void InitializeOutputtedSubtitles()
{
_outputtedSubtitles = new HashSet<string>();
_outputtedSubtitlesEn = new HashSet<string>();
}
private void SubtitleTimer_Tick(object sender, EventArgs e)
{
if (MediaPlayer.NaturalDuration.HasTimeSpan)
{
var currentTime = MediaPlayer.Position;
ProgressSlider.Value = MediaPlayer.Position.TotalSeconds;
UpdateHighlightedSubtitles(currentTime);
}
}
private void UpdateHighlightedSubtitles(TimeSpan currentTime)
{
UpdateHighlightedSubtitle(currentTime, _subtitles, _textRange, ClearHighlight,scrollViewer);
UpdateHighlightedSubtitle(currentTime,_subtitlesEn, _textRangeEn, ClearHighlight, scrollViewerEn);
}
private void UpdateHighlightedSubtitle(TimeSpan currentTime, List<Subtitle> subtitlesList, TextRange textRange
, Action<TextRange> clearHighlightAction
, ScrollViewer scrollViewer
)
{
var currentSubtitle = subtitlesList.Find(s => currentTime >= s.StartTime && currentTime <= s.EndTime);
if (currentSubtitle != null)
{
HighlightSpecificText(currentSubtitle.Text, textRange,scrollViewer);
}
else
{
clearHighlightAction(textRange); // 如果没有字幕,清除高亮
}
}
private void HighlightSpecificText(string textToHighlight, TextRange textRange, ScrollViewer scrollViewer)
{
ClearHighlight(textRange); // 清除之前的高亮
if (string.IsNullOrEmpty(textToHighlight))
return;
string fullText = textRange.Text;
int startIndex = 0;
while (startIndex < fullText.Length)
{
startIndex = fullText.IndexOf(textToHighlight, startIndex, StringComparison.OrdinalIgnoreCase);
if (startIndex < 0)
break;
TextPointer startPointer = textRange.Start.GetPositionAtOffset(startIndex);
TextPointer endPointer = startPointer.GetPositionAtOffset(textToHighlight.Length);
TextRange highlightRange = new TextRange(startPointer, endPointer);
highlightRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Yellow);
highlightRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Black);
// 自动滚动到高亮文本的位置
ScrollToHighlight(startPointer, scrollViewer);
startIndex += textToHighlight.Length;
}
}
private void ScrollToHighlight(TextPointer startPointer, ScrollViewer scrollViewer)
{
// 获取高亮文本的可视位置
Rect rect = startPointer.GetCharacterRect(LogicalDirection.Forward);
if (rect != Rect.Empty)
{
// 计算滚动偏移量
double verticalOffset = rect.Top - (scrollViewer.ViewportHeight / 2);
if (verticalOffset < 0)
{
verticalOffset = 0;
}
// 滚动到目标位置
scrollViewer.ScrollToVerticalOffset(verticalOffset);
}
}
private void ClearHighlight(TextRange textRange)
{
TextRange fullTextRange = new TextRange(textRange.Start, textRange.End);
fullTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Transparent);
fullTextRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Black);
}
private void ProgressSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (MediaPlayer.NaturalDuration.HasTimeSpan)
{
UpdateMediaPosition();
var currentTime = MediaPlayer.Position;
UpdateHighlightedSubtitles(currentTime);
}
}
private void UpdateMediaPosition()
{
if (MediaPlayer.NaturalDuration.TimeSpan.TotalSeconds > 0)
{
MediaPlayer.Position = TimeSpan.FromSeconds(ProgressSlider.Value);
//Debug.WriteLine($"位置:" + MediaPlayer.Position);
}
}
private void MediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
if (MediaPlayer.NaturalDuration.HasTimeSpan)
{
ProgressSlider.Maximum = MediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
}
_subtitleTimer.Start();
}
private void PlayButton_Click(object sender, RoutedEventArgs e)
{
MediaPlayer.Play();
}
private void PauseButton_Click(object sender, RoutedEventArgs e)
{
MediaPlayer.Pause();
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
ResetToInitialState(); // 重置到初始状态
}
private void MediaPlayer_MediaEnded(object sender, EventArgs e)
{
Debug.WriteLine("音频播放完毕");
ResetToInitialState(); // 重置到初始状态
}
private void ResetToInitialState()
{
MediaPlayer.Stop();
_subtitleTimer.Stop();
ProgressSlider.Value = 0;
ClearHighlight(_textRange);
ClearHighlight(_textRangeEn);
scrollViewer.ScrollToHome();
scrollViewerEn.ScrollToHome();
_outputtedSubtitles.Clear();
_outputtedSubtitlesEn.Clear();
}
private class Subtitle
{
public TimeSpan StartTime { get; set; }
public TimeSpan EndTime { get; set; }
public string Text { get; set; }
}
}
}