Migrate to androidx media3 (#213)
* Migrate to media3 * Update docs * Move display_extended_title to AppPreferences * Move display_extended_title to AppPreferences p2 * Add MediaSession support to the player * Fix mpv player * Disable animations on tv player controls and rename the tv_control_view file * New media3 decoder ffmpeg
This commit is contained in:
parent
6ed7e12035
commit
65f4c2f639
20 changed files with 156 additions and 134 deletions
|
@ -77,6 +77,9 @@ dependencies {
|
||||||
implementation(libs.androidx.leanback)
|
implementation(libs.androidx.leanback)
|
||||||
implementation(libs.androidx.lifecycle.runtime)
|
implementation(libs.androidx.lifecycle.runtime)
|
||||||
implementation(libs.androidx.lifecycle.viewmodel)
|
implementation(libs.androidx.lifecycle.viewmodel)
|
||||||
|
implementation(libs.androidx.media3.exoplayer)
|
||||||
|
implementation(libs.androidx.media3.ui)
|
||||||
|
implementation(libs.androidx.media3.session)
|
||||||
implementation(libs.androidx.navigation.fragment)
|
implementation(libs.androidx.navigation.fragment)
|
||||||
implementation(libs.androidx.navigation.ui)
|
implementation(libs.androidx.navigation.ui)
|
||||||
implementation(libs.androidx.paging)
|
implementation(libs.androidx.paging)
|
||||||
|
@ -87,8 +90,6 @@ dependencies {
|
||||||
kapt(libs.androidx.room.compiler)
|
kapt(libs.androidx.room.compiler)
|
||||||
implementation(libs.androidx.room.ktx)
|
implementation(libs.androidx.room.ktx)
|
||||||
implementation(libs.androidx.swiperefreshlayout)
|
implementation(libs.androidx.swiperefreshlayout)
|
||||||
implementation(libs.exoplayer.core)
|
|
||||||
implementation(libs.exoplayer.ui)
|
|
||||||
implementation(libs.glide)
|
implementation(libs.glide)
|
||||||
kapt(libs.glide.compiler)
|
kapt(libs.glide.compiler)
|
||||||
implementation(libs.hilt.android)
|
implementation(libs.hilt.android)
|
||||||
|
@ -97,9 +98,9 @@ dependencies {
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
implementation(libs.timber)
|
implementation(libs.timber)
|
||||||
|
|
||||||
// ExoPlayer FFmpeg extension
|
|
||||||
implementation(files("libs/extension-ffmpeg-release.aar"))
|
|
||||||
|
|
||||||
// MPV
|
// MPV
|
||||||
implementation(files("libs/libmpv.aar"))
|
implementation(files("libs/libmpv.aar"))
|
||||||
|
|
||||||
|
// Media3 FFmpeg decoder
|
||||||
|
implementation(files("libs/lib-decoder-ffmpeg-release.aar"))
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
BIN
app/libs/lib-decoder-ffmpeg-release.aar
Normal file
BIN
app/libs/lib-decoder-ffmpeg-release.aar
Normal file
Binary file not shown.
7
app/lint.xml
Normal file
7
app/lint.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<lint>
|
||||||
|
<issue id="UnsafeOptInUsageError">
|
||||||
|
<ignore
|
||||||
|
regexp='\(markerClass = androidx\.media3\.common\.util\.UnstableApi\.class\)' />
|
||||||
|
</issue>
|
||||||
|
</lint>
|
|
@ -5,23 +5,39 @@ import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector
|
import androidx.media3.exoplayer.trackselection.MappingTrackSelector
|
||||||
|
import androidx.media3.session.MediaSession
|
||||||
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
|
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
|
||||||
|
|
||||||
abstract class BasePlayerActivity : AppCompatActivity() {
|
abstract class BasePlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
abstract val viewModel: PlayerActivityViewModel
|
abstract val viewModel: PlayerActivityViewModel
|
||||||
|
|
||||||
|
lateinit var mediaSession: MediaSession
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
|
||||||
|
mediaSession = MediaSession.Builder(this, viewModel.player).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
viewModel.player.playWhenReady = viewModel.playWhenReady
|
||||||
|
hideSystemUI()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
viewModel.playWhenReady = viewModel.player.playWhenReady == true
|
viewModel.playWhenReady = viewModel.player.playWhenReady == true
|
||||||
viewModel.player.playWhenReady = false
|
viewModel.player.playWhenReady = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onStop() {
|
||||||
super.onResume()
|
super.onStop()
|
||||||
viewModel.player.playWhenReady = viewModel.playWhenReady
|
|
||||||
hideSystemUI()
|
mediaSession.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
|
|
@ -8,10 +8,10 @@ import android.view.WindowManager
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.ui.TrackSelectionDialogBuilder
|
||||||
import androidx.navigation.navArgs
|
import androidx.navigation.navArgs
|
||||||
import com.google.android.exoplayer2.C
|
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.ui.TrackSelectionDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import dev.jdtech.jellyfin.databinding.ActivityPlayerBinding
|
import dev.jdtech.jellyfin.databinding.ActivityPlayerBinding
|
||||||
import dev.jdtech.jellyfin.dialogs.SpeedSelectionDialogFragment
|
import dev.jdtech.jellyfin.dialogs.SpeedSelectionDialogFragment
|
||||||
|
|
|
@ -12,32 +12,31 @@ import android.view.SurfaceHolder
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
import android.view.TextureView
|
import android.view.TextureView
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import com.google.android.exoplayer2.BasePlayer
|
|
||||||
import com.google.android.exoplayer2.C
|
|
||||||
import com.google.android.exoplayer2.DeviceInfo
|
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException
|
|
||||||
import com.google.android.exoplayer2.Format
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.MediaMetadata
|
|
||||||
import com.google.android.exoplayer2.PlaybackParameters
|
|
||||||
import com.google.android.exoplayer2.Player
|
|
||||||
import com.google.android.exoplayer2.Player.Commands
|
|
||||||
import com.google.android.exoplayer2.Timeline
|
|
||||||
import com.google.android.exoplayer2.Tracks
|
|
||||||
import com.google.android.exoplayer2.audio.AudioAttributes
|
|
||||||
import com.google.android.exoplayer2.source.TrackGroup
|
|
||||||
import com.google.android.exoplayer2.text.Cue
|
|
||||||
import com.google.android.exoplayer2.text.CueGroup
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters
|
|
||||||
import com.google.android.exoplayer2.util.Clock
|
|
||||||
import com.google.android.exoplayer2.util.FlagSet
|
|
||||||
import com.google.android.exoplayer2.util.ListenerSet
|
|
||||||
import com.google.android.exoplayer2.util.MimeTypes
|
|
||||||
import com.google.android.exoplayer2.util.Size
|
|
||||||
import com.google.android.exoplayer2.util.Util
|
|
||||||
import com.google.android.exoplayer2.video.VideoSize
|
|
||||||
import dev.jdtech.jellyfin.utils.AppPreferences
|
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||||
import `is`.xyz.mpv.MPVLib
|
import `is`.xyz.mpv.MPVLib
|
||||||
|
import androidx.media3.common.AudioAttributes
|
||||||
|
import androidx.media3.common.BasePlayer
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.DeviceInfo
|
||||||
|
import androidx.media3.common.FlagSet
|
||||||
|
import androidx.media3.common.Format
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.MediaMetadata
|
||||||
|
import androidx.media3.common.MimeTypes
|
||||||
|
import androidx.media3.common.PlaybackParameters
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.Player.Commands
|
||||||
|
import androidx.media3.common.Timeline
|
||||||
|
import androidx.media3.common.TrackGroup
|
||||||
|
import androidx.media3.common.TrackSelectionParameters
|
||||||
|
import androidx.media3.common.Tracks
|
||||||
|
import androidx.media3.common.VideoSize
|
||||||
|
import androidx.media3.common.text.CueGroup
|
||||||
|
import androidx.media3.common.util.Clock
|
||||||
|
import androidx.media3.common.util.ListenerSet
|
||||||
|
import androidx.media3.common.util.Size
|
||||||
|
import androidx.media3.common.util.Util
|
||||||
|
import androidx.media3.exoplayer.ExoPlaybackException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.util.concurrent.CopyOnWriteArraySet
|
import java.util.concurrent.CopyOnWriteArraySet
|
||||||
|
@ -177,6 +176,7 @@ class MPVPlayer(
|
||||||
var currentMpvTracks: List<Track> = emptyList()
|
var currentMpvTracks: List<Track> = emptyList()
|
||||||
private var initialCommands = mutableListOf<Array<String>>()
|
private var initialCommands = mutableListOf<Array<String>>()
|
||||||
private var initialSeekTo: Long = 0L
|
private var initialSeekTo: Long = 0L
|
||||||
|
private var trackSelectionParameters: TrackSelectionParameters = TrackSelectionParameters.Builder(context).build()
|
||||||
|
|
||||||
// mpv events
|
// mpv events
|
||||||
override fun eventProperty(property: String) {
|
override fun eventProperty(property: String) {
|
||||||
|
@ -386,13 +386,13 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates a [com.google.android.exoplayer2.Timeline.Window] with data for the window at the specified index.
|
* Populates a [androidx.media3.common.Timeline.Window] with data for the window at the specified index.
|
||||||
*
|
*
|
||||||
* @param windowIndex The index of the window.
|
* @param windowIndex The index of the window.
|
||||||
* @param window The [com.google.android.exoplayer2.Timeline.Window] to populate. Must not be null.
|
* @param window The [androidx.media3.common.Timeline.Window] to populate. Must not be null.
|
||||||
* @param defaultPositionProjectionUs A duration into the future that the populated window's
|
* @param defaultPositionProjectionUs A duration into the future that the populated window's
|
||||||
* default start position should be projected.
|
* default start position should be projected.
|
||||||
* @return The populated [com.google.android.exoplayer2.Timeline.Window], for convenience.
|
* @return The populated [androidx.media3.common.Timeline.Window], for convenience.
|
||||||
*/
|
*/
|
||||||
override fun getWindow(
|
override fun getWindow(
|
||||||
windowIndex: Int,
|
windowIndex: Int,
|
||||||
|
@ -427,14 +427,14 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates a [com.google.android.exoplayer2.Timeline.Period] with data for the period at the specified index.
|
* Populates a [androidx.media3.common.Timeline.Period] with data for the period at the specified index.
|
||||||
*
|
*
|
||||||
* @param periodIndex The index of the period.
|
* @param periodIndex The index of the period.
|
||||||
* @param period The [com.google.android.exoplayer2.Timeline.Period] to populate. Must not be null.
|
* @param period The [androidx.media3.common.Timeline.Period] to populate. Must not be null.
|
||||||
* @param setIds Whether [com.google.android.exoplayer2.Timeline.Period.id] and [com.google.android.exoplayer2.Timeline.Period.uid] should be populated. If false,
|
* @param setIds Whether [androidx.media3.common.Timeline.Period.id] and [androidx.media3.common.Timeline.Period.uid] should be populated. If false,
|
||||||
* the fields will be set to null. The caller should pass false for efficiency reasons unless
|
* the fields will be set to null. The caller should pass false for efficiency reasons unless
|
||||||
* the fields are required.
|
* the fields are required.
|
||||||
* @return The populated [com.google.android.exoplayer2.Timeline.Period], for convenience.
|
* @return The populated [androidx.media3.common.Timeline.Period], for convenience.
|
||||||
*/
|
*/
|
||||||
override fun getPeriod(periodIndex: Int, period: Period, setIds: Boolean): Period {
|
override fun getPeriod(periodIndex: Int, period: Period, setIds: Boolean): Period {
|
||||||
return period.set(
|
return period.set(
|
||||||
|
@ -447,7 +447,7 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the index of the period identified by its unique [com.google.android.exoplayer2.Timeline.Period.uid], or [ ][C.INDEX_UNSET] if the period is not in the timeline.
|
* Returns the index of the period identified by its unique [Timeline.Period.uid], or [ ][C.INDEX_UNSET] if the period is not in the timeline.
|
||||||
*
|
*
|
||||||
* @param uid A unique identifier for a period.
|
* @param uid A unique identifier for a period.
|
||||||
* @return The index of the period, or [C.INDEX_UNSET] if the period was not found.
|
* @return The index of the period, or [C.INDEX_UNSET] if the period was not found.
|
||||||
|
@ -557,12 +557,12 @@ class MPVPlayer(
|
||||||
* Clears the playlist and adds the specified [MediaItems][MediaItem].
|
* Clears the playlist and adds the specified [MediaItems][MediaItem].
|
||||||
*
|
*
|
||||||
* @param mediaItems The new [MediaItems][MediaItem].
|
* @param mediaItems The new [MediaItems][MediaItem].
|
||||||
* @param startWindowIndex The window index to start playback from. If [com.google.android.exoplayer2.C.INDEX_UNSET] is
|
* @param startWindowIndex The window index to start playback from. If [C.INDEX_UNSET] is
|
||||||
* passed, the current position is not reset.
|
* passed, the current position is not reset.
|
||||||
* @param startPositionMs The position in milliseconds to start playback from. If [ ][com.google.android.exoplayer2.C.TIME_UNSET] is passed, the default position of the given window is used. In any case, if
|
* @param startPositionMs The position in milliseconds to start playback from. If [ ][C.TIME_UNSET] is passed, the default position of the given window is used. In any case, if
|
||||||
* `startWindowIndex` is set to [com.google.android.exoplayer2.C.INDEX_UNSET], this parameter is ignored and the
|
* `startWindowIndex` is set to [C.INDEX_UNSET], this parameter is ignored and the
|
||||||
* position is not reset at all.
|
* position is not reset at all.
|
||||||
* @throws com.google.android.exoplayer2.IllegalSeekPositionException If the provided `startWindowIndex` is not within the
|
* @throws androidx.media3.common.IllegalSeekPositionException If the provided `startWindowIndex` is not within the
|
||||||
* bounds of the list of media items.
|
* bounds of the list of media items.
|
||||||
*/
|
*/
|
||||||
override fun setMediaItems(
|
override fun setMediaItems(
|
||||||
|
@ -611,10 +611,10 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the player's currently available [com.google.android.exoplayer2.Player.Commands].
|
* Returns the player's currently available [Commands].
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The returned [com.google.android.exoplayer2.Player.Commands] are not updated when available commands change. Use [ ][com.google.android.exoplayer2.Player.Listener.onAvailableCommandsChanged] to get an update when the available commands
|
* The returned [Commands] are not updated when available commands change. Use [ ][androidx.media3.common.Player.Listener.onAvailableCommandsChanged] to get an update when the available commands
|
||||||
* change.
|
* change.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -625,8 +625,8 @@ class MPVPlayer(
|
||||||
* [.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM] and [.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM]
|
* [.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM] and [.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM]
|
||||||
* are unavailable if there is no such [MediaItem].
|
* are unavailable if there is no such [MediaItem].
|
||||||
*
|
*
|
||||||
* @return The currently available [com.google.android.exoplayer2.Player.Commands].
|
* @return The currently available [Commands].
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onAvailableCommandsChanged
|
* @see androidx.media3.common.Player.Listener.onAvailableCommandsChanged
|
||||||
*/
|
*/
|
||||||
override fun getAvailableCommands(): Commands {
|
override fun getAvailableCommands(): Commands {
|
||||||
return Commands.Builder()
|
return Commands.Builder()
|
||||||
|
@ -682,10 +682,10 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current [playback state][com.google.android.exoplayer2.Player.State] of the player.
|
* Returns the current [playback state][androidx.media3.common.Player.State] of the player.
|
||||||
*
|
*
|
||||||
* @return The current [playback state][com.google.android.exoplayer2.Player.State].
|
* @return The current [playback state][androidx.media3.common.Player.State].
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onPlaybackStateChanged
|
* @see androidx.media3.common.Player.Listener.onPlaybackStateChanged
|
||||||
*/
|
*/
|
||||||
override fun getPlaybackState(): Int {
|
override fun getPlaybackState(): Int {
|
||||||
return playbackState
|
return playbackState
|
||||||
|
@ -694,8 +694,8 @@ class MPVPlayer(
|
||||||
/**
|
/**
|
||||||
* Returns the reason why playback is suppressed even though [.getPlayWhenReady] is `true`, or [.PLAYBACK_SUPPRESSION_REASON_NONE] if playback is not suppressed.
|
* Returns the reason why playback is suppressed even though [.getPlayWhenReady] is `true`, or [.PLAYBACK_SUPPRESSION_REASON_NONE] if playback is not suppressed.
|
||||||
*
|
*
|
||||||
* @return The current [playback suppression reason][com.google.android.exoplayer2.Player.PlaybackSuppressionReason].
|
* @return The current [playback suppression reason][androidx.media3.common.Player.PlaybackSuppressionReason].
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onPlaybackSuppressionReasonChanged
|
* @see androidx.media3.common.Player.Listener.onPlaybackSuppressionReasonChanged
|
||||||
*/
|
*/
|
||||||
override fun getPlaybackSuppressionReason(): Int {
|
override fun getPlaybackSuppressionReason(): Int {
|
||||||
return PLAYBACK_SUPPRESSION_REASON_NONE
|
return PLAYBACK_SUPPRESSION_REASON_NONE
|
||||||
|
@ -703,7 +703,7 @@ class MPVPlayer(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error that caused playback to fail. This is the same error that will have been
|
* Returns the error that caused playback to fail. This is the same error that will have been
|
||||||
* reported via [com.google.android.exoplayer2.Player.Listener.onPlayerError] at the time of failure. It
|
* reported via [androidx.media3.common.Player.Listener.onPlayerError] at the time of failure. It
|
||||||
* can be queried using this method until the player is re-prepared.
|
* can be queried using this method until the player is re-prepared.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -711,7 +711,7 @@ class MPVPlayer(
|
||||||
* [.STATE_IDLE].
|
* [.STATE_IDLE].
|
||||||
*
|
*
|
||||||
* @return The error, or `null`.
|
* @return The error, or `null`.
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onPlayerError
|
* @see androidx.media3.common.Player.Listener.onPlayerError
|
||||||
*/
|
*/
|
||||||
override fun getPlayerError(): ExoPlaybackException? {
|
override fun getPlayerError(): ExoPlaybackException? {
|
||||||
return null
|
return null
|
||||||
|
@ -741,14 +741,14 @@ class MPVPlayer(
|
||||||
* Whether playback will proceed when [.getPlaybackState] == [.STATE_READY].
|
* Whether playback will proceed when [.getPlaybackState] == [.STATE_READY].
|
||||||
*
|
*
|
||||||
* @return Whether playback will proceed when ready.
|
* @return Whether playback will proceed when ready.
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onPlayWhenReadyChanged
|
* @see androidx.media3.common.Player.Listener.onPlayWhenReadyChanged
|
||||||
*/
|
*/
|
||||||
override fun getPlayWhenReady(): Boolean {
|
override fun getPlayWhenReady(): Boolean {
|
||||||
return currentPlayWhenReady
|
return currentPlayWhenReady
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the [com.google.android.exoplayer2.Player.RepeatMode] to be used for playback.
|
* Sets the [androidx.media3.common.Player.RepeatMode] to be used for playback.
|
||||||
*
|
*
|
||||||
* @param repeatMode The repeat mode.
|
* @param repeatMode The repeat mode.
|
||||||
*/
|
*/
|
||||||
|
@ -757,10 +757,10 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current [com.google.android.exoplayer2.Player.RepeatMode] used for playback.
|
* Returns the current [androidx.media3.common.Player.RepeatMode] used for playback.
|
||||||
*
|
*
|
||||||
* @return The current repeat mode.
|
* @return The current repeat mode.
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onRepeatModeChanged
|
* @see androidx.media3.common.Player.Listener.onRepeatModeChanged
|
||||||
*/
|
*/
|
||||||
override fun getRepeatMode(): Int {
|
override fun getRepeatMode(): Int {
|
||||||
return repeatMode
|
return repeatMode
|
||||||
|
@ -778,7 +778,7 @@ class MPVPlayer(
|
||||||
/**
|
/**
|
||||||
* Returns whether shuffling of windows is enabled.
|
* Returns whether shuffling of windows is enabled.
|
||||||
*
|
*
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onShuffleModeEnabledChanged
|
* @see androidx.media3.common.Player.Listener.onShuffleModeEnabledChanged
|
||||||
*/
|
*/
|
||||||
override fun getShuffleModeEnabled(): Boolean {
|
override fun getShuffleModeEnabled(): Boolean {
|
||||||
return false
|
return false
|
||||||
|
@ -788,7 +788,7 @@ class MPVPlayer(
|
||||||
* Whether the player is currently loading the source.
|
* Whether the player is currently loading the source.
|
||||||
*
|
*
|
||||||
* @return Whether the player is currently loading the source.
|
* @return Whether the player is currently loading the source.
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onIsLoadingChanged
|
* @see androidx.media3.common.Player.Listener.onIsLoadingChanged
|
||||||
*/
|
*/
|
||||||
override fun isLoading(): Boolean {
|
override fun isLoading(): Boolean {
|
||||||
return false
|
return false
|
||||||
|
@ -798,9 +798,9 @@ class MPVPlayer(
|
||||||
* Seeks to a position specified in milliseconds in the specified window.
|
* Seeks to a position specified in milliseconds in the specified window.
|
||||||
*
|
*
|
||||||
* @param windowIndex The index of the window.
|
* @param windowIndex The index of the window.
|
||||||
* @param positionMs The seek position in the specified window, or [com.google.android.exoplayer2.C.TIME_UNSET] to seek to
|
* @param positionMs The seek position in the specified window, or [C.TIME_UNSET] to seek to
|
||||||
* the window's default position.
|
* the window's default position.
|
||||||
* @throws com.google.android.exoplayer2.IllegalSeekPositionException If the player has a non-empty timeline and the provided
|
* @throws androidx.media3.common.IllegalSeekPositionException If the player has a non-empty timeline and the provided
|
||||||
* `windowIndex` is not within the bounds of the current timeline.
|
* `windowIndex` is not within the bounds of the current timeline.
|
||||||
*/
|
*/
|
||||||
override fun seekTo(windowIndex: Int, positionMs: Long) {
|
override fun seekTo(windowIndex: Int, positionMs: Long) {
|
||||||
|
@ -866,7 +866,7 @@ class MPVPlayer(
|
||||||
* player to the default, which means there is no speed or pitch adjustment.
|
* player to the default, which means there is no speed or pitch adjustment.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Playback parameters changes may cause the player to buffer. [ ][com.google.android.exoplayer2.Player.Listener.onPlaybackParametersChanged] will be called whenever the currently
|
* Playback parameters changes may cause the player to buffer. [ ][androidx.media3.common.Player.Listener.onPlaybackParametersChanged] will be called whenever the currently
|
||||||
* active playback parameters change.
|
* active playback parameters change.
|
||||||
*
|
*
|
||||||
* @param playbackParameters The playback parameters.
|
* @param playbackParameters The playback parameters.
|
||||||
|
@ -880,7 +880,7 @@ class MPVPlayer(
|
||||||
/**
|
/**
|
||||||
* Returns the currently active playback parameters.
|
* Returns the currently active playback parameters.
|
||||||
*
|
*
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onPlaybackParametersChanged
|
* @see androidx.media3.common.Player.Listener.onPlaybackParametersChanged
|
||||||
*/
|
*/
|
||||||
override fun getPlaybackParameters(): PlaybackParameters {
|
override fun getPlaybackParameters(): PlaybackParameters {
|
||||||
return playbackParameters
|
return playbackParameters
|
||||||
|
@ -914,11 +914,11 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTrackSelectionParameters(): TrackSelectionParameters {
|
override fun getTrackSelectionParameters(): TrackSelectionParameters {
|
||||||
TODO("Not yet implemented")
|
return trackSelectionParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTrackSelectionParameters(parameters: TrackSelectionParameters) {
|
override fun setTrackSelectionParameters(parameters: TrackSelectionParameters) {
|
||||||
TODO("Not yet implemented")
|
trackSelectionParameters = parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -927,15 +927,15 @@ class MPVPlayer(
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This [MediaMetadata] is a combination of the [MediaItem.mediaMetadata] and the
|
* This [MediaMetadata] is a combination of the [MediaItem.mediaMetadata] and the
|
||||||
* static and dynamic metadata sourced from [com.google.android.exoplayer2.Player.Listener.onMediaMetadataChanged] and
|
* static and dynamic metadata sourced from [androidx.media3.common.Player.Listener.onMediaMetadataChanged] and
|
||||||
* [com.google.android.exoplayer2.metadata.MetadataOutput.onMetadata].
|
* [androidx.media3.exoplayer.metadata.MetadataOutput.onMetadata].
|
||||||
*/
|
*/
|
||||||
override fun getMediaMetadata(): MediaMetadata {
|
override fun getMediaMetadata(): MediaMetadata {
|
||||||
return MediaMetadata.EMPTY
|
return MediaMetadata.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPlaylistMetadata(): MediaMetadata {
|
override fun getPlaylistMetadata(): MediaMetadata {
|
||||||
TODO("Not yet implemented")
|
return MediaMetadata.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setPlaylistMetadata(mediaMetadata: MediaMetadata) {
|
override fun setPlaylistMetadata(mediaMetadata: MediaMetadata) {
|
||||||
|
@ -945,7 +945,7 @@ class MPVPlayer(
|
||||||
/**
|
/**
|
||||||
* Returns the current [Timeline]. Never null, but may be empty.
|
* Returns the current [Timeline]. Never null, but may be empty.
|
||||||
*
|
*
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onTimelineChanged
|
* @see androidx.media3.common.Player.Listener.onTimelineChanged
|
||||||
*/
|
*/
|
||||||
override fun getCurrentTimeline(): Timeline {
|
override fun getCurrentTimeline(): Timeline {
|
||||||
return timeline
|
return timeline
|
||||||
|
@ -961,7 +961,7 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the duration of the current content window or ad in milliseconds, or [ ][com.google.android.exoplayer2.C.TIME_UNSET] if the duration is not known.
|
* Returns the duration of the current content window or ad in milliseconds, or [ ][C.TIME_UNSET] if the duration is not known.
|
||||||
*/
|
*/
|
||||||
override fun getDuration(): Long {
|
override fun getDuration(): Long {
|
||||||
return timeline.getWindow(currentMediaItemIndex, window).durationMs
|
return timeline.getWindow(currentMediaItemIndex, window).durationMs
|
||||||
|
@ -999,7 +999,7 @@ class MPVPlayer(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If [.isPlayingAd] returns true, returns the index of the ad group in the period
|
* If [.isPlayingAd] returns true, returns the index of the ad group in the period
|
||||||
* currently being played. Returns [com.google.android.exoplayer2.C.INDEX_UNSET] otherwise.
|
* currently being played. Returns [C.INDEX_UNSET] otherwise.
|
||||||
*/
|
*/
|
||||||
override fun getCurrentAdGroupIndex(): Int {
|
override fun getCurrentAdGroupIndex(): Int {
|
||||||
return C.INDEX_UNSET
|
return C.INDEX_UNSET
|
||||||
|
@ -1007,7 +1007,7 @@ class MPVPlayer(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If [.isPlayingAd] returns true, returns the index of the ad in its ad group. Returns
|
* If [.isPlayingAd] returns true, returns the index of the ad in its ad group. Returns
|
||||||
* [com.google.android.exoplayer2.C.INDEX_UNSET] otherwise.
|
* [C.INDEX_UNSET] otherwise.
|
||||||
*/
|
*/
|
||||||
override fun getCurrentAdIndexInAdGroup(): Int {
|
override fun getCurrentAdIndexInAdGroup(): Int {
|
||||||
return C.INDEX_UNSET
|
return C.INDEX_UNSET
|
||||||
|
@ -1051,7 +1051,7 @@ class MPVPlayer(
|
||||||
* @return The linear gain applied to all audio channels.
|
* @return The linear gain applied to all audio channels.
|
||||||
*/
|
*/
|
||||||
override fun getVolume(): Float {
|
override fun getVolume(): Float {
|
||||||
TODO("Not yet implemented")
|
return MPVLib.getPropertyInt("volume") / 100F
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1154,7 +1154,7 @@ class MPVPlayer(
|
||||||
* The video's width and height are `0` if there is no video or its size has not been
|
* The video's width and height are `0` if there is no video or its size has not been
|
||||||
* determined yet.
|
* determined yet.
|
||||||
*
|
*
|
||||||
* @see com.google.android.exoplayer2.Player.Listener.onVideoSizeChanged
|
* @see androidx.media3.common.Player.Listener.onVideoSizeChanged
|
||||||
*/
|
*/
|
||||||
override fun getVideoSize(): VideoSize {
|
override fun getVideoSize(): VideoSize {
|
||||||
return VideoSize.UNKNOWN
|
return VideoSize.UNKNOWN
|
||||||
|
@ -1169,14 +1169,14 @@ class MPVPlayer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the current [Cues][Cue]. This list may be empty. */
|
/** Returns the current [CueGroup]. This list may be empty. */
|
||||||
override fun getCurrentCues(): CueGroup {
|
override fun getCurrentCues(): CueGroup {
|
||||||
TODO("Not yet implemented")
|
return CueGroup(emptyList(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the device information. */
|
/** Gets the device information. */
|
||||||
override fun getDeviceInfo(): DeviceInfo {
|
override fun getDeviceInfo(): DeviceInfo {
|
||||||
TODO("Not yet implemented")
|
return DeviceInfo(DeviceInfo.PLAYBACK_TYPE_LOCAL, 0, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1184,7 +1184,7 @@ class MPVPlayer(
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* For devices with [local playback][DeviceInfo.PLAYBACK_TYPE_LOCAL], the volume returned
|
* For devices with [local playback][DeviceInfo.PLAYBACK_TYPE_LOCAL], the volume returned
|
||||||
* by this method varies according to the current [stream type][com.google.android.exoplayer2.C.StreamType]. The stream
|
* by this method varies according to the current [stream type][C.StreamType]. The stream
|
||||||
* type is determined by [AudioAttributes.usage] which can be converted to stream type with
|
* type is determined by [AudioAttributes.usage] which can be converted to stream type with
|
||||||
* [Util.getStreamTypeForAudioUsage].
|
* [Util.getStreamTypeForAudioUsage].
|
||||||
*
|
*
|
||||||
|
@ -1193,12 +1193,12 @@ class MPVPlayer(
|
||||||
* remote device is returned.
|
* remote device is returned.
|
||||||
*/
|
*/
|
||||||
override fun getDeviceVolume(): Int {
|
override fun getDeviceVolume(): Int {
|
||||||
TODO("Not yet implemented")
|
return MPVLib.getPropertyInt("volume")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets whether the device is muted or not. */
|
/** Gets whether the device is muted or not. */
|
||||||
override fun isDeviceMuted(): Boolean {
|
override fun isDeviceMuted(): Boolean {
|
||||||
TODO("Not yet implemented")
|
return MPVLib.getPropertyBoolean("mute")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,7 +42,7 @@ internal class TvPlayerActivity : BasePlayerActivity() {
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
|
||||||
binding.playerView.player = viewModel.player
|
binding.playerView.player = viewModel.player
|
||||||
val playerControls = binding.playerView.findViewById<View>(R.id.tv_player_controls)
|
val playerControls = binding.playerView.findViewById<View>(R.id.player_controls)
|
||||||
configureInsets(playerControls)
|
configureInsets(playerControls)
|
||||||
|
|
||||||
bind()
|
bind()
|
||||||
|
@ -51,7 +51,7 @@ internal class TvPlayerActivity : BasePlayerActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
return if (!binding.playerView.isControllerVisible) {
|
return if (!binding.playerView.isControllerFullyVisible) {
|
||||||
binding.playerView.showController()
|
binding.playerView.showController()
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,8 +3,8 @@ package dev.jdtech.jellyfin.utils
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.google.android.exoplayer2.C.DEFAULT_SEEK_BACK_INCREMENT_MS
|
import androidx.media3.common.C.DEFAULT_SEEK_BACK_INCREMENT_MS
|
||||||
import com.google.android.exoplayer2.C.DEFAULT_SEEK_FORWARD_INCREMENT_MS
|
import androidx.media3.common.C.DEFAULT_SEEK_FORWARD_INCREMENT_MS
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AppPreferences
|
class AppPreferences
|
||||||
|
@ -26,6 +26,8 @@ constructor(
|
||||||
val dynamicColors = sharedPreferences.getBoolean(Constants.PREF_DYNAMIC_COLORS, true)
|
val dynamicColors = sharedPreferences.getBoolean(Constants.PREF_DYNAMIC_COLORS, true)
|
||||||
|
|
||||||
// Player
|
// Player
|
||||||
|
val displayExtendedTitle = sharedPreferences.getBoolean(Constants.PREF_DISPLAY_EXTENDED_TITLE, false)
|
||||||
|
|
||||||
val playerGestures = sharedPreferences.getBoolean(Constants.PREF_PLAYER_GESTURES, true)
|
val playerGestures = sharedPreferences.getBoolean(Constants.PREF_PLAYER_GESTURES, true)
|
||||||
val playerGesturesVB = sharedPreferences.getBoolean(Constants.PREF_PLAYER_GESTURES_VB, true)
|
val playerGesturesVB = sharedPreferences.getBoolean(Constants.PREF_PLAYER_GESTURES_VB, true)
|
||||||
val playerGesturesZoom = sharedPreferences.getBoolean(Constants.PREF_PLAYER_GESTURES_ZOOM, true)
|
val playerGesturesZoom = sharedPreferences.getBoolean(Constants.PREF_PLAYER_GESTURES_ZOOM, true)
|
||||||
|
|
|
@ -9,6 +9,7 @@ object Constants {
|
||||||
|
|
||||||
// pref
|
// pref
|
||||||
const val PREF_CURRENT_SERVER = "pref_current_server"
|
const val PREF_CURRENT_SERVER = "pref_current_server"
|
||||||
|
const val PREF_DISPLAY_EXTENDED_TITLE = "pref_player_display_extended_title"
|
||||||
const val PREF_PLAYER_GESTURES = "pref_player_gestures"
|
const val PREF_PLAYER_GESTURES = "pref_player_gestures"
|
||||||
const val PREF_PLAYER_GESTURES_VB = "pref_player_gestures_vb"
|
const val PREF_PLAYER_GESTURES_VB = "pref_player_gestures_vb"
|
||||||
const val PREF_PLAYER_GESTURES_ZOOM = "pref_player_gestures_zoom"
|
const val PREF_PLAYER_GESTURES_ZOOM = "pref_player_gestures_zoom"
|
||||||
|
|
|
@ -10,8 +10,8 @@ import android.view.ScaleGestureDetector
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
|
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
|
||||||
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF
|
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
import androidx.media3.ui.AspectRatioFrameLayout
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
import dev.jdtech.jellyfin.PlayerActivity
|
import dev.jdtech.jellyfin.PlayerActivity
|
||||||
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
@ -20,7 +20,7 @@ import timber.log.Timber
|
||||||
class PlayerGestureHelper(
|
class PlayerGestureHelper(
|
||||||
private val appPreferences: AppPreferences,
|
private val appPreferences: AppPreferences,
|
||||||
private val activity: PlayerActivity,
|
private val activity: PlayerActivity,
|
||||||
private val playerView: StyledPlayerView,
|
private val playerView: PlayerView,
|
||||||
private val audioManager: AudioManager
|
private val audioManager: AudioManager
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,14 +7,14 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.media3.common.AudioAttributes
|
||||||
import com.google.android.exoplayer2.C
|
import androidx.media3.common.C
|
||||||
import com.google.android.exoplayer2.DefaultRenderersFactory
|
import androidx.media3.common.MediaItem
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
import androidx.media3.common.MediaMetadata
|
||||||
import com.google.android.exoplayer2.MediaItem
|
import androidx.media3.common.Player
|
||||||
import com.google.android.exoplayer2.Player
|
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||||
import com.google.android.exoplayer2.audio.AudioAttributes
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.jdtech.jellyfin.database.DownloadDatabaseDao
|
import dev.jdtech.jellyfin.database.DownloadDatabaseDao
|
||||||
import dev.jdtech.jellyfin.models.PlayerItem
|
import dev.jdtech.jellyfin.models.PlayerItem
|
||||||
|
@ -36,7 +36,7 @@ constructor(
|
||||||
application: Application,
|
application: Application,
|
||||||
private val jellyfinRepository: JellyfinRepository,
|
private val jellyfinRepository: JellyfinRepository,
|
||||||
private val downloadDatabase: DownloadDatabaseDao,
|
private val downloadDatabase: DownloadDatabaseDao,
|
||||||
appPreferences: AppPreferences,
|
private val appPreferences: AppPreferences,
|
||||||
) : ViewModel(), Player.Listener {
|
) : ViewModel(), Player.Listener {
|
||||||
val player: Player
|
val player: Player
|
||||||
|
|
||||||
|
@ -63,8 +63,6 @@ constructor(
|
||||||
var playbackSpeed: Float = 1f
|
var playbackSpeed: Float = 1f
|
||||||
var disableSubtitle: Boolean = false
|
var disableSubtitle: Boolean = false
|
||||||
|
|
||||||
private val sp = PreferenceManager.getDefaultSharedPreferences(application)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (appPreferences.playerMpv) {
|
if (appPreferences.playerMpv) {
|
||||||
player = MPVPlayer(
|
player = MPVPlayer(
|
||||||
|
@ -126,6 +124,11 @@ constructor(
|
||||||
MediaItem.Builder()
|
MediaItem.Builder()
|
||||||
.setMediaId(item.itemId.toString())
|
.setMediaId(item.itemId.toString())
|
||||||
.setUri(streamUrl)
|
.setUri(streamUrl)
|
||||||
|
.setMediaMetadata(
|
||||||
|
MediaMetadata.Builder()
|
||||||
|
.setTitle(item.name)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
.setSubtitleConfigurations(mediaSubtitles)
|
.setSubtitleConfigurations(mediaSubtitles)
|
||||||
.build()
|
.build()
|
||||||
mediaItems.add(mediaItem)
|
mediaItems.add(mediaItem)
|
||||||
|
@ -135,8 +138,7 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
player.setMediaItems(mediaItems, currentMediaItemIndex, items.getOrNull(currentMediaItemIndex)?.playbackPosition ?: C.TIME_UNSET)
|
player.setMediaItems(mediaItems, currentMediaItemIndex, items.getOrNull(currentMediaItemIndex)?.playbackPosition ?: C.TIME_UNSET)
|
||||||
val useMpv = sp.getBoolean("mpv_player", false)
|
if (!appPreferences.playerMpv || !playFromDownloads)
|
||||||
if (!useMpv || !playFromDownloads)
|
|
||||||
player.prepare() // TODO: This line causes a crash when playing from downloads with MPV
|
player.prepare() // TODO: This line causes a crash when playing from downloads with MPV
|
||||||
player.play()
|
player.play()
|
||||||
pollPosition(player)
|
pollPosition(player)
|
||||||
|
@ -196,10 +198,7 @@ constructor(
|
||||||
try {
|
try {
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
if (item.itemId.toString() == (player.currentMediaItem?.mediaId ?: "")) {
|
if (item.itemId.toString() == (player.currentMediaItem?.mediaId ?: "")) {
|
||||||
if (sp.getBoolean(
|
if (appPreferences.displayExtendedTitle && item.parentIndexNumber != null && item.indexNumber != null && item.name != null
|
||||||
"display_extended_title",
|
|
||||||
false
|
|
||||||
) && item.parentIndexNumber != null && item.indexNumber != null && item.name != null
|
|
||||||
)
|
)
|
||||||
_currentItemTitle.value =
|
_currentItemTitle.value =
|
||||||
"S${item.parentIndexNumber}:E${item.indexNumber} - ${item.name}"
|
"S${item.parentIndexNumber}:E${item.indexNumber} - ${item.name}"
|
||||||
|
|
|
@ -5,7 +5,7 @@ import android.net.Uri
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.google.android.exoplayer2.util.MimeTypes
|
import androidx.media3.common.MimeTypes
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.jdtech.jellyfin.R
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.database.DownloadDatabaseDao
|
import dev.jdtech.jellyfin.database.DownloadDatabaseDao
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/tv_player_controls"
|
android:id="@+id/player_controls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/player_background"
|
android:background="@color/player_background"
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
app:layout_constraintStart_toEndOf="@id/btn_audio_track"
|
app:layout_constraintStart_toEndOf="@id/btn_audio_track"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@+id/exo_progress"
|
android:id="@+id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
|
@ -6,15 +6,13 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".PlayerActivity">
|
tools:context=".PlayerActivity">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.StyledPlayerView
|
<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"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
app:animation_enabled="false"
|
app:animation_enabled="false"
|
||||||
app:show_buffering="always">
|
app:show_buffering="always" />
|
||||||
|
|
||||||
</com.google.android.exoplayer2.ui.StyledPlayerView>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/progress_scrubber_layout"
|
android:id="@+id/progress_scrubber_layout"
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".PlayerActivity"
|
tools:context=".PlayerActivity">
|
||||||
>
|
|
||||||
|
|
||||||
<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"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
app:controller_layout_id="@layout/tv_player_controls"
|
app:animation_enabled="false"
|
||||||
app:show_buffering="always"
|
app:show_buffering="always" />
|
||||||
/>
|
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -212,7 +212,7 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<androidx.media3.ui.DefaultTimeBar
|
||||||
android:id="@+id/exo_progress"
|
android:id="@+id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
|
@ -2,7 +2,7 @@
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
<androidx.media3.ui.AspectRatioFrameLayout
|
||||||
android:id="@id/exo_content_frame"
|
android:id="@id/exo_content_frame"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -46,9 +46,9 @@
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
</androidx.media3.ui.AspectRatioFrameLayout>
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.SubtitleView
|
<androidx.media3.ui.SubtitleView
|
||||||
android:id="@id/exo_subtitles"
|
android:id="@id/exo_subtitles"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
app:key="display_extended_title"
|
app:key="pref_player_display_extended_title"
|
||||||
app:summary="@string/display_extended_title_summary"
|
app:summary="@string/display_extended_title_summary"
|
||||||
app:title="@string/display_extended_title" />
|
app:title="@string/display_extended_title" />
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ androidx-constraintlayout = "2.1.4"
|
||||||
androidx-core = "1.9.0"
|
androidx-core = "1.9.0"
|
||||||
androidx-leanback = "1.2.0-alpha02"
|
androidx-leanback = "1.2.0-alpha02"
|
||||||
androidx-lifecycle = "2.5.1"
|
androidx-lifecycle = "2.5.1"
|
||||||
|
androidx-media3 = "1.0.0-beta03"
|
||||||
androidx-navigation = "2.5.3"
|
androidx-navigation = "2.5.3"
|
||||||
androidx-paging = "3.1.1"
|
androidx-paging = "3.1.1"
|
||||||
androidx-preference = "1.2.0"
|
androidx-preference = "1.2.0"
|
||||||
|
@ -14,7 +15,6 @@ androidx-recyclerview = "1.2.1"
|
||||||
androidx-recyclerview-selection = "1.1.0"
|
androidx-recyclerview-selection = "1.1.0"
|
||||||
androidx-room = "2.4.3"
|
androidx-room = "2.4.3"
|
||||||
androidx-swiperefreshlayout = "1.1.0"
|
androidx-swiperefreshlayout = "1.1.0"
|
||||||
exoplayer = "2.18.2"
|
|
||||||
glide = "4.14.2"
|
glide = "4.14.2"
|
||||||
hilt = "2.44.2"
|
hilt = "2.44.2"
|
||||||
jellyfin = "1.3.7"
|
jellyfin = "1.3.7"
|
||||||
|
@ -33,6 +33,9 @@ androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-cor
|
||||||
androidx-leanback = { module = "androidx.leanback:leanback", version.ref = "androidx-leanback" }
|
androidx-leanback = { module = "androidx.leanback:leanback", version.ref = "androidx-leanback" }
|
||||||
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
|
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
|
||||||
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
|
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
|
||||||
|
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "androidx-media3" }
|
||||||
|
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "androidx-media3" }
|
||||||
|
androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "androidx-media3" }
|
||||||
androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" }
|
androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" }
|
||||||
androidx-navigation-ui = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" }
|
androidx-navigation-ui = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" }
|
||||||
androidx-paging = { module = "androidx.paging:paging-runtime-ktx", version.ref = "androidx-paging" }
|
androidx-paging = { module = "androidx.paging:paging-runtime-ktx", version.ref = "androidx-paging" }
|
||||||
|
@ -43,8 +46,6 @@ androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "
|
||||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" }
|
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" }
|
||||||
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" }
|
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" }
|
||||||
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
|
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
|
||||||
exoplayer-core = { module = "com.google.android.exoplayer:exoplayer-core", version.ref = "exoplayer" }
|
|
||||||
exoplayer-ui = { module = "com.google.android.exoplayer:exoplayer-ui", version.ref = "exoplayer" }
|
|
||||||
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
|
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
|
||||||
glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" }
|
glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" }
|
||||||
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
|
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
|
||||||
|
|
Loading…
Reference in a new issue