@@ -629,7 +629,6 @@ fun parseLrc(lyricText: String, trimEnabled: Boolean, multiLineEnabled: Boolean)
629629 // it's an explicit line end ts, so use it. otherwise, use the last word's sync
630630 // point as end time. otherwise we will fill it later based on next (temporal,
631631 // not file order) line.
632- // TODO(ASAP): but, do we REALLY want to use that estimation? not next line start?
633632 val lastWordSyncForEnd = lastWordSyncPoint?.let { it - 1uL }
634633 val lastWordBegin = words?.lastOrNull()?.begin
635634 val end = if (lastWordSyncForEnd != null && lastWordBegin != null &&
@@ -899,23 +898,12 @@ fun UsltFrameDecoder.Result.Sylt.toSyncedLyrics(trimEnabled: Boolean): SyncedLyr
899898 // If we have a next word (with sync point), use its sync
900899 // point minus 1ms as end point of this word
901900 next.timestamp - 1uL
902- } else {
903- // Estimate how long this word will take based on character
904- // to time ratio. To avoid this estimation, add a last word
905- // sync point to the line after the text :)
906- it.timestamp + (wout.map {
907- it.timeRange.count() /
908- it.charRange.count().toFloat()
909- }.average().let {
910- if (it.isNaN()) 100.0 else it
911- } *
912- textWithoutWhitespaces.length).toULong()
913- }
914- if (endInclusive > it.timestamp)
901+ } else null
902+ if (endInclusive == null || endInclusive > it.timestamp)
915903 // isRtl is filled in later in splitBidirectionalWords
916904 wout.add(
917905 Word (
918- it.timestamp.toULong().. endInclusive,
906+ it.timestamp.toULong(), endInclusive,
919907 startIndex.. < endIndex,
920908 isRtl = false
921909 )
@@ -959,10 +947,9 @@ fun UsltFrameDecoder.Result.Sylt.toSyncedLyrics(trimEnabled: Boolean): SyncedLyr
959947 // if we had trailing sync point only with new line, it's explicit line end ts, use it.
960948 // if we have >1 segment, use it's last sync point (possibly estimated) as end time,
961949 // otherwise we will fill it later based on next line.
962- // TODO(ASAP): but, do we REALLY want to use that estimation? not next line start?
963950 val explicitEnd = if (i < j - 1 && text[j - 1 ].text.isBlank())
964951 text[j - 1 ].timestamp.toULong() - 1uL
965- else if (wout.size > 1 ) wout.last().timeRange.last else null
952+ else if (wout.size > 1 ) wout.last().endInclusive else null
966953 out .add(
967954 LyricLine (
968955 string, text[i].timestamp.toULong(), explicitEnd ? : 0uL
@@ -978,13 +965,30 @@ fun UsltFrameDecoder.Result.Sylt.toSyncedLyrics(trimEnabled: Boolean): SyncedLyr
978965 out .forEach { lyric ->
979966 val mainEnd = if (lyric.start == previousTimestamp) out .firstOrNull {
980967 it.start == lyric.start && ! it.endIsImplicit }?.end else null
968+ val wordWithoutEnd = lyric.words?.lastOrNull()
969+ if (wordWithoutEnd != null && wordWithoutEnd.endInclusive == null ) {
970+ wordWithoutEnd.endInclusive = mainEnd?.takeIf { it > wordWithoutEnd.begin }
971+ ? : out .find { it.start > lyric.start }?.start?.minus(1uL )
972+ ?.takeIf { it > wordWithoutEnd.begin }
973+ ? : run {
974+ // Estimate how long this word will take based on character
975+ // to time ratio. To avoid this estimation, add a last word
976+ // sync point to the line after the text :)
977+ wordWithoutEnd.begin + (lyric.words.subList(0 , lyric.words.size - 1 )
978+ .map { it.timeRange.count() / it.charRange.count().toFloat() }
979+ .average().let { if (it.isNaN()) 100.0 else it } *
980+ lyric.text.substring(wordWithoutEnd.charRange).length).toULong()
981+ }
982+ }
981983 if (lyric.endIsImplicit) {
982984 if (mainEnd != null ) {
983985 lyric.end = mainEnd
984986 lyric.endIsImplicit = false
985987 } else {
986- lyric.end = out .find { it.start > lyric.start }?.start?.minus(1uL )
987- ? : Long .MAX_VALUE .toULong()
988+ lyric.end = wordWithoutEnd?.endInclusive
989+ ? : out .find { it.start > lyric.start }?.start?.minus(1uL )
990+ ? : Long .MAX_VALUE .toULong()
991+ lyric.endIsImplicit = wordWithoutEnd == null // TODO: should this just stay true?
988992 }
989993 }
990994 lyric.isTranslated = lyric.start == previousTimestamp
0 commit comments