new: add subtitle translations

This commit is contained in:
2026-06-22 19:25:05 +02:00
parent feb3896727
commit ec9f927157
10 changed files with 129 additions and 28 deletions
@@ -12,14 +12,30 @@ internal class LrcSubtitleRepository(
private val dispatcherProvider: DispatcherProvider,
private val logger: Logger,
) : SubtitleRepository {
override suspend fun getSubtitle(content: String): Subtitle =
override suspend fun getSubtitle(
content: String,
translationContent: String?,
): Subtitle =
withContext(dispatcherProvider.default) {
try {
parser.parse(content = content)
val subtitle = parser.parse(content = content)
val translation = translationContent?.let { parser.parse(content = it) }
subtitle.mergeTranslation(translation)
} catch (exception: Exception) {
val message = "Failed to load subtitle: $content"
logger.error(message = message, throwable = exception)
throw CantGetSubtitleException(message)
}
}
/** Attaches each [translation] line's text to the matching original line, paired by timestamp. */
private fun Subtitle.mergeTranslation(translation: Subtitle?): Subtitle {
if (translation == null) return this
val translationByStart = translation.lines.associate { it.startMs to it.text }
return Subtitle(
lines = lines.map { line ->
line.copy(translation = translationByStart[line.startMs])
},
)
}
}
@@ -1,7 +1,11 @@
package fr.ajaury.gwenedeg.subtitle.domain
/** A single timed subtitle cue: [text] becomes active at [startMs]. */
/**
* A single timed subtitle cue: [text] becomes active at [startMs]. [translation] is the optional
* translation of [text] in the user's language (e.g. French), shown alongside the original.
*/
data class SubtitleLine(
val startMs: Long,
val text: String,
val translation: String? = null,
)
@@ -1,5 +1,12 @@
package fr.ajaury.gwenedeg.subtitle.domain
interface SubtitleRepository {
suspend fun getSubtitle(content: String): Subtitle
/**
* Parses the subtitle [content]. When [translationContent] is provided, each line is matched to
* its translation by timestamp.
*/
suspend fun getSubtitle(
content: String,
translationContent: String? = null,
): Subtitle
}