Rework how player items are created
Add support for intros and improve loading speed
This commit is contained in:
parent
fb1755e8b8
commit
25ac5524d7
11 changed files with 160 additions and 89 deletions
|
@ -38,7 +38,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (viewModel.player.value == null) {
|
if (viewModel.player.value == null) {
|
||||||
viewModel.initializePlayer(args.items, args.playbackPosition)
|
viewModel.initializePlayer(args.items)
|
||||||
}
|
}
|
||||||
hideSystemUI()
|
hideSystemUI()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@ class VideoVersionDialogFragment(
|
||||||
private val viewModel: MediaInfoViewModel
|
private val viewModel: MediaInfoViewModel
|
||||||
) : DialogFragment() {
|
) : DialogFragment() {
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val items = viewModel.mediaSources.value!!.map { it.name }
|
val items = viewModel.item.value?.mediaSources?.map { it.name }
|
||||||
return activity?.let {
|
return activity?.let {
|
||||||
val builder = AlertDialog.Builder(it)
|
val builder = AlertDialog.Builder(it)
|
||||||
builder.setTitle("Select a version")
|
builder.setTitle("Select a version")
|
||||||
.setItems(items.toTypedArray()) { _, which ->
|
.setItems(items?.toTypedArray()) { _, which ->
|
||||||
viewModel.navigateToPlayer(viewModel.mediaSources.value!![which])
|
viewModel.preparePlayerItems(which)
|
||||||
}
|
}
|
||||||
builder.create()
|
builder.create()
|
||||||
} ?: throw IllegalStateException("Activity cannot be null")
|
} ?: throw IllegalStateException("Activity cannot be null")
|
||||||
|
|
|
@ -91,10 +91,14 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
if (it) {
|
if (it) {
|
||||||
navigateToPlayerActivity(
|
navigateToPlayerActivity(
|
||||||
viewModel.playerItems.toTypedArray(),
|
viewModel.playerItems.toTypedArray(),
|
||||||
viewModel.item.value!!.userData!!.playbackPositionTicks.div(10000)
|
|
||||||
)
|
)
|
||||||
viewModel.doneNavigateToPlayer()
|
viewModel.doneNavigateToPlayer()
|
||||||
binding.playButton.setImageDrawable(ContextCompat.getDrawable(requireActivity(), R.drawable.ic_play))
|
binding.playButton.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
requireActivity(),
|
||||||
|
R.drawable.ic_play
|
||||||
|
)
|
||||||
|
)
|
||||||
binding.progressCircular.visibility = View.INVISIBLE
|
binding.progressCircular.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -102,7 +106,12 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
viewModel.playerItemsError.observe(viewLifecycleOwner, { errorMessage ->
|
viewModel.playerItemsError.observe(viewLifecycleOwner, { errorMessage ->
|
||||||
if (errorMessage != null) {
|
if (errorMessage != null) {
|
||||||
binding.playerItemsError.visibility = View.VISIBLE
|
binding.playerItemsError.visibility = View.VISIBLE
|
||||||
binding.playButton.setImageDrawable(ContextCompat.getDrawable(requireActivity(), R.drawable.ic_play))
|
binding.playButton.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
requireActivity(),
|
||||||
|
R.drawable.ic_play
|
||||||
|
)
|
||||||
|
)
|
||||||
binding.progressCircular.visibility = View.INVISIBLE
|
binding.progressCircular.visibility = View.INVISIBLE
|
||||||
} else {
|
} else {
|
||||||
binding.playerItemsError.visibility = View.GONE
|
binding.playerItemsError.visibility = View.GONE
|
||||||
|
@ -110,7 +119,9 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.playerItemsErrorDetails.setOnClickListener {
|
binding.playerItemsErrorDetails.setOnClickListener {
|
||||||
ErrorDialogFragment(viewModel.playerItemsError.value ?: getString(R.string.unknown_error)).show(parentFragmentManager, "errordialog")
|
ErrorDialogFragment(
|
||||||
|
viewModel.playerItemsError.value ?: getString(R.string.unknown_error)
|
||||||
|
).show(parentFragmentManager, "errordialog")
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.loadEpisode(args.episodeId)
|
viewModel.loadEpisode(args.episodeId)
|
||||||
|
@ -120,12 +131,10 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
private fun navigateToPlayerActivity(
|
private fun navigateToPlayerActivity(
|
||||||
playerItems: Array<PlayerItem>,
|
playerItems: Array<PlayerItem>,
|
||||||
playbackPosition: Long
|
|
||||||
) {
|
) {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
EpisodeBottomSheetFragmentDirections.actionEpisodeBottomSheetFragmentToPlayerActivity(
|
EpisodeBottomSheetFragmentDirections.actionEpisodeBottomSheetFragmentToPlayerActivity(
|
||||||
playerItems,
|
playerItems,
|
||||||
playbackPosition
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,10 @@ class MediaInfoFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.errorLayout.errorDetailsButton.setOnClickListener {
|
binding.errorLayout.errorDetailsButton.setOnClickListener {
|
||||||
ErrorDialogFragment(viewModel.error.value ?: getString(R.string.unknown_error)).show(parentFragmentManager, "errordialog")
|
ErrorDialogFragment(viewModel.error.value ?: getString(R.string.unknown_error)).show(
|
||||||
|
parentFragmentManager,
|
||||||
|
"errordialog"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.item.observe(viewLifecycleOwner, { item ->
|
viewModel.item.observe(viewLifecycleOwner, { item ->
|
||||||
|
@ -91,8 +94,7 @@ class MediaInfoFragment : Fragment() {
|
||||||
viewModel.navigateToPlayer.observe(viewLifecycleOwner, { playerItems ->
|
viewModel.navigateToPlayer.observe(viewLifecycleOwner, { playerItems ->
|
||||||
if (playerItems != null) {
|
if (playerItems != null) {
|
||||||
navigateToPlayerActivity(
|
navigateToPlayerActivity(
|
||||||
playerItems,
|
playerItems
|
||||||
viewModel.item.value!!.userData!!.playbackPositionTicks.div(10000)
|
|
||||||
)
|
)
|
||||||
viewModel.doneNavigatingToPlayer()
|
viewModel.doneNavigatingToPlayer()
|
||||||
binding.playButton.setImageDrawable(
|
binding.playButton.setImageDrawable(
|
||||||
|
@ -139,7 +141,9 @@ class MediaInfoFragment : Fragment() {
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.playerItemsErrorDetails.setOnClickListener {
|
binding.playerItemsErrorDetails.setOnClickListener {
|
||||||
ErrorDialogFragment(viewModel.playerItemsError.value ?: getString(R.string.unknown_error)).show(parentFragmentManager, "errordialog")
|
ErrorDialogFragment(
|
||||||
|
viewModel.playerItemsError.value ?: getString(R.string.unknown_error)
|
||||||
|
).show(parentFragmentManager, "errordialog")
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.trailerButton.setOnClickListener {
|
binding.trailerButton.setOnClickListener {
|
||||||
|
@ -164,29 +168,14 @@ class MediaInfoFragment : Fragment() {
|
||||||
binding.playButton.setImageResource(android.R.color.transparent)
|
binding.playButton.setImageResource(android.R.color.transparent)
|
||||||
binding.progressCircular.visibility = View.VISIBLE
|
binding.progressCircular.visibility = View.VISIBLE
|
||||||
if (args.itemType == "Movie") {
|
if (args.itemType == "Movie") {
|
||||||
if (!viewModel.mediaSources.value.isNullOrEmpty()) {
|
if (viewModel.item.value?.mediaSources != null) {
|
||||||
if (viewModel.mediaSources.value!!.size > 1) {
|
if (viewModel.item.value?.mediaSources?.size!! > 1) {
|
||||||
VideoVersionDialogFragment(viewModel).show(
|
VideoVersionDialogFragment(viewModel).show(
|
||||||
parentFragmentManager,
|
parentFragmentManager,
|
||||||
"videoversiondialog"
|
"videoversiondialog"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
navigateToPlayerActivity(
|
viewModel.preparePlayerItems()
|
||||||
arrayOf(
|
|
||||||
PlayerItem(
|
|
||||||
args.itemId,
|
|
||||||
viewModel.mediaSources.value!![0].id!!
|
|
||||||
)
|
|
||||||
),
|
|
||||||
viewModel.item.value!!.userData!!.playbackPositionTicks.div(10000),
|
|
||||||
)
|
|
||||||
binding.playButton.setImageDrawable(
|
|
||||||
ContextCompat.getDrawable(
|
|
||||||
requireActivity(),
|
|
||||||
R.drawable.ic_play
|
|
||||||
)
|
|
||||||
)
|
|
||||||
binding.progressCircular.visibility = View.INVISIBLE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (args.itemType == "Series") {
|
} else if (args.itemType == "Series") {
|
||||||
|
@ -232,12 +221,10 @@ class MediaInfoFragment : Fragment() {
|
||||||
|
|
||||||
private fun navigateToPlayerActivity(
|
private fun navigateToPlayerActivity(
|
||||||
playerItems: Array<PlayerItem>,
|
playerItems: Array<PlayerItem>,
|
||||||
playbackPosition: Long,
|
|
||||||
) {
|
) {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
MediaInfoFragmentDirections.actionMediaInfoFragmentToPlayerActivity(
|
MediaInfoFragmentDirections.actionMediaInfoFragmentToPlayerActivity(
|
||||||
playerItems,
|
playerItems,
|
||||||
playbackPosition
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,6 @@ import java.util.*
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class PlayerItem(
|
data class PlayerItem(
|
||||||
val itemId: UUID,
|
val itemId: UUID,
|
||||||
val mediaSourceId: String
|
val mediaSourceId: String,
|
||||||
|
val playbackPosition: Long
|
||||||
) : Parcelable
|
) : Parcelable
|
|
@ -54,4 +54,6 @@ interface JellyfinRepository {
|
||||||
suspend fun markAsPlayed(itemId: UUID)
|
suspend fun markAsPlayed(itemId: UUID)
|
||||||
|
|
||||||
suspend fun markAsUnplayed(itemId: UUID)
|
suspend fun markAsUnplayed(itemId: UUID)
|
||||||
|
|
||||||
|
suspend fun getIntros(itemId: UUID): List<BaseItemDto>
|
||||||
}
|
}
|
|
@ -266,4 +266,14 @@ class JellyfinRepositoryImpl(private val jellyfinApi: JellyfinApi) : JellyfinRep
|
||||||
jellyfinApi.playStateApi.markUnplayedItem(jellyfinApi.userId!!, itemId)
|
jellyfinApi.playStateApi.markUnplayedItem(jellyfinApi.userId!!, itemId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getIntros(itemId: UUID): List<BaseItemDto> {
|
||||||
|
val intros: List<BaseItemDto>
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
intros =
|
||||||
|
jellyfinApi.userLibraryApi.getIntros(jellyfinApi.userId!!, itemId).content.items
|
||||||
|
?: listOf()
|
||||||
|
}
|
||||||
|
return intros
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ import dev.jdtech.jellyfin.models.PlayerItem
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
|
import org.jellyfin.sdk.model.api.ItemFields
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
|
@ -74,17 +75,39 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createPlayerItems(startEpisode: BaseItemDto) {
|
private suspend fun createPlayerItems(startEpisode: BaseItemDto) {
|
||||||
|
playerItems.clear()
|
||||||
|
|
||||||
|
val playbackPosition = startEpisode.userData?.playbackPositionTicks?.div(10000) ?: 0
|
||||||
|
// Intros
|
||||||
|
var introsCount = 0
|
||||||
|
|
||||||
|
if (playbackPosition <= 0) {
|
||||||
|
val intros = jellyfinRepository.getIntros(startEpisode.id)
|
||||||
|
for (intro in intros) {
|
||||||
|
if (intro.mediaSources.isNullOrEmpty()) continue
|
||||||
|
playerItems.add(PlayerItem(intro.id, intro.mediaSources?.get(0)?.id!!, 0))
|
||||||
|
introsCount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val episodes = jellyfinRepository.getEpisodes(
|
val episodes = jellyfinRepository.getEpisodes(
|
||||||
startEpisode.seriesId!!,
|
startEpisode.seriesId!!,
|
||||||
startEpisode.seasonId!!,
|
startEpisode.seasonId!!,
|
||||||
startItemId = startEpisode.id
|
startItemId = startEpisode.id,
|
||||||
|
fields = listOf(ItemFields.MEDIA_SOURCES)
|
||||||
)
|
)
|
||||||
for (episode in episodes) {
|
for (episode in episodes) {
|
||||||
val mediaSources = jellyfinRepository.getMediaSources(episode.id)
|
if (episode.mediaSources.isNullOrEmpty()) continue
|
||||||
if (mediaSources.isEmpty()) continue
|
playerItems.add(
|
||||||
playerItems.add(PlayerItem(episode.id, mediaSources[0].id!!))
|
PlayerItem(
|
||||||
|
episode.id,
|
||||||
|
episode.mediaSources?.get(0)?.id!!,
|
||||||
|
playbackPosition
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (playerItems.isEmpty()) throw Exception("No playable items found")
|
|
||||||
|
if (playerItems.isEmpty() || playerItems.count() == introsCount) throw Exception("No playable items found")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun markAsPlayed(itemId: UUID) {
|
fun markAsPlayed(itemId: UUID) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
import org.jellyfin.sdk.model.api.ItemFields
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -52,9 +52,6 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
private val _seasons = MutableLiveData<List<BaseItemDto>>()
|
private val _seasons = MutableLiveData<List<BaseItemDto>>()
|
||||||
val seasons: LiveData<List<BaseItemDto>> = _seasons
|
val seasons: LiveData<List<BaseItemDto>> = _seasons
|
||||||
|
|
||||||
private val _mediaSources = MutableLiveData<List<MediaSourceInfo>>()
|
|
||||||
val mediaSources: LiveData<List<MediaSourceInfo>> = _mediaSources
|
|
||||||
|
|
||||||
private val _navigateToPlayer = MutableLiveData<Array<PlayerItem>>()
|
private val _navigateToPlayer = MutableLiveData<Array<PlayerItem>>()
|
||||||
val navigateToPlayer: LiveData<Array<PlayerItem>> = _navigateToPlayer
|
val navigateToPlayer: LiveData<Array<PlayerItem>> = _navigateToPlayer
|
||||||
|
|
||||||
|
@ -91,9 +88,6 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
_nextUp.value = getNextUp(itemId)
|
_nextUp.value = getNextUp(itemId)
|
||||||
_seasons.value = jellyfinRepository.getSeasons(itemId)
|
_seasons.value = jellyfinRepository.getSeasons(itemId)
|
||||||
}
|
}
|
||||||
if (itemType == "Movie") {
|
|
||||||
_mediaSources.value = jellyfinRepository.getMediaSources(itemId)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
_error.value = e.toString()
|
_error.value = e.toString()
|
||||||
|
@ -183,11 +177,11 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun preparePlayerItems() {
|
fun preparePlayerItems(mediaSourceIndex: Int? = null) {
|
||||||
_playerItemsError.value = null
|
_playerItemsError.value = null
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
createPlayerItems(_item.value!!)
|
createPlayerItems(_item.value!!, mediaSourceIndex)
|
||||||
_navigateToPlayer.value = playerItems.toTypedArray()
|
_navigateToPlayer.value = playerItems.toTypedArray()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
_playerItemsError.value = e.message
|
_playerItemsError.value = e.message
|
||||||
|
@ -195,35 +189,76 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createPlayerItems(series: BaseItemDto) {
|
private suspend fun createPlayerItems(series: BaseItemDto, mediaSourceIndex: Int? = null) {
|
||||||
if (nextUp.value != null) {
|
playerItems.clear()
|
||||||
val startEpisode = nextUp.value!!
|
|
||||||
val episodes = jellyfinRepository.getEpisodes(
|
val playbackPosition = item.value?.userData?.playbackPositionTicks?.div(10000) ?: 0
|
||||||
startEpisode.seriesId!!,
|
|
||||||
startEpisode.seasonId!!,
|
// Intros
|
||||||
startItemId = startEpisode.id
|
var introsCount = 0
|
||||||
)
|
|
||||||
for (episode in episodes) {
|
if (playbackPosition <= 0) {
|
||||||
val mediaSources = jellyfinRepository.getMediaSources(episode.id)
|
val intros = jellyfinRepository.getIntros(series.id)
|
||||||
if (mediaSources.isEmpty()) continue
|
for (intro in intros) {
|
||||||
playerItems.add(PlayerItem(episode.id, mediaSources[0].id!!))
|
if (intro.mediaSources.isNullOrEmpty()) continue
|
||||||
|
playerItems.add(PlayerItem(intro.id, intro.mediaSources?.get(0)?.id!!, 0))
|
||||||
|
introsCount += 1
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
for (season in seasons.value!!) {
|
|
||||||
if (season.indexNumber == 0) continue
|
when (series.type) {
|
||||||
val episodes = jellyfinRepository.getEpisodes(series.id, season.id)
|
"Movie" -> {
|
||||||
for (episode in episodes) {
|
playerItems.add(
|
||||||
val mediaSources = jellyfinRepository.getMediaSources(episode.id)
|
PlayerItem(
|
||||||
if (mediaSources.isEmpty()) continue
|
series.id,
|
||||||
playerItems.add(PlayerItem(episode.id, mediaSources[0].id!!))
|
series.mediaSources?.get(mediaSourceIndex ?: 0)?.id!!,
|
||||||
|
playbackPosition
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"Series" -> {
|
||||||
|
if (nextUp.value != null) {
|
||||||
|
val startEpisode = nextUp.value!!
|
||||||
|
val episodes = jellyfinRepository.getEpisodes(
|
||||||
|
startEpisode.seriesId!!,
|
||||||
|
startEpisode.seasonId!!,
|
||||||
|
startItemId = startEpisode.id,
|
||||||
|
fields = listOf(ItemFields.MEDIA_SOURCES)
|
||||||
|
)
|
||||||
|
for (episode in episodes) {
|
||||||
|
if (episode.mediaSources.isNullOrEmpty()) continue
|
||||||
|
playerItems.add(
|
||||||
|
PlayerItem(
|
||||||
|
episode.id,
|
||||||
|
episode.mediaSources?.get(0)?.id!!,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (season in seasons.value!!) {
|
||||||
|
if (season.indexNumber == 0) continue
|
||||||
|
val episodes = jellyfinRepository.getEpisodes(
|
||||||
|
series.id,
|
||||||
|
season.id,
|
||||||
|
fields = listOf(ItemFields.MEDIA_SOURCES)
|
||||||
|
)
|
||||||
|
for (episode in episodes) {
|
||||||
|
if (episode.mediaSources.isNullOrEmpty()) continue
|
||||||
|
playerItems.add(
|
||||||
|
PlayerItem(
|
||||||
|
episode.id,
|
||||||
|
episode.mediaSources?.get(0)?.id!!,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (playerItems.isEmpty()) throw Exception("No playable items found")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun navigateToPlayer(mediaSource: MediaSourceInfo) {
|
if (playerItems.isEmpty() || playerItems.count() == introsCount) throw Exception("No playable items found")
|
||||||
_navigateToPlayer.value = arrayOf(PlayerItem(item.value!!.id, mediaSource.id!!))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doneNavigatingToPlayer() {
|
fun doneNavigatingToPlayer() {
|
||||||
|
|
|
@ -39,8 +39,7 @@ constructor(
|
||||||
private val sp = PreferenceManager.getDefaultSharedPreferences(application)
|
private val sp = PreferenceManager.getDefaultSharedPreferences(application)
|
||||||
|
|
||||||
fun initializePlayer(
|
fun initializePlayer(
|
||||||
items: Array<PlayerItem>,
|
items: Array<PlayerItem>
|
||||||
playbackPosition: Long
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val renderersFactory =
|
val renderersFactory =
|
||||||
|
@ -61,18 +60,22 @@ constructor(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val mediaItems: MutableList<MediaItem> = mutableListOf()
|
val mediaItems: MutableList<MediaItem> = mutableListOf()
|
||||||
|
|
||||||
for (item in items) {
|
try {
|
||||||
val streamUrl = jellyfinRepository.getStreamUrl(item.itemId, item.mediaSourceId)
|
for (item in items) {
|
||||||
Timber.d("Stream url: $streamUrl")
|
val streamUrl = jellyfinRepository.getStreamUrl(item.itemId, item.mediaSourceId)
|
||||||
val mediaItem =
|
Timber.d("Stream url: $streamUrl")
|
||||||
MediaItem.Builder()
|
val mediaItem =
|
||||||
.setMediaId(item.itemId.toString())
|
MediaItem.Builder()
|
||||||
.setUri(streamUrl)
|
.setMediaId(item.itemId.toString())
|
||||||
.build()
|
.setUri(streamUrl)
|
||||||
mediaItems.add(mediaItem)
|
.build()
|
||||||
|
mediaItems.add(mediaItem)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
player.setMediaItems(mediaItems, currentWindow, playbackPosition)
|
player.setMediaItems(mediaItems, currentWindow, items[0].playbackPosition)
|
||||||
player.playWhenReady = playWhenReady
|
player.playWhenReady = playWhenReady
|
||||||
player.prepare()
|
player.prepare()
|
||||||
_player.value = player
|
_player.value = player
|
||||||
|
@ -131,7 +134,11 @@ constructor(
|
||||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||||
Timber.d("Playing MediaItem: ${mediaItem?.mediaId}")
|
Timber.d("Playing MediaItem: ${mediaItem?.mediaId}")
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
jellyfinRepository.postPlaybackStart(UUID.fromString(mediaItem?.mediaId))
|
try {
|
||||||
|
jellyfinRepository.postPlaybackStart(UUID.fromString(mediaItem?.mediaId))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,9 +160,6 @@
|
||||||
<argument
|
<argument
|
||||||
android:name="items"
|
android:name="items"
|
||||||
app:argType="dev.jdtech.jellyfin.models.PlayerItem[]" />
|
app:argType="dev.jdtech.jellyfin.models.PlayerItem[]" />
|
||||||
<argument
|
|
||||||
android:name="playbackPosition"
|
|
||||||
app:argType="long" />
|
|
||||||
</activity>
|
</activity>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/favoriteFragment"
|
android:id="@+id/favoriteFragment"
|
||||||
|
|
Loading…
Reference in a new issue