add subtitle selection to player

This commit is contained in:
Jannik 2021-12-29 20:51:53 +01:00
parent a14db062ed
commit 206a00fed5
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
10 changed files with 64 additions and 64 deletions

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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>