2021-02-06 19:02:12 +01:00
package org.mosad.teapod.ui.activity.main.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
2021-12-28 20:32:44 +01:00
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
2021-12-29 19:36:33 +01:00
import org.mosad.teapod.parser.crunchyroll.*
2022-01-02 17:51:45 +01:00
import org.mosad.teapod.util.DataTypes.MediaType
2021-12-31 16:03:15 +01:00
import org.mosad.teapod.util.tmdb.*
2021-02-06 19:02:12 +01:00
/ * *
* handle media , next ep and tmdb
2021-07-11 12:56:21 +02:00
* TODO this lives in activity , is this correct ?
2021-02-06 19:02:12 +01:00
* /
class MediaFragmentViewModel ( application : Application ) : AndroidViewModel ( application ) {
2023-02-19 15:13:31 +01:00
var seriesCrunchy = NoneSeriesItem // movies are also series
2021-12-20 22:14:58 +01:00
internal set
var seasonsCrunchy = NoneSeasons
internal set
2021-12-29 19:36:33 +01:00
var currentSeasonCrunchy = NoneSeason
internal set
2021-12-20 22:14:58 +01:00
var episodesCrunchy = NoneEpisodes
internal set
2021-12-29 20:51:53 +01:00
val currentEpisodesCrunchy = arrayListOf < Episode > ( ) // used for EpisodeItemAdapter (easier updates)
2022-01-09 18:41:23 +01:00
// additional media info
2022-01-29 20:32:45 +01:00
val currentPlayheads : MutableMap < String , PlayheadObject > = mutableMapOf ( )
2022-01-02 22:39:31 +01:00
var isWatchlist = false
internal set
2023-02-19 14:21:46 +01:00
var upNextSeries = NoneUpNextSeriesList
2022-04-03 16:14:22 +02:00
internal set
var similarTo = NoneSimilarToResult
internal set
2021-12-20 22:14:58 +01:00
2022-01-02 22:39:31 +01:00
// TMDB stuff
2022-01-02 17:51:45 +01:00
var mediaType = MediaType . OTHER
internal set
2021-12-31 16:03:15 +01:00
var tmdbResult : TMDBResult = NoneTMDB // TODO rename
2021-02-06 19:02:12 +01:00
internal set
2021-12-31 16:03:15 +01:00
var tmdbTVSeason : TMDBTVSeason = NoneTMDBTVSeason
2021-07-11 12:56:21 +02:00
internal set
2021-02-06 19:02:12 +01:00
2021-12-28 20:32:44 +01:00
/ * *
* @param crunchyId the crunchyroll series id
* /
2021-12-20 22:14:58 +01:00
2021-12-31 16:03:15 +01:00
suspend fun loadCrunchy ( crunchyId : String ) {
2021-12-28 20:32:44 +01:00
// load series and seasons info in parallel
listOf (
2023-02-19 15:13:31 +01:00
viewModelScope . launch { seriesCrunchy = Crunchyroll . series ( crunchyId ) . data . first ( ) } ,
2022-01-02 22:39:31 +01:00
viewModelScope . launch { seasonsCrunchy = Crunchyroll . seasons ( crunchyId ) } ,
2022-01-09 18:41:23 +01:00
viewModelScope . launch { isWatchlist = Crunchyroll . isWatchlist ( crunchyId ) } ,
2022-04-03 16:14:22 +02:00
viewModelScope . launch { upNextSeries = Crunchyroll . upNextSeries ( crunchyId ) } ,
viewModelScope . launch { similarTo = Crunchyroll . similarTo ( crunchyId ) }
2021-12-28 20:32:44 +01:00
) . joinAll ( )
2021-12-31 16:03:15 +01:00
2022-11-26 15:52:20 +01:00
// load the preferred season:
2023-02-19 15:13:31 +01:00
// 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 ( )
}
2022-03-30 20:12:04 +02:00
// Note: if we need to query metaDB, do it now
2022-01-09 18:41:23 +01:00
2022-03-30 20:12:04 +02:00
// load episodes and metaDB in parallel (tmdb needs mediaType, which is set via episodes)
viewModelScope . launch { episodesCrunchy = Crunchyroll . episodes ( currentSeasonCrunchy . id ) } . join ( )
2021-12-29 20:51:53 +01:00
currentEpisodesCrunchy . clear ( )
2023-01-25 19:51:38 +01:00
currentEpisodesCrunchy . addAll ( episodesCrunchy . data )
2022-01-05 01:28:39 +01:00
2022-01-02 17:51:45 +01:00
// set media type
2023-01-25 19:51:38 +01:00
mediaType = episodesCrunchy . data . firstOrNull ( ) ?. let {
2022-01-02 17:51:45 +01:00
if ( it . episodeNumber != null ) MediaType . TVSHOW else MediaType . MOVIE
} ?: MediaType . OTHER
2022-01-09 18:41:23 +01:00
// load playheads and tmdb in parallel
listOf (
viewModelScope . launch {
// get playheads (including fully watched state)
2023-01-25 19:51:38 +01:00
val episodeIDs = episodesCrunchy . data . map { it . id }
2022-01-29 20:32:45 +01:00
currentPlayheads . clear ( )
currentPlayheads . putAll ( Crunchyroll . playheads ( episodeIDs ) )
2022-01-09 18:41:23 +01:00
} ,
viewModelScope . launch { loadTmdbInfo ( ) } // use tmdb search to get media info
) . joinAll ( )
2021-12-20 22:14:58 +01:00
}
2021-02-06 19:02:12 +01:00
/ * *
2021-12-31 16:03:15 +01:00
* Load the tmdb info for the selected media .
* The TMDB search return a media type , use this to get the details ( movie / tv show and season )
2021-02-06 19:02:12 +01:00
* /
2022-01-02 22:39:31 +01:00
private suspend fun loadTmdbInfo ( ) {
2021-12-31 16:03:15 +01:00
val tmdbApiController = TMDBApiController ( )
2022-01-02 17:51:45 +01:00
val tmdbSearchResult = when ( mediaType ) {
MediaType . MOVIE -> tmdbApiController . searchMovie ( seriesCrunchy . title )
MediaType . TVSHOW -> tmdbApiController . searchTVShow ( seriesCrunchy . title )
else -> NoneTMDBSearch
}
2021-12-31 16:03:15 +01:00
tmdbResult = if ( tmdbSearchResult . results . isNotEmpty ( ) ) {
2022-01-02 17:51:45 +01:00
when ( val result = tmdbSearchResult . results . first ( ) ) {
is TMDBSearchResultMovie -> tmdbApiController . getMovieDetails ( result . id )
is TMDBSearchResultTVShow -> tmdbApiController . getTVShowDetails ( result . id )
2021-12-31 16:03:15 +01:00
else -> NoneTMDB
}
} else NoneTMDB
// currently not used
// tmdbTVSeason = if (tmdbResult is TMDBTVShow) {
// tmdbApiController.getTVSeasonDetails(tmdbResult.id, 0)
// } else NoneTMDBTVSeason
}
2021-02-06 19:02:12 +01:00
2022-01-02 22:39:31 +01:00
/ * *
* Set currentSeasonCrunchy based on the season id . Also set the new seasons episodes .
*
* @param seasonId the id of the season to set
* /
suspend fun setCurrentSeason ( seasonId : String ) {
// return if the id hasn't changed (performance)
if ( currentSeasonCrunchy . id == seasonId ) return
// set currentSeasonCrunchy to the new season with id == seasonId, if the id isn't found,
// don't change the current season (this should/can never happen)
2023-01-25 19:51:38 +01:00
currentSeasonCrunchy = seasonsCrunchy . data . firstOrNull {
2022-01-02 22:39:31 +01:00
it . id == seasonId
} ?: currentSeasonCrunchy
episodesCrunchy = Crunchyroll . episodes ( currentSeasonCrunchy . id )
currentEpisodesCrunchy . clear ( )
2023-01-25 19:51:38 +01:00
currentEpisodesCrunchy . addAll ( episodesCrunchy . data )
2022-03-30 20:12:04 +02:00
// update playheads playheads (including fully watched state)
2023-01-25 19:51:38 +01:00
val episodeIDs = episodesCrunchy . data . map { it . id }
2022-03-30 20:12:04 +02:00
currentPlayheads . clear ( )
currentPlayheads . putAll ( Crunchyroll . playheads ( episodeIDs ) )
2022-01-02 22:39:31 +01:00
}
suspend fun setWatchlist ( ) {
isWatchlist = if ( isWatchlist ) {
Crunchyroll . deleteWatchlist ( seriesCrunchy . id )
false
} else {
Crunchyroll . postWatchlist ( seriesCrunchy . id )
true
}
}
2022-01-09 19:23:33 +01:00
suspend fun updateOnResume ( ) {
2022-01-29 20:32:45 +01:00
joinAll (
2022-01-09 18:41:23 +01:00
viewModelScope . launch {
2023-01-25 19:51:38 +01:00
val episodeIDs = episodesCrunchy . data . map { it . id }
2022-01-29 20:32:45 +01:00
currentPlayheads . clear ( )
currentPlayheads . putAll ( Crunchyroll . playheads ( episodeIDs ) )
2022-01-09 18:41:23 +01:00
} ,
viewModelScope . launch { upNextSeries = Crunchyroll . upNextSeries ( seriesCrunchy . id ) }
2022-01-29 20:32:45 +01:00
)
2022-01-09 18:41:23 +01:00
}
2021-12-31 16:03:15 +01:00
}