feat: time offset playback
This commit is contained in:
@@ -94,6 +94,8 @@ export function groupAlignedWordsToLineItems(
|
||||
const original = String(w.word || '')
|
||||
const textNoNewline = original.replace(/\n/g, ' ')
|
||||
const textNoTag = removeTags ? textNoNewline.replace(/^\s*\[[^\]]+\]\s*/i, '') : textNoNewline
|
||||
const next = alignedWords[i + 1] || null
|
||||
const gapToNext = next ? Math.max(0, Number(next.startS || 0) - Number(w.endS || 0)) : 0
|
||||
if (buf.length === 0) start = Number(w.startS || 0)
|
||||
|
||||
if (isSectionTag(textNoNewline)) {
|
||||
@@ -132,10 +134,11 @@ export function groupAlignedWordsToLineItems(
|
||||
buf.push(wordItem)
|
||||
|
||||
const eolByNewline = /\n/.test(original)
|
||||
const eolByPause = gapToNext >= 0.6 // threshold for a logical break
|
||||
const eolByPunct = isSentenceEnd(textNoTag)
|
||||
const isLast = i === alignedWords.length - 1
|
||||
|
||||
if (buf.length && (eolByNewline || eolByPunct || isLast)) {
|
||||
if (buf.length && (eolByNewline || eolByPause || eolByPunct || isLast)) {
|
||||
pushLine(buf, Number(w.endS || 0))
|
||||
buf = []
|
||||
start = null
|
||||
@@ -151,6 +154,7 @@ const alphaWhite = (alpha) => `rgba(255,255,255,${alpha})`
|
||||
export default function KaraokeLyrics({
|
||||
alignedWords = [],
|
||||
currentTimeS = 0,
|
||||
timeOffsetS = 0,
|
||||
showContext = true,
|
||||
removeTags = true,
|
||||
mode = 'focus',
|
||||
@@ -170,17 +174,21 @@ export default function KaraokeLyrics({
|
||||
)
|
||||
|
||||
const activeLines = mode === 'teleprompter' ? teleprompterData : lines
|
||||
const effectiveTimeS = useMemo(
|
||||
() => Math.max(0, Number(currentTimeS || 0) + Number(timeOffsetS || 0)),
|
||||
[currentTimeS, timeOffsetS]
|
||||
)
|
||||
|
||||
const currentLineIdx = useMemo(() => {
|
||||
if (!activeLines || activeLines.length === 0) return -1
|
||||
if (effectiveTimeS <= (activeLines[0]?.startS || 0)) return 0
|
||||
for (let i = 0; i < activeLines.length; i++) {
|
||||
const L = activeLines[i]
|
||||
if (currentTimeS >= (L.startS || 0) && currentTimeS <= (L.endS || 0)) return i
|
||||
if (effectiveTimeS < (L.startS || 0)) return Math.max(0, i - 1)
|
||||
if (effectiveTimeS >= (L.startS || 0) && effectiveTimeS <= (L.endS || 0)) return i
|
||||
}
|
||||
if (currentTimeS > (activeLines[activeLines.length - 1]?.endS || 0))
|
||||
return activeLines.length - 1
|
||||
return -1
|
||||
}, [activeLines, currentTimeS])
|
||||
return activeLines.length - 1
|
||||
}, [activeLines, effectiveTimeS])
|
||||
|
||||
if (!activeLines.length) return null
|
||||
|
||||
@@ -208,8 +216,8 @@ export default function KaraokeLyrics({
|
||||
}}
|
||||
>
|
||||
{activeLines.map((line, idx) => {
|
||||
const isUpcoming = currentTimeS < (line.startS || 0)
|
||||
const isPast = currentTimeS > (line.endS || 0)
|
||||
const isUpcoming = effectiveTimeS < (line.startS || 0)
|
||||
const isPast = effectiveTimeS > (line.endS || 0)
|
||||
const lineKey = `${line.startS}-${idx}`
|
||||
|
||||
if (isUpcoming) {
|
||||
@@ -258,7 +266,7 @@ export default function KaraokeLyrics({
|
||||
>
|
||||
{line.words.map((word, wordIndex) => {
|
||||
const duration = Math.max(0.001, (word.endS || 0) - (word.startS || 0))
|
||||
const progress = clamp01((currentTimeS - (word.startS || 0)) / duration)
|
||||
const progress = clamp01((effectiveTimeS - (word.startS || 0)) / duration)
|
||||
const alpha = inactiveAlpha + (activeAlpha - inactiveAlpha) * progress
|
||||
const text = word.text
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user