From 2e7db26d1d1f72f3a135e750d76c7fcb54c82b27 Mon Sep 17 00:00:00 2001 From: Jannik Date: Sun, 19 Feb 2023 15:13:31 +0100 Subject: [PATCH] migrate more api calls to v2 --- .../teapod/parser/crunchyroll/Crunchyroll.kt | 59 +++++++++---------- .../teapod/parser/crunchyroll/DataTypes.kt | 54 ++++++----------- .../main/viewmodel/MediaFragmentViewModel.kt | 18 +++--- .../ui/activity/player/PlayerViewModel.kt | 5 -- 4 files changed, 58 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Crunchyroll.kt b/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Crunchyroll.kt index 8208466..a42dd15 100644 --- a/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Crunchyroll.kt +++ b/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Crunchyroll.kt @@ -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) + .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) } - } /** diff --git a/app/src/main/java/org/mosad/teapod/parser/crunchyroll/DataTypes.kt b/app/src/main/java/org/mosad/teapod/parser/crunchyroll/DataTypes.kt index 44227c8..591a970 100644 --- a/app/src/main/java/org/mosad/teapod/parser/crunchyroll/DataTypes.kt +++ b/app/src/main/java/org/mosad/teapod/parser/crunchyroll/DataTypes.kt @@ -127,7 +127,6 @@ typealias SearchResult = Collection typealias SearchCollection = Collection typealias BrowseResult = Collection typealias SimilarToResult = Collection -typealias DiscSeasonList = Collection typealias Watchlist = Collection2 typealias HistoryList = Collection2 typealias UpNextSeriesList = Collection2 @@ -159,21 +158,6 @@ data class Images(val poster_tall: List>, val poster_wide: List(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 + @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 + @SerialName("is_simulcast") val isSimulcast: Boolean, + @SerialName("maturity_ratings") val maturityRatings: List, + @SerialName("audio_locales") val audioLocales: List + ) -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 -) { - 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( diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt b/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt index 3638528..aed13e4 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt @@ -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) diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt index 9c79574..8545174 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt @@ -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 {