Merge pull request #8 from MertUyanik/codex/investigate-missing-subtitle-display
Fix SRT subtitle parsing and auto-select default track
This commit is contained in:
@@ -265,6 +265,28 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
|||||||
}
|
}
|
||||||
}, [subtitles])
|
}, [subtitles])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const video = videoRef.current
|
||||||
|
if (!video) return
|
||||||
|
if (processedSubtitles.length === 0) return
|
||||||
|
if (settings.subtitle) return
|
||||||
|
|
||||||
|
const defaultSubtitle = processedSubtitles.find((subtitle) => subtitle.default)
|
||||||
|
if (!defaultSubtitle) return
|
||||||
|
|
||||||
|
const tracks = video.textTracks
|
||||||
|
if (!tracks || tracks.length === 0) return
|
||||||
|
|
||||||
|
for (let i = 0; i < tracks.length; i++) {
|
||||||
|
const track = tracks[i]
|
||||||
|
if (track.language === defaultSubtitle.lang) {
|
||||||
|
track.mode = 'showing'
|
||||||
|
setSubtitle(defaultSubtitle)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [processedSubtitles, settings.subtitle, setSubtitle, videoRef])
|
||||||
|
|
||||||
// Detect HLS source and load hls.js if needed
|
// Detect HLS source and load hls.js if needed
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const video = videoRef.current
|
const video = videoRef.current
|
||||||
|
|||||||
+44
-21
@@ -2,34 +2,57 @@
|
|||||||
* Parse SRT subtitle format to WebVTT
|
* Parse SRT subtitle format to WebVTT
|
||||||
*/
|
*/
|
||||||
export const parseSRT = (srtContent: string): string => {
|
export const parseSRT = (srtContent: string): string => {
|
||||||
const lines = srtContent.trim().split('\n')
|
const normalised = srtContent.replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim()
|
||||||
let vttContent = 'WEBVTT\n\n'
|
|
||||||
|
|
||||||
let i = 0
|
if (!normalised) {
|
||||||
while (i < lines.length) {
|
return 'WEBVTT\n\n'
|
||||||
// Skip subtitle number
|
|
||||||
if (/^\d+$/.test(lines[i].trim())) {
|
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse timestamp line
|
const cues = normalised
|
||||||
if (lines[i] && lines[i].includes('-->')) {
|
.split(/\n{2,}/)
|
||||||
const timeLine = lines[i].replace(/,/g, '.') // SRT uses comma, VTT uses dot
|
.map((cueBlock) => {
|
||||||
vttContent += timeLine + '\n'
|
const lines = cueBlock
|
||||||
i++
|
.split('\n')
|
||||||
|
.map((line) => line.replace(/^\ufeff/, '').trimEnd())
|
||||||
|
.filter((line, index, arr) => !(line === '' && index === arr.length - 1))
|
||||||
|
|
||||||
// Add subtitle text
|
if (lines.length === 0) {
|
||||||
while (i < lines.length && lines[i].trim() !== '') {
|
return null
|
||||||
vttContent += lines[i] + '\n'
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
vttContent += '\n'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i++
|
if (/^\d+$/.test(lines[0].trim())) {
|
||||||
|
lines.shift()
|
||||||
}
|
}
|
||||||
|
|
||||||
return vttContent
|
if (lines.length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeLine = lines.shift()
|
||||||
|
if (!timeLine || !timeLine.includes('-->')) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const vttTimeLine = timeLine
|
||||||
|
.split('-->')
|
||||||
|
.map((part) => part.trim().replace(/,/g, '.'))
|
||||||
|
.join(' --> ')
|
||||||
|
|
||||||
|
if (!vttTimeLine.includes('-->')) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = lines.join('\n')
|
||||||
|
return `${vttTimeLine}\n${text}`.trim()
|
||||||
|
})
|
||||||
|
.filter((cueBlock): cueBlock is string => Boolean(cueBlock))
|
||||||
|
|
||||||
|
const header = 'WEBVTT\n\n'
|
||||||
|
if (cues.length === 0) {
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
return header + cues.join('\n\n') + '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +60,7 @@ export const parseSRT = (srtContent: string): string => {
|
|||||||
*/
|
*/
|
||||||
export const createSubtitleBlobURL = (content: string, format: 'vtt' | 'srt'): string => {
|
export const createSubtitleBlobURL = (content: string, format: 'vtt' | 'srt'): string => {
|
||||||
const vttContent = format === 'srt' ? parseSRT(content) : content
|
const vttContent = format === 'srt' ? parseSRT(content) : content
|
||||||
const blob = new Blob([vttContent], { type: 'text/vtt' })
|
const blob = new Blob([vttContent], { type: 'text/vtt;charset=utf-8' })
|
||||||
return URL.createObjectURL(blob)
|
return URL.createObjectURL(blob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user