mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Add toggles to override direct playback (#24)
Fixes #10
Adds toggles to disable direct play of AC3 audio, ASS subtitles, and PGS
subtitles. Also a toggle to force down mixing audio to stereo.
This copies the behavior from the official client. I'm not sure if there
is a way to determine if direct playing AC3 is possible because it can
depend on devices other than the Android TV device such as a sound bar.
So it's up to the user to toggle off support if necessary.
Attribution: This PR uses on [code from the official
client](c775603df4/app/src/main/java/org/jellyfin/androidtv/util/profile/deviceProfile.kt).
This commit is contained in:
parent
bd4d4d5092
commit
f220aeee44
7 changed files with 190 additions and 10 deletions
|
|
@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation3.runtime.rememberNavBackStack
|
||||
import androidx.tv.material3.ExperimentalTvMaterial3Api
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
|
|
@ -34,9 +35,13 @@ import com.github.damontecres.wholphin.ui.nav.ApplicationContent
|
|||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.nav.NavigationManager
|
||||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||
import com.github.damontecres.wholphin.util.AppUpgradeHandler
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.UpdateChecker
|
||||
import com.github.damontecres.wholphin.util.profile.createDeviceProfile
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.OkHttpClient
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
|
@ -59,10 +64,16 @@ class MainActivity : AppCompatActivity() {
|
|||
@Inject
|
||||
lateinit var updateChecker: UpdateChecker
|
||||
|
||||
@Inject
|
||||
lateinit var appUpgradeHandler: AppUpgradeHandler
|
||||
|
||||
@OptIn(ExperimentalTvMaterial3Api::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
Timber.i("MainActivity.onCreate")
|
||||
lifecycleScope.launch(Dispatchers.IO + ExceptionHandler()) {
|
||||
appUpgradeHandler.run()
|
||||
}
|
||||
setContent {
|
||||
CoilConfig(okHttpClient, false)
|
||||
val appPreferences by userPreferencesDataStore.data.collectAsState(null)
|
||||
|
|
|
|||
|
|
@ -313,6 +313,51 @@ sealed interface AppPreference<T> {
|
|||
},
|
||||
)
|
||||
|
||||
val Ac3Supported =
|
||||
AppSwitchPreference(
|
||||
title = R.string.ac3_supported,
|
||||
defaultValue = true,
|
||||
getter = { it.playbackPreferences.overrides.ac3Supported },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackOverrides { ac3Supported = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
val DownMixStereo =
|
||||
AppSwitchPreference(
|
||||
title = R.string.downmix_stereo,
|
||||
defaultValue = false,
|
||||
getter = { it.playbackPreferences.overrides.downmixStereo },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackOverrides { downmixStereo = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
val DirectPlayAss =
|
||||
AppSwitchPreference(
|
||||
title = R.string.direct_play_ass,
|
||||
defaultValue = true,
|
||||
getter = { it.playbackPreferences.overrides.directPlayAss },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackOverrides { directPlayAss = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
val DirectPlayPgs =
|
||||
AppSwitchPreference(
|
||||
title = R.string.direct_play_pgs,
|
||||
defaultValue = true,
|
||||
getter = { it.playbackPreferences.overrides.directPlayPgs },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackOverrides { directPlayPgs = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
|
||||
val RememberSelectedTab =
|
||||
AppSwitchPreference(
|
||||
title = R.string.remember_selected_tab,
|
||||
|
|
@ -521,6 +566,16 @@ val advancedPreferences =
|
|||
AppPreference.PlaybackDebugInfo,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.playback_overrides,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.DownMixStereo,
|
||||
AppPreference.Ac3Supported,
|
||||
AppPreference.DirectPlayAss,
|
||||
AppPreference.DirectPlayPgs,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.updates,
|
||||
preferences =
|
||||
|
|
|
|||
|
|
@ -42,6 +42,16 @@ class AppPreferencesSerializer
|
|||
skipCommercials = AppPreference.SkipCommercials.defaultValue
|
||||
skipPreviews = AppPreference.SkipPreviews.defaultValue
|
||||
skipRecaps = AppPreference.SkipRecaps.defaultValue
|
||||
|
||||
overrides =
|
||||
PlaybackOverrides
|
||||
.newBuilder()
|
||||
.apply {
|
||||
ac3Supported = AppPreference.Ac3Supported.defaultValue
|
||||
downmixStereo = AppPreference.DownMixStereo.defaultValue
|
||||
directPlayAss = AppPreference.DirectPlayAss.defaultValue
|
||||
directPlayPgs = AppPreference.DirectPlayPgs.defaultValue
|
||||
}.build()
|
||||
}.build()
|
||||
homePagePreferences =
|
||||
HomePagePreferences
|
||||
|
|
@ -81,6 +91,11 @@ inline fun AppPreferences.updatePlaybackPreferences(block: PlaybackPreferences.B
|
|||
playbackPreferences = playbackPreferences.toBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
inline fun AppPreferences.updatePlaybackOverrides(block: PlaybackOverrides.Builder.() -> Unit): AppPreferences =
|
||||
updatePlaybackPreferences {
|
||||
overrides = overrides.toBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
inline fun AppPreferences.updateHomePagePreferences(block: HomePagePreferences.Builder.() -> Unit): AppPreferences =
|
||||
update {
|
||||
homePagePreferences = homePagePreferences.toBuilder().apply(block).build()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
package com.github.damontecres.wholphin.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.core.content.edit
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.github.damontecres.wholphin.WholphinApplication
|
||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.updatePlaybackOverrides
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class AppUpgradeHandler
|
||||
@Inject
|
||||
constructor(
|
||||
@param:ApplicationContext private val context: Context,
|
||||
private val appPreferences: DataStore<AppPreferences>,
|
||||
) {
|
||||
suspend fun run() {
|
||||
val pkgInfo = WholphinApplication.instance.packageManager.getPackageInfo(WholphinApplication.instance.packageName, 0)
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val previousVersion = prefs.getString(VERSION_NAME_CURRENT_KEY, null)
|
||||
val previousVersionCode = prefs.getLong(VERSION_CODE_CURRENT_KEY, -1)
|
||||
|
||||
val newVersion = pkgInfo.versionName!!
|
||||
val newVersionCode =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
pkgInfo.longVersionCode
|
||||
} else {
|
||||
pkgInfo.versionCode.toLong()
|
||||
}
|
||||
if (newVersion != previousVersion || newVersionCode != previousVersionCode) {
|
||||
Timber.i(
|
||||
"App updated: $previousVersion=>$newVersion, $previousVersionCode=>$newVersionCode",
|
||||
)
|
||||
prefs.edit(true) {
|
||||
putString(VERSION_NAME_PREVIOUS_KEY, previousVersion)
|
||||
putLong(VERSION_CODE_PREVIOUS_KEY, previousVersionCode)
|
||||
putString(VERSION_NAME_CURRENT_KEY, newVersion)
|
||||
putLong(VERSION_CODE_CURRENT_KEY, newVersionCode)
|
||||
}
|
||||
try {
|
||||
upgradeApp(
|
||||
context,
|
||||
Version.fromString(previousVersion ?: "0.0.0"),
|
||||
Version.fromString(newVersion),
|
||||
appPreferences,
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Exception during app upgrade")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val VERSION_NAME_PREVIOUS_KEY = "version.previous.name"
|
||||
const val VERSION_CODE_PREVIOUS_KEY = "version.previous.code"
|
||||
const val VERSION_NAME_CURRENT_KEY = "version.current.name"
|
||||
const val VERSION_CODE_CURRENT_KEY = "version.current.code"
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun upgradeApp(
|
||||
context: Context,
|
||||
previous: Version,
|
||||
current: Version,
|
||||
appPreferences: DataStore<AppPreferences>,
|
||||
) {
|
||||
if (previous.isEqualOrBefore(Version.fromString("0.1.0-2-g0"))) {
|
||||
appPreferences.updateData {
|
||||
it.updatePlaybackOverrides {
|
||||
ac3Supported = AppPreference.Ac3Supported.defaultValue
|
||||
downmixStereo = AppPreference.DownMixStereo.defaultValue
|
||||
directPlayAss = AppPreference.DirectPlayAss.defaultValue
|
||||
directPlayPgs = AppPreference.DirectPlayPgs.defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -45,20 +45,21 @@ private val supportedAudioCodecs =
|
|||
Codec.Audio.VORBIS,
|
||||
)
|
||||
|
||||
// TODO use preferences
|
||||
fun createDeviceProfile(
|
||||
context: Context,
|
||||
userPreferences: UserPreferences,
|
||||
disableDirectPlay: Boolean = false,
|
||||
) = createDeviceProfile(
|
||||
) = userPreferences.appPreferences.playbackPreferences.let { prefs ->
|
||||
createDeviceProfile(
|
||||
mediaTest = MediaCodecCapabilitiesTest(context),
|
||||
maxBitrate = 100_000_000,
|
||||
disableDirectPlay = disableDirectPlay,
|
||||
isAC3Enabled = true,
|
||||
downMixAudio = false,
|
||||
assDirectPlay = true,
|
||||
pgsDirectPlay = true,
|
||||
)
|
||||
isAC3Enabled = prefs.overrides.ac3Supported,
|
||||
downMixAudio = prefs.overrides.downmixStereo,
|
||||
assDirectPlay = prefs.overrides.directPlayAss,
|
||||
pgsDirectPlay = prefs.overrides.directPlayPgs,
|
||||
)
|
||||
}
|
||||
|
||||
fun createDeviceProfile(
|
||||
mediaTest: MediaCodecCapabilitiesTest,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,13 @@ enum SkipSegmentBehavior{
|
|||
ASK_TO_SKIP = 2;
|
||||
}
|
||||
|
||||
message PlaybackOverrides{
|
||||
bool ac3_supported = 1;
|
||||
bool downmix_stereo = 2;
|
||||
bool direct_play_ass = 3;
|
||||
bool direct_play_pgs = 4;
|
||||
}
|
||||
|
||||
message PlaybackPreferences {
|
||||
int64 skip_forward_ms = 1;
|
||||
int64 skip_back_ms = 2;
|
||||
|
|
@ -25,6 +32,8 @@ message PlaybackPreferences {
|
|||
SkipSegmentBehavior skip_commercials = 12;
|
||||
SkipSegmentBehavior skip_recaps = 13;
|
||||
SkipSegmentBehavior skip_previews = 14;
|
||||
|
||||
PlaybackOverrides overrides = 15;
|
||||
}
|
||||
|
||||
message HomePagePreferences{
|
||||
|
|
|
|||
|
|
@ -77,5 +77,10 @@
|
|||
<string name="clear_image_cache">Clear image cache</string>
|
||||
<string name="shuffle">Shuffle</string>
|
||||
<string name="combine_continue_next"><![CDATA[Combine Continue Watching & Next Up]]></string>
|
||||
<string name="ac3_supported">Device supports AC3/Dolby Digital</string>
|
||||
<string name="downmix_stereo">Always downmix to stereo</string>
|
||||
<string name="playback_overrides">Playback overrides</string>
|
||||
<string name="direct_play_ass">Direct play ASS subtitles</string>
|
||||
<string name="direct_play_pgs">Direct play PGS subtitles</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue