migrate playheads() to crunchyroll v2 api

This commit is contained in:
Jannik 2023-02-19 16:53:54 +01:00
parent 2e7db26d1d
commit d40ab9519c
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
7 changed files with 50 additions and 35 deletions

View File

@ -567,18 +567,20 @@ object Crunchyroll {
* @param episodeIDs A **[List]** of episodes IDs as strings.
* @return A **[Map]**<String, **[PlayheadObject]**> containing playback info.
*/
suspend fun playheads(episodeIDs: List<String>): PlayheadsMap {
val playheadsEndpoint = "/content/v1/playheads/$accountID/${episodeIDs.joinToString(",")}"
val parameters = listOf("locale" to Preferences.preferredSubtitleLocale.toLanguageTag())
suspend fun playheads(episodeIDs: List<String>): Playheads {
val playheadsEndpoint = "/content/v2/$accountID/playheads"
val parameters = listOf(
"content_ids" to episodeIDs.joinToString(","),
"preferred_audio_language" to Preferences.preferredAudioLocale.toLanguageTag(),
"locale" to Preferences.preferredSubtitleLocale.toLanguageTag()
)
return try {
requestGet(playheadsEndpoint, parameters)
} catch (ex: SerializationException) {
Log.e(TAG, "SerializationException in playheads().", ex)
emptyMap()
} catch (ex: Throwable) {
} catch (ex: Exception) {
Log.e(TAG, "Exception in playheads().", ex.cause)
emptyMap()
NonePlayheads
}
}

View File

@ -127,9 +127,6 @@ typealias SearchResult = Collection<SearchCollection>
typealias SearchCollection = Collection<Item>
typealias BrowseResult = Collection<Item>
typealias SimilarToResult = Collection<Item>
typealias Watchlist = Collection2<WatchlistItem>
typealias HistoryList = Collection2<UpNextAccountItem>
typealias UpNextSeriesList = Collection2<UpNextSeriesItem>
typealias RecommendationsList = Collection<Item>
typealias Benefits = Collection<Benefit>
@ -159,9 +156,13 @@ data class Images(val poster_tall: List<List<Poster>>, val poster_wide: List<Lis
data class Poster(val height: Int, val width: Int, val source: String, val type: String)
/**
* continue_watching_item data classes
* up next & watchlist data classes
*/
typealias Watchlist = Collection2<WatchlistItem>
typealias HistoryList = Collection2<UpNextAccountItem>
typealias UpNextSeriesList = Collection2<UpNextSeriesItem>
@Serializable
data class WatchlistItem(
@SerialName("panel") val panel: EpisodePanel,
@ -352,7 +353,7 @@ val NoneVersion = Version(
variant = ""
)
typealias PlayheadsMap = Map<String, PlayheadObject>
typealias Playheads = Collection2<PlayheadObject>
@Serializable
data class PlayheadObject(
@ -362,6 +363,8 @@ data class PlayheadObject(
@SerialName("last_modified") val lastModified: String,
)
val NonePlayheads = Playheads(0, emptyList())
/**
* Meta data for a episode intro. All time values are in seconds.
*/

View File

@ -3,11 +3,13 @@ package org.mosad.teapod.ui.activity.main.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.async
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import org.mosad.teapod.parser.crunchyroll.*
import org.mosad.teapod.util.DataTypes.MediaType
import org.mosad.teapod.util.tmdb.*
import org.mosad.teapod.util.toPlayheadsMap
/**
* handle media, next ep and tmdb
@ -25,7 +27,8 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
internal set
val currentEpisodesCrunchy = arrayListOf<Episode>() // used for EpisodeItemAdapter (easier updates)
// additional media info
// additional media info, might change during during user interaction
// use a map to update the episode adapter values
val currentPlayheads: MutableMap<String, PlayheadObject> = mutableMapOf()
var isWatchlist = false
internal set
@ -80,12 +83,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
// load playheads and tmdb in parallel
listOf(
viewModelScope.launch {
// get playheads (including fully watched state)
val episodeIDs = episodesCrunchy.data.map { it.id }
currentPlayheads.clear()
currentPlayheads.putAll(Crunchyroll.playheads(episodeIDs))
},
updatePlayheadsAsync(),
viewModelScope.launch { loadTmdbInfo() } // use tmdb search to get media info
).joinAll()
}
@ -117,6 +115,16 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
// } else NoneTMDBTVSeason
}
/**
* Get current playheads for all episodes
*/
private fun updatePlayheadsAsync() = viewModelScope.async {
currentPlayheads.clear()
currentPlayheads.putAll(
Crunchyroll.playheads(episodesCrunchy.data.map { it.id }).toPlayheadsMap()
)
}
/**
* Set currentSeasonCrunchy based on the season id. Also set the new seasons episodes.
*
@ -137,9 +145,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
currentEpisodesCrunchy.addAll(episodesCrunchy.data)
// update playheads playheads (including fully watched state)
val episodeIDs = episodesCrunchy.data.map { it.id }
currentPlayheads.clear()
currentPlayheads.putAll(Crunchyroll.playheads(episodeIDs))
updatePlayheadsAsync().await()
}
suspend fun setWatchlist() {
@ -154,11 +160,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
suspend fun updateOnResume() {
joinAll(
viewModelScope.launch {
val episodeIDs = episodesCrunchy.data.map { it.id }
currentPlayheads.clear()
currentPlayheads.putAll(Crunchyroll.playheads(episodeIDs))
},
updatePlayheadsAsync(),
viewModelScope.launch { upNextSeries = Crunchyroll.upNextSeries(seriesCrunchy.id) }
)
}

View File

@ -40,6 +40,7 @@ import org.mosad.teapod.util.metadb.EpisodeMeta
import org.mosad.teapod.util.metadb.Meta
import org.mosad.teapod.util.metadb.MetaDBController
import org.mosad.teapod.util.metadb.TVShowMeta
import org.mosad.teapod.util.toPlayheadsMap
import java.util.*
import kotlin.concurrent.scheduleAtFixedRate
@ -63,7 +64,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
internal set
var currentEpisodeMeta: EpisodeMeta? = null
internal set
var currentPlayheads: PlayheadsMap = mutableMapOf()
var currentPlayheads = mapOf<String, PlayheadObject>()
internal set
var currentIntroMetadata: DatalabIntro = NoneDatalabIntro
internal set
@ -142,7 +143,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
viewModelScope.launch { mediaMeta = loadMediaMeta(episodes.data.first().seriesId) },
viewModelScope.launch {
val episodeIDs = episodes.data.map { it.id }
currentPlayheads = Crunchyroll.playheads(episodeIDs)
currentPlayheads = Crunchyroll.playheads(episodeIDs).toPlayheadsMap()
}
).joinAll()
Log.d(classTag, "meta: $mediaMeta")
@ -233,7 +234,9 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
Log.d(classTag, currentVersion.toString())
},
viewModelScope.launch(Dispatchers.IO) {
Crunchyroll.playheads(listOf(currentEpisode.id))[currentEpisode.id]?.let {
Crunchyroll.playheads(listOf(currentEpisode.id)).data.firstOrNull {
it.contentId == currentEpisode.id
}?.let {
// if the episode was fully watched, start at the beginning
currentPlayhead = if (it.fullyWatched) {
0
@ -330,7 +333,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
viewModelScope.launch {
val episodeIDs = episodes.data.map { it.id }
currentPlayheads = Crunchyroll.playheads(episodeIDs)
currentPlayheads = Crunchyroll.playheads(episodeIDs).toPlayheadsMap()
}
}

View File

@ -44,7 +44,7 @@ class EpisodeListDialogFragment : DialogFragment() {
val adapterRecEpisodes = EpisodeItemAdapter(
model.episodes.data,
null,
model.currentPlayheads.toMap(),
model.currentPlayheads,
EpisodeItemAdapter.OnClickListener { episode ->
dismiss()
// TODO make this none blocking, if necessary?

View File

@ -10,7 +10,9 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.fragment.app.Fragment
import org.mosad.teapod.R
import org.mosad.teapod.parser.crunchyroll.Collection
import org.mosad.teapod.parser.crunchyroll.Collection2
import org.mosad.teapod.parser.crunchyroll.Item
import org.mosad.teapod.parser.crunchyroll.PlayheadObject
import org.mosad.teapod.ui.activity.player.PlayerActivity
import java.util.*
@ -57,6 +59,10 @@ fun Locale.toDisplayString(fallback: String): String {
}
}
fun Collection2<PlayheadObject>.toPlayheadsMap(): Map<String, PlayheadObject> {
return this.data.associateBy { it.contentId }
}
fun hideBars(window: Window?, root: View) {
if (window != null) {
WindowCompat.setDecorFitsSystemWindows(window, false)

View File

@ -16,13 +16,12 @@ import org.mosad.teapod.databinding.ItemEpisodeBinding
import org.mosad.teapod.databinding.ItemEpisodePlayerBinding
import org.mosad.teapod.parser.crunchyroll.Episode
import org.mosad.teapod.parser.crunchyroll.PlayheadObject
import org.mosad.teapod.parser.crunchyroll.PlayheadsMap
import org.mosad.teapod.util.tmdb.TMDBTVEpisode
class EpisodeItemAdapter(
private val episodes: List<Episode>,
private val tmdbEpisodes: List<TMDBTVEpisode>?,
private val playheads: PlayheadsMap,
private val playheads: Map<String, PlayheadObject>,
private val onClickListener: OnClickListener,
private val viewType: ViewType
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {