add upNextSeries
the MediaFragment will show the next episodes title instead for the series title and play the "next up" episode when the play button is clicked
This commit is contained in:
parent
e98e75456e
commit
a10287f747
|
@ -14,7 +14,7 @@ android {
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 4200 //00.04.200
|
versionCode 4200 //00.04.200
|
||||||
versionName "1.0.0-alpha2"
|
versionName "1.0.0-alpha3"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
resValue "string", "build_time", buildTime()
|
resValue "string", "build_time", buildTime()
|
||||||
|
|
|
@ -295,6 +295,23 @@ object Crunchyroll {
|
||||||
} ?: NoneSeries
|
} ?: NoneSeries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
suspend fun upNextSeries(seriesId: String): UpNextSeriesItem {
|
||||||
|
val upNextSeriesEndpoint = "/content/v1/up_next_series"
|
||||||
|
val parameters = listOf(
|
||||||
|
"series_id" to seriesId,
|
||||||
|
"locale" to locale
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = request(upNextSeriesEndpoint, parameters)
|
||||||
|
|
||||||
|
return result.component1()?.obj()?.let {
|
||||||
|
json.decodeFromString(it.toString())
|
||||||
|
} ?: NoneUpNextSeriesItem
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun seasons(seriesId: String): Seasons {
|
suspend fun seasons(seriesId: String): Seasons {
|
||||||
val episodesEndpoint = "/cms/v2/$country/M3/crunchyroll/seasons"
|
val episodesEndpoint = "/cms/v2/$country/M3/crunchyroll/seasons"
|
||||||
val parameters = listOf(
|
val parameters = listOf(
|
||||||
|
@ -404,6 +421,18 @@ object Crunchyroll {
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun postPlayheads(episodeId: String, playhead: Int) {
|
||||||
|
val playheadsEndpoint = "/content/v1/playheads/$accountID"
|
||||||
|
val parameters = listOf("locale" to locale)
|
||||||
|
|
||||||
|
val json = buildJsonObject {
|
||||||
|
put("content_id", episodeId)
|
||||||
|
put("playhead", playhead)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestPost(playheadsEndpoint, parameters, json.toString())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listing functions: watchlist (list), up_next_account
|
* Listing functions: watchlist (list), up_next_account
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,6 +31,14 @@ typealias DiscSeasonList = Collection<SeasonListItem>
|
||||||
typealias Watchlist = Collection<Item>
|
typealias Watchlist = Collection<Item>
|
||||||
typealias ContinueWatchingList = Collection<ContinueWatchingItem>
|
typealias ContinueWatchingList = Collection<ContinueWatchingItem>
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class UpNextSeriesItem(
|
||||||
|
val playhead: Int,
|
||||||
|
val fully_watched: Boolean,
|
||||||
|
val never_watched: Boolean,
|
||||||
|
val panel: EpisodePanel,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* panel data classes
|
* panel data classes
|
||||||
*/
|
*/
|
||||||
|
@ -73,17 +81,18 @@ data class SeasonListLocalization(
|
||||||
/**
|
/**
|
||||||
* continue_watching_item data classes
|
* continue_watching_item data classes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ContinueWatchingItem(
|
data class ContinueWatchingItem(
|
||||||
@SerialName("panel") val panel: EpisodePanel,
|
@SerialName("panel") val panel: EpisodePanel,
|
||||||
@SerialName("new") val new: Boolean,
|
@SerialName("new") val new: Boolean,
|
||||||
@SerialName("new_content") val newContent: Boolean,
|
@SerialName("new_content") val newContent: Boolean,
|
||||||
// not present in up_next_account's continue_watching_item
|
// not present in up_next_account -> continue_watching_item
|
||||||
// @SerialName("is_favorite") val isFavorite: Boolean,
|
// @SerialName("is_favorite") val isFavorite: Boolean,
|
||||||
// @SerialName("never_watched") val neverWatched: Boolean,
|
// @SerialName("never_watched") val neverWatched: Boolean,
|
||||||
// @SerialName("completion_status") val completionStatus: Boolean,
|
// @SerialName("completion_status") val completionStatus: Boolean,
|
||||||
@SerialName("playhead") val playhead: Int,
|
@SerialName("playhead") val playhead: Int,
|
||||||
|
// not present in watchlist -> continue_watching_item
|
||||||
|
// @SerialName("fully_watched") val fullyWatched: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
// EpisodePanel is used in ContinueWatchingItem
|
// EpisodePanel is used in ContinueWatchingItem
|
||||||
|
@ -94,24 +103,31 @@ data class EpisodePanel(
|
||||||
@SerialName("type") val type: String,
|
@SerialName("type") val type: String,
|
||||||
@SerialName("channel_id") val channelId: String,
|
@SerialName("channel_id") val channelId: String,
|
||||||
@SerialName("description") val description: String,
|
@SerialName("description") val description: String,
|
||||||
@SerialName("images") val images: Thumbnail,
|
|
||||||
@SerialName("episode_metadata") val episodeMetadata: EpisodeMetadata,
|
@SerialName("episode_metadata") val episodeMetadata: EpisodeMetadata,
|
||||||
|
@SerialName("images") val images: Thumbnail,
|
||||||
|
@SerialName("playback") val playback: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class EpisodeMetadata(
|
data class EpisodeMetadata(
|
||||||
|
@SerialName("duration_ms") val durationMs: Int,
|
||||||
|
@SerialName("season_id") val seasonId: String,
|
||||||
@SerialName("series_id") val seriesId: String,
|
@SerialName("series_id") val seriesId: String,
|
||||||
@SerialName("series_title") val seriesTitle: String,
|
@SerialName("series_title") val seriesTitle: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
val NoneItem = Item("", "", "", "", "", Images(emptyList(), emptyList()))
|
val NoneItem = Item("", "", "", "", "", Images(emptyList(), emptyList()))
|
||||||
|
val NoneEpisodeMetadata = EpisodeMetadata(0, "", "", "")
|
||||||
|
val NoneEpisodePanel = EpisodePanel("", "", "", "", "", NoneEpisodeMetadata, Thumbnail(listOf()), "")
|
||||||
|
|
||||||
val NoneCollection = Collection<Item>(0, emptyList())
|
val NoneCollection = Collection<Item>(0, emptyList())
|
||||||
val NoneSearchResult = SearchResult(0, emptyList())
|
val NoneSearchResult = SearchResult(0, emptyList())
|
||||||
val NoneBrowseResult = BrowseResult(0, emptyList())
|
val NoneBrowseResult = BrowseResult(0, emptyList())
|
||||||
val NoneDiscSeasonList = DiscSeasonList(0, emptyList())
|
val NoneDiscSeasonList = DiscSeasonList(0, emptyList())
|
||||||
val NoneWatchlist = Watchlist(0, emptyList())
|
|
||||||
val NoneContinueWatchingList = ContinueWatchingList(0, emptyList())
|
val NoneContinueWatchingList = ContinueWatchingList(0, emptyList())
|
||||||
|
|
||||||
|
val NoneUpNextSeriesItem =UpNextSeriesItem(0, false, false, NoneEpisodePanel)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Series data type
|
* Series data type
|
||||||
*/
|
*/
|
||||||
|
@ -163,7 +179,7 @@ data class Season(
|
||||||
@SerialName("is_dubbed") val isDubbed: Boolean,
|
@SerialName("is_dubbed") val isDubbed: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
val NoneSeasons = Seasons(0, listOf())
|
val NoneSeasons = Seasons(0, emptyList())
|
||||||
val NoneSeason = Season("", "", "", 0, isSubbed = false, isDubbed = false)
|
val NoneSeason = Season("", "", "", 0, isSubbed = false, isDubbed = false)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ import com.bumptech.glide.request.RequestOptions
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.databinding.FragmentMediaBinding
|
import org.mosad.teapod.databinding.FragmentMediaBinding
|
||||||
|
import org.mosad.teapod.parser.crunchyroll.NoneUpNextSeriesItem
|
||||||
import org.mosad.teapod.ui.activity.main.MainActivity
|
import org.mosad.teapod.ui.activity.main.MainActivity
|
||||||
import org.mosad.teapod.ui.activity.main.viewmodel.MediaFragmentViewModel
|
import org.mosad.teapod.ui.activity.main.viewmodel.MediaFragmentViewModel
|
||||||
import org.mosad.teapod.util.tmdb.TMDBApiController
|
import org.mosad.teapod.util.tmdb.TMDBApiController
|
||||||
|
@ -37,19 +37,23 @@ class MediaFragment(private val mediaIdStr: String) : Fragment() {
|
||||||
private lateinit var binding: FragmentMediaBinding
|
private lateinit var binding: FragmentMediaBinding
|
||||||
private lateinit var pagerAdapter: FragmentStateAdapter
|
private lateinit var pagerAdapter: FragmentStateAdapter
|
||||||
|
|
||||||
|
private val model: MediaFragmentViewModel by activityViewModels()
|
||||||
|
|
||||||
private val fragments = arrayListOf<Fragment>()
|
private val fragments = arrayListOf<Fragment>()
|
||||||
private var watchlistJobRunning = false
|
private var watchlistJobRunning = false
|
||||||
|
private var runOnResume = false
|
||||||
|
|
||||||
private val model: MediaFragmentViewModel by activityViewModels()
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
binding = FragmentMediaBinding.inflate(inflater, container, false)
|
binding = FragmentMediaBinding.inflate(inflater, container, false)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
println("onViewCreated")
|
||||||
|
|
||||||
binding.frameLoading.visibility = View.VISIBLE
|
binding.frameLoading.visibility = View.VISIBLE
|
||||||
|
|
||||||
// tab layout and pager
|
// tab layout and pager
|
||||||
|
@ -77,11 +81,21 @@ class MediaFragment(private val mediaIdStr: String) : Fragment() {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
// update the next ep text if there is one, since it may have changed
|
if (runOnResume) {
|
||||||
// TODO reimplement
|
lifecycleScope.launch {
|
||||||
// if (model.media.getEpisodeById(model.nextEpisodeId).title.isNotEmpty()) {
|
model.updateOnResume()
|
||||||
// binding.textTitle.text = model.media.getEpisodeById(model.nextEpisodeId).title
|
|
||||||
// }
|
if (model.upNextSeries != NoneUpNextSeriesItem) {
|
||||||
|
binding.textTitle.text = model.upNextSeries.panel.title
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragments.elementAtOrNull(0) is MediaFragmentEpisodes) {
|
||||||
|
(fragments[0] as MediaFragmentEpisodes).updateWatchedState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
runOnResume = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,15 +116,17 @@ class MediaFragment(private val mediaIdStr: String) : Fragment() {
|
||||||
.apply(RequestOptions.bitmapTransform(BlurTransformation(20, 3)))
|
.apply(RequestOptions.bitmapTransform(BlurTransformation(20, 3)))
|
||||||
.into(binding.imageBackdrop)
|
.into(binding.imageBackdrop)
|
||||||
|
|
||||||
binding.textTitle.text = seriesCrunchy.title
|
|
||||||
binding.textOverview.text = seriesCrunchy.description
|
|
||||||
binding.textAge.text = seriesCrunchy.maturityRatings.firstOrNull()
|
|
||||||
|
|
||||||
binding.textYear.text = when(tmdbResult) {
|
binding.textYear.text = when(tmdbResult) {
|
||||||
is TMDBTVShow -> (tmdbResult as TMDBTVShow).firstAirDate.substring(0, 4)
|
is TMDBTVShow -> (tmdbResult as TMDBTVShow).firstAirDate.substring(0, 4)
|
||||||
is TMDBMovie -> (tmdbResult as TMDBMovie).releaseDate.substring(0, 4)
|
is TMDBMovie -> (tmdbResult as TMDBMovie).releaseDate.substring(0, 4)
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
binding.textAge.text = seriesCrunchy.maturityRatings.firstOrNull()
|
||||||
|
|
||||||
|
binding.textTitle.text = if (upNextSeries != NoneUpNextSeriesItem) {
|
||||||
|
upNextSeries.panel.title
|
||||||
|
} else seriesCrunchy.title
|
||||||
|
binding.textOverview.text = seriesCrunchy.description
|
||||||
|
|
||||||
// set "watchlist" indicator
|
// set "watchlist" indicator
|
||||||
val watchlistIcon = if (isWatchlist) R.drawable.ic_baseline_check_24 else R.drawable.ic_baseline_add_24
|
val watchlistIcon = if (isWatchlist) R.drawable.ic_baseline_check_24 else R.drawable.ic_baseline_add_24
|
||||||
|
@ -127,8 +143,7 @@ class MediaFragment(private val mediaIdStr: String) : Fragment() {
|
||||||
pagerAdapter.notifyItemInserted(fragments.indexOf(it))
|
pagerAdapter.notifyItemInserted(fragments.indexOf(it))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO reimplement via tmdb/metaDB
|
// specific gui (via tmdb)
|
||||||
// specific gui
|
|
||||||
when (tmdbResult) {
|
when (tmdbResult) {
|
||||||
is TMDBTVShow -> {
|
is TMDBTVShow -> {
|
||||||
// episodes count
|
// episodes count
|
||||||
|
@ -156,40 +171,6 @@ class MediaFragment(private val mediaIdStr: String) : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (mediaCrunchy.type == MediaType.TVSHOW.str) {
|
|
||||||
// // TODO get next episode
|
|
||||||
//// nextEpisodeId = media.playlist.firstOrNull{ !it.watched }?.mediaId
|
|
||||||
//// ?: media.playlist.first().mediaId
|
|
||||||
//
|
|
||||||
// // TODO title is the next episodes title
|
|
||||||
//// binding.textTitle.text = media.getEpisodeById(nextEpisodeId).title
|
|
||||||
//
|
|
||||||
// // episodes count
|
|
||||||
// binding.textEpisodesOrRuntime.text = resources.getQuantityString(
|
|
||||||
// R.plurals.text_episodes_count,
|
|
||||||
// episodesCrunchy.total,
|
|
||||||
// episodesCrunchy.total
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// // episodes
|
|
||||||
// MediaFragmentEpisodes().also {
|
|
||||||
// fragments.add(it)
|
|
||||||
// pagerAdapter.notifyItemInserted(fragments.indexOf(it))
|
|
||||||
// }
|
|
||||||
// } else if (media.type == MediaType.MOVIE) {
|
|
||||||
// val tmdbMovie = (tmdbResult as TMDBMovie?)
|
|
||||||
//
|
|
||||||
// if (tmdbMovie?.runtime != null) {
|
|
||||||
// binding.textEpisodesOrRuntime.text = resources.getQuantityString(
|
|
||||||
// R.plurals.text_runtime,
|
|
||||||
// tmdbMovie.runtime,
|
|
||||||
// tmdbMovie.runtime
|
|
||||||
// )
|
|
||||||
// } else {
|
|
||||||
// binding.textEpisodesOrRuntime.visibility = View.GONE
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if has similar titles
|
// if has similar titles
|
||||||
// TODO reimplement
|
// TODO reimplement
|
||||||
// if (media.similar.isNotEmpty()) {
|
// if (media.similar.isNotEmpty()) {
|
||||||
|
@ -210,12 +191,9 @@ class MediaFragment(private val mediaIdStr: String) : Fragment() {
|
||||||
|
|
||||||
private fun initActions() = with(model) {
|
private fun initActions() = with(model) {
|
||||||
binding.buttonPlay.setOnClickListener {
|
binding.buttonPlay.setOnClickListener {
|
||||||
// TODO reimplement
|
if (upNextSeries != NoneUpNextSeriesItem) {
|
||||||
// when (media.type) {
|
playEpisode(upNextSeries.panel.episodeMetadata.seasonId, upNextSeries.panel.id)
|
||||||
// MediaType.MOVIE -> playEpisode(media.playlist.first().mediaId)
|
}
|
||||||
// MediaType.TVSHOW -> playEpisode(nextEpisodeId)
|
|
||||||
// else -> Log.e(javaClass.name, "Wrong Type: ${media.type}")
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add or remove media from myList
|
// add or remove media from myList
|
||||||
|
|
|
@ -60,6 +60,7 @@ class MediaFragmentEpisodes : Fragment() {
|
||||||
// if adapterRecEpisodes is initialized, update the watched state for the episodes
|
// if adapterRecEpisodes is initialized, update the watched state for the episodes
|
||||||
if (this::adapterRecEpisodes.isInitialized) {
|
if (this::adapterRecEpisodes.isInitialized) {
|
||||||
// TODO reimplement, if needed
|
// TODO reimplement, if needed
|
||||||
|
// update via playheads?
|
||||||
// model.media.playlist.forEachIndexed { index, episodeInfo ->
|
// model.media.playlist.forEachIndexed { index, episodeInfo ->
|
||||||
// adapterRecEpisodes.updateWatchedState(episodeInfo.watched, index)
|
// adapterRecEpisodes.updateWatchedState(episodeInfo.watched, index)
|
||||||
// }
|
// }
|
||||||
|
@ -67,6 +68,11 @@ class MediaFragmentEpisodes : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateWatchedState() {
|
||||||
|
// TODO update watched state of all episodes
|
||||||
|
// use a mutable list for playheads and notify dataset changed
|
||||||
|
}
|
||||||
|
|
||||||
private fun showSeasonSelection(v: View) {
|
private fun showSeasonSelection(v: View) {
|
||||||
// TODO replace with Exposed dropdown menu: https://material.io/components/menus/android#exposed-dropdown-menus
|
// TODO replace with Exposed dropdown menu: https://material.io/components/menus/android#exposed-dropdown-menus
|
||||||
val popup = PopupMenu(requireContext(), v)
|
val popup = PopupMenu(requireContext(), v)
|
||||||
|
|
|
@ -3,9 +3,9 @@ package org.mosad.teapod.ui.activity.main.viewmodel
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.joinAll
|
import kotlinx.coroutines.joinAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import org.mosad.teapod.parser.crunchyroll.*
|
import org.mosad.teapod.parser.crunchyroll.*
|
||||||
import org.mosad.teapod.preferences.Preferences
|
import org.mosad.teapod.preferences.Preferences
|
||||||
import org.mosad.teapod.util.DataTypes.MediaType
|
import org.mosad.teapod.util.DataTypes.MediaType
|
||||||
|
@ -29,9 +29,12 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
|
||||||
var episodesCrunchy = NoneEpisodes
|
var episodesCrunchy = NoneEpisodes
|
||||||
internal set
|
internal set
|
||||||
val currentEpisodesCrunchy = arrayListOf<Episode>() // used for EpisodeItemAdapter (easier updates)
|
val currentEpisodesCrunchy = arrayListOf<Episode>() // used for EpisodeItemAdapter (easier updates)
|
||||||
|
|
||||||
|
// additional media info
|
||||||
var currentPlayheads: PlayheadsMap = emptyMap()
|
var currentPlayheads: PlayheadsMap = emptyMap()
|
||||||
var isWatchlist = false
|
var isWatchlist = false
|
||||||
internal set
|
internal set
|
||||||
|
var upNextSeries = NoneUpNextSeriesItem
|
||||||
|
|
||||||
// TMDB stuff
|
// TMDB stuff
|
||||||
var mediaType = MediaType.OTHER
|
var mediaType = MediaType.OTHER
|
||||||
|
@ -52,35 +55,40 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
|
||||||
listOf(
|
listOf(
|
||||||
viewModelScope.launch { seriesCrunchy = Crunchyroll.series(crunchyId) },
|
viewModelScope.launch { seriesCrunchy = Crunchyroll.series(crunchyId) },
|
||||||
viewModelScope.launch { seasonsCrunchy = Crunchyroll.seasons(crunchyId) },
|
viewModelScope.launch { seasonsCrunchy = Crunchyroll.seasons(crunchyId) },
|
||||||
viewModelScope.launch { isWatchlist = Crunchyroll.isWatchlist(crunchyId) }
|
viewModelScope.launch { isWatchlist = Crunchyroll.isWatchlist(crunchyId) },
|
||||||
|
viewModelScope.launch { upNextSeries = Crunchyroll.upNextSeries(crunchyId) }
|
||||||
).joinAll()
|
).joinAll()
|
||||||
|
// println("series: $seriesCrunchy")
|
||||||
println("series: $seriesCrunchy")
|
// println("seasons: $seasonsCrunchy")
|
||||||
println("seasons: $seasonsCrunchy")
|
println(upNextSeries)
|
||||||
|
|
||||||
// TODO load episodes, metaDB and tmdb in parallel
|
|
||||||
|
|
||||||
// load the preferred season (preferred language, language per season, not per stream)
|
// load the preferred season (preferred language, language per season, not per stream)
|
||||||
currentSeasonCrunchy = seasonsCrunchy.getPreferredSeason(Preferences.preferredLocal)
|
currentSeasonCrunchy = seasonsCrunchy.getPreferredSeason(Preferences.preferredLocal)
|
||||||
episodesCrunchy = Crunchyroll.episodes(currentSeasonCrunchy.id)
|
|
||||||
|
// load episodes and metaDB in parallel (tmdb needs mediaType, which is set via episodes)
|
||||||
|
listOf(
|
||||||
|
viewModelScope.launch { episodesCrunchy = Crunchyroll.episodes(currentSeasonCrunchy.id) },
|
||||||
|
viewModelScope.launch { mediaMeta = null }, // TODO metaDB
|
||||||
|
).joinAll()
|
||||||
|
// println("episodes: $episodesCrunchy")
|
||||||
|
|
||||||
currentEpisodesCrunchy.clear()
|
currentEpisodesCrunchy.clear()
|
||||||
currentEpisodesCrunchy.addAll(episodesCrunchy.items)
|
currentEpisodesCrunchy.addAll(episodesCrunchy.items)
|
||||||
println("episodes: $episodesCrunchy")
|
|
||||||
|
|
||||||
// get playheads (including fully watched state)
|
|
||||||
val episodeIDs = episodesCrunchy.items.map { it.id }
|
|
||||||
currentPlayheads = Crunchyroll.playheads(episodeIDs)
|
|
||||||
|
|
||||||
// set media type
|
// set media type
|
||||||
mediaType = episodesCrunchy.items.firstOrNull()?.let {
|
mediaType = episodesCrunchy.items.firstOrNull()?.let {
|
||||||
if (it.episodeNumber != null) MediaType.TVSHOW else MediaType.MOVIE
|
if (it.episodeNumber != null) MediaType.TVSHOW else MediaType.MOVIE
|
||||||
} ?: MediaType.OTHER
|
} ?: MediaType.OTHER
|
||||||
|
|
||||||
// TODO check if metaDB knows the title
|
// load playheads and tmdb in parallel
|
||||||
mediaMeta = null // set mediaMeta to null, if metaDB doesn't know the media
|
listOf(
|
||||||
|
viewModelScope.launch {
|
||||||
// use tmdb search to get media info
|
// get playheads (including fully watched state)
|
||||||
loadTmdbInfo()
|
val episodeIDs = episodesCrunchy.items.map { it.id }
|
||||||
|
currentPlayheads = Crunchyroll.playheads(episodeIDs)
|
||||||
|
},
|
||||||
|
viewModelScope.launch { loadTmdbInfo() } // use tmdb search to get media info
|
||||||
|
).joinAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,6 +151,16 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun updateOnResume(): List<Job> {
|
||||||
|
return listOf(
|
||||||
|
viewModelScope.launch {
|
||||||
|
val episodeIDs = episodesCrunchy.items.map { it.id }
|
||||||
|
currentPlayheads = Crunchyroll.playheads(episodeIDs)
|
||||||
|
},
|
||||||
|
viewModelScope.launch { upNextSeries = Crunchyroll.upNextSeries(seriesCrunchy.id) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the next episode based on episodeId
|
* get the next episode based on episodeId
|
||||||
* if no matching is found, use first episode
|
* if no matching is found, use first episode
|
||||||
|
|
Loading…
Reference in New Issue