From 206a00fed5e1a6ebdad760f0523962e605835c71 Mon Sep 17 00:00:00 2001 From: Jannik Date: Wed, 29 Dec 2021 20:51:53 +0100 Subject: [PATCH] add subtitle selection to player --- .../main/fragments/MediaFragmentEpisodes.kt | 1 + .../main/viewmodel/MediaFragmentViewModel.kt | 30 +------------- .../ui/activity/player/PlayerViewModel.kt | 40 ++++++++++++------- .../ui/components/LanguageSettingsPlayer.kt | 27 +++++++------ .../teapod/util/adapter/EpisodeItemAdapter.kt | 11 +++-- .../util/adapter/PlayerEpisodeItemAdapter.kt | 11 +++-- app/src/main/res/layout/player_controls.xml | 2 +- .../res/layout/player_language_settings.xml | 2 +- app/src/main/res/values-de-rDE/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 10 files changed, 64 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/MediaFragmentEpisodes.kt b/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/MediaFragmentEpisodes.kt index 301385e..8682060 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/MediaFragmentEpisodes.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/MediaFragmentEpisodes.kt @@ -39,6 +39,7 @@ class MediaFragmentEpisodes : Fragment() { playEpisode(seasonId, episodeId) } + // TODO don't show selection if only one season is present binding.buttonSeasonSelection.text = model.currentSeasonCrunchy.title binding.buttonSeasonSelection.setOnClickListener { v -> showSeasonSelection(v) diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt b/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt index 112a71e..adc6b25 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/main/viewmodel/MediaFragmentViewModel.kt @@ -30,7 +30,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic internal set var episodesCrunchy = NoneEpisodes internal set - val currentEpisodesCrunchy = arrayListOf() + val currentEpisodesCrunchy = arrayListOf() // used for EpisodeItemAdapter (easier updates) var tmdbResult: TMDBResult? = null // TODO rename internal set @@ -57,6 +57,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic // load the preferred season (preferred language, language per season, not per stream) currentSeasonCrunchy = seasonsCrunchy.getPreferredSeason(Preferences.preferredLocal) episodesCrunchy = Crunchyroll.episodes(currentSeasonCrunchy.id) + currentEpisodesCrunchy.clear() currentEpisodesCrunchy.addAll(episodesCrunchy.items) println("episodes: $episodesCrunchy") @@ -90,7 +91,6 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic /** * set media, tmdb and nextEpisode - * TODO run aod and tmdb load parallel */ // suspend fun loadAoD(aodId: Int) { // val tmdbApiController = TMDBApiController() @@ -146,30 +146,4 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic // ?: media.playlist.first().mediaId } - // remove unneeded info from the media title before searching - private fun stripTitleInfo(title: String): String { - return title.replace("(Sub)", "") - .replace(Regex("-?\\s?[0-9]+.\\s?(Staffel|Season)"), "") - .replace(Regex("(Staffel|Season)\\s?[0-9]+"), "") - .trim() - } - - /** guess Season from title - * if the title ends with a number, that could be the season - * if the title ends with Regex("-?\\s?[0-9]+.\\s?(Staffel|Season)") or - * Regex("(Staffel|Season)\\s?[0-9]+"), that is the season information - */ - private fun guessSeasonFromTitle(title: String): Int { - val helpTitle = title.replace("(Sub)", "").trim() - Log.d("test", "helpTitle: $helpTitle") - - return if (helpTitle.last().isDigit()) { - helpTitle.last().digitToInt() - } else { - Regex("([0-9]+.\\s?(Staffel|Season))|((Staffel|Season)\\s?[0-9]+)") - .find(helpTitle) - ?.value?.filter { it.isDigit() }?.toInt() ?: 1 - } - } - } \ No newline at end of file diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt index 615bea1..4d27a15 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt @@ -52,10 +52,10 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) internal set var currentEpisode = NoneEpisode internal set - private var currentPlayback = NonePlayback + var currentPlayback = NonePlayback // current playback settings - var currentLanguage: Locale = Locale.ROOT + var currentLanguage: Locale = Preferences.preferredLocal internal set init { @@ -113,11 +113,6 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) fun setLanguage(language: Locale) { currentLanguage = language playCurrentMedia(player.currentPosition) - -// val mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource( -// MediaItem.fromUri(Uri.parse(currentEpisodeAoD.getPreferredStream(language).url)) -// ) -// playMedia(mediaSource, seekTime) } // player actions @@ -167,10 +162,24 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) // update player gui (title, next ep button) after nextEpisodeId has been set currentEpisodeChangedListener.forEach { it() } - // get preferred stream url TODO implement - val localeKey = Preferences.preferredLocal.toLanguageTag() - val url = currentPlayback.streams.adaptive_hls[localeKey]?.url - ?: currentPlayback.streams.adaptive_hls[""]?.url ?: "" + // get preferred stream url, set current language if it differs from the preferred one + val preferredLocale = currentLanguage + val fallbackLocal = Locale.US + val url = when { + currentPlayback.streams.adaptive_hls.containsKey(preferredLocale.toLanguageTag()) -> { + currentPlayback.streams.adaptive_hls[preferredLocale.toLanguageTag()]?.url + } + currentPlayback.streams.adaptive_hls.containsKey(fallbackLocal.toLanguageTag()) -> { + currentLanguage = fallbackLocal + currentPlayback.streams.adaptive_hls[fallbackLocal.toLanguageTag()]?.url + } + else -> { + currentLanguage = Locale.ROOT + currentPlayback.streams.adaptive_hls[Locale.ROOT.toLanguageTag()]?.url ?: "" + } + } + + println("stream url: $url") // create the media source object @@ -187,17 +196,18 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) // TODO reimplement mark as watched for cr, if needed } + /** + * Returns the current episode title (with episode number, if it's a tv show) + */ fun getMediaTitle(): String { - // TODO add tvshow/movie diff - val isTVShow = true - return if(isTVShow) { + // currentEpisode.episodeNumber defines the media type (tv show = none null, movie = null) + return if (currentEpisode.episodeNumber != null) { getApplication().getString( R.string.component_episode_title, currentEpisode.episode, currentEpisode.title ) } else { - // TODO movie currentEpisode.title } } diff --git a/app/src/main/java/org/mosad/teapod/ui/components/LanguageSettingsPlayer.kt b/app/src/main/java/org/mosad/teapod/ui/components/LanguageSettingsPlayer.kt index 8c90188..897fc47 100644 --- a/app/src/main/java/org/mosad/teapod/ui/components/LanguageSettingsPlayer.kt +++ b/app/src/main/java/org/mosad/teapod/ui/components/LanguageSettingsPlayer.kt @@ -16,6 +16,7 @@ import org.mosad.teapod.databinding.PlayerLanguageSettingsBinding import org.mosad.teapod.ui.activity.player.PlayerViewModel import java.util.* +// TODO port to DialogFragment class LanguageSettingsPlayer @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @@ -24,34 +25,34 @@ class LanguageSettingsPlayer @JvmOverloads constructor( ) : LinearLayout(context, attrs, defStyleAttr) { private val binding = PlayerLanguageSettingsBinding.inflate(LayoutInflater.from(context), this, true) - var onViewRemovedAction: (() -> Unit)? = null // TODO find a better solution for this + var onViewRemovedAction: (() -> Unit)? = null - private var currentLanguage = model?.currentLanguage ?: Locale.ROOT + private var selectedLocale = model?.currentLanguage ?: Locale.ROOT init { - model?.let { - // TODO reimplement for cr -// it.currentEpisode.streams.forEach { stream -> -// addLanguage(stream.language.displayName, stream.language == currentLanguage) { -// currentLanguage = stream.language -// updateSelectedLanguage(it as TextView) -// } -// } + model?.let { m -> + m.currentPlayback.streams.adaptive_hls.keys.forEach { languageTag -> + val locale = Locale.forLanguageTag(languageTag) + addLanguage(locale, locale == m.currentLanguage) { v -> + selectedLocale = locale + updateSelectedLanguage(v as TextView) + } + } } binding.buttonCloseLanguageSettings.setOnClickListener { close() } binding.buttonCancel.setOnClickListener { close() } binding.buttonSelect.setOnClickListener { - model?.setLanguage(currentLanguage) + model?.setLanguage(selectedLocale) close() } } - private fun addLanguage(str: String, isSelected: Boolean, onClick: OnClickListener) { + private fun addLanguage(locale: Locale, isSelected: Boolean, onClick: OnClickListener) { val text = TextView(context).apply { height = 96 gravity = Gravity.CENTER_VERTICAL - text = str + text = if (locale == Locale.ROOT) context.getString(R.string.no_subtitles) else locale.displayLanguage setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f) if (isSelected) { 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 f90347c..2220c60 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 @@ -25,10 +25,15 @@ class EpisodeItemAdapter(private val episodes: List, private val tmdbEp val context = holder.binding.root.context val ep = episodes[position] - val titleText = if (ep.isDubbed) { - context.getString(R.string.component_episode_title, ep.episode, ep.title) + val titleText = if (ep.episodeNumber != null) { + // for tv shows add ep prefix and episode number + if (ep.isDubbed) { + context.getString(R.string.component_episode_title, ep.episode, ep.title) + } else { + context.getString(R.string.component_episode_title_sub, ep.episode, ep.title) + } } else { - context.getString(R.string.component_episode_title_sub, ep.episode, ep.title) + ep.title } 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 4efecaa..2035898 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 @@ -25,10 +25,15 @@ class PlayerEpisodeItemAdapter(private val episodes: Episodes, private val tmdbE val context = holder.binding.root.context val ep = episodes.items[position] - val titleText = if (ep.isDubbed) { - context.getString(R.string.component_episode_title, ep.episode, ep.title) + val titleText = if (ep.episodeNumber != null) { + // for tv shows add ep prefix and episode number + if (ep.isDubbed) { + context.getString(R.string.component_episode_title, ep.episode, ep.title) + } else { + context.getString(R.string.component_episode_title_sub, ep.episode, ep.title) + } } else { - context.getString(R.string.component_episode_title_sub, ep.episode, ep.title) + ep.title } holder.binding.textEpisodeTitle2.text = titleText diff --git a/app/src/main/res/layout/player_controls.xml b/app/src/main/res/layout/player_controls.xml index 459e147..c014874 100644 --- a/app/src/main/res/layout/player_controls.xml +++ b/app/src/main/res/layout/player_controls.xml @@ -125,7 +125,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="7dp" - android:text="@string/language" + android:text="@string/subtitles" android:textAllCaps="false" app:icon="@drawable/ic_baseline_subtitles_24" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/layout/player_language_settings.xml b/app/src/main/res/layout/player_language_settings.xml index b887b41..badc45f 100644 --- a/app/src/main/res/layout/player_language_settings.xml +++ b/app/src/main/res/layout/player_language_settings.xml @@ -35,7 +35,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="44dp" - android:text="@string/language" + android:text="@string/subtitles" android:textAlignment="center" android:textColor="@color/exo_white" android:textSize="16sp" diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index d7ed368..4f3d2b0 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -71,8 +71,10 @@ Nächste Folge Intro überspringen Sprache + Untertitel Folgen Folge + Aus Überspringen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3f122c5..ca77eca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -92,8 +92,10 @@ %1$02d:%2$02d %1$d:%2$02d:%3$02d Language + Subtitles Episodes Episode + None Skip