migrate more api calls to v2

This commit is contained in:
Jannik 2023-02-19 15:13:31 +01:00
parent 8b7fb3ac5f
commit 2e7db26d1d
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
4 changed files with 58 additions and 78 deletions

View File

@ -322,6 +322,8 @@ object Crunchyroll {
* Search fo a query term.
* Note: currently this function only supports series/tv shows.
*
* TODO migrate to v2
*
* @param query The query term as String
* @param n The maximum number of results to return, default = 10
* @return A **[SearchResult]** object
@ -370,22 +372,6 @@ object Crunchyroll {
}
}
/**
* List all available seasons as **[SeasonListItem]**.
*/
@Suppress("unused")
suspend fun seasonList(): DiscSeasonList {
val seasonListEndpoint = "/content/v1/season_list"
val parameters = listOf("locale" to Preferences.preferredSubtitleLocale.toLanguageTag())
return try {
requestGet(seasonListEndpoint, parameters)
} catch (ex: Exception) {
Log.e(TAG, "Exception in seasonList().", ex)
NoneDiscSeasonList
}
}
/**
* Main media functions: series, season, episodes, playback
*/
@ -394,12 +380,10 @@ object Crunchyroll {
* series id == crunchyroll id?
*/
suspend fun series(seriesId: String): Series {
val seriesEndpoint = "/cms/v2/${token.country}/M3/crunchyroll/series/$seriesId"
val seriesEndpoint = "/content/v2/cms/series/$seriesId"
val parameters = listOf(
"locale" to Preferences.preferredSubtitleLocale.toLanguageTag(),
"Signature" to signature,
"Policy" to policy,
"Key-Pair-Id" to keyPairID
"preferred_audio_language" to Preferences.preferredAudioLocale.toLanguageTag(),
"locale" to Preferences.preferredSubtitleLocale.toLanguageTag()
)
return try {
@ -413,6 +397,8 @@ object Crunchyroll {
/**
* Get the next episode for a series.
*
* FIXME up_next returns no content if the is no next episode
*
* @param seriesId The series id for which to call up next
* @return A **[UpNextSeriesItem]** with a Panel representing the up next episode
*/
@ -425,6 +411,9 @@ object Crunchyroll {
return try {
requestGet(upNextSeriesEndpoint, parameters)
} catch (ex: NoTransformationFoundException) {
// should be 204 No Content
NoneUpNextSeriesList
} catch (ex: JsonConvertException) {
Log.e(TAG, "JsonConvertException in upNextSeries() with seriesId=$seriesId", ex)
NoneUpNextSeriesList
@ -512,12 +501,16 @@ object Crunchyroll {
* @return **[Boolean]**: ture if it was found, else false
*/
suspend fun isWatchlist(seriesId: String): Boolean {
val watchlistSeriesEndpoint = "/content/v1/watchlist/$accountID/$seriesId"
val parameters = listOf("locale" to Preferences.preferredSubtitleLocale.toLanguageTag())
val watchlistSeriesEndpoint = "/content/v2/$accountID/watchlist"
val parameters = listOf(
"content_ids" to seriesId,
"preferred_audio_language" to Preferences.preferredAudioLocale.toLanguageTag(),
"locale" to Preferences.preferredSubtitleLocale.toLanguageTag()
)
return try {
(requestGet(watchlistSeriesEndpoint, parameters) as JsonObject)
.containsKey(seriesId)
(requestGet(watchlistSeriesEndpoint, parameters) as Collection2<IsWatchlistItem>)
.total == 1
} catch (ex: Exception) {
Log.e(TAG, "Exception in isWatchlist() with seriesId = $seriesId", ex)
false
@ -530,8 +523,11 @@ object Crunchyroll {
* @param seriesId The crunchyroll series id of the media to check
*/
suspend fun postWatchlist(seriesId: String) {
val watchlistPostEndpoint = "/content/v1/watchlist/$accountID"
val parameters = listOf("locale" to Preferences.preferredSubtitleLocale.toLanguageTag())
val watchlistPostEndpoint = "/content/v2/$accountID/watchlist"
val parameters = listOf(
"preferred_audio_language" to Preferences.preferredAudioLocale.toLanguageTag(),
"locale" to Preferences.preferredSubtitleLocale.toLanguageTag()
)
val json = buildJsonObject {
put("content_id", seriesId)
@ -542,7 +538,6 @@ object Crunchyroll {
} catch (ex: Exception) {
Log.e(TAG, "Exception in postWatchlist() with seriesId = $seriesId", ex)
}
}
/**
@ -551,15 +546,17 @@ object Crunchyroll {
* @param seriesId The crunchyroll series id of the media to check
*/
suspend fun deleteWatchlist(seriesId: String) {
val watchlistDeleteEndpoint = "/content/v1/watchlist/$accountID/$seriesId"
val parameters = listOf("locale" to Preferences.preferredSubtitleLocale.toLanguageTag())
val watchlistDeleteEndpoint = "/content/v2/$accountID/watchlist/$seriesId"
val parameters = listOf(
"preferred_audio_language" to Preferences.preferredAudioLocale.toLanguageTag(),
"locale" to Preferences.preferredSubtitleLocale.toLanguageTag()
)
try {
requestDelete(watchlistDeleteEndpoint, parameters)
} catch (ex: Exception) {
Log.e(TAG, "Exception in deleteWatchlist() with seriesId = $seriesId", ex)
}
}
/**

View File

@ -127,7 +127,6 @@ typealias SearchResult = Collection<SearchCollection>
typealias SearchCollection = Collection<Item>
typealias BrowseResult = Collection<Item>
typealias SimilarToResult = Collection<Item>
typealias DiscSeasonList = Collection<SeasonListItem>
typealias Watchlist = Collection2<WatchlistItem>
typealias HistoryList = Collection2<UpNextAccountItem>
typealias UpNextSeriesList = Collection2<UpNextSeriesItem>
@ -159,21 +158,6 @@ data class Images(val poster_tall: List<List<Poster>>, val poster_wide: List<Lis
@Serializable
data class Poster(val height: Int, val width: Int, val source: String, val type: String)
/**
* season list data classes
*/
@Serializable
data class SeasonListItem(
@SerialName("id") val id: String,
@SerialName("localization") val localization: SeasonListLocalization
)
@Serializable
data class SeasonListLocalization(
@SerialName("title") val title: String,
@SerialName("description") val description: String,
)
/**
* continue_watching_item data classes
*/
@ -188,6 +172,13 @@ data class WatchlistItem(
@SerialName("is_favorite") val isFavorite: Boolean,
)
@Serializable
data class IsWatchlistItem(
@SerialName("id") val id: String,
@SerialName("is_favorite") val isFavorite: Boolean,
@SerialName("date_added") val dateAdded: String
)
@Serializable
data class UpNextAccountItem(
@SerialName("panel") val panel: EpisodePanel,
@ -229,15 +220,10 @@ data class EpisodeMetadata(
@SerialName("series_title") val seriesTitle: String,
)
val NoneItem = Item("", "", "", "", "", Images(emptyList(), emptyList()))
val NoneEpisodeMetadata = EpisodeMetadata(0, 0, "", 0, "", "", "")
val NoneEpisodePanel = EpisodePanel("", "", "", "", "", NoneEpisodeMetadata, Thumbnail(listOf())) //, "")
val NoneCollection = Collection<Item>(0, emptyList())
val NoneSearchResult = SearchResult(0, emptyList())
val NoneBrowseResult = BrowseResult(0, emptyList())
val NoneSimilarToResult = SimilarToResult(0, emptyList())
val NoneDiscSeasonList = DiscSeasonList(0, emptyList())
val NoneWatchlist = Watchlist(0, emptyList())
val NoneHistoryList = HistoryList(0, emptyList())
val NoneUpNextSeriesList = UpNextSeriesList(0, emptyList())
@ -247,15 +233,23 @@ val NoneBenefits = Benefits(0, emptyList())
/**
* series data class
*/
typealias Series = Collection2<SeriesItem>
@Serializable
data class Series(
data class SeriesItem(
@SerialName("id") val id: String,
@SerialName("title") val title: String,
@SerialName("description") val description: String,
@SerialName("images") val images: Images,
@SerialName("maturity_ratings") val maturityRatings: List<String>
@SerialName("is_simulcast") val isSimulcast: Boolean,
@SerialName("maturity_ratings") val maturityRatings: List<String>,
@SerialName("audio_locales") val audioLocales: List<String>
)
val NoneSeries = Series("", "", "", Images(emptyList(), emptyList()), emptyList())
val NoneSeriesItem = SeriesItem("", "", "", Images(emptyList(), emptyList()), false, emptyList(), emptyList())
val NoneSeries = Series(1, listOf(NoneSeriesItem))
/**
* Seasons data classes
@ -264,17 +258,7 @@ val NoneSeries = Series("", "", "", Images(emptyList(), emptyList()), emptyList(
data class Seasons(
@SerialName("total") val total: Int,
@SerialName("data") val data: List<Season>
) {
fun getPreferredSeasonByLocal(local: Locale): Season {
return data.firstOrNull { season ->
// try to get the the first seasons which matches the preferred local
season.slugTitle.endsWith("${local.getDisplayLanguage(Locale.ENGLISH)}-dub", true)
} ?: data.firstOrNull { season ->
// if there is no season with the preferred local, try to find a subbed season
season.isSubbed
} ?: data.first() // if no preferred language and no sub, use the first season
}
}
)
@Serializable
data class Season(

View File

@ -6,7 +6,6 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import org.mosad.teapod.parser.crunchyroll.*
import org.mosad.teapod.preferences.Preferences
import org.mosad.teapod.util.DataTypes.MediaType
import org.mosad.teapod.util.tmdb.*
@ -16,7 +15,7 @@ import org.mosad.teapod.util.tmdb.*
*/
class MediaFragmentViewModel(application: Application) : AndroidViewModel(application) {
var seriesCrunchy = NoneSeries // movies are also series
var seriesCrunchy = NoneSeriesItem // movies are also series
internal set
var seasonsCrunchy = NoneSeasons
internal set
@ -50,7 +49,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
suspend fun loadCrunchy(crunchyId: String) {
// load series and seasons info in parallel
listOf(
viewModelScope.launch { seriesCrunchy = Crunchyroll.series(crunchyId) },
viewModelScope.launch { seriesCrunchy = Crunchyroll.series(crunchyId).data.first() },
viewModelScope.launch { seasonsCrunchy = Crunchyroll.seasons(crunchyId) },
viewModelScope.launch { isWatchlist = Crunchyroll.isWatchlist(crunchyId) },
viewModelScope.launch { upNextSeries = Crunchyroll.upNextSeries(crunchyId) },
@ -58,10 +57,15 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
).joinAll()
// load the preferred season:
// next episode > preferred language (language per season, not per stream)
currentSeasonCrunchy = seasonsCrunchy.data.firstOrNull{ season ->
season.id == upNextSeries.data.first().panel.episodeMetadata.seasonId
} ?: seasonsCrunchy.getPreferredSeasonByLocal(Preferences.preferredSubtitleLocale)
// next episode > first season
currentSeasonCrunchy = if (upNextSeries != NoneUpNextSeriesList) {
seasonsCrunchy.data.firstOrNull{ season ->
season.id == upNextSeries.data.first().panel.episodeMetadata.seasonId
} ?: seasonsCrunchy.data.first()
} else {
seasonsCrunchy.data.first()
}
// Note: if we need to query metaDB, do it now
// load episodes and metaDB in parallel (tmdb needs mediaType, which is set via episodes)

View File

@ -171,10 +171,6 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
playCurrentMedia(player.currentPosition)
}
println(newSubtitleLocale != currentSubtitleLocale)
println("currentSubtitleLocale: $currentSubtitleLocale")
println("newSubtitleLocale: $newSubtitleLocale")
// else nothing has changed so no need do do anything
}
@ -235,7 +231,6 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
currentStreams = Crunchyroll.streamsFromMediaGUID(currentVersion.mediaGUID)
Log.d(classTag, currentVersion.toString())
println("stream: $currentStreams")
},
viewModelScope.launch(Dispatchers.IO) {
Crunchyroll.playheads(listOf(currentEpisode.id))[currentEpisode.id]?.let {