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:
parent
062013489d
commit
5ea94b7ded
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue