parseWebVTT static method
Parse WebVTT subtitle format
Implementation
static List<SubtitleCue> parseWebVTT(String content) {
final cues = <SubtitleCue>[];
final lines = content.split('\n');
String? currentText;
Duration? startTime;
Duration? endTime;
for (var i = 0; i < lines.length; i++) {
final line = lines[i].trim();
// Skip empty lines and WebVTT header
if (line.isEmpty || line == 'WEBVTT' || line.startsWith('NOTE')) {
continue;
}
// Check for timestamp line (format: 00:00:00.000 --> 00:00:00.000)
if (line.contains('-->')) {
final parts = line.split('-->');
if (parts.length == 2) {
startTime = _parseTime(parts[0].trim());
endTime = _parseTime(parts[1].trim().split(' ').first);
currentText = '';
}
} else if (startTime != null && endTime != null && line.isNotEmpty) {
// This is subtitle text
if (currentText != null && currentText.isNotEmpty) {
currentText += '\n$line';
} else {
currentText = line;
}
// Check if next line is empty or timestamp (end of cue)
final isLastLine = i + 1 >= lines.length;
final nextLineEmpty = !isLastLine && lines[i + 1].trim().isEmpty;
final nextLineIsTimestamp = !isLastLine && lines[i + 1].contains('-->');
if (isLastLine || nextLineEmpty || nextLineIsTimestamp) {
// At this point, startTime, endTime, and currentText are guaranteed to be non-null
// due to the outer else-if condition and the text assignment above
if (currentText.isNotEmpty) {
cues.add(
SubtitleCue(start: startTime, end: endTime, text: currentText),
);
}
currentText = null;
startTime = null;
endTime = null;
}
}
}
// Add last cue if exists
if (currentText != null && startTime != null && endTime != null) {
cues.add(SubtitleCue(start: startTime, end: endTime, text: currentText));
}
return cues;
}