From 8a435677379b41be481d0388a69672d0cdae2f49 Mon Sep 17 00:00:00 2001 From: Jannik Date: Sat, 26 Dec 2020 14:39:35 +0100 Subject: [PATCH] rework how different streams/languages per episode are handled * potentially support more than 2 streams * part of language settings in player --- .../java/org/mosad/teapod/parser/AoDParser.kt | 84 +++++++++---------- .../mosad/teapod/player/PlayerViewModel.kt | 11 ++- .../java/org/mosad/teapod/util/DataTypes.kt | 38 +++++++-- .../teapod/util/adapter/EpisodeItemAdapter.kt | 6 +- .../util/adapter/PlayerEpisodeItemAdapter.kt | 6 +- app/src/main/res/values-de-rDE/strings.xml | 4 +- app/src/main/res/values/strings.xml | 4 +- 7 files changed, 85 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt b/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt index 567cbb8..9e38568 100644 --- a/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt +++ b/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt @@ -284,55 +284,45 @@ object AoDParser { //Log.i(javaClass.name, "New csrf token is $csrfToken") } - val pl = res.select("input.streamstarter_html5").first() - val primary = pl.attr("data-playlist") - val secondary = pl.attr("data-otherplaylist") - val secondaryIsOmU = secondary.contains("OmU", true) + val besides = res.select("div.besides").first() + val playlists = besides.select("input.streamstarter_html5").map { streamstarter -> + parsePlaylistAsync( + streamstarter.attr("data-playlist"), + streamstarter.attr("data-lang") + ) + }.awaitAll() - // load primary and secondary playlist - val primaryPlaylist = parsePlaylistAsync(primary) - val secondaryPlaylist = parsePlaylistAsync(secondary) - - primaryPlaylist.await().playlist.forEach { ep -> - try { - media.episodes.add(Episode( - id = ep.mediaid, - priStreamUrl = ep.sources.first().file, - posterUrl = ep.image, - title = ep.title, - description = ep.description, - number = getNumberFromTitle(ep.title, media.type) - )) - } catch (ex: Exception) { - Log.w(javaClass.name, "Could not parse episode information.", ex) + playlists.forEach { aod -> + // TODO improve language handling + val locale = when (aod.extLanguage) { + "ger" -> Locale.GERMAN + "jap" -> Locale.JAPANESE + else -> Locale.ROOT } - } - Log.i(javaClass.name, "Loading primary playlist finished") - secondaryPlaylist.await().playlist.forEach { ep -> - try { - val episode = media.episodes.firstOrNull { it.id == ep.mediaid } - - // if media contains already a episode with this id, add as secondary, else add as primary - if (episode != null) { - episode.secStreamUrl = ep.sources.first().file - episode.secStreamOmU = secondaryIsOmU - } else { - media.episodes.add(Episode( - id = ep.mediaid, - secStreamUrl = ep.sources.first().file, - secStreamOmU = secondaryIsOmU, - posterUrl = ep.image, - title = ep.title, - description = ep.description, - number = getNumberFromTitle(ep.title, media.type) - )) + aod.playlist.forEach { ep -> + try { + if (media.hasEpisode(ep.mediaid)) { + media.getEpisodeById(ep.mediaid).streams.add( + Stream(ep.sources.first().file, locale) + ) + } else { + media.episodes.add(Episode( + id = ep.mediaid, + streams = mutableListOf(Stream(ep.sources.first().file, locale)), + posterUrl = ep.image, + title = ep.title, + description = ep.description, + number = getNumberFromTitle(ep.title, media.type) + )) + println(getNumberFromTitle(ep.title, media.type)) + } + } catch (ex: Exception) { + Log.w(javaClass.name, "Could not parse episode information.", ex) } - } catch (ex: Exception) { - Log.w(javaClass.name, "Could not parse episode information.", ex) } } - Log.i(javaClass.name, "Loading secondary playlist finished") + Log.i(javaClass.name, "Loaded playlists successfully") // parse additional info from the media page res.select("table.vertical-table").select("tr").forEach { row -> @@ -371,9 +361,9 @@ object AoDParser { /** * don't use Gson().fromJson() as we don't have any control over the api and it may change */ - private fun parsePlaylistAsync(playlistPath: String): Deferred { + private fun parsePlaylistAsync(playlistPath: String, language: String): Deferred { if (playlistPath == "[]") { - return CompletableDeferred(AoDObject(listOf())) + return CompletableDeferred(AoDObject(listOf(), language)) } return GlobalScope.async(Dispatchers.IO) { @@ -406,7 +396,9 @@ object AoDParser { description = it.asJsonObject.get("description").asString, mediaid = it.asJsonObject.get("mediaid").asInt ) - }) + }, + language + ) } } diff --git a/app/src/main/java/org/mosad/teapod/player/PlayerViewModel.kt b/app/src/main/java/org/mosad/teapod/player/PlayerViewModel.kt index b7b61d9..ea7a9a8 100644 --- a/app/src/main/java/org/mosad/teapod/player/PlayerViewModel.kt +++ b/app/src/main/java/org/mosad/teapod/player/PlayerViewModel.kt @@ -9,6 +9,8 @@ import org.mosad.teapod.ui.fragments.MediaFragment import org.mosad.teapod.util.DataTypes import org.mosad.teapod.util.Episode import org.mosad.teapod.util.Media +import java.util.* +import kotlin.collections.ArrayList import kotlin.properties.Delegates /** @@ -55,13 +57,10 @@ class PlayerViewModel : ViewModel() { * If no stream is present, return empty string. */ fun autoSelectStream(episode: Episode): String { - return if ((Preferences.preferSecondary || episode.priStreamUrl.isEmpty()) && episode.secStreamOmU) { - episode.secStreamUrl - } else if (episode.priStreamUrl.isNotEmpty()) { - episode.priStreamUrl + return if (Preferences.preferSecondary) { + episode.getPreferredStream(Locale.JAPANESE).url } else { - Log.e(javaClass.name, "No stream url set. ${episode.id}") - "" + episode.getPreferredStream(Locale.GERMAN).url } } diff --git a/app/src/main/java/org/mosad/teapod/util/DataTypes.kt b/app/src/main/java/org/mosad/teapod/util/DataTypes.kt index 57cda35..0aa9094 100644 --- a/app/src/main/java/org/mosad/teapod/util/DataTypes.kt +++ b/app/src/main/java/org/mosad/teapod/util/DataTypes.kt @@ -1,5 +1,8 @@ package org.mosad.teapod.util +import java.util.* +import kotlin.collections.ArrayList + class DataTypes { enum class MediaType { OTHER, @@ -47,7 +50,10 @@ data class Media( val type: DataTypes.MediaType, val info: Info = Info(), var episodes: ArrayList = arrayListOf() -) +) { + fun hasEpisode(id: Int) = episodes.any { it.id == id } + fun getEpisodeById(id: Int) = episodes.first { it.id == id } +} data class Info( var title: String = "", @@ -60,23 +66,37 @@ data class Info( ) /** - * if secStreamOmU == true, then a secondary stream is present * number = episode number (0..n) */ data class Episode( val id: Int = 0, + val streams: MutableList = mutableListOf(), var title: String = "", - var priStreamUrl: String = "", - var secStreamUrl: String = "", - var secStreamOmU: Boolean = false, var posterUrl: String = "", var description: String = "", var shortDesc: String = "", var number: Int = 0, var watched: Boolean = false, var watchedCallback: String = "" +) { + /** + * get the preferred stream + * @return the preferred stream, if not present use the first stream + */ + fun getPreferredStream(language: Locale) = + streams.firstOrNull { it.language == language } ?: streams.first() + + fun hasDub() = streams.any { it.language == Locale.GERMAN } +} + +data class Stream( + val url: String, + val language : Locale ) +/** + * this class is used for tmdb responses + */ data class TMDBResponse( val id: Int = 0, val title: String = "", @@ -86,7 +106,13 @@ data class TMDBResponse( var runtime: Int = 0 ) -data class AoDObject(val playlist: List) +/** + * this class is used to represent the aod json API? + */ +data class AoDObject( + val playlist: List, + val extLanguage: String +) data class Playlist( val sources: List, diff --git a/app/src/main/java/org/mosad/teapod/util/adapter/EpisodeItemAdapter.kt b/app/src/main/java/org/mosad/teapod/util/adapter/EpisodeItemAdapter.kt index cb0a96a..9438dc8 100644 --- a/app/src/main/java/org/mosad/teapod/util/adapter/EpisodeItemAdapter.kt +++ b/app/src/main/java/org/mosad/teapod/util/adapter/EpisodeItemAdapter.kt @@ -23,10 +23,10 @@ class EpisodeItemAdapter(private val episodes: List) : RecyclerView.Ada val context = holder.binding.root.context val ep = episodes[position] - val titleText = if (ep.priStreamUrl.isEmpty() && ep.secStreamOmU) { - context.getString(R.string.component_episode_title_sub, ep.number, ep.description) - } else { + val titleText = if (ep.hasDub()) { context.getString(R.string.component_episode_title, ep.number, ep.description) + } else { + context.getString(R.string.component_episode_title_sub, ep.number, ep.description) } holder.binding.textEpisodeTitle.text = titleText diff --git a/app/src/main/java/org/mosad/teapod/util/adapter/PlayerEpisodeItemAdapter.kt b/app/src/main/java/org/mosad/teapod/util/adapter/PlayerEpisodeItemAdapter.kt index 470a559..f9f34b0 100644 --- a/app/src/main/java/org/mosad/teapod/util/adapter/PlayerEpisodeItemAdapter.kt +++ b/app/src/main/java/org/mosad/teapod/util/adapter/PlayerEpisodeItemAdapter.kt @@ -22,10 +22,10 @@ class PlayerEpisodeItemAdapter(private val episodes: List) : RecyclerVi val context = holder.binding.root.context val ep = episodes[position] - val titleText = if (ep.priStreamUrl.isEmpty() && ep.secStreamOmU) { - context.getString(R.string.component_episode_title_sub, ep.number, ep.description) - } else { + val titleText = if (ep.hasDub()) { context.getString(R.string.component_episode_title, ep.number, ep.description) + } else { + context.getString(R.string.component_episode_title_sub, ep.number, ep.description) } holder.binding.textEpisodeTitle2.text = titleText diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index c407343..e5ca39f 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -28,8 +28,8 @@ Info Version %1$s (%2$s) Einstellungen - Bevorzuge alternativen Stream - Untertitle-Stream verwenden, sofern vorhanden + Bevorzuge Japanisch (OmU) + Japanisch verwenden, sofern vorhanden Autoplay Nächste Episode automatisch abspielen Design diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f8eae25..ac708df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -37,8 +37,8 @@ Teapod by @Seil0 Version %1$s (%2$s) Settings - Prefer secondary (sub) stream - Use the subtitles stream if present + Prefer japanese (sub) + Use the japanese, if present Autoplay Play next episode automatically Theme