fix: resolve Jellyfin, logout, playback, and Android regressions

This commit is contained in:
edde746
2026-07-09 17:14:45 +02:00
parent a4a2942546
commit 5867809560
22 changed files with 243 additions and 166 deletions
@@ -89,7 +89,6 @@ class MainActivity : FlutterActivity() {
private val DEVICE_ADJUSTMENT_CHANNEL = "com.plezy/device_adjustment"
private val TEXT_INPUT_CHANNEL = "com.plezy/text_input"
private val APP_EXIT_CHANNEL = "com.plezy/app_exit"
private val APP_FOREGROUND_CHANNEL = "com.plezy/app_foreground"
private var watchNextPlugin: WatchNextPlugin? = null
private var nativeTextInputFocused = false
private var pendingExternalPlayerResult: MethodChannel.Result? = null
@@ -532,13 +531,6 @@ class MainActivity : FlutterActivity() {
}
}
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, APP_FOREGROUND_CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
"requestForeground" -> result.success(requestForeground())
else -> result.notImplemented()
}
}
// External player: open local video files with proper content:// URIs
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, EXTERNAL_PLAYER_CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
@@ -723,31 +715,6 @@ class MainActivity : FlutterActivity() {
}
}
private fun requestForeground(): Boolean = try {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
activityManager.moveTaskToFront(taskId, 0)
true
} catch (e: Exception) {
Log.w(TAG, "Failed to move task to foreground", e)
try {
val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
if (launchIntent != null) {
startActivity(launchIntent)
true
} else {
false
}
} catch (launchError: Exception) {
Log.w(TAG, "Failed to start foreground activity", launchError)
false
}
}
private fun handleDeviceAdjustmentCall(method: String, arguments: Any?, result: MethodChannel.Result) {
try {
when (method) {
@@ -84,6 +84,7 @@ interface ExoPlayerDelegate : com.edde746.plezy.shared.PlayerDelegate {
uri: String,
headers: Map<String, String>?,
positionMs: Long,
playWhenReady: Boolean,
errorMessage: String
): Boolean = false
}
@@ -1110,6 +1111,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
uri = currentMediaUri!!,
headers = currentHeaders,
positionMs = effectivePosition,
playWhenReady = exoPlayer?.playWhenReady ?: true,
errorMessage = "Video track present but no decoder available"
)
return
@@ -1217,6 +1219,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
uri = currentMediaUri!!,
headers = currentHeaders,
positionMs = effectivePosition,
playWhenReady = exoPlayer?.playWhenReady ?: true,
errorMessage = error.message ?: "Unknown error"
) ?: false
@@ -2650,6 +2653,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
uri = uri,
headers = currentHeaders,
positionMs = effectivePosition,
playWhenReady = player.playWhenReady,
errorMessage = "Decoder hang: $decoderName accepted input but produced no output"
)
}
@@ -2700,6 +2704,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
uri = uri,
headers = currentHeaders,
positionMs = player.currentPosition,
playWhenReady = player.playWhenReady,
errorMessage = "Video track present but no decoder available"
)
return
@@ -2715,6 +2720,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
uri = uri,
headers = currentHeaders,
positionMs = player.currentPosition,
playWhenReady = player.playWhenReady,
errorMessage = "Black screen detected: 0 video frames rendered after ${elapsed}ms"
)
return
@@ -3722,8 +3728,9 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
fun triggerFallback() {
val uri = currentMediaUri ?: return
val pos = exoPlayer?.currentPosition ?: 0L
delegate?.onFormatUnsupported(uri, currentHeaders, pos, "debug: manual fallback trigger")
val player = exoPlayer
val pos = player?.currentPosition ?: 0L
delegate?.onFormatUnsupported(uri, currentHeaders, pos, player?.playWhenReady ?: true, "debug: manual fallback trigger")
}
// Cleanup
@@ -302,9 +302,7 @@ class ExoPlayerPlugin :
options.add("sid=no")
options.add("secondary-sid=no")
appendExternalSubtitleOptions(options, externalSubtitleSnapshot)
headers?.forEach { (key, value) ->
options.add("http-header-fields-append=$key: $value")
}
appendHttpHeaderOptions(options, headers)
val optionsStr = options.joinToString(",")
// Convert content:// URIs to fdclose:// for MPV (SAF SD card downloads)
val mpvUri = openContentFd(uri)?.let { "fdclose://$it" } ?: uri
@@ -827,6 +825,16 @@ class ExoPlayerPlugin :
private fun escapeMpvPathListEntry(value: String): String = value.replace("\\", "\\\\").replace(":", "\\:")
private fun appendHttpHeaderOptions(options: MutableList<String>, headers: Map<String, String>?) {
if (headers.isNullOrEmpty()) return
options.add("http-header-fields-clr=")
headers.forEach { (key, value) ->
val header = "$key: $value"
options.add("http-header-fields-append=%${header.toByteArray(Charsets.UTF_8).size}%$header")
}
}
/**
* Configure a freshly initialized MPV fallback core: replay the properties
* and observers Dart registered against the ExoPlayer session, then resume
@@ -839,7 +847,8 @@ class ExoPlayerPlugin :
uri: String,
headers: Map<String, String>?,
positionMs: Long,
externalSubtitles: List<Map<String, Any?>>?
externalSubtitles: List<Map<String, Any?>>?,
playWhenReady: Boolean
) {
// Snapshot Dart-registered state on main thread before clearing
val pendingProps = pendingMpvProperties.toList()
@@ -886,12 +895,11 @@ class ExoPlayerPlugin :
val startSeconds = positionMs / 1000.0
val options = mutableListOf<String>()
options.add(if (positionMs > 0L) "start=$startSeconds" else "start=none")
if (!playWhenReady) options.add("pause=yes")
options.add("sid=no")
options.add("secondary-sid=no")
appendExternalSubtitleOptions(options, externalSubtitles)
headers?.forEach { (key, value) ->
options.add("http-header-fields-append=$key: $value")
}
appendHttpHeaderOptions(options, headers)
val optionsStr = options.joinToString(",")
notifyBackendSwitched()
core.command(arrayOf("loadfile", mpvUri, "replace", "-1", optionsStr))
@@ -919,6 +927,7 @@ class ExoPlayerPlugin :
uri: String,
headers: Map<String, String>?,
positionMs: Long,
playWhenReady: Boolean,
errorMessage: String
): Boolean {
if (usingMpvFallback || fallbackInProgress) {
@@ -993,7 +1002,7 @@ class ExoPlayerPlugin :
usingMpvFallback = true
fallbackInProgress = false
setupMpvFallback(core, act, uri, headers, positionMs, fallbackExternalSubtitles)
setupMpvFallback(core, act, uri, headers, positionMs, fallbackExternalSubtitles, playWhenReady)
}
} catch (e: Exception) {
fallbackInProgress = false