Self similarity/master (#525)

* Migrated to Media3

---------

Co-authored-by: self-similarity <137652432+self-similarity@users.noreply.github.com>
This commit is contained in:
Osten 2023-08-01 01:25:28 +02:00 committed by GitHub
parent 6b87fb7831
commit 8dae4c2b0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 189 additions and 130 deletions

View file

@ -18,7 +18,7 @@ fun String.execute() = ByteArrayOutputStream().use { baot ->
workingDir = projectDir workingDir = projectDir
commandLine = this@execute.split(Regex("\\s")) commandLine = this@execute.split(Regex("\\s"))
standardOutput = baot standardOutput = baot
}.exitValue == 0) }.exitValue == 0)
String(baot.toByteArray()).trim() String(baot.toByteArray()).trim()
else null else null
} }
@ -78,12 +78,18 @@ android {
isDebuggable = false isDebuggable = false
isMinifyEnabled = false isMinifyEnabled = false
isShrinkResources = false isShrinkResources = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
debug { debug {
isDebuggable = true isDebuggable = true
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
} }
flavorDimensions.add("state") flavorDimensions.add("state")
@ -160,10 +166,16 @@ dependencies {
// implementation("androidx.leanback:leanback-paging:1.1.0-alpha09") // implementation("androidx.leanback:leanback-paging:1.1.0-alpha09")
// Exoplayer // Exoplayer
implementation("com.google.android.exoplayer:exoplayer:2.18.2") implementation("androidx.media3:media3-common:1.1.0")
implementation("com.google.android.exoplayer:extension-cast:2.18.2") implementation("androidx.media3:media3-exoplayer:1.1.0")
implementation("com.google.android.exoplayer:extension-mediasession:2.18.2") implementation("androidx.media3:media3-datasource-okhttp:1.1.0")
implementation("com.google.android.exoplayer:extension-okhttp:2.18.2") implementation("androidx.media3:media3-ui:1.1.0")
implementation("androidx.media3:media3-session:1.1.0")
implementation("androidx.media3:media3-cast:1.1.0")
implementation("androidx.media3:media3-exoplayer-hls:1.1.0")
implementation("androidx.media3:media3-exoplayer-dash:1.1.0")
// Use the Jellyfin ffmpeg extension for easy ffmpeg audio decoding in exoplayer. Thank you Jellyfin <3 // Use the Jellyfin ffmpeg extension for easy ffmpeg audio decoding in exoplayer. Thank you Jellyfin <3
// implementation("org.jellyfin.exoplayer:exoplayer-ffmpeg-extension:2.18.2+1") // implementation("org.jellyfin.exoplayer:exoplayer-ffmpeg-extension:2.18.2+1")

View file

@ -40,6 +40,7 @@ import androidx.preference.PreferenceManager
import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.gms.cast.framework.CastContext import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.Session import com.google.android.gms.cast.framework.Session
import com.google.android.gms.cast.framework.SessionManager import com.google.android.gms.cast.framework.SessionManager
@ -62,10 +63,10 @@ import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.CommonActivity.updateLocale import com.lagradost.cloudstream3.CommonActivity.updateLocale
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.databinding.ActivityMainBinding import com.lagradost.cloudstream3.databinding.ActivityMainBinding
import com.lagradost.cloudstream3.databinding.ActivityMainTvBinding import com.lagradost.cloudstream3.databinding.ActivityMainTvBinding
import com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding import com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.debugAssert import com.lagradost.cloudstream3.mvvm.debugAssert
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.normalSafeApiCall

View file

@ -7,7 +7,6 @@ import android.graphics.drawable.AnimatedVectorDrawable
import android.media.metrics.PlaybackErrorEvent import android.media.metrics.PlaybackErrorEvent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.v4.media.session.MediaSessionCompat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -20,15 +19,14 @@ import androidx.annotation.LayoutRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.media.session.MediaButtonReceiver
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.google.android.exoplayer2.ExoPlayer import androidx.media3.common.PlaybackException
import com.google.android.exoplayer2.PlaybackException import androidx.media3.exoplayer.ExoPlayer
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector import androidx.media3.session.MediaSession
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import androidx.media3.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.PlayerView import androidx.media3.ui.PlayerView
import com.google.android.exoplayer2.ui.SubtitleView import androidx.media3.ui.SubtitleView
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode
@ -38,6 +36,7 @@ import com.lagradost.cloudstream3.CommonActivity.playerEventListener
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils
@ -179,15 +178,16 @@ abstract class AbstractPlayerFragment(
} }
canEnterPipMode = isPlayingRightNow && hasPipModeSupport canEnterPipMode = isPlayingRightNow && hasPipModeSupport
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isInPIPMode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
activity?.let { act -> activity?.let { act ->
PlayerPipHelper.updatePIPModeActions(act, isPlayingRightNow) PlayerPipHelper.updatePIPModeActions(act, isPlayingRightNow, player.getAspectRatio())
} }
} }
} }
private var pipReceiver: BroadcastReceiver? = null private var pipReceiver: BroadcastReceiver? = null
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) { override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode)
try { try {
isInPIPMode = isInPictureInPictureMode isInPIPMode = isInPictureInPictureMode
if (isInPictureInPictureMode) { if (isInPictureInPictureMode) {
@ -210,9 +210,7 @@ abstract class AbstractPlayerFragment(
} }
} }
val filter = IntentFilter() val filter = IntentFilter()
filter.addAction( filter.addAction(ACTION_MEDIA_CONTROL)
ACTION_MEDIA_CONTROL
)
activity?.registerReceiver(pipReceiver, filter) activity?.registerReceiver(pipReceiver, filter)
val isPlaying = player.getIsPlaying() val isPlaying = player.getIsPlaying()
val isPlayingValue = val isPlayingValue =
@ -223,7 +221,10 @@ abstract class AbstractPlayerFragment(
piphide?.isVisible = true piphide?.isVisible = true
exitedPipMode() exitedPipMode()
pipReceiver?.let { pipReceiver?.let {
activity?.unregisterReceiver(it) // Prevents java.lang.IllegalArgumentException: Receiver not registered
normalSafeApiCall {
activity?.unregisterReceiver(it)
}
} }
activity?.hideSystemUI() activity?.hideSystemUI()
this.view?.let { UIHelper.hideKeyboard(it) } this.view?.let { UIHelper.hideKeyboard(it) }
@ -276,18 +277,21 @@ abstract class AbstractPlayerFragment(
gotoNext = true gotoNext = true
) )
} }
PlaybackException.ERROR_CODE_REMOTE_ERROR, PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, PlaybackException.ERROR_CODE_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> { PlaybackException.ERROR_CODE_REMOTE_ERROR, PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, PlaybackException.ERROR_CODE_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> {
showToast( showToast(
"${ctx.getString(R.string.remote_error)}\n$errorName ($code)\n$msg", "${ctx.getString(R.string.remote_error)}\n$errorName ($code)\n$msg",
gotoNext = true gotoNext = true
) )
} }
PlaybackException.ERROR_CODE_DECODING_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> { PlaybackException.ERROR_CODE_DECODING_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> {
showToast( showToast(
"${ctx.getString(R.string.render_error)}\n$errorName ($code)\n$msg", "${ctx.getString(R.string.render_error)}\n$errorName ($code)\n$msg",
gotoNext = true gotoNext = true
) )
} }
else -> { else -> {
showToast( showToast(
"${ctx.getString(R.string.unexpected_error)}\n$errorName ($code)\n$msg", "${ctx.getString(R.string.unexpected_error)}\n$errorName ($code)\n$msg",
@ -296,12 +300,14 @@ abstract class AbstractPlayerFragment(
} }
} }
} }
is InvalidFileException -> { is InvalidFileException -> {
showToast( showToast(
"${ctx.getString(R.string.source_error)}\n${exception.message}", "${ctx.getString(R.string.source_error)}\n${exception.message}",
gotoNext = true gotoNext = true
) )
} }
else -> { else -> {
exception.message?.let { exception.message?.let {
showToast( showToast(
@ -322,15 +328,8 @@ abstract class AbstractPlayerFragment(
private fun playerUpdated(player: Any?) { private fun playerUpdated(player: Any?) {
if (player is ExoPlayer) { if (player is ExoPlayer) {
context?.let { ctx -> context?.let { ctx ->
val mediaButtonReceiver = ComponentName(ctx, MediaButtonReceiver::class.java) mMediaSession?.release()
MediaSessionCompat(ctx, "Player", mediaButtonReceiver, null).let { media -> mMediaSession = MediaSession.Builder(ctx, player).build()
//media.setCallback(mMediaSessionCallback)
//media.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
val mediaSessionConnector = MediaSessionConnector(media)
mediaSessionConnector.setPlayer(player)
media.isActive = true
mMediaSessionCompat = media
}
} }
// Necessary for multiple combined videos // Necessary for multiple combined videos
@ -340,8 +339,7 @@ abstract class AbstractPlayerFragment(
} }
} }
private var mediaSessionConnector: MediaSessionConnector? = null private var mMediaSession: MediaSession? = null
private var mMediaSessionCompat: MediaSessionCompat? = null
// this can be used in the future for players other than exoplayer // this can be used in the future for players other than exoplayer
//private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() { //private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() {
@ -442,6 +440,7 @@ abstract class AbstractPlayerFragment(
playerEventListener = null playerEventListener = null
keyEventListener = null keyEventListener = null
canEnterPipMode = false canEnterPipMode = false
mMediaSession?.release()
SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged
keepScreenOn(false) keepScreenOn(false)

View file

@ -5,30 +5,42 @@ import android.net.Uri
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.util.Rational
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.media3.common.C
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.* import androidx.media3.common.C.*
import com.google.android.exoplayer2.C.* import androidx.media3.common.Format
import com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON import androidx.media3.common.MediaItem
import com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER import androidx.media3.common.TrackSelectionOverride
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider import androidx.media3.common.MimeTypes
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource import androidx.media3.common.PlaybackException
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector import androidx.media3.common.Player
import com.google.android.exoplayer2.source.* import androidx.media3.common.TrackGroup
import com.google.android.exoplayer2.text.TextRenderer import androidx.media3.common.Tracks
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector import androidx.media3.common.VideoSize
import com.google.android.exoplayer2.trackselection.TrackSelectionOverride import androidx.media3.database.StandaloneDatabaseProvider
import com.google.android.exoplayer2.trackselection.TrackSelector import androidx.media3.datasource.DataSource
import com.google.android.exoplayer2.ui.SubtitleView import androidx.media3.datasource.DefaultDataSourceFactory
import com.google.android.exoplayer2.upstream.DataSource import androidx.media3.datasource.DefaultHttpDataSource
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory import androidx.media3.datasource.HttpDataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource import androidx.media3.datasource.cache.CacheDataSource
import com.google.android.exoplayer2.upstream.HttpDataSource import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
import com.google.android.exoplayer2.upstream.cache.CacheDataSource import androidx.media3.datasource.cache.SimpleCache
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor import androidx.media3.datasource.okhttp.OkHttpDataSource
import com.google.android.exoplayer2.upstream.cache.SimpleCache import androidx.media3.exoplayer.DefaultLoadControl
import com.google.android.exoplayer2.util.MimeTypes import androidx.media3.exoplayer.DefaultRenderersFactory
import com.google.android.exoplayer2.video.VideoSize import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.SeekParameters
import androidx.media3.exoplayer.source.ClippingMediaSource
import androidx.media3.exoplayer.source.ConcatenatingMediaSource
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.exoplayer.source.MergingMediaSource
import androidx.media3.exoplayer.source.SingleSampleMediaSource
import androidx.media3.exoplayer.text.TextRenderer
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.media3.exoplayer.trackselection.TrackSelector
import androidx.media3.ui.SubtitleView
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
@ -44,7 +56,6 @@ import com.lagradost.cloudstream3.utils.ExtractorLinkPlayList
import com.lagradost.cloudstream3.utils.ExtractorUri import com.lagradost.cloudstream3.utils.ExtractorUri
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
import java.io.File import java.io.File
import java.time.Duration
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSession import javax.net.ssl.SSLSession
@ -451,6 +462,12 @@ class CS3IPlayer : IPlayer {
} }
} }
override fun getAspectRatio(): Rational? {
return exoPlayer?.videoFormat?.let { format ->
Rational(format.width, format.height)
}
}
override fun updateSubtitleStyle(style: SaveCaptionStyle) { override fun updateSubtitleStyle(style: SaveCaptionStyle) {
subtitleHelper.setSubStyle(style) subtitleHelper.setSubStyle(style)
} }

View file

@ -3,19 +3,23 @@ package com.lagradost.cloudstream3.ui.player
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.Format import androidx.media3.common.Format
import com.google.android.exoplayer2.text.* import androidx.media3.common.MimeTypes
import com.google.android.exoplayer2.text.cea.Cea608Decoder import androidx.media3.exoplayer.text.ExoplayerCuesDecoder
import com.google.android.exoplayer2.text.cea.Cea708Decoder import androidx.media3.exoplayer.text.SubtitleDecoderFactory
import com.google.android.exoplayer2.text.dvb.DvbDecoder import androidx.media3.extractor.text.SubtitleDecoder
import com.google.android.exoplayer2.text.pgs.PgsDecoder import androidx.media3.extractor.text.SubtitleInputBuffer
import com.google.android.exoplayer2.text.ssa.SsaDecoder import androidx.media3.extractor.text.SubtitleOutputBuffer
import com.google.android.exoplayer2.text.subrip.SubripDecoder import androidx.media3.extractor.text.cea.Cea608Decoder
import com.google.android.exoplayer2.text.ttml.TtmlDecoder import androidx.media3.extractor.text.cea.Cea708Decoder
import com.google.android.exoplayer2.text.tx3g.Tx3gDecoder import androidx.media3.extractor.text.dvb.DvbDecoder
import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder import androidx.media3.extractor.text.pgs.PgsDecoder
import com.google.android.exoplayer2.text.webvtt.WebvttDecoder import androidx.media3.extractor.text.ssa.SsaDecoder
import com.google.android.exoplayer2.util.MimeTypes import androidx.media3.extractor.text.subrip.SubripDecoder
import androidx.media3.extractor.text.ttml.TtmlDecoder
import androidx.media3.extractor.text.tx3g.Tx3gDecoder
import androidx.media3.extractor.text.webvtt.Mp4WebvttDecoder
import androidx.media3.extractor.text.webvtt.WebvttDecoder
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import org.mozilla.universalchardet.UniversalDetector import org.mozilla.universalchardet.UniversalDetector

View file

@ -1,8 +1,8 @@
package com.lagradost.cloudstream3.ui.player package com.lagradost.cloudstream3.ui.player
import android.os.Looper import android.os.Looper
import com.google.android.exoplayer2.text.SubtitleDecoderFactory import androidx.media3.exoplayer.text.SubtitleDecoderFactory
import com.google.android.exoplayer2.text.TextOutput import androidx.media3.exoplayer.text.TextOutput
class CustomTextRenderer( class CustomTextRenderer(
offset: Long, offset: Long,

View file

@ -19,8 +19,8 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.Format.NO_VALUE import androidx.media3.common.Format.NO_VALUE
import com.google.android.exoplayer2.util.MimeTypes import androidx.media3.common.MimeTypes
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.ui.player package com.lagradost.cloudstream3.ui.player
import android.content.Context import android.content.Context
import android.util.Rational
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.EpisodeSkip
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
@ -167,6 +168,19 @@ interface IPlayer {
fun getVideoTracks(): CurrentTracks fun getVideoTracks(): CurrentTracks
/**
* Original video aspect ratio used for PiP mode
*
* Set using: Width, Height.
* Example: Rational(16, 9)
*
* If null will default to set no aspect ratio.
*
* PiP functions calling this needs to coerce this value between 0.418410 and 2.390000
* to prevent crashes.
*/
fun getAspectRatio(): Rational?
/** If no parameters are set it'll default to no set size, Specifying the id allows for track overrides to force the player to pick the quality. */ /** If no parameters are set it'll default to no set size, Specifying the id allows for track overrides to force the player to pick the quality. */
fun setMaxVideoSize(width: Int = Int.MAX_VALUE, height: Int = Int.MAX_VALUE, id: String? = null) fun setMaxVideoSize(width: Int = Int.MAX_VALUE, height: Int = Int.MAX_VALUE, id: String? = null)

View file

@ -15,10 +15,10 @@
*/ */
package com.lagradost.cloudstream3.ui.player; package com.lagradost.cloudstream3.ui.player;
import static com.google.android.exoplayer2.text.Cue.DIMEN_UNSET; import static androidx.media3.common.text.Cue.DIMEN_UNSET;
import static com.google.android.exoplayer2.text.Cue.LINE_TYPE_NUMBER; import static androidx.media3.common.text.Cue.LINE_TYPE_NUMBER;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Handler; import android.os.Handler;
@ -28,25 +28,24 @@ import android.os.Message;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C;
import com.google.android.exoplayer2.BaseRenderer; import androidx.media3.common.Format;
import com.google.android.exoplayer2.C; import androidx.media3.common.text.Cue;
import com.google.android.exoplayer2.Format; import androidx.media3.common.text.CueGroup;
import com.google.android.exoplayer2.FormatHolder; import androidx.media3.common.MimeTypes;
import com.google.android.exoplayer2.RendererCapabilities; import androidx.media3.common.util.Log;
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult; import androidx.media3.common.util.Util;
import com.google.android.exoplayer2.text.Cue; import androidx.media3.exoplayer.BaseRenderer;
import com.google.android.exoplayer2.text.CueGroup; import androidx.media3.exoplayer.FormatHolder;
import com.google.android.exoplayer2.text.Subtitle; import androidx.media3.exoplayer.RendererCapabilities;
import com.google.android.exoplayer2.text.SubtitleDecoder; import androidx.media3.exoplayer.source.SampleStream;
import com.google.android.exoplayer2.text.SubtitleDecoderException; import androidx.media3.exoplayer.text.SubtitleDecoderFactory;
import com.google.android.exoplayer2.text.SubtitleDecoderFactory; import androidx.media3.exoplayer.text.TextOutput;
import com.google.android.exoplayer2.text.SubtitleInputBuffer; import androidx.media3.extractor.text.Subtitle;
import com.google.android.exoplayer2.text.SubtitleOutputBuffer; import androidx.media3.extractor.text.SubtitleDecoder;
import com.google.android.exoplayer2.text.TextOutput; import androidx.media3.extractor.text.SubtitleDecoderException;
import com.google.android.exoplayer2.util.Log; import androidx.media3.extractor.text.SubtitleInputBuffer;
import com.google.android.exoplayer2.util.MimeTypes; import androidx.media3.extractor.text.SubtitleOutputBuffer;
import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -310,7 +309,7 @@ public class NonFinalTextRenderer extends BaseRenderer implements Callback {
return; return;
} }
// Try and read the next subtitle from the source. // Try and read the next subtitle from the source.
@ReadDataResult int result = readSource(formatHolder, nextInputBuffer, /* readFlags= */ 0); @SampleStream.ReadDataResult int result = readSource(formatHolder, nextInputBuffer, /* readFlags= */ 0);
if (result == C.RESULT_BUFFER_READ) { if (result == C.RESULT_BUFFER_READ) {
if (nextInputBuffer.isEndOfStream()) { if (nextInputBuffer.isEndOfStream()) {
inputStreamEnded = true; inputStreamEnded = true;

View file

@ -7,28 +7,22 @@ import android.app.RemoteAction
import android.content.Intent import android.content.Intent
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.os.Build import android.os.Build
import android.util.Rational
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import kotlin.math.roundToInt
class PlayerPipHelper { class PlayerPipHelper {
companion object { companion object {
@RequiresApi(Build.VERSION_CODES.O)
private fun getPen(activity: Activity, code: Int): PendingIntent { private fun getPen(activity: Activity, code: Int): PendingIntent {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return PendingIntent.getBroadcast(
PendingIntent.getBroadcast( activity,
activity, code,
code, Intent(ACTION_MEDIA_CONTROL).putExtra(EXTRA_CONTROL_TYPE, code),
Intent("media_control").putExtra("control_type", code), PendingIntent.FLAG_IMMUTABLE
PendingIntent.FLAG_IMMUTABLE )
)
} else {
PendingIntent.getBroadcast(
activity,
code,
Intent("media_control").putExtra("control_type", code),
0
)
}
} }
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@ -48,7 +42,7 @@ class PlayerPipHelper {
} }
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
fun updatePIPModeActions(activity: Activity, isPlaying: Boolean) { fun updatePIPModeActions(activity: Activity, isPlaying: Boolean, aspectRatio: Rational?) {
val actions: ArrayList<RemoteAction> = ArrayList() val actions: ArrayList<RemoteAction> = ArrayList()
actions.add( actions.add(
getRemoteAction( getRemoteAction(
@ -87,8 +81,28 @@ class PlayerPipHelper {
CSPlayerEvent.SeekForward CSPlayerEvent.SeekForward
) )
) )
// Nessecary to prevent crashing.
val mixAspectRatio = 0.41841f // ~1/2.39
val maxAspectRatio = 2.39f // widescreen standard
val ratioAccuracy = 100000 // To convert the float to int
// java.lang.IllegalArgumentException: setPictureInPictureParams: Aspect ratio is too extreme (must be between 0.418410 and 2.390000)
val fixedRational = aspectRatio?.toFloat()?.coerceIn(mixAspectRatio, maxAspectRatio)?.let {
Rational((it * ratioAccuracy).roundToInt(), ratioAccuracy)
}
activity.setPictureInPictureParams( activity.setPictureInPictureParams(
PictureInPictureParams.Builder().setActions(actions).build() PictureInPictureParams.Builder()
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
setSeamlessResizeEnabled(true)
setAutoEnterEnabled(isPlaying)
}
}
.setAspectRatio(fixedRational)
.setActions(actions)
.build()
) )
} }
} }

View file

@ -4,8 +4,8 @@ import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import com.google.android.exoplayer2.ui.SubtitleView import androidx.media3.common.MimeTypes
import com.google.android.exoplayer2.util.MimeTypes import androidx.media3.ui.SubtitleView
import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.regexSubtitlesToRemoveBloat import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.regexSubtitlesToRemoveBloat
import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.regexSubtitlesToRemoveCaptions import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.regexSubtitlesToRemoveCaptions

View file

@ -14,7 +14,7 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.google.android.exoplayer2.text.Cue import androidx.media3.common.text.Cue
import com.google.android.gms.cast.TextTrackStyle import com.google.android.gms.cast.TextTrackStyle
import com.google.android.gms.cast.TextTrackStyle.* import com.google.android.gms.cast.TextTrackStyle.*
import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.jaredrummler.android.colorpicker.ColorPickerDialog

View file

@ -18,8 +18,8 @@ import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.google.android.exoplayer2.text.Cue import androidx.media3.common.text.Cue
import com.google.android.exoplayer2.ui.CaptionStyleCompat import androidx.media3.ui.CaptionStyleCompat
import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey

View file

@ -1,7 +1,7 @@
package com.lagradost.cloudstream3.utils package com.lagradost.cloudstream3.utils
import android.net.Uri import android.net.Uri
import com.google.android.exoplayer2.util.MimeTypes import androidx.media3.common.MimeTypes
import com.google.android.gms.cast.* import com.google.android.gms.cast.*
import com.google.android.gms.cast.framework.CastSession import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.media.RemoteMediaClient import com.google.android.gms.cast.framework.media.RemoteMediaClient

View file

@ -35,7 +35,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:contentDescription="@string/preview_background_img_des" /> android:contentDescription="@string/preview_background_img_des" />
<com.google.android.exoplayer2.ui.SubtitleView <androidx.media3.ui.SubtitleView
android:id="@+id/subtitle_text" android:id="@+id/subtitle_text"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -13,7 +13,7 @@
<!-- <!--
app:fastforward_increment="10000" app:fastforward_increment="10000"
app:rewind_increment="10000"--> app:rewind_increment="10000"-->
<com.google.android.exoplayer2.ui.PlayerView <androidx.media3.ui.PlayerView
android:id="@+id/player_view" android:id="@+id/player_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -13,7 +13,7 @@
<!-- <!--
app:fastforward_increment="10000" app:fastforward_increment="10000"
app:rewind_increment="10000"--> app:rewind_increment="10000"-->
<com.google.android.exoplayer2.ui.PlayerView <androidx.media3.ui.PlayerView
android:id="@+id/player_view" android:id="@+id/player_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -14,7 +14,7 @@
<!-- <!--
app:fastforward_increment="10000" app:fastforward_increment="10000"
app:rewind_increment="10000"--> app:rewind_increment="10000"-->
<com.google.android.exoplayer2.ui.PlayerView <androidx.media3.ui.PlayerView
android:id="@+id/player_view" android:id="@+id/player_view"
app:show_timeout="0" app:show_timeout="0"
app:hide_on_touch="false" app:hide_on_touch="false"

View file

@ -450,7 +450,7 @@
android:textStyle="normal" android:textStyle="normal"
tools:text="15:30" /> tools:text="15:30" />
<!--app:buffered_color="@color/videoCache"--> <!--app:buffered_color="@color/videoCache"-->
<com.google.android.exoplayer2.ui.DefaultTimeBar <androidx.media3.ui.DefaultTimeBar
android:id="@id/exo_progress" android:id="@id/exo_progress"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="30dp" android:layout_height="30dp"

View file

@ -543,7 +543,7 @@
android:textStyle="normal" android:textStyle="normal"
tools:text="15:30" /> tools:text="15:30" />
<!--app:buffered_color="@color/videoCache"--> <!--app:buffered_color="@color/videoCache"-->
<com.google.android.exoplayer2.ui.DefaultTimeBar <androidx.media3.ui.DefaultTimeBar
android:id="@id/exo_progress" android:id="@id/exo_progress"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="30dp" android:layout_height="30dp"

View file

@ -35,9 +35,8 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:src="@drawable/subtitles_preview_background" /> android:src="@drawable/subtitles_preview_background" />
<com.google.android.exoplayer2.ui.SubtitleView <androidx.media3.ui.SubtitleView
android:id="@+id/subtitle_text" android:id="@+id/subtitle_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"

View file

@ -443,7 +443,7 @@
android:textStyle="normal" android:textStyle="normal"
tools:text="15:30" /> tools:text="15:30" />
<!--app:buffered_color="@color/videoCache"--> <!--app:buffered_color="@color/videoCache"-->
<com.google.android.exoplayer2.ui.DefaultTimeBar <androidx.media3.ui.DefaultTimeBar
android:id="@id/exo_progress" android:id="@id/exo_progress"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="30dp" android:layout_height="30dp"

View file

@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true # android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
android.defaults.buildfeatures.buildconfig=true android.defaults.buildfeatures.buildconfig=true