diff --git a/CHANGELOG.md b/CHANGELOG.md
index cbb8bdee65..c3ac2e9a5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- `Other` - for technical stuff.
## [Unreleased]
+### Added
+- Added system font fallback ([@Secozzi](https://github.com/Secozzi)) ([#156](https://github.com/quickdesh/Animiru/pull/156))
## [v0.19.7.3] - 2026-04-17
### Improved
diff --git a/app/src/main/java/animiru/feature/mpvfiles/MpvConfig.kt b/app/src/main/java/animiru/feature/mpvfiles/MpvConfig.kt
index 2c79b0aed9..e0bba787c2 100644
--- a/app/src/main/java/animiru/feature/mpvfiles/MpvConfig.kt
+++ b/app/src/main/java/animiru/feature/mpvfiles/MpvConfig.kt
@@ -37,6 +37,7 @@ class MpvConfig(
copyUserFiles(mpvDir)
copyFontsDirectory(mpvDir)
copyAssets(mpvDir)
+ writeFontsConf(context, mpvDir)
}
}
@@ -116,7 +117,7 @@ class MpvConfig(
private fun copyAssets(mpvDir: UniFile) {
val assetManager = context.assets
- val files = arrayOf("subfont.ttf", "cacert.pem")
+ val files = arrayOf("cacert.pem")
for (filename in files) {
var ins: InputStream? = null
var out: OutputStream? = null
@@ -141,6 +142,43 @@ class MpvConfig(
}
}
+ private fun writeFontsConf(context: Context, mpvDir: UniFile) {
+ val parts = mutableListOf(
+ "",
+ // Android system fonts reside here
+ "/system/fonts/",
+ "/product/fonts/",
+ // User provided fonts
+ "${mpvDir.createDirectory(MPV_FONTS_DIR)!!.filePath!!}",
+ // Point fontconfig to the right cache path so that caching works
+ "${context.cacheDir.path}",
+ // Conveniently there is *no* Java API to query the system default fonts, but we can
+ // manually specify the font families we know Android uses and provides by default.
+ // (compare to 60-latin.conf shipped with fontconfig)
+ "serif",
+ "Noto Serif",
+ "",
+ "Sans Serif",
+ "",
+ "Roboto",
+ "Noto Sans", // other languages
+ "",
+ "",
+ "monospace",
+ "Droid Sans Mono",
+ "",
+ "",
+ )
+ try {
+ val file = mpvDir.createFile("fonts.conf")
+ file?.openOutputStream()?.bufferedWriter()?.use {
+ it.write(parts.joinToString("\n"))
+ }
+ } catch (e: IOException) {
+ logcat(LogPriority.ERROR, e) { "Failed to write fonts.conf" }
+ }
+ }
+
private fun deleteAndGet(parent: UniFile, name: String): UniFile {
parent.createDirectory(name)?.delete()
return parent.createDirectory(name)!!
diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/player/PlayerSettingsSubtitleScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/player/PlayerSettingsSubtitleScreen.kt
index 038a14220d..aa37e4ee70 100644
--- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/player/PlayerSettingsSubtitleScreen.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/player/PlayerSettingsSubtitleScreen.kt
@@ -28,6 +28,7 @@ object PlayerSettingsSubtitleScreen : SearchableSettings {
val whitelist = subtitlePreferences.subtitleWhitelist
val blacklist = subtitlePreferences.subtitleBlacklist
val blackBars = subtitlePreferences.subtitleBlackBars
+ val systemFonts = subtitlePreferences.subtitleSystemFonts
return listOf(
Preference.PreferenceItem.EditTextInfoPreference(
@@ -86,6 +87,10 @@ object PlayerSettingsSubtitleScreen : SearchableSettings {
title = stringResource(AMMR.strings.player_pref_subtitle_black_bars),
subtitle = stringResource(AMMR.strings.player_pref_subtitle_black_bars_summary),
),
+ Preference.PreferenceItem.SwitchPreference(
+ preference = systemFonts,
+ title = stringResource(AMMR.strings.player_pref_subtitle_system_fonts),
+ ),
)
}
}
diff --git a/app/src/main/java/eu/kanade/presentation/player/components/ExposedTextDropDownMenu.kt b/app/src/main/java/eu/kanade/presentation/player/components/ExposedTextDropDownMenu.kt
index 433d128119..2f82c01db2 100644
--- a/app/src/main/java/eu/kanade/presentation/player/components/ExposedTextDropDownMenu.kt
+++ b/app/src/main/java/eu/kanade/presentation/player/components/ExposedTextDropDownMenu.kt
@@ -18,6 +18,10 @@
package eu.kanade.presentation.player.components
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
@@ -31,6 +35,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalWindowInfo
+import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableList
@Composable
@@ -64,15 +71,32 @@ fun ExposedTextDropDownMenu(
.fillMaxWidth(),
)
+ val sizeOfOneItem by remember {
+ mutableStateOf(50.dp)
+ }
+ val screenHeight = with(LocalDensity.current) {
+ LocalWindowInfo.current.containerSize.height.toDp()
+ }
+ val height by remember(options.size) {
+ val itemsSize = sizeOfOneItem * options.size
+ mutableStateOf(minOf(itemsSize, screenHeight * 3 / 4))
+ }
+
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
- options.forEach { option: String ->
- DropdownMenuItem(
- text = { Text(text = option) },
- onClick = {
- expanded = false
- onValueChangedEvent(option)
- },
- )
+ LazyColumn(
+ modifier = Modifier
+ .width(500.dp)
+ .height(height),
+ ) {
+ items(options) { option ->
+ DropdownMenuItem(
+ text = { Text(text = option) },
+ onClick = {
+ expanded = false
+ onValueChangedEvent(option)
+ },
+ )
+ }
}
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt
index 387616569a..0decf7371e 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt
@@ -450,7 +450,6 @@ class PlayerActivity : BaseActivity() {
private fun setupPlayerMPV() {
val mpvDir = UniFile.fromFile(applicationContext.filesDir)!!.createDirectory(MPV_DIR)!!
- val fontsDirectory = mpvDir.createDirectory(MPV_FONTS_DIR)!!
val mpvConfFile = mpvDir.createFile("mpv.conf")!!
advancedPlayerPreferences.mpvConf.get().let { mpvConfFile.writeText(it) }
@@ -459,8 +458,6 @@ class PlayerActivity : BaseActivity() {
player.init(mpv)
- mpv.setPropertyString("sub-fonts-dir", fontsDirectory.filePath!!)
- mpv.setPropertyString("osd-fonts-dir", fontsDirectory.filePath!!)
val showBlackBars = if (subtitlePreferences.subtitleBlackBars.get()) "yes" else "no"
mpv.setOptionString("sub-ass-force-margins", showBlackBars)
mpv.setOptionString("sub-use-margins", showBlackBars)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt
index dfe6e29ef4..c221842c1a 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt
@@ -27,6 +27,7 @@ import android.net.Uri
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
+import com.yubyf.truetypeparser.TTFFile
import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.anime.interactor.SetAnimeViewerFlags
import eu.kanade.domain.base.BasePreferences
@@ -67,6 +68,7 @@ import eu.kanade.tachiyomi.ui.player.loader.HosterLoader
import eu.kanade.tachiyomi.ui.player.settings.AudioPreferences
import eu.kanade.tachiyomi.ui.player.settings.GesturePreferences
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
+import eu.kanade.tachiyomi.ui.player.settings.SubtitlePreferences
import eu.kanade.tachiyomi.ui.player.utils.AniSkipApi
import eu.kanade.tachiyomi.ui.player.utils.ChapterUtils
import eu.kanade.tachiyomi.ui.player.utils.ChapterUtils.Companion.getStringRes
@@ -93,6 +95,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
@@ -124,6 +127,7 @@ import tachiyomi.domain.history.interactor.UpsertHistory
import tachiyomi.domain.history.model.HistoryUpdate
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.source.service.SourceManager
+import tachiyomi.domain.storage.service.StorageManager
import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.i18n.aniyomi.AYMR
import tachiyomi.source.local.isLocal
@@ -133,6 +137,7 @@ import java.io.File
import java.io.InputStream
import java.util.Date
import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.collections.first
import kotlin.coroutines.cancellation.CancellationException
class PlayerViewModel @JvmOverloads constructor(
@@ -141,6 +146,7 @@ class PlayerViewModel @JvmOverloads constructor(
private val json: Json = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(),
private val downloadManager: DownloadManager = Injekt.get(),
+ private val storageManager: StorageManager = Injekt.get(),
private val imageSaver: ImageSaver = Injekt.get(),
private val downloadPreferences: DownloadPreferences = Injekt.get(),
private val trackPreferences: TrackPreferences = Injekt.get(),
@@ -155,6 +161,7 @@ class PlayerViewModel @JvmOverloads constructor(
private val setAnimeViewerFlags: SetAnimeViewerFlags = Injekt.get(),
private val playerPreferences: PlayerPreferences = Injekt.get(),
private val audioPreferences: AudioPreferences = Injekt.get(),
+ private val subtitlePreferences: SubtitlePreferences = Injekt.get(),
private val gesturePreferences: GesturePreferences = Injekt.get(),
private val basePreferences: BasePreferences = Injekt.get(),
private val getCustomButtons: GetCustomButtons = Injekt.get(),
@@ -311,7 +318,16 @@ class PlayerViewModel @JvmOverloads constructor(
private val _remainingTime = MutableStateFlow(0)
val remainingTime = _remainingTime.asStateFlow()
+ private val _fontList = MutableStateFlow>(persistentListOf())
+ val fontList = _fontList.asStateFlow()
+
init {
+ viewModelScope.launchIO {
+ subtitlePreferences.subtitleSystemFonts.changes().collectLatest {
+ _fontList.update { _ -> fetchFonts(it).toPersistentList() }
+ }
+ }
+
mpv.propFlow("time-pos")
.filterNotNull()
.onEach(::onSecondReached)
@@ -357,6 +373,49 @@ class PlayerViewModel @JvmOverloads constructor(
}
}
+ fun fetchFonts(includeSystemFonts: Boolean): List {
+ val fontFiles = mutableListOf()
+
+ storageManager.getFontsDirectory()?.listFiles()?.filter { file ->
+ file.name?.lowercase()?.matches(FONT_EXTENSION_REGEX) == true
+ }?.mapNotNull {
+ try {
+ TTFFile.open(it.openInputStream()).families.values.first()
+ } catch (_: Exception) {
+ null
+ }
+ }?.let {
+ fontFiles.addAll(it)
+ }
+
+ if (!includeSystemFonts) {
+ return fontFiles.distinct()
+ }
+
+ val fontDirectories = listOf(
+ "/system/fonts/",
+ "/product/fonts/",
+ )
+
+ for (directory in fontDirectories) {
+ val dir = File(directory)
+ if (dir.exists() && dir.isDirectory) {
+ val files = dir.listFiles()
+ files?.filter { file ->
+ file.isFile && file.name.lowercase().matches(FONT_EXTENSION_REGEX)
+ }?.forEach { file ->
+ try {
+ fontFiles.add(
+ TTFFile.open(file.inputStream()).families.values.first(),
+ )
+ } catch (_: Exception) { }
+ }
+ }
+ }
+
+ return fontFiles.distinct()
+ }
+
private fun setCustomButtons(buttons: List) {
_customButtons.update { _ -> buttons.toPersistentList() }
buttons.firstOrNull { it.isFavorite }?.let {
@@ -2155,6 +2214,8 @@ class PlayerViewModel @JvmOverloads constructor(
}
}
+private val FONT_EXTENSION_REGEX = Regex($$""".*\.[ot]tf$""")
+
fun CustomButton.execute(mpv: MPV) {
mpv.command("script-message", "call_button_$id")
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerControls.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerControls.kt
index d241d7f126..a2fe579a5b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerControls.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerControls.kt
@@ -711,6 +711,7 @@ fun PlayerControls(
val isItalic by viewModel.mpv.propFlow("sub-italic").collectAsState()
val subJustify by viewModel.mpv.propFlow("sub-justify").collectAsState()
val subFont by viewModel.mpv.propFlow("sub-font").collectAsState()
+ val subFontList by viewModel.fontList.collectAsState()
val subFontSize by viewModel.mpv.propFlow("sub-font-size").collectAsState()
val subBorderStyle by viewModel.mpv.propFlow("sub-border-style").collectAsState()
val subBorderSize by viewModel.mpv.propFlow("sub-outline-size").collectAsState()
@@ -741,6 +742,7 @@ fun PlayerControls(
subJustify?.let { SubtitleJustification.byValue(it) }
?: subtitlePreferences.subtitleJustification.get(),
subFont = subFont ?: subtitlePreferences.subtitleFont.get(),
+ subFontList = subFontList,
subFontSize = subFontSize ?: subtitlePreferences.subtitleFontSize.get(),
subBorderStyle = subBorderStyle?.let { SubtitlesBorderStyle.byValue(it) }
?: subtitlePreferences.borderStyleSubtitles.get(),
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerPanels.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerPanels.kt
index 5ff6751895..9c1fad4230 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerPanels.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/PlayerPanels.kt
@@ -46,6 +46,7 @@ import eu.kanade.tachiyomi.ui.player.controls.components.panels.VideoSettingsPan
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
import eu.kanade.tachiyomi.ui.player.settings.SubtitleAssOverride
import eu.kanade.tachiyomi.ui.player.settings.SubtitleJustification
+import kotlinx.collections.immutable.ImmutableList
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@@ -58,6 +59,7 @@ fun PlayerPanels(
isItalic: Boolean,
subJustify: SubtitleJustification,
subFont: String,
+ subFontList: ImmutableList,
subFontSize: Int,
subBorderStyle: SubtitlesBorderStyle,
subBorderSize: Int,
@@ -129,6 +131,7 @@ fun PlayerPanels(
isItalic = isItalic,
justify = subJustify,
font = subFont,
+ fontList = subFontList,
fontSize = subFontSize,
borderStyle = subBorderStyle,
borderSize = subBorderSize,
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsPanel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsPanel.kt
index 6f0c466557..a01de7625a 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsPanel.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsPanel.kt
@@ -22,6 +22,7 @@ import androidx.compose.ui.Modifier
import eu.kanade.tachiyomi.ui.player.controls.components.panels.components.MultiCardPanel
import eu.kanade.tachiyomi.ui.player.settings.SubtitleAssOverride
import eu.kanade.tachiyomi.ui.player.settings.SubtitleJustification
+import kotlinx.collections.immutable.ImmutableList
import tachiyomi.i18n.aniyomi.AYMR
import tachiyomi.presentation.core.i18n.stringResource
@@ -33,6 +34,7 @@ fun SubtitleSettingsPanel(
isItalic: Boolean,
justify: SubtitleJustification,
font: String,
+ fontList: ImmutableList,
fontSize: Int,
borderStyle: SubtitlesBorderStyle,
borderSize: Int,
@@ -74,6 +76,7 @@ fun SubtitleSettingsPanel(
isItalic = isItalic,
justify = justify,
font = font,
+ fontList = fontList,
fontSize = fontSize,
borderStyle = borderStyle,
borderSize = borderSize,
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt
index 5aa4f9a499..34e349d3b0 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt
@@ -46,7 +46,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -55,7 +54,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
-import com.yubyf.truetypeparser.TTFFile
import dev.icerock.moko.resources.StringResource
import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.presentation.player.components.ExpandableCard
@@ -67,17 +65,12 @@ import eu.kanade.tachiyomi.ui.player.controls.panelCardsColors
import eu.kanade.tachiyomi.ui.player.settings.SubtitleJustification
import eu.kanade.tachiyomi.ui.player.settings.SubtitlePreferences
import `is`.xyz.mpv.MPV
-import kotlinx.collections.immutable.toImmutableList
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
+import kotlinx.collections.immutable.ImmutableList
import tachiyomi.core.common.preference.deleteAndGet
-import tachiyomi.domain.storage.service.StorageManager
import tachiyomi.i18n.MR
import tachiyomi.i18n.aniyomi.AYMR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
@Composable
fun SubtitleSettingsTypographyCard(
@@ -85,6 +78,7 @@ fun SubtitleSettingsTypographyCard(
isItalic: Boolean,
justify: SubtitleJustification,
font: String,
+ fontList: ImmutableList,
fontSize: Int,
borderStyle: SubtitlesBorderStyle,
borderSize: Int,
@@ -100,36 +94,14 @@ fun SubtitleSettingsTypographyCard(
onReset: () -> Unit,
modifier: Modifier = Modifier,
) {
- val preferences = remember { Injekt.get() }
- val storageManager = remember { Injekt.get() }
var isExpanded by remember { mutableStateOf(true) }
- val fontsDir = storageManager.getFontsDirectory()
- val fonts by remember { mutableStateOf(mutableListOf(preferences.subtitleFont.defaultValue())) }
var fontsLoadingIndicator: (@Composable () -> Unit)? by remember {
val indicator: (@Composable () -> Unit) = {
CircularProgressIndicator(Modifier.size(32.dp))
}
mutableStateOf(indicator)
}
- LaunchedEffect(Unit) {
- if (fontsDir == null) {
- fontsLoadingIndicator = null
- return@LaunchedEffect
- }
- withContext(Dispatchers.IO) {
- fontsDir.listFiles()?.filter { file ->
- file.name?.lowercase()?.matches(FONT_EXTENSION_REGEX) == true
- }?.mapNotNull {
- runCatching { TTFFile.open(it.openInputStream()).families.values.first() }.getOrNull()
- }?.let {
- fonts.addAll(
- it.distinct(),
- )
- }
- fontsLoadingIndicator = null
- }
- }
ExpandableCard(
isExpanded = isExpanded,
@@ -204,10 +176,10 @@ fun SubtitleSettingsTypographyCard(
)
ExposedTextDropDownMenu(
selectedValue = font,
- options = fonts.toImmutableList(),
+ options = fontList,
label = stringResource(AYMR.strings.player_sheets_sub_typography_font),
onValueChangedEvent = onFontChange,
- leadingIcon = fontsLoadingIndicator,
+ leadingIcon = if (fontList.isEmpty()) fontsLoadingIndicator else null,
)
}
SliderItem(
@@ -287,8 +259,6 @@ fun SubtitleSettingsTypographyCard(
}
}
-private val FONT_EXTENSION_REGEX = Regex($$""".*\.[ot]tf$""")
-
fun resetTypography(
mpv: MPV,
preferences: SubtitlePreferences,
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/SubtitlePreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/SubtitlePreferences.kt
index d3d9511f5e..4cfe30f7c2 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/SubtitlePreferences.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/SubtitlePreferences.kt
@@ -22,6 +22,7 @@ class SubtitlePreferences(
val subtitleWhitelist: Preference = preferenceStore.getString("pref_subtitle_whitelist", "")
val subtitleBlacklist: Preference = preferenceStore.getString("pref_subtitle_blacklist", "")
val subtitleBlackBars: Preference = preferenceStore.getBoolean("pref_subtitle_black_bars", false)
+ val subtitleSystemFonts: Preference = preferenceStore.getBoolean("pref_subtitle_system_fonts", false)
// Non-preferences
diff --git a/gradle/aniyomi.versions.toml b/gradle/aniyomi.versions.toml
index 9758a36446..de6f0f26ac 100644
--- a/gradle/aniyomi.versions.toml
+++ b/gradle/aniyomi.versions.toml
@@ -1,5 +1,5 @@
[versions]
-mpv-lib = "0.1.13"
+mpv-lib = "0.1.14"
arthenica-smartexceptions = "0.2.1"
constraint-layout = "1.1.0"
ffmpeg-kit = "1.18"
diff --git a/i18n-animiru/src/commonMain/moko-resources/base/strings.xml b/i18n-animiru/src/commonMain/moko-resources/base/strings.xml
index 9f6735b7aa..c5afaf652c 100644
--- a/i18n-animiru/src/commonMain/moko-resources/base/strings.xml
+++ b/i18n-animiru/src/commonMain/moko-resources/base/strings.xml
@@ -208,6 +208,7 @@
Render on black bars
Display subtitles on black bars when available
+ Include system fonts
Video settings