chromecast bug fix

This commit is contained in:
LagradOst 2021-06-14 21:24:07 +02:00
parent 50abf2c74c
commit efeb42fd2e
3 changed files with 125 additions and 53 deletions

View file

@ -2,8 +2,7 @@ package com.lagradost.cloudstream3.ui
import android.os.Bundle
import android.view.Menu
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.View.*
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import com.fasterxml.jackson.databind.DeserializationFeature
@ -13,6 +12,7 @@ import com.google.android.gms.cast.MediaQueueItem
import com.google.android.gms.cast.MediaStatus.REPEAT_MODE_REPEAT_OFF
import com.google.android.gms.cast.framework.CastButtonFactory
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.uicontroller.UIController
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.lagradost.cloudstream3.APIHolder.getApiFromName
@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.sortUrls
import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks
import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
@ -38,6 +39,37 @@ class SkipOpController(val view: ImageView) : UIController() {
}
}
private fun RemoteMediaClient.getItemIndex(): Int? {
return try {
val index = this.mediaQueue?.itemIds?.indexOf(this.currentItem?.itemId ?: 0)
if (index == null || index < 0) null else index
} catch (e: Exception) {
null
}
}
class SkipNextEpisodeController(val view: ImageView) : UIController() {
init {
view.setImageResource(R.drawable.exo_controls_fastforward)
view.setOnClickListener {
remoteMediaClient?.let {
it.queueNext(JSONObject())
view.visibility = GONE // TO PREVENT MULTI CLICK
}
}
}
override fun onMediaStatusUpdated() {
super.onMediaStatusUpdated()
view.visibility = GONE
val currentIdIndex = remoteMediaClient?.getItemIndex() ?: return
val itemCount = remoteMediaClient?.mediaQueue?.itemCount ?: return
if (itemCount - currentIdIndex > 1 && remoteMediaClient?.isLoadingNextItem == false) {
view.visibility = VISIBLE
}
}
}
data class MetadataHolder(
val apiName: String,
val title: String?,
@ -59,13 +91,13 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
if (holder != null) {
val items = holder.currentLinks
if (items.isNotEmpty() && remoteMediaClient.currentItem != null) {
if (items.isNotEmpty() && remoteMediaClient?.currentItem != null) {
val builder = AlertDialog.Builder(view.context, R.style.AlertDialogCustom)
builder.setTitle("Pick source")
//https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation
val contentUrl = (remoteMediaClient.currentItem.media.contentUrl
?: remoteMediaClient.currentItem.media.contentId)
val contentUrl = (remoteMediaClient?.currentItem?.media?.contentUrl
?: remoteMediaClient?.currentItem?.media?.contentId)
builder.setSingleChoiceItems(
items.map { it.name }.toTypedArray(),
@ -73,30 +105,44 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
) { _, which ->
val epData = holder.episodes[holder.currentEpisodeIndex]
val mediaItem = getMediaInfo(epData,
fun loadMirror(index: Int) {
if (holder.currentLinks.size <= index) return
val mediaItem = getMediaInfo(
epData,
holder,
holder.currentLinks[which],
remoteMediaClient.mediaInfo.customData)
index,
remoteMediaClient?.mediaInfo?.customData)
val startAt = remoteMediaClient.approximateStreamPosition
val startAt = remoteMediaClient?.approximateStreamPosition ?: 0
try {
//remoteMediaClient.load(mediaItem, true, startAt)
try { // THIS IS VERY IMPORTANT BECAUSE WE NEVER WANT TO AUTOLOAD THE NEXT EPISODE
val currentIdIndex = remoteMediaClient?.getItemIndex()
val currentIdIndex = getItemIndex() ?: return@setSingleChoiceItems
val nextId = remoteMediaClient.mediaQueue.itemIds?.get(currentIdIndex?.plus(1) ?: 0)
val nextId = remoteMediaClient.mediaQueue.itemIds?.get(currentIdIndex + 1)
if (nextId != null) {
remoteMediaClient.queueInsertAndPlayItem(MediaQueueItem.Builder(mediaItem).build(),
if (currentIdIndex == null && nextId != null) {
awaitLinks(remoteMediaClient?.queueInsertAndPlayItem(MediaQueueItem.Builder(
mediaItem)
.build(),
nextId,
startAt,
JSONObject())
JSONObject())) {
loadMirror(index + 1)
}
} else {
remoteMediaClient.load(mediaItem, true, startAt)
awaitLinks(remoteMediaClient?.load(mediaItem, true, startAt)) {
loadMirror(index + 1)
}
}
} catch (e: Exception) {
remoteMediaClient.load(mediaItem, true, startAt)
awaitLinks(remoteMediaClient?.load(mediaItem, true, startAt)) {
loadMirror(index + 1)
}
}
}
loadMirror(which)
dialog.dismiss()
}
@ -107,11 +153,6 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
}
}
private fun getItemIndex(): Int? {
val index = remoteMediaClient?.mediaQueue?.itemIds?.indexOf(remoteMediaClient.currentItem.itemId)
return if (index == null || index < 0) null else index
}
private fun getCurrentMetaData(): MetadataHolder? {
return try {
val data = remoteMediaClient?.mediaInfo?.customData?.toString()
@ -133,7 +174,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
try {
if (meta != null && meta.episodes.size > meta.currentEpisodeIndex + 1) {
val currentIdIndex = getItemIndex() ?: return
val currentIdIndex = remoteMediaClient?.getItemIndex() ?: return
val itemCount = remoteMediaClient?.mediaQueue?.itemCount
if (itemCount != null && itemCount - currentIdIndex == 1 && !isLoadingMore) {
@ -152,19 +193,41 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
links.add(it)
}
}
if (res is Resource.Success) {
val sorted = sortUrls(links)
if (sorted.isNotEmpty()) {
val jsonCopy = meta.copy(currentLinks = sorted, currentEpisodeIndex = index)
val done = withContext(Dispatchers.IO) {
getMediaInfo(epData,
meta,
sorted.first(),
JSONObject(mapper.writeValueAsString(jsonCopy)))
JSONObject(mapper.writeValueAsString(jsonCopy))
}
val mediaInfo = getMediaInfo(
epData,
jsonCopy,
0,
done)
/*fun loadIndex(index: Int) {
println("LOAD INDEX::::: $index")
if (meta.currentLinks.size <= index) return
val info = getMediaInfo(
epData,
meta,
index,
done)
awaitLinks(remoteMediaClient?.load(info, true, 0)) {
loadIndex(index + 1)
}
}*/
awaitLinks(remoteMediaClient?.queueAppendItem(MediaQueueItem.Builder(mediaInfo).build(),
JSONObject())) {
println("FAILED TO LOAD NEXT ITEM")
// loadIndex(1)
}
remoteMediaClient?.queueAppendItem(MediaQueueItem.Builder(done).build(), JSONObject())
isLoadingMore = false
}
}
@ -212,6 +275,6 @@ class ControllerActivity : ExpandedControllerActivity() {
uiMediaController.bindViewToUIController(sourcesButton, SelectSourceController(sourcesButton, this))
uiMediaController.bindViewToUIController(skipBackButton, SkipTimeController(skipBackButton, false))
uiMediaController.bindViewToUIController(skipForwardButton, SkipTimeController(skipForwardButton, true))
uiMediaController.bindViewToUIController(skipOpButton, SkipOpController(skipOpButton))
uiMediaController.bindViewToUIController(skipOpButton, SkipNextEpisodeController(skipOpButton))
}
}

View file

@ -517,10 +517,10 @@ class PlayerFragment : Fragment() {
val alphaAnimation = AlphaAnimation(0f, 1f)
alphaAnimation.duration = 100
alphaAnimation.fillAfter = true
video_go_back_holder.visibility = VISIBLE
video_go_back_holder?.visibility = VISIBLE
overlay_loading_skip_button.visibility = VISIBLE
loading_overlay.startAnimation(alphaAnimation)
overlay_loading_skip_button?.visibility = VISIBLE
loading_overlay?.startAnimation(alphaAnimation)
if (this::exoPlayer.isInitialized) {
isPlayerPlaying = exoPlayer.playWhenReady
playbackPosition = exoPlayer.currentPosition
@ -555,11 +555,10 @@ class PlayerFragment : Fragment() {
private fun savePos() {
if (this::exoPlayer.isInitialized) {
/*if (
&& exoPlayer.duration > 0 && exoPlayer.currentPosition > 0
) {
setViewPosDur(data!!, exoPlayer.currentPosition, exoPlayer.duration)
}*/
if (exoPlayer.duration > 0 && exoPlayer.currentPosition > 0) {
//TODO FIX SAVE POS
// setViewPosDur(data!!, exoPlayer.currentPosition, exoPlayer.duration)
}
}
}
@ -1175,11 +1174,10 @@ class PlayerFragment : Fragment() {
}
}
//TODO FIX NON PIP MODE BUG
override fun onDestroy() {
super.onDestroy()
isInPlayer = false
// releasePlayer()
releasePlayer()
activity?.showSystemUI()
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
@ -1247,6 +1245,7 @@ class PlayerFragment : Fragment() {
hasUsedFirstRender = false
try {
if (!isInPlayer) return
if (this::exoPlayer.isInitialized) {
savePos()
exoPlayer.release()

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.utils
import android.app.Activity
import android.content.Context
import android.net.Uri
import com.fasterxml.jackson.databind.DeserializationFeature
@ -19,7 +20,9 @@ import com.google.android.gms.common.images.WebImage
import com.lagradost.cloudstream3.ui.MetadataHolder
import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.Coroutines.main
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext
import org.json.JSONObject
import kotlin.concurrent.thread
@ -27,7 +30,8 @@ object CastHelper {
private val mapper: JsonMapper = JsonMapper.builder().addModule(KotlinModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()
fun getMediaInfo(epData: ResultEpisode, holder: MetadataHolder, link: ExtractorLink, data: JSONObject?): MediaInfo {
fun getMediaInfo(epData: ResultEpisode, holder: MetadataHolder, index: Int, data: JSONObject?): MediaInfo {
val link = holder.currentLinks[index]
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
(epData.name ?: "Episode ${epData.episode}") + " - ${link.name}")
@ -47,20 +51,22 @@ object CastHelper {
.build()
}
fun awaitLinks(pending: PendingResult<RemoteMediaClient.MediaChannelResult>?) {
fun awaitLinks(pending: PendingResult<RemoteMediaClient.MediaChannelResult>?, callback: (Boolean) -> Unit) {
if (pending == null) return
thread {
val res = pending.await()
main {
val res = withContext(Dispatchers.IO) { pending.await() }
when (res.status?.statusCode) {
CastStatusCodes.FAILED -> {
println("FAILED WITH DATA: " + res.customData)
callback.invoke(true)
println("FAILED AND LOAD NEXT")
}
else -> {
println("FAILED::: " + res.status)
}
}
}
}
}
}
}
}
fun Context.startCast(
apiName: String,
@ -80,16 +86,20 @@ object CastHelper {
val holder = MetadataHolder(apiName, title, poster, currentEpisodeIndex, episodes, currentLinks)
val index = startIndex ?: 0
val mediaItem =
getMediaInfo(epData, holder, currentLinks[startIndex ?: 0], JSONObject(mapper.writeValueAsString(holder)))
getMediaInfo(epData, holder, index, JSONObject(mapper.writeValueAsString(holder)))
val castPlayer = CastPlayer(castContext)
castPlayer.repeatMode = REPEAT_MODE_REPEAT_OFF
castPlayer.stop()
awaitLinks(castPlayer.loadItem(
MediaQueueItem.Builder(mediaItem).build(),
startTime ?: 0,
))
)) {
if (currentLinks.size > index + 1)
startCast(apiName, title, poster, currentEpisodeIndex, episodes, currentLinks, index + 1, startTime)
}
}
}