add numberStr to AoDEpisode type & show tmdb episode info in player

* use numberStr instead of index to display the correct episode number, allowing for number such as "12.5"
* show tmdb episode description in player if found and aod description is missing
This commit is contained in:
Jannik 2021-09-05 00:08:03 +02:00
parent 062013489d
commit 5ea94b7ded
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
10 changed files with 44 additions and 26 deletions

View File

@ -393,7 +393,8 @@ object AoDParser {
description = episode.description, description = episode.description,
shortDesc = episodesInfo[episode.mediaid]?.shortDesc ?: "", shortDesc = episodesInfo[episode.mediaid]?.shortDesc ?: "",
imageURL = episode.image, imageURL = episode.image,
number = index, numberStr = episode.title.substringAfter(", Ep. ", ""), // TODO move to parsePalylist
index = index,
watched = episodesInfo[episode.mediaid]?.watched ?: false, watched = episodesInfo[episode.mediaid]?.watched ?: false,
watchedCallback = episodesInfo[episode.mediaid]?.watchedCallback ?: "", watchedCallback = episodesInfo[episode.mediaid]?.watchedCallback ?: "",
streams = mutableListOf(Stream(episode.sources.first().file, aodPlaylist.language)) streams = mutableListOf(Stream(episode.sources.first().file, aodPlaylist.language))

View File

@ -81,7 +81,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic
fun updateNextEpisode(episodeId: Int) { fun updateNextEpisode(episodeId: Int) {
if (media.type == MediaType.MOVIE) return // return if movie if (media.type == MediaType.MOVIE) return // return if movie
nextEpisodeId = media.playlist.firstOrNull { it.number > media.getEpisodeById(episodeId).number }?.mediaId nextEpisodeId = media.playlist.firstOrNull { it.index > media.getEpisodeById(episodeId).index }?.mediaId
?: media.playlist.first().mediaId ?: media.playlist.first().mediaId
} }

View File

@ -20,6 +20,8 @@ import org.mosad.teapod.R
import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.Preferences import org.mosad.teapod.preferences.Preferences
import org.mosad.teapod.util.* import org.mosad.teapod.util.*
import org.mosad.teapod.util.tmdb.TMDBApiController
import org.mosad.teapod.util.tmdb.TMDBTVSeason
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -46,6 +48,8 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
internal set internal set
var nextEpisode: AoDEpisode? = null var nextEpisode: AoDEpisode? = null
internal set internal set
var tmdbTVSeason: TMDBTVSeason? =null
internal set
var mediaMeta: Meta? = null var mediaMeta: Meta? = null
internal set internal set
var currentEpisodeMeta: EpisodeMeta? = null var currentEpisodeMeta: EpisodeMeta? = null
@ -83,6 +87,15 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
mediaMeta = loadMediaMeta(media.aodId) // can be done blocking, since it should be cached mediaMeta = loadMediaMeta(media.aodId) // can be done blocking, since it should be cached
} }
// run async as it should be loaded by the time the episodes a
viewModelScope.launch {
// get season info, if metaDB knows the tv show
if (media.type == DataTypes.MediaType.TVSHOW && mediaMeta != null) {
val tvShowMeta = mediaMeta as TVShowMeta
//tmdbTVSeason = TMDBApiController().getTVSeasonDetails(tvShowMeta.tmdbId, tvShowMeta.tmdbSeasonNumber)
}
}
currentEpisode = media.getEpisodeById(episodeId) currentEpisode = media.getEpisodeById(episodeId)
nextEpisode = selectNextEpisode() nextEpisode = selectNextEpisode()
currentEpisodeMeta = getEpisodeMetaByAoDMediaId(currentEpisode.mediaId) currentEpisodeMeta = getEpisodeMetaByAoDMediaId(currentEpisode.mediaId)
@ -159,7 +172,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
return if (media.type == DataTypes.MediaType.TVSHOW) { return if (media.type == DataTypes.MediaType.TVSHOW) {
getApplication<Application>().getString( getApplication<Application>().getString(
R.string.component_episode_title, R.string.component_episode_title,
currentEpisode.number, currentEpisode.numberStr,
currentEpisode.description currentEpisode.description
) )
} else { } else {
@ -189,7 +202,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
* episode, return null * episode, return null
*/ */
private fun selectNextEpisode(): AoDEpisode? { private fun selectNextEpisode(): AoDEpisode? {
return media.playlist.firstOrNull { it.number > media.getEpisodeById(currentEpisode.mediaId).number } return media.playlist.firstOrNull { it.index > media.getEpisodeById(currentEpisode.mediaId).index }
} }
} }

View File

@ -28,16 +28,15 @@ class EpisodesListPlayer @JvmOverloads constructor(
} }
model?.let { model?.let {
adapterRecEpisodes = PlayerEpisodeItemAdapter(model.media.playlist) adapterRecEpisodes = PlayerEpisodeItemAdapter(model.media.playlist, model.tmdbTVSeason?.episodes)
adapterRecEpisodes.onImageClick = { _, position -> adapterRecEpisodes.onImageClick = { _, position ->
(this.parent as ViewGroup).removeView(this) (this.parent as ViewGroup).removeView(this)
model.playEpisode(model.media.playlist[position], replace = true) model.playEpisode(model.media.playlist[position], replace = true)
} }
adapterRecEpisodes.currentSelected = model.currentEpisode.number - 1 adapterRecEpisodes.currentSelected = model.currentEpisode.index
binding.recyclerEpisodesPlayer.adapter = adapterRecEpisodes binding.recyclerEpisodesPlayer.adapter = adapterRecEpisodes
binding.recyclerEpisodesPlayer.scrollToPosition(model.currentEpisode.number - 1) // number != index binding.recyclerEpisodesPlayer.scrollToPosition(model.currentEpisode.index)
} }
} }

View File

@ -1,7 +1,6 @@
package org.mosad.teapod.util package org.mosad.teapod.util
import java.util.* import java.util.Locale
import kotlin.collections.ArrayList
class DataTypes { class DataTypes {
enum class MediaType { enum class MediaType {
@ -41,9 +40,6 @@ data class ItemMedia(
val posterUrl: String val posterUrl: String
) )
/**
* TODO the episodes workflow could use a clean up/rework
*/
// TODO replace playlist: List<AoDEpisode> with a map? // TODO replace playlist: List<AoDEpisode> with a map?
data class AoDMedia( data class AoDMedia(
val aodId: Int, val aodId: Int,
@ -56,7 +52,6 @@ data class AoDMedia(
val similar: List<ItemMedia>, val similar: List<ItemMedia>,
val playlist: List<AoDEpisode>, val playlist: List<AoDEpisode>,
) { ) {
fun hasEpisode(mediaId: Int) = playlist.any { it.mediaId == mediaId }
fun getEpisodeById(mediaId: Int) = playlist.firstOrNull { it.mediaId == mediaId } fun getEpisodeById(mediaId: Int) = playlist.firstOrNull { it.mediaId == mediaId }
?: AoDEpisodeNone ?: AoDEpisodeNone
} }
@ -67,7 +62,8 @@ data class AoDEpisode(
val description: String, val description: String,
val shortDesc: String, val shortDesc: String,
val imageURL: String, val imageURL: String,
val number: Int, val numberStr: String,
val index: Int,
var watched: Boolean, var watched: Boolean,
val watchedCallback: String, val watchedCallback: String,
val streams: MutableList<Stream>, val streams: MutableList<Stream>,
@ -113,6 +109,7 @@ val AoDEpisodeNone = AoDEpisode(
"", "",
"", "",
"", "",
"",
-1, -1,
false, false,
"", "",

View File

@ -27,9 +27,9 @@ class EpisodeItemAdapter(private val episodes: List<AoDEpisode>, private val tmd
val ep = episodes[position] val ep = episodes[position]
val titleText = if (ep.hasDub()) { val titleText = if (ep.hasDub()) {
context.getString(R.string.component_episode_title, ep.number, ep.description) context.getString(R.string.component_episode_title, ep.numberStr, ep.description)
} else { } else {
context.getString(R.string.component_episode_title_sub, ep.number, ep.description) context.getString(R.string.component_episode_title_sub, ep.numberStr, ep.description)
} }
holder.binding.textEpisodeTitle.text = titleText holder.binding.textEpisodeTitle.text = titleText

View File

@ -10,8 +10,9 @@ import jp.wasabeef.glide.transformations.RoundedCornersTransformation
import org.mosad.teapod.R import org.mosad.teapod.R
import org.mosad.teapod.databinding.ItemEpisodePlayerBinding import org.mosad.teapod.databinding.ItemEpisodePlayerBinding
import org.mosad.teapod.util.AoDEpisode import org.mosad.teapod.util.AoDEpisode
import org.mosad.teapod.util.tmdb.TMDBTVEpisode
class PlayerEpisodeItemAdapter(private val episodes: List<AoDEpisode>) : RecyclerView.Adapter<PlayerEpisodeItemAdapter.EpisodeViewHolder>() { class PlayerEpisodeItemAdapter(private val episodes: List<AoDEpisode>, private val tmdbEpisodes: List<TMDBTVEpisode>?) : RecyclerView.Adapter<PlayerEpisodeItemAdapter.EpisodeViewHolder>() {
var onImageClick: ((String, Int) -> Unit)? = null var onImageClick: ((String, Int) -> Unit)? = null
var currentSelected: Int = -1 // -1, since position should never be < 0 var currentSelected: Int = -1 // -1, since position should never be < 0
@ -25,13 +26,19 @@ class PlayerEpisodeItemAdapter(private val episodes: List<AoDEpisode>) : Recycle
val ep = episodes[position] val ep = episodes[position]
val titleText = if (ep.hasDub()) { val titleText = if (ep.hasDub()) {
context.getString(R.string.component_episode_title, ep.number, ep.description) context.getString(R.string.component_episode_title, ep.numberStr, ep.description)
} else { } else {
context.getString(R.string.component_episode_title_sub, ep.number, ep.description) context.getString(R.string.component_episode_title_sub, ep.numberStr, ep.description)
} }
holder.binding.textEpisodeTitle2.text = titleText holder.binding.textEpisodeTitle2.text = titleText
holder.binding.textEpisodeDesc2.text = ep.shortDesc holder.binding.textEpisodeDesc2.text = if (ep.shortDesc.isNotEmpty()) {
ep.shortDesc
} else if (tmdbEpisodes != null && position < tmdbEpisodes.size){
tmdbEpisodes[position].overview
} else {
""
}
if (ep.imageURL.isNotEmpty()) { if (ep.imageURL.isNotEmpty()) {
Glide.with(context).load(ep.imageURL) Glide.with(context).load(ep.imageURL)

View File

@ -51,7 +51,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:maxLines="10"
android:text="@string/text_overview_ex" android:text="@string/text_overview_ex"
android:textColor="@color/textPrimaryDark"/> android:textColor="@color/textPrimaryDark" />
</LinearLayout> </LinearLayout>

View File

@ -27,8 +27,8 @@
<item quantity="other">%d Minuten</item> <item quantity="other">%d Minuten</item>
</plurals> </plurals>
<string name="similar_titles">Ähnliche Titel</string> <string name="similar_titles">Ähnliche Titel</string>
<string name="component_episode_title">Flg. %1$d %2$s</string> <string name="component_episode_title">Flg. %1$s %2$s</string>
<string name="component_episode_title_sub">Flg. %1$d %2$s (OmU)</string> <string name="component_episode_title_sub">Flg. %1$s %2$s (OmU)</string>
<!-- settings fragment --> <!-- settings fragment -->
<string name="account">Account</string> <string name="account">Account</string>

View File

@ -34,8 +34,8 @@
<item quantity="other">%d Minutes</item> <item quantity="other">%d Minutes</item>
</plurals> </plurals>
<string name="similar_titles">Similar titles</string> <string name="similar_titles">Similar titles</string>
<string name="component_episode_title">Ep. %1$d %2$s</string> <string name="component_episode_title">Ep. %1$s %2$s</string>
<string name="component_episode_title_sub">Ep. %1$d %2$s (Sub)</string> <string name="component_episode_title_sub">Ep. %1$s %2$s (Sub)</string>
<string name="component_poster_desc" translatable="false">episode poster</string> <string name="component_poster_desc" translatable="false">episode poster</string>
<string name="component_watched_desc" translatable="false">already watched</string> <string name="component_watched_desc" translatable="false">already watched</string>