diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt index b7b4fb7c..d9f20770 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt @@ -353,7 +353,7 @@ class PlayerActivity : BasePlayerActivity() { private var selectedIndex = 1 // Default to "Original" (index 1) private fun showQualitySelectionDialog() { - val originalResolution = viewModel.getoriginalResolution() ?: 0// TODO: Rework getting originalResolution + val originalResolution = viewModel.getOriginalResolution() ?: 0 val qualityEntries = resources.getStringArray(CoreR.array.quality_entries).toList() val qualityValues = resources.getStringArray(CoreR.array.quality_values).toList() diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt index 83d13407..a2245399 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt @@ -172,11 +172,11 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() { }else if (!appPreferences.downloadQualityDefault) { createPickQualityDialog() } else { - download() + startDownload() } } - private fun download(){ + private fun startDownload(){ binding.itemActions.downloadButton.setIconResource(AndroidR.color.transparent) binding.itemActions.progressDownload.isIndeterminate = true binding.itemActions.progressDownload.isVisible = true @@ -428,7 +428,7 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() { builder.setPositiveButton("Download") { dialog, _ -> appPreferences.downloadQuality = selectedQuality dialog.dismiss() - download() + startDownload() } builder.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt index a70d4456..abfa1f94 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt @@ -209,11 +209,11 @@ class MovieFragment : Fragment() { } else if (!appPreferences.downloadQualityDefault) { createPickQualityDialog() } else { - download() + startDownload() } } - private fun download() { + private fun startDownload() { binding.itemActions.downloadButton.setIconResource(android.R.color.transparent) binding.itemActions.progressDownload.isIndeterminate = true binding.itemActions.progressDownload.isVisible = true @@ -520,7 +520,7 @@ class MovieFragment : Fragment() { } builder.setPositiveButton("Download") { dialog, _ -> appPreferences.downloadQuality = selectedQuality - download() + startDownload() dialog.dismiss() } builder.setNegativeButton("Cancel") { dialog, _ -> diff --git a/core/src/main/res/xml/fragment_settings_downloads.xml b/core/src/main/res/xml/fragment_settings_downloads.xml index f0d0aa53..295a08a9 100644 --- a/core/src/main/res/xml/fragment_settings_downloads.xml +++ b/core/src/main/res/xml/fragment_settings_downloads.xml @@ -9,7 +9,6 @@ android:defaultValue="false" app:key="pref_downloads_roaming" app:title="@string/download_roaming" /> - suspend fun stopEncodingProcess(playSessionId: String) + + suspend fun getAccessToken(): String? } diff --git a/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt b/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt index a0847349..43c65951 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt @@ -786,4 +786,8 @@ class JellyfinRepositoryImpl( playSessionId = playSessionId, ) } + + override suspend fun getAccessToken(): String? { + return jellyfinApi.api.accessToken + } } diff --git a/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryOfflineImpl.kt b/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryOfflineImpl.kt index dcc4a39e..2bc0a7db 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryOfflineImpl.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryOfflineImpl.kt @@ -372,4 +372,8 @@ class JellyfinRepositoryOfflineImpl( override suspend fun stopEncodingProcess(playSessionId: String) { TODO("Not yet implemented") } + + override suspend fun getAccessToken(): String? { + TODO("Not yet implemented") + } } diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/SubtitleUtils.kt b/player/video/src/main/java/dev/jdtech/jellyfin/SubtitleUtils.kt new file mode 100644 index 00000000..1403ac2c --- /dev/null +++ b/player/video/src/main/java/dev/jdtech/jellyfin/SubtitleUtils.kt @@ -0,0 +1,20 @@ +package dev.jdtech.jellyfin + +import androidx.media3.common.MimeTypes + +public fun setSubtitlesMimeTypes(codec: String): String { + return when (codec) { + "subrip" -> MimeTypes.APPLICATION_SUBRIP + "webvtt" -> MimeTypes.TEXT_VTT + "ssa" -> MimeTypes.TEXT_SSA + "pgs" -> MimeTypes.APPLICATION_PGS + "ass" -> MimeTypes.TEXT_SSA + "srt" -> MimeTypes.APPLICATION_SUBRIP + "vtt" -> MimeTypes.TEXT_VTT + "ttml" -> MimeTypes.APPLICATION_TTML + "dfxp" -> MimeTypes.APPLICATION_TTML + "stl" -> MimeTypes.APPLICATION_TTML + "sbv" -> MimeTypes.APPLICATION_SUBRIP + else -> MimeTypes.TEXT_UNKNOWN + } +} diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt index ed808c49..ec9ab034 100644 --- a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt +++ b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt @@ -14,22 +14,20 @@ import androidx.media3.common.AudioAttributes import androidx.media3.common.C import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata -import androidx.media3.common.MimeTypes import androidx.media3.common.Player import androidx.media3.common.TrackSelectionOverride import androidx.media3.common.TrackSelectionParameters -import androidx.media3.common.VideoSize import androidx.media3.exoplayer.DefaultRenderersFactory import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.trackselection.DefaultTrackSelector import dagger.hilt.android.lifecycle.HiltViewModel import dev.jdtech.jellyfin.AppPreferences -import dev.jdtech.jellyfin.api.JellyfinApi import dev.jdtech.jellyfin.models.Intro import dev.jdtech.jellyfin.models.PlayerChapter import dev.jdtech.jellyfin.models.PlayerItem import dev.jdtech.jellyfin.models.Trickplay import dev.jdtech.jellyfin.models.VideoQuality +import dev.jdtech.jellyfin.setSubtitlesMimeTypes import dev.jdtech.jellyfin.mpv.MPVPlayer import dev.jdtech.jellyfin.player.video.R import dev.jdtech.jellyfin.repository.JellyfinRepository @@ -57,7 +55,6 @@ class PlayerActivityViewModel constructor( private val application: Application, private val jellyfinRepository: JellyfinRepository, - private val jellyfinApi: JellyfinApi, private val appPreferences: AppPreferences, private val savedStateHandle: SavedStateHandle, ) : ViewModel(), Player.Listener { @@ -510,29 +507,13 @@ constructor( val embeddedSubtitles = mediaSources[currentMediaItemIndex].mediaStreams .filter { it.type == MediaStreamType.SUBTITLE && !it.isExternal && it.path != null } .map { mediaStream -> - val test = mediaStream.codec - Timber.d("Deliver: %s", test) var deliveryUrl = mediaStream.path Timber.d("Deliverurl: %s", deliveryUrl) +// Not sure if still needed if (mediaStream.codec == "webvtt") { deliveryUrl = deliveryUrl?.replace("Stream.srt", "Stream.vtt")} MediaItem.SubtitleConfiguration.Builder(Uri.parse(deliveryUrl)) - .setMimeType( - when (mediaStream.codec) { - "subrip" -> MimeTypes.APPLICATION_SUBRIP - "webvtt" -> MimeTypes.TEXT_VTT - "ssa" -> MimeTypes.TEXT_SSA - "pgs" -> MimeTypes.APPLICATION_PGS - "ass" -> MimeTypes.TEXT_SSA - "srt" -> MimeTypes.APPLICATION_SUBRIP - "vtt" -> MimeTypes.TEXT_VTT - "ttml" -> MimeTypes.APPLICATION_TTML - "dfxp" -> MimeTypes.APPLICATION_TTML - "stl" -> MimeTypes.APPLICATION_TTML - "sbv" -> MimeTypes.APPLICATION_SUBRIP - else -> MimeTypes.TEXT_UNKNOWN - } - ) + .setMimeType(setSubtitlesMimeTypes(mediaStream.codec)) .setLanguage(mediaStream.language.ifBlank { "Unknown" }) .setLabel("Embedded") .build() @@ -541,20 +522,20 @@ constructor( val allSubtitles = - if (VideoQuality.getOriginal(videoQuality)) { + if (VideoQuality.getIsOriginalQuality(videoQuality)) { externalSubtitles }else { embeddedSubtitles.apply { addAll(externalSubtitles) } } - val url = if (VideoQuality.getOriginal(videoQuality)){ + val url = if (VideoQuality.getIsOriginalQuality(videoQuality)){ jellyfinRepository.getStreamUrl(currentItem.itemId, currentItem.mediaSourceId, playSessionId) } else { val mediaSourceId = mediaSources[currentMediaItemIndex].id val deviceId = jellyfinRepository.getDeviceId() val url = jellyfinRepository.getTranscodedVideoStream(currentItem.itemId, deviceId ,mediaSourceId, playSessionId!!, VideoQuality.getBitrate(videoQuality)) val uriBuilder = url.toUri().buildUpon() - val apiKey = jellyfinApi.api.accessToken // TODO: add in repo + val apiKey = jellyfinRepository.getAccessToken() uriBuilder.appendQueryParameter("api_key",apiKey ) val newUri = uriBuilder.build() newUri.toString() @@ -591,7 +572,7 @@ constructor( } } - fun getoriginalResolution(): Int? { + fun getOriginalResolution(): Int? { return originalResolution } } diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerViewModel.kt b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerViewModel.kt index 50a0fc1c..317367d0 100644 --- a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerViewModel.kt +++ b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerViewModel.kt @@ -18,6 +18,7 @@ import dev.jdtech.jellyfin.models.PlayerChapter import dev.jdtech.jellyfin.models.PlayerItem import dev.jdtech.jellyfin.models.TrickplayInfo import dev.jdtech.jellyfin.repository.JellyfinRepository +import dev.jdtech.jellyfin.setSubtitlesMimeTypes import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -126,6 +127,7 @@ class PlayerViewModel @Inject internal constructor( .map { episode -> episode.toPlayerItem(mediaSourceIndex, playbackPosition) } } + private suspend fun FindroidItem.toPlayerItem( mediaSourceIndex: Int?, playbackPosition: Long, @@ -136,7 +138,7 @@ class PlayerViewModel @Inject internal constructor( } else { mediaSources[mediaSourceIndex] } - // Embedded Sub externally for offline prep next commit + // Embedded Sub externally for offline playback val externalSubtitles = if (mediaSource.type.toString() == "LOCAL" ) { mediaSource.mediaStreams .filter { mediaStream -> @@ -147,13 +149,7 @@ class PlayerViewModel @Inject internal constructor( mediaStream.title, mediaStream.language, Uri.parse(mediaStream.path!!), - when (mediaStream.codec) { - "subrip" -> MimeTypes.APPLICATION_SUBRIP - "webvtt" -> MimeTypes.APPLICATION_SUBRIP - "pgs" -> MimeTypes.APPLICATION_PGS - "ass" -> MimeTypes.TEXT_SSA - else -> MimeTypes.TEXT_UNKNOWN - }, + setSubtitlesMimeTypes(mediaStream.codec), ) } }else { @@ -166,13 +162,7 @@ class PlayerViewModel @Inject internal constructor( mediaStream.title, mediaStream.language, Uri.parse(mediaStream.path!!), - when (mediaStream.codec) { - "subrip" -> MimeTypes.APPLICATION_SUBRIP - "webvtt" -> MimeTypes.APPLICATION_SUBRIP - "pgs" -> MimeTypes.APPLICATION_PGS - "ass" -> MimeTypes.TEXT_SSA - else -> MimeTypes.TEXT_UNKNOWN - }, + setSubtitlesMimeTypes(mediaStream.codec) ) } }