mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Add setting for subtitle outline size (#375)
Adds a settings allowing for adjusting the thickness of unstyled subtitle outlines, if outline is enabled. This is applied for both ExoPlayer & MPV Closes #179  Dev note: the ExoPlayer implementation is bad code, don't write code like this. It works though
This commit is contained in:
parent
a197f6911b
commit
ac10517028
9 changed files with 116 additions and 0 deletions
|
|
@ -170,4 +170,5 @@ fun SubtitlePreferences.Builder.resetSubtitles() {
|
||||||
backgroundOpacity = SubtitleSettings.BackgroundOpacity.defaultValue.toInt()
|
backgroundOpacity = SubtitleSettings.BackgroundOpacity.defaultValue.toInt()
|
||||||
backgroundStyle = SubtitleSettings.BackgroundStylePref.defaultValue
|
backgroundStyle = SubtitleSettings.BackgroundStylePref.defaultValue
|
||||||
margin = SubtitleSettings.Margin.defaultValue.toInt()
|
margin = SubtitleSettings.Margin.defaultValue.toInt()
|
||||||
|
edgeThickness = SubtitleSettings.EdgeThickness.defaultValue.toInt()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -163,4 +163,14 @@ suspend fun upgradeApp(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (previous.isEqualOrBefore(Version.fromString("0.3.5-0-g0"))) {
|
||||||
|
appPreferences.updateData {
|
||||||
|
it.updateSubtitlePreferences {
|
||||||
|
if (edgeThickness < 1) {
|
||||||
|
edgeThickness = SubtitleSettings.EdgeThickness.defaultValue.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,14 @@ import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.applyToMpv
|
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.applyToMpv
|
||||||
|
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.calculateEdgeSize
|
||||||
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.toSubtitleStyle
|
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.toSubtitleStyle
|
||||||
import com.github.damontecres.wholphin.ui.seasonEpisode
|
import com.github.damontecres.wholphin.ui.seasonEpisode
|
||||||
import com.github.damontecres.wholphin.ui.skipStringRes
|
import com.github.damontecres.wholphin.ui.skipStringRes
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
import com.github.damontecres.wholphin.util.LoadingState
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
|
import com.github.damontecres.wholphin.util.Media3SubtitleOverride
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -329,6 +331,10 @@ fun PlaybackPage(
|
||||||
},
|
},
|
||||||
update = {
|
update = {
|
||||||
it.setCues(cues)
|
it.setCues(cues)
|
||||||
|
Media3SubtitleOverride(
|
||||||
|
preferences.appPreferences.interfacePreferences.subtitlesPreferences
|
||||||
|
.calculateEdgeSize(density),
|
||||||
|
).apply(it)
|
||||||
},
|
},
|
||||||
onReset = {
|
onReset = {
|
||||||
it.setCues(null)
|
it.setCues(null)
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,23 @@ object SubtitleSettings {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val EdgeThickness =
|
||||||
|
AppSliderPreference<AppPreferences>(
|
||||||
|
title = R.string.edge_size,
|
||||||
|
defaultValue = 4,
|
||||||
|
min = 1,
|
||||||
|
max = 32,
|
||||||
|
interval = 1,
|
||||||
|
getter = {
|
||||||
|
it.interfacePreferences.subtitlesPreferences.edgeThickness
|
||||||
|
.toLong()
|
||||||
|
},
|
||||||
|
setter = { prefs, value ->
|
||||||
|
prefs.updateSubtitlePreferences { edgeThickness = value.toInt() }
|
||||||
|
},
|
||||||
|
summarizer = { value -> value?.let { "${it / 2.0}" } },
|
||||||
|
)
|
||||||
|
|
||||||
val BackgroundColor =
|
val BackgroundColor =
|
||||||
AppChoicePreference<AppPreferences, Color>(
|
AppChoicePreference<AppPreferences, Color>(
|
||||||
title = R.string.background_color,
|
title = R.string.background_color,
|
||||||
|
|
@ -230,6 +247,7 @@ object SubtitleSettings {
|
||||||
listOf(
|
listOf(
|
||||||
EdgeStylePref,
|
EdgeStylePref,
|
||||||
EdgeColor,
|
EdgeColor,
|
||||||
|
EdgeThickness,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PreferenceGroup(
|
PreferenceGroup(
|
||||||
|
|
@ -278,6 +296,8 @@ object SubtitleSettings {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun SubtitlePreferences.calculateEdgeSize(density: Density): Float = with(density) { (edgeThickness / 2f).dp.toPx() }
|
||||||
|
|
||||||
fun SubtitlePreferences.applyToMpv(
|
fun SubtitlePreferences.applyToMpv(
|
||||||
configuration: Configuration,
|
configuration: Configuration,
|
||||||
density: Density,
|
density: Density,
|
||||||
|
|
@ -316,6 +336,8 @@ object SubtitleSettings {
|
||||||
MPVLib.setPropertyDouble("sub-outline-size", 0.0)
|
MPVLib.setPropertyDouble("sub-outline-size", 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val outlineSizePx = calculateEdgeSize(density) * .8
|
||||||
|
MPVLib.setPropertyDouble("sub-outline-size", outlineSizePx)
|
||||||
|
|
||||||
// if (fontBold) {
|
// if (fontBold) {
|
||||||
// MPVLib.setPropertyString("sub-font", "Roboto Bold")
|
// MPVLib.setPropertyString("sub-font", "Roboto Bold")
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
|
@ -32,7 +33,9 @@ import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption
|
import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption
|
||||||
import com.github.damontecres.wholphin.ui.preferences.PreferencesContent
|
import com.github.damontecres.wholphin.ui.preferences.PreferencesContent
|
||||||
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
|
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
|
||||||
|
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.calculateEdgeSize
|
||||||
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.toSubtitleStyle
|
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.toSubtitleStyle
|
||||||
|
import com.github.damontecres.wholphin.util.Media3SubtitleOverride
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -41,6 +44,7 @@ fun SubtitleStylePage(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: PreferencesViewModel = hiltViewModel(),
|
viewModel: PreferencesViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
|
val density = LocalDensity.current
|
||||||
var preferences by remember { mutableStateOf(initialPreferences) }
|
var preferences by remember { mutableStateOf(initialPreferences) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.preferenceDataStore.data.collect {
|
viewModel.preferenceDataStore.data.collect {
|
||||||
|
|
@ -95,6 +99,7 @@ fun SubtitleStylePage(
|
||||||
Cue.Builder().setText(text).build(),
|
Cue.Builder().setText(text).build(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
Media3SubtitleOverride(prefs.calculateEdgeSize(density)).apply(it)
|
||||||
},
|
},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package com.github.damontecres.wholphin.util
|
||||||
|
|
||||||
|
import androidx.media3.ui.SubtitleView
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to override private fields in media3's [SubtitleView]
|
||||||
|
*/
|
||||||
|
class Media3SubtitleOverride(
|
||||||
|
val outlineThicknessPx: Float,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private lateinit var outputField: Field
|
||||||
|
private lateinit var classCanvasSubtitleOutput: Class<*>
|
||||||
|
private lateinit var paintersField: Field
|
||||||
|
private lateinit var classSubtitlePainter: Class<*>
|
||||||
|
private lateinit var outlineWidthField: Field
|
||||||
|
|
||||||
|
var initialized: Boolean
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
try {
|
||||||
|
// This is bad times
|
||||||
|
outputField = SubtitleView::class.java.getDeclaredField("output")
|
||||||
|
classCanvasSubtitleOutput = Class.forName("androidx.media3.ui.CanvasSubtitleOutput")
|
||||||
|
paintersField = classCanvasSubtitleOutput.getDeclaredField("painters")
|
||||||
|
classSubtitlePainter = Class.forName("androidx.media3.ui.SubtitlePainter")
|
||||||
|
outlineWidthField = classSubtitlePainter.getDeclaredField("outlineWidth")
|
||||||
|
outputField.isAccessible = true
|
||||||
|
outlineWidthField.isAccessible = true
|
||||||
|
paintersField.isAccessible = true
|
||||||
|
initialized = true
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.w(ex, "Error initializing")
|
||||||
|
initialized = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apply(subtitleView: SubtitleView) {
|
||||||
|
try {
|
||||||
|
if (initialized) {
|
||||||
|
// Basically hijack the field that controls the subtitle outline size
|
||||||
|
val canvasSubtitleOutput = outputField.get(subtitleView)
|
||||||
|
val painters = paintersField.get(canvasSubtitleOutput) as List<*>
|
||||||
|
painters.forEach { painter ->
|
||||||
|
outlineWidthField.set(painter, outlineThicknessPx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.w(ex, "Failed to apply")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -121,6 +121,7 @@ message SubtitlePreferences{
|
||||||
bool font_bold = 9;
|
bool font_bold = 9;
|
||||||
bool font_italic = 10;
|
bool font_italic = 10;
|
||||||
int32 margin = 11;
|
int32 margin = 11;
|
||||||
|
int32 edge_thickness = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InterfacePreferences {
|
message InterfacePreferences {
|
||||||
|
|
|
||||||
|
|
@ -349,6 +349,7 @@
|
||||||
<string name="image_type">Image type</string>
|
<string name="image_type">Image type</string>
|
||||||
<string name="cast_and_crew"><![CDATA[Cast & Crew]]></string>
|
<string name="cast_and_crew"><![CDATA[Cast & Crew]]></string>
|
||||||
<string name="guest_stars">Guest stars</string>
|
<string name="guest_stars">Guest stars</string>
|
||||||
|
<string name="edge_size">Edge size</string>
|
||||||
|
|
||||||
|
|
||||||
<string-array name="theme_song_volume">
|
<string-array name="theme_song_volume">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.github.damontecres.wholphin.test
|
||||||
|
|
||||||
|
import com.github.damontecres.wholphin.util.Media3SubtitleOverride
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class TestMedia3SubtitleOverride {
|
||||||
|
@Test
|
||||||
|
fun test() {
|
||||||
|
// This tests whether the class and field names exist
|
||||||
|
Media3SubtitleOverride(2f)
|
||||||
|
Assert.assertTrue(Media3SubtitleOverride.Companion.initialized)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue