add subtitle selection to player
This commit is contained in:
		| @ -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) | ||||
|  | ||||
| @ -30,7 +30,7 @@ class MediaFragmentViewModel(application: Application) : AndroidViewModel(applic | ||||
|         internal set | ||||
|     var episodesCrunchy = NoneEpisodes | ||||
|         internal set | ||||
|     val currentEpisodesCrunchy = arrayListOf<Episode>() | ||||
|     val currentEpisodesCrunchy = arrayListOf<Episode>() // 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 | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -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<Application>().getString( | ||||
|                 R.string.component_episode_title, | ||||
|                 currentEpisode.episode, | ||||
|                 currentEpisode.title | ||||
|             ) | ||||
|         } else { | ||||
|             // TODO movie | ||||
|             currentEpisode.title | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -25,10 +25,15 @@ class EpisodeItemAdapter(private val episodes: List<Episode>, 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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -71,8 +71,10 @@ | ||||
|     <string name="next_episode">Nächste Folge</string> | ||||
|     <string name="skip_opening">Intro überspringen</string> | ||||
|     <string name="language">Sprache</string> | ||||
|     <string name="subtitles">Untertitel</string> | ||||
|     <string name="episodes">Folgen</string> | ||||
|     <string name="episode">Folge</string> | ||||
|     <string name="no_subtitles">Aus</string> | ||||
|  | ||||
|     <!-- Onboarding --> | ||||
|     <string name="skip">Überspringen</string> | ||||
|  | ||||
| @ -92,8 +92,10 @@ | ||||
|     <string name="time_min_sec" translatable="false">%1$02d:%2$02d</string> | ||||
|     <string name="time_hour_min_sec" translatable="false">%1$d:%2$02d:%3$02d</string> | ||||
|     <string name="language">Language</string> | ||||
|     <string name="subtitles">Subtitles</string> | ||||
|     <string name="episodes">Episodes</string> | ||||
|     <string name="episode">Episode</string> | ||||
|     <string name="no_subtitles">None</string> | ||||
|  | ||||
|     <!-- Onboarding --> | ||||
|     <string name="skip">Skip</string> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user