refactor: extract shared mixins and helpers, drop dead abstractions
Introduces shared seams for paginated views, D-pad reorder, media control routing, async singletons and the device method channel, then points the open-coded copies at them. Also removes unused models and duplicated provider/server plumbing, folds the twice-implemented artifact store in the server, and factors the repeated Flutter toolchain prologue in CI into a composite action.
This commit is contained in:
@@ -77,6 +77,7 @@ import com.edde746.plezy.shared.FlutterOverlayHelper
|
||||
import com.edde746.plezy.shared.FrameRateManager
|
||||
import com.edde746.plezy.shared.MediaCodecQuery
|
||||
import com.edde746.plezy.shared.PlayerSurfaceHost
|
||||
import com.edde746.plezy.shared.SurfacePlayerCore
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import org.chromium.net.CronetEngine
|
||||
@@ -102,7 +103,7 @@ interface ExoPlayerDelegate : com.edde746.plezy.shared.PlayerDelegate {
|
||||
internal fun playbackMimeType(isLive: Boolean): String? = if (isLive) MimeTypes.APPLICATION_M3U8 else null
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
class ExoPlayerCore(private val activity: Activity) : Player.Listener, SurfacePlayerCore {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ExoPlayerCore"
|
||||
@@ -3400,7 +3401,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun setVisible(visible: Boolean) {
|
||||
override fun setVisible(visible: Boolean) {
|
||||
if (disposing) return
|
||||
currentVisible = visible
|
||||
activity.runOnUiThread {
|
||||
@@ -3493,7 +3494,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
fun onPipModeChanged(isInPipMode: Boolean) {
|
||||
override fun onPipModeChanged(isInPipMode: Boolean) {
|
||||
if (disposing) return
|
||||
activity.runOnUiThread {
|
||||
if (disposing) return@runOnUiThread
|
||||
@@ -3509,7 +3510,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateFrame() {
|
||||
override fun updateFrame() {
|
||||
if (disposing) return
|
||||
activity.runOnUiThread {
|
||||
if (disposing) return@runOnUiThread
|
||||
@@ -3524,15 +3525,15 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
|
||||
// Audio Focus
|
||||
|
||||
fun requestAudioFocus(): Boolean = audioFocusManager?.requestAudioFocus() ?: false
|
||||
override fun requestAudioFocus(): Boolean = audioFocusManager?.requestAudioFocus() ?: false
|
||||
|
||||
fun abandonAudioFocus() {
|
||||
override fun abandonAudioFocus() {
|
||||
audioFocusManager?.abandonAudioFocus()
|
||||
}
|
||||
|
||||
// Frame Rate Matching
|
||||
|
||||
fun setVideoFrameRate(
|
||||
override fun setVideoFrameRate(
|
||||
fps: Float,
|
||||
videoDurationMs: Long,
|
||||
extraDelayMs: Long,
|
||||
@@ -3548,7 +3549,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
|
||||
mgr.setVideoFrameRate(fps, videoDurationMs, extraDelayMs, videoWidth, videoHeight, onComplete)
|
||||
}
|
||||
|
||||
fun clearVideoFrameRate() {
|
||||
override fun clearVideoFrameRate() {
|
||||
frameRateManager?.clearVideoFrameRate()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.edde746.plezy.shared.MpvContentUriResolver
|
||||
import com.edde746.plezy.shared.PlayerChannelBinding
|
||||
import com.edde746.plezy.shared.PlayerDelegate
|
||||
import com.edde746.plezy.shared.ResolvedMpvUri
|
||||
import com.edde746.plezy.shared.SurfacePlayerCore
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
@@ -45,6 +46,10 @@ class ExoPlayerPlugin :
|
||||
private var activity: Activity? = null
|
||||
private var activityBinding: ActivityPluginBinding? = null
|
||||
|
||||
/** Whichever core currently owns the surface; both expose [SurfacePlayerCore] identically. */
|
||||
private val activeSurfaceCore: SurfacePlayerCore?
|
||||
get() = if (usingMpvFallback) mpvCore else playerCore
|
||||
|
||||
// Every Dart observeProperty registration, kept so an ExoPlayer→MPV
|
||||
// fallback can re-observe exactly what Dart asked for instead of
|
||||
// maintaining a parallel hard-coded list.
|
||||
@@ -949,20 +954,12 @@ class ExoPlayerPlugin :
|
||||
return
|
||||
}
|
||||
|
||||
if (usingMpvFallback) {
|
||||
mpvCore?.setVisible(visible)
|
||||
} else {
|
||||
playerCore?.setVisible(visible)
|
||||
}
|
||||
activeSurfaceCore?.setVisible(visible)
|
||||
result.success(null)
|
||||
}
|
||||
|
||||
private fun handleUpdateFrame(result: MethodChannel.Result) {
|
||||
if (usingMpvFallback) {
|
||||
mpvCore?.updateFrame()
|
||||
} else {
|
||||
playerCore?.updateFrame()
|
||||
}
|
||||
activeSurfaceCore?.updateFrame()
|
||||
result.success(null)
|
||||
}
|
||||
|
||||
@@ -974,51 +971,31 @@ class ExoPlayerPlugin :
|
||||
val videoHeight = call.argument<Number>("videoHeight")?.toInt() ?: 0
|
||||
|
||||
Log.d(TAG, "setVideoFrameRate: fps=$fps, duration=$duration, extraDelayMs=$extraDelayMs, video=${videoWidth}x$videoHeight")
|
||||
val onComplete: (Boolean) -> Unit = { switched -> result.success(switched) }
|
||||
if (usingMpvFallback) {
|
||||
val core = mpvCore
|
||||
if (core == null) {
|
||||
result.success(false)
|
||||
} else {
|
||||
core.setVideoFrameRate(fps, duration, extraDelayMs, videoWidth, videoHeight, onComplete)
|
||||
}
|
||||
} else {
|
||||
val core = playerCore
|
||||
if (core == null) {
|
||||
result.success(false)
|
||||
} else {
|
||||
core.setVideoFrameRate(fps, duration, extraDelayMs, videoWidth, videoHeight, onComplete)
|
||||
}
|
||||
val core = activeSurfaceCore
|
||||
if (core == null) {
|
||||
result.success(false)
|
||||
return
|
||||
}
|
||||
core.setVideoFrameRate(fps, duration, extraDelayMs, videoWidth, videoHeight) { switched ->
|
||||
result.success(switched)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleClearVideoFrameRate(result: MethodChannel.Result) {
|
||||
Log.d(TAG, "clearVideoFrameRate")
|
||||
if (usingMpvFallback) {
|
||||
mpvCore?.clearVideoFrameRate()
|
||||
} else {
|
||||
playerCore?.clearVideoFrameRate()
|
||||
}
|
||||
activeSurfaceCore?.clearVideoFrameRate()
|
||||
result.success(null)
|
||||
}
|
||||
|
||||
private fun handleRequestAudioFocus(result: MethodChannel.Result) {
|
||||
Log.d(TAG, "requestAudioFocus")
|
||||
val granted = if (usingMpvFallback) {
|
||||
mpvCore?.requestAudioFocus() ?: false
|
||||
} else {
|
||||
playerCore?.requestAudioFocus() ?: false
|
||||
}
|
||||
val granted = activeSurfaceCore?.requestAudioFocus() ?: false
|
||||
result.success(granted)
|
||||
}
|
||||
|
||||
private fun handleAbandonAudioFocus(result: MethodChannel.Result) {
|
||||
Log.d(TAG, "abandonAudioFocus")
|
||||
if (usingMpvFallback) {
|
||||
mpvCore?.abandonAudioFocus()
|
||||
} else {
|
||||
playerCore?.abandonAudioFocus()
|
||||
}
|
||||
activeSurfaceCore?.abandonAudioFocus()
|
||||
result.success(null)
|
||||
}
|
||||
|
||||
@@ -1228,11 +1205,7 @@ class ExoPlayerPlugin :
|
||||
|
||||
fun onPipModeChanged(isInPipMode: Boolean) {
|
||||
activity?.runOnUiThread {
|
||||
if (usingMpvFallback) {
|
||||
mpvCore?.onPipModeChanged(isInPipMode)
|
||||
} else {
|
||||
playerCore?.onPipModeChanged(isInPipMode)
|
||||
}
|
||||
activeSurfaceCore?.onPipModeChanged(isInPipMode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.edde746.plezy.shared.AudioFocusManager
|
||||
import com.edde746.plezy.shared.FrameRateManager
|
||||
import com.edde746.plezy.shared.PlayerDelegate
|
||||
import com.edde746.plezy.shared.PlayerSurfaceHost
|
||||
import com.edde746.plezy.shared.SurfacePlayerCore
|
||||
import dev.jdtech.mpv.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@@ -40,7 +41,7 @@ class MpvPlayerCore private constructor(
|
||||
private val audioOnly: Boolean,
|
||||
private val propertyWriterOverride: (suspend (String, String) -> Unit)?,
|
||||
initializedForTesting: Boolean
|
||||
) : SurfaceHolder.Callback {
|
||||
) : SurfaceHolder.Callback, SurfacePlayerCore {
|
||||
constructor(context: Context, audioOnly: Boolean = false) : this(context, audioOnly, null, false)
|
||||
|
||||
internal constructor(
|
||||
@@ -405,7 +406,7 @@ class MpvPlayerCore private constructor(
|
||||
|
||||
// Audio Focus
|
||||
|
||||
fun requestAudioFocus(): Boolean {
|
||||
override fun requestAudioFocus(): Boolean {
|
||||
val granted = audioFocusManager?.requestAudioFocus() ?: false
|
||||
if (granted && pausedForAudioFocusLoss) {
|
||||
resumeAfterAudioFocusGain("audio focus request granted")
|
||||
@@ -413,7 +414,7 @@ class MpvPlayerCore private constructor(
|
||||
return granted
|
||||
}
|
||||
|
||||
fun abandonAudioFocus() {
|
||||
override fun abandonAudioFocus() {
|
||||
audioFocusManager?.abandonAudioFocus()
|
||||
}
|
||||
|
||||
@@ -1042,7 +1043,7 @@ class MpvPlayerCore private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun setVisible(visible: Boolean) {
|
||||
override fun setVisible(visible: Boolean) {
|
||||
// Audio-only: no render layer to show or hide — tolerated no-op.
|
||||
if (audioOnly || disposing) return
|
||||
runOnMain {
|
||||
@@ -1067,11 +1068,11 @@ class MpvPlayerCore private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onPipModeChanged(isInPipMode: Boolean) {
|
||||
override fun onPipModeChanged(isInPipMode: Boolean) {
|
||||
// MPV handles aspect ratio internally via its own surface management
|
||||
}
|
||||
|
||||
fun updateFrame() {
|
||||
override fun updateFrame() {
|
||||
// Audio-only: no surface to refresh — tolerated no-op.
|
||||
if (audioOnly || disposing) return
|
||||
runOnMain {
|
||||
@@ -1106,7 +1107,7 @@ class MpvPlayerCore private constructor(
|
||||
|
||||
// Frame Rate Matching
|
||||
|
||||
fun setVideoFrameRate(
|
||||
override fun setVideoFrameRate(
|
||||
fps: Float,
|
||||
videoDurationMs: Long,
|
||||
extraDelayMs: Long,
|
||||
@@ -1128,7 +1129,7 @@ class MpvPlayerCore private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun clearVideoFrameRate() {
|
||||
override fun clearVideoFrameRate() {
|
||||
frameRateManager?.clearVideoFrameRate()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.edde746.plezy.shared
|
||||
|
||||
/**
|
||||
* Surface and display concerns that the ExoPlayer and mpv cores implement
|
||||
* identically, so a plugin holding either one dispatches without branching
|
||||
* on which backend is active.
|
||||
*
|
||||
* Only backend-independent members belong here: playback control
|
||||
* (play/seek/track selection) stays off this interface because mpv drives it
|
||||
* through properties and commands where ExoPlayer uses direct method calls.
|
||||
*/
|
||||
interface SurfacePlayerCore {
|
||||
fun setVisible(visible: Boolean)
|
||||
fun updateFrame()
|
||||
fun onPipModeChanged(isInPipMode: Boolean)
|
||||
fun requestAudioFocus(): Boolean
|
||||
fun abandonAudioFocus()
|
||||
fun clearVideoFrameRate()
|
||||
fun setVideoFrameRate(
|
||||
fps: Float,
|
||||
videoDurationMs: Long,
|
||||
extraDelayMs: Long,
|
||||
videoWidth: Int,
|
||||
videoHeight: Int,
|
||||
onComplete: (switched: Boolean) -> Unit
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user