code: cleanup
This commit is contained in:
parent
d70253140d
commit
5609f7368d
11 changed files with 51 additions and 51 deletions
|
@ -353,7 +353,7 @@ class PlayerActivity : BasePlayerActivity() {
|
||||||
|
|
||||||
private var selectedIndex = 1 // Default to "Original" (index 1)
|
private var selectedIndex = 1 // Default to "Original" (index 1)
|
||||||
private fun showQualitySelectionDialog() {
|
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 qualityEntries = resources.getStringArray(CoreR.array.quality_entries).toList()
|
||||||
val qualityValues = resources.getStringArray(CoreR.array.quality_values).toList()
|
val qualityValues = resources.getStringArray(CoreR.array.quality_values).toList()
|
||||||
|
|
||||||
|
|
|
@ -172,11 +172,11 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
}else if (!appPreferences.downloadQualityDefault) {
|
}else if (!appPreferences.downloadQualityDefault) {
|
||||||
createPickQualityDialog()
|
createPickQualityDialog()
|
||||||
} else {
|
} else {
|
||||||
download()
|
startDownload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun download(){
|
private fun startDownload(){
|
||||||
binding.itemActions.downloadButton.setIconResource(AndroidR.color.transparent)
|
binding.itemActions.downloadButton.setIconResource(AndroidR.color.transparent)
|
||||||
binding.itemActions.progressDownload.isIndeterminate = true
|
binding.itemActions.progressDownload.isIndeterminate = true
|
||||||
binding.itemActions.progressDownload.isVisible = true
|
binding.itemActions.progressDownload.isVisible = true
|
||||||
|
@ -428,7 +428,7 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
builder.setPositiveButton("Download") { dialog, _ ->
|
builder.setPositiveButton("Download") { dialog, _ ->
|
||||||
appPreferences.downloadQuality = selectedQuality
|
appPreferences.downloadQuality = selectedQuality
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
download()
|
startDownload()
|
||||||
}
|
}
|
||||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
builder.setNegativeButton("Cancel") { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
|
|
@ -209,11 +209,11 @@ class MovieFragment : Fragment() {
|
||||||
} else if (!appPreferences.downloadQualityDefault) {
|
} else if (!appPreferences.downloadQualityDefault) {
|
||||||
createPickQualityDialog()
|
createPickQualityDialog()
|
||||||
} else {
|
} else {
|
||||||
download()
|
startDownload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun download() {
|
private fun startDownload() {
|
||||||
binding.itemActions.downloadButton.setIconResource(android.R.color.transparent)
|
binding.itemActions.downloadButton.setIconResource(android.R.color.transparent)
|
||||||
binding.itemActions.progressDownload.isIndeterminate = true
|
binding.itemActions.progressDownload.isIndeterminate = true
|
||||||
binding.itemActions.progressDownload.isVisible = true
|
binding.itemActions.progressDownload.isVisible = true
|
||||||
|
@ -520,7 +520,7 @@ class MovieFragment : Fragment() {
|
||||||
}
|
}
|
||||||
builder.setPositiveButton("Download") { dialog, _ ->
|
builder.setPositiveButton("Download") { dialog, _ ->
|
||||||
appPreferences.downloadQuality = selectedQuality
|
appPreferences.downloadQuality = selectedQuality
|
||||||
download()
|
startDownload()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
builder.setNegativeButton("Cancel") { dialog, _ ->
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
app:key="pref_downloads_roaming"
|
app:key="pref_downloads_roaming"
|
||||||
app:title="@string/download_roaming" />
|
app:title="@string/download_roaming" />
|
||||||
<!-- TODO: Strings -->
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="pref_downloads_quality"
|
android:key="pref_downloads_quality"
|
||||||
android:title="@string/download_quality"
|
android:title="@string/download_quality"
|
||||||
|
|
|
@ -4,7 +4,7 @@ enum class VideoQuality(
|
||||||
val bitrate: Int,
|
val bitrate: Int,
|
||||||
val height: Int,
|
val height: Int,
|
||||||
val width: Int,
|
val width: Int,
|
||||||
val original: Boolean,
|
val isOriginalQuality: Boolean,
|
||||||
) {
|
) {
|
||||||
Auto(10000000, 1080, 1920, false),
|
Auto(10000000, 1080, 1920, false),
|
||||||
Original(1000000000, 1080, 1920, true),
|
Original(1000000000, 1080, 1920, true),
|
||||||
|
@ -26,6 +26,6 @@ enum class VideoQuality(
|
||||||
fun getBitrate(quality: VideoQuality): Int = quality.bitrate
|
fun getBitrate(quality: VideoQuality): Int = quality.bitrate
|
||||||
fun getHeight(quality: VideoQuality): Int = quality.height
|
fun getHeight(quality: VideoQuality): Int = quality.height
|
||||||
fun getWidth(quality: VideoQuality): Int = quality.width
|
fun getWidth(quality: VideoQuality): Int = quality.width
|
||||||
fun getOriginal(quality: VideoQuality): Boolean = quality.original
|
fun getIsOriginalQuality(quality: VideoQuality): Boolean = quality.isOriginalQuality
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -175,4 +175,6 @@ interface JellyfinRepository {
|
||||||
): Response<PlaybackInfoResponse>
|
): Response<PlaybackInfoResponse>
|
||||||
|
|
||||||
suspend fun stopEncodingProcess(playSessionId: String)
|
suspend fun stopEncodingProcess(playSessionId: String)
|
||||||
|
|
||||||
|
suspend fun getAccessToken(): String?
|
||||||
}
|
}
|
||||||
|
|
|
@ -786,4 +786,8 @@ class JellyfinRepositoryImpl(
|
||||||
playSessionId = playSessionId,
|
playSessionId = playSessionId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAccessToken(): String? {
|
||||||
|
return jellyfinApi.api.accessToken
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,4 +372,8 @@ class JellyfinRepositoryOfflineImpl(
|
||||||
override suspend fun stopEncodingProcess(playSessionId: String) {
|
override suspend fun stopEncodingProcess(playSessionId: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAccessToken(): String? {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,22 +14,20 @@ import androidx.media3.common.AudioAttributes
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.MediaMetadata
|
import androidx.media3.common.MediaMetadata
|
||||||
import androidx.media3.common.MimeTypes
|
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.common.TrackSelectionOverride
|
import androidx.media3.common.TrackSelectionOverride
|
||||||
import androidx.media3.common.TrackSelectionParameters
|
import androidx.media3.common.TrackSelectionParameters
|
||||||
import androidx.media3.common.VideoSize
|
|
||||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.jdtech.jellyfin.AppPreferences
|
import dev.jdtech.jellyfin.AppPreferences
|
||||||
import dev.jdtech.jellyfin.api.JellyfinApi
|
|
||||||
import dev.jdtech.jellyfin.models.Intro
|
import dev.jdtech.jellyfin.models.Intro
|
||||||
import dev.jdtech.jellyfin.models.PlayerChapter
|
import dev.jdtech.jellyfin.models.PlayerChapter
|
||||||
import dev.jdtech.jellyfin.models.PlayerItem
|
import dev.jdtech.jellyfin.models.PlayerItem
|
||||||
import dev.jdtech.jellyfin.models.Trickplay
|
import dev.jdtech.jellyfin.models.Trickplay
|
||||||
import dev.jdtech.jellyfin.models.VideoQuality
|
import dev.jdtech.jellyfin.models.VideoQuality
|
||||||
|
import dev.jdtech.jellyfin.setSubtitlesMimeTypes
|
||||||
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||||
import dev.jdtech.jellyfin.player.video.R
|
import dev.jdtech.jellyfin.player.video.R
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
|
@ -57,7 +55,6 @@ class PlayerActivityViewModel
|
||||||
constructor(
|
constructor(
|
||||||
private val application: Application,
|
private val application: Application,
|
||||||
private val jellyfinRepository: JellyfinRepository,
|
private val jellyfinRepository: JellyfinRepository,
|
||||||
private val jellyfinApi: JellyfinApi,
|
|
||||||
private val appPreferences: AppPreferences,
|
private val appPreferences: AppPreferences,
|
||||||
private val savedStateHandle: SavedStateHandle,
|
private val savedStateHandle: SavedStateHandle,
|
||||||
) : ViewModel(), Player.Listener {
|
) : ViewModel(), Player.Listener {
|
||||||
|
@ -510,29 +507,13 @@ constructor(
|
||||||
val embeddedSubtitles = mediaSources[currentMediaItemIndex].mediaStreams
|
val embeddedSubtitles = mediaSources[currentMediaItemIndex].mediaStreams
|
||||||
.filter { it.type == MediaStreamType.SUBTITLE && !it.isExternal && it.path != null }
|
.filter { it.type == MediaStreamType.SUBTITLE && !it.isExternal && it.path != null }
|
||||||
.map { mediaStream ->
|
.map { mediaStream ->
|
||||||
val test = mediaStream.codec
|
|
||||||
Timber.d("Deliver: %s", test)
|
|
||||||
var deliveryUrl = mediaStream.path
|
var deliveryUrl = mediaStream.path
|
||||||
Timber.d("Deliverurl: %s", deliveryUrl)
|
Timber.d("Deliverurl: %s", deliveryUrl)
|
||||||
|
// Not sure if still needed
|
||||||
if (mediaStream.codec == "webvtt") {
|
if (mediaStream.codec == "webvtt") {
|
||||||
deliveryUrl = deliveryUrl?.replace("Stream.srt", "Stream.vtt")}
|
deliveryUrl = deliveryUrl?.replace("Stream.srt", "Stream.vtt")}
|
||||||
MediaItem.SubtitleConfiguration.Builder(Uri.parse(deliveryUrl))
|
MediaItem.SubtitleConfiguration.Builder(Uri.parse(deliveryUrl))
|
||||||
.setMimeType(
|
.setMimeType(setSubtitlesMimeTypes(mediaStream.codec))
|
||||||
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
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.setLanguage(mediaStream.language.ifBlank { "Unknown" })
|
.setLanguage(mediaStream.language.ifBlank { "Unknown" })
|
||||||
.setLabel("Embedded")
|
.setLabel("Embedded")
|
||||||
.build()
|
.build()
|
||||||
|
@ -541,20 +522,20 @@ constructor(
|
||||||
|
|
||||||
|
|
||||||
val allSubtitles =
|
val allSubtitles =
|
||||||
if (VideoQuality.getOriginal(videoQuality)) {
|
if (VideoQuality.getIsOriginalQuality(videoQuality)) {
|
||||||
externalSubtitles
|
externalSubtitles
|
||||||
}else {
|
}else {
|
||||||
embeddedSubtitles.apply { addAll(externalSubtitles) }
|
embeddedSubtitles.apply { addAll(externalSubtitles) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val url = if (VideoQuality.getOriginal(videoQuality)){
|
val url = if (VideoQuality.getIsOriginalQuality(videoQuality)){
|
||||||
jellyfinRepository.getStreamUrl(currentItem.itemId, currentItem.mediaSourceId, playSessionId)
|
jellyfinRepository.getStreamUrl(currentItem.itemId, currentItem.mediaSourceId, playSessionId)
|
||||||
} else {
|
} else {
|
||||||
val mediaSourceId = mediaSources[currentMediaItemIndex].id
|
val mediaSourceId = mediaSources[currentMediaItemIndex].id
|
||||||
val deviceId = jellyfinRepository.getDeviceId()
|
val deviceId = jellyfinRepository.getDeviceId()
|
||||||
val url = jellyfinRepository.getTranscodedVideoStream(currentItem.itemId, deviceId ,mediaSourceId, playSessionId!!, VideoQuality.getBitrate(videoQuality))
|
val url = jellyfinRepository.getTranscodedVideoStream(currentItem.itemId, deviceId ,mediaSourceId, playSessionId!!, VideoQuality.getBitrate(videoQuality))
|
||||||
val uriBuilder = url.toUri().buildUpon()
|
val uriBuilder = url.toUri().buildUpon()
|
||||||
val apiKey = jellyfinApi.api.accessToken // TODO: add in repo
|
val apiKey = jellyfinRepository.getAccessToken()
|
||||||
uriBuilder.appendQueryParameter("api_key",apiKey )
|
uriBuilder.appendQueryParameter("api_key",apiKey )
|
||||||
val newUri = uriBuilder.build()
|
val newUri = uriBuilder.build()
|
||||||
newUri.toString()
|
newUri.toString()
|
||||||
|
@ -591,7 +572,7 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getoriginalResolution(): Int? {
|
fun getOriginalResolution(): Int? {
|
||||||
return originalResolution
|
return originalResolution
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import dev.jdtech.jellyfin.models.PlayerChapter
|
||||||
import dev.jdtech.jellyfin.models.PlayerItem
|
import dev.jdtech.jellyfin.models.PlayerItem
|
||||||
import dev.jdtech.jellyfin.models.TrickplayInfo
|
import dev.jdtech.jellyfin.models.TrickplayInfo
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
|
import dev.jdtech.jellyfin.setSubtitlesMimeTypes
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -126,6 +127,7 @@ class PlayerViewModel @Inject internal constructor(
|
||||||
.map { episode -> episode.toPlayerItem(mediaSourceIndex, playbackPosition) }
|
.map { episode -> episode.toPlayerItem(mediaSourceIndex, playbackPosition) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private suspend fun FindroidItem.toPlayerItem(
|
private suspend fun FindroidItem.toPlayerItem(
|
||||||
mediaSourceIndex: Int?,
|
mediaSourceIndex: Int?,
|
||||||
playbackPosition: Long,
|
playbackPosition: Long,
|
||||||
|
@ -136,7 +138,7 @@ class PlayerViewModel @Inject internal constructor(
|
||||||
} else {
|
} else {
|
||||||
mediaSources[mediaSourceIndex]
|
mediaSources[mediaSourceIndex]
|
||||||
}
|
}
|
||||||
// Embedded Sub externally for offline prep next commit
|
// Embedded Sub externally for offline playback
|
||||||
val externalSubtitles = if (mediaSource.type.toString() == "LOCAL" ) {
|
val externalSubtitles = if (mediaSource.type.toString() == "LOCAL" ) {
|
||||||
mediaSource.mediaStreams
|
mediaSource.mediaStreams
|
||||||
.filter { mediaStream ->
|
.filter { mediaStream ->
|
||||||
|
@ -147,13 +149,7 @@ class PlayerViewModel @Inject internal constructor(
|
||||||
mediaStream.title,
|
mediaStream.title,
|
||||||
mediaStream.language,
|
mediaStream.language,
|
||||||
Uri.parse(mediaStream.path!!),
|
Uri.parse(mediaStream.path!!),
|
||||||
when (mediaStream.codec) {
|
setSubtitlesMimeTypes(mediaStream.codec),
|
||||||
"subrip" -> MimeTypes.APPLICATION_SUBRIP
|
|
||||||
"webvtt" -> MimeTypes.APPLICATION_SUBRIP
|
|
||||||
"pgs" -> MimeTypes.APPLICATION_PGS
|
|
||||||
"ass" -> MimeTypes.TEXT_SSA
|
|
||||||
else -> MimeTypes.TEXT_UNKNOWN
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
|
@ -166,13 +162,7 @@ class PlayerViewModel @Inject internal constructor(
|
||||||
mediaStream.title,
|
mediaStream.title,
|
||||||
mediaStream.language,
|
mediaStream.language,
|
||||||
Uri.parse(mediaStream.path!!),
|
Uri.parse(mediaStream.path!!),
|
||||||
when (mediaStream.codec) {
|
setSubtitlesMimeTypes(mediaStream.codec)
|
||||||
"subrip" -> MimeTypes.APPLICATION_SUBRIP
|
|
||||||
"webvtt" -> MimeTypes.APPLICATION_SUBRIP
|
|
||||||
"pgs" -> MimeTypes.APPLICATION_PGS
|
|
||||||
"ass" -> MimeTypes.TEXT_SSA
|
|
||||||
else -> MimeTypes.TEXT_UNKNOWN
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue