Merge pull request #7262 from Bnyro/master

refactor: merge OfflinePlayerService with VideoOfflinePlayerService
This commit is contained in:
Bnyro 2025-03-31 19:01:35 +02:00 committed by GitHub
commit a0a6694017
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 116 deletions

View File

@ -17,7 +17,6 @@ import com.github.libretube.parcelable.PlayerData
import com.github.libretube.services.AbstractPlayerService
import com.github.libretube.services.OfflinePlayerService
import com.github.libretube.services.OnlinePlayerService
import com.github.libretube.services.VideoOfflinePlayerService
import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.activities.NoInternetActivity
import com.github.libretube.ui.fragments.DownloadTab
@ -65,8 +64,7 @@ object BackgroundHelper {
fun stopBackgroundPlay(context: Context) {
arrayOf(
OnlinePlayerService::class.java,
OfflinePlayerService::class.java,
VideoOfflinePlayerService::class.java
OfflinePlayerService::class.java
).forEach {
val intent = Intent(context, it)
context.stopService(intent)
@ -104,7 +102,8 @@ object BackgroundHelper {
IntentData.videoId to videoId,
IntentData.shuffle to shuffle,
IntentData.downloadTab to downloadTab,
IntentData.noInternet to noInternet
IntentData.noInternet to noInternet,
IntentData.audioOnly to true
)
startMediaService(context, OfflinePlayerService::class.java, arguments)

View File

@ -15,7 +15,6 @@ import androidx.media3.common.ForwardingPlayer
import androidx.media3.common.MediaMetadata
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.Log
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
@ -119,13 +118,6 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
onServiceCreated(args)
notificationProvider?.intentActivity = getIntentActivity()
if (isAudioOnlyPlayer) {
trackSelector?.updateParameters {
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, true)
}
}
Log.e("custom start", "custom start")
if (::videoId.isInitialized) startPlayback()
}
}

View File

@ -3,9 +3,16 @@ package com.github.libretube.services
import android.content.Intent
import android.os.Bundle
import androidx.annotation.OptIn
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaItem.SubtitleConfiguration
import androidx.media3.common.MimeTypes
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.FileDataSource
import androidx.media3.exoplayer.source.MergingMediaSource
import androidx.media3.exoplayer.source.ProgressiveMediaSource
import androidx.media3.exoplayer.source.SingleSampleMediaSource
import com.github.libretube.constants.IntentData
import com.github.libretube.db.DatabaseHelper
import com.github.libretube.db.DatabaseHolder.Database
@ -15,6 +22,7 @@ import com.github.libretube.enums.FileType
import com.github.libretube.extensions.serializable
import com.github.libretube.extensions.setMetadata
import com.github.libretube.extensions.toAndroidUri
import com.github.libretube.extensions.updateParameters
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.activities.NoInternetActivity
@ -65,6 +73,7 @@ open class OfflinePlayerService : AbstractPlayerService() {
downloadTab = args.serializable(IntentData.downloadTab)!!
shuffle = args.getBoolean(IntentData.shuffle, false)
noInternetService = args.getBoolean(IntentData.noInternet, false)
isAudioOnlyPlayer = args.getBoolean(IntentData.audioOnly, false)
val videoId = if (shuffle) {
runBlocking(Dispatchers.IO) {
@ -75,10 +84,12 @@ open class OfflinePlayerService : AbstractPlayerService() {
} ?: return
setVideoId(videoId)
PlayingQueue.clear()
exoPlayer?.addListener(playerListener)
trackSelector?.updateParameters {
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, isAudioOnlyPlayer)
}
PlayingQueue.clear()
fillQueue()
}
@ -116,23 +127,71 @@ open class OfflinePlayerService : AbstractPlayerService() {
}
}
open fun setMediaItem(downloadWithItems: DownloadWithItems) {
val audioItem = downloadWithItems.downloadItems.filter { it.path.exists() }
.firstOrNull { it.type == FileType.AUDIO }
?: // in some rare cases, video files can contain audio
downloadWithItems.downloadItems.firstOrNull { it.type == FileType.VIDEO }
private fun setMediaItem(downloadWithItems: DownloadWithItems) {
val downloadFiles = downloadWithItems.downloadItems.filter { it.path.exists() }
if (audioItem == null) {
val videoUri = downloadFiles.firstOrNull { it.type == FileType.VIDEO }?.path?.toAndroidUri()
val audioUri = downloadFiles.firstOrNull { it.type == FileType.AUDIO }?.path?.toAndroidUri()
if (isAudioOnlyPlayer && audioUri == null) {
stopSelf()
return
}
val mediaItem = MediaItem.Builder()
.setUri(audioItem.path.toAndroidUri())
val subtitleInfo = downloadFiles.firstOrNull { it.type == FileType.SUBTITLE }
val subtitle = subtitleInfo?.let {
SubtitleConfiguration.Builder(it.path.toAndroidUri())
.setMimeType(MimeTypes.APPLICATION_TTML)
.setLanguage(it.language ?: "en")
.build()
}
when {
videoUri != null && audioUri != null -> {
val videoItem = MediaItem.Builder()
.setUri(videoUri)
.setMetadata(downloadWithItems)
.setSubtitleConfigurations(listOfNotNull(subtitle))
.build()
exoPlayer?.setMediaItem(mediaItem)
val videoSource = ProgressiveMediaSource.Factory(FileDataSource.Factory())
.createMediaSource(videoItem)
val audioSource = ProgressiveMediaSource.Factory(FileDataSource.Factory())
.createMediaSource(MediaItem.fromUri(audioUri))
var mediaSource = MergingMediaSource(audioSource, videoSource)
if (subtitle != null) {
val subtitleSource = SingleSampleMediaSource.Factory(FileDataSource.Factory())
.createMediaSource(subtitle, C.TIME_UNSET)
mediaSource = MergingMediaSource(mediaSource, subtitleSource)
}
exoPlayer?.setMediaSource(mediaSource)
}
videoUri != null -> exoPlayer?.setMediaItem(
MediaItem.Builder()
.setUri(videoUri)
.setMetadata(downloadWithItems)
.setSubtitleConfigurations(listOfNotNull(subtitle))
.build()
)
audioUri != null -> exoPlayer?.setMediaItem(
MediaItem.Builder()
.setUri(audioUri)
.setMetadata(downloadWithItems)
.setSubtitleConfigurations(listOfNotNull(subtitle))
.build()
)
}
trackSelector?.updateParameters {
setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
setPreferredTextLanguage(subtitle?.language)
}
}
private suspend fun fillQueue() {

View File

@ -4,6 +4,7 @@ import android.net.Uri
import android.os.Bundle
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaItem.SubtitleConfiguration
import androidx.media3.common.MimeTypes
@ -25,6 +26,7 @@ import com.github.libretube.extensions.parcelable
import com.github.libretube.extensions.setMetadata
import com.github.libretube.extensions.toastFromMainDispatcher
import com.github.libretube.extensions.toastFromMainThread
import com.github.libretube.extensions.updateParameters
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.PlayerHelper.checkForSegments
import com.github.libretube.helpers.PlayerHelper.getSubtitleRoleFlags
@ -112,13 +114,14 @@ open class OnlinePlayerService : AbstractPlayerService() {
if (!playerData.keepQueue) PlayingQueue.clear()
exoPlayer?.addListener(playerListener)
trackSelector?.updateParameters {
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, isAudioOnlyPlayer)
}
}
override suspend fun startPlayback() {
super.startPlayback()
Log.e("start", "playback")
val timestampMs = startTimestampSeconds?.times(1000) ?: 0L
startTimestampSeconds = null

View File

@ -1,85 +0,0 @@
package com.github.libretube.services
import androidx.annotation.OptIn
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaItem.SubtitleConfiguration
import androidx.media3.common.MimeTypes
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.FileDataSource
import androidx.media3.exoplayer.source.MergingMediaSource
import androidx.media3.exoplayer.source.ProgressiveMediaSource
import androidx.media3.exoplayer.source.SingleSampleMediaSource
import com.github.libretube.db.obj.DownloadWithItems
import com.github.libretube.enums.FileType
import com.github.libretube.extensions.setMetadata
import com.github.libretube.extensions.toAndroidUri
import com.github.libretube.extensions.updateParameters
import kotlin.io.path.exists
@OptIn(UnstableApi::class)
class VideoOfflinePlayerService: OfflinePlayerService() {
override var isAudioOnlyPlayer = false
override fun setMediaItem(downloadWithItems: DownloadWithItems) {
val downloadFiles = downloadWithItems.downloadItems.filter { it.path.exists() }
val videoUri = downloadFiles.firstOrNull { it.type == FileType.VIDEO }?.path?.toAndroidUri()
val audioUri = downloadFiles.firstOrNull { it.type == FileType.AUDIO }?.path?.toAndroidUri()
val subtitleInfo = downloadFiles.firstOrNull { it.type == FileType.SUBTITLE }
val subtitle = subtitleInfo?.let {
SubtitleConfiguration.Builder(it.path.toAndroidUri())
.setMimeType(MimeTypes.APPLICATION_TTML)
.setLanguage(it.language ?: "en")
.build()
}
when {
videoUri != null && audioUri != null -> {
val videoItem = MediaItem.Builder()
.setUri(videoUri)
.setMetadata(downloadWithItems)
.setSubtitleConfigurations(listOfNotNull(subtitle))
.build()
val videoSource = ProgressiveMediaSource.Factory(FileDataSource.Factory())
.createMediaSource(videoItem)
val audioSource = ProgressiveMediaSource.Factory(FileDataSource.Factory())
.createMediaSource(MediaItem.fromUri(audioUri))
var mediaSource = MergingMediaSource(audioSource, videoSource)
if (subtitle != null) {
val subtitleSource = SingleSampleMediaSource.Factory(FileDataSource.Factory())
.createMediaSource(subtitle, C.TIME_UNSET)
mediaSource = MergingMediaSource(mediaSource, subtitleSource)
}
exoPlayer?.setMediaSource(mediaSource)
}
videoUri != null -> exoPlayer?.setMediaItem(
MediaItem.Builder()
.setUri(videoUri)
.setMetadata(downloadWithItems)
.setSubtitleConfigurations(listOfNotNull(subtitle))
.build()
)
audioUri != null -> exoPlayer?.setMediaItem(
MediaItem.Builder()
.setUri(audioUri)
.setMetadata(downloadWithItems)
.setSubtitleConfigurations(listOfNotNull(subtitle))
.build()
)
}
trackSelector?.updateParameters {
setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
setPreferredTextLanguage(subtitle?.language)
}
}
}

View File

@ -32,7 +32,7 @@ import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.WindowHelper
import com.github.libretube.services.AbstractPlayerService
import com.github.libretube.services.VideoOfflinePlayerService
import com.github.libretube.services.OfflinePlayerService
import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.fragments.DownloadTab
import com.github.libretube.ui.interfaces.TimeFrameReceiver
@ -139,9 +139,10 @@ class OfflinePlayerActivity : BaseActivity() {
val arguments = bundleOf(
IntentData.downloadTab to DownloadTab.VIDEO,
IntentData.videoId to videoId
IntentData.videoId to videoId,
IntentData.audioOnly to false
)
BackgroundHelper.startMediaService(this, VideoOfflinePlayerService::class.java, arguments) {
BackgroundHelper.startMediaService(this, OfflinePlayerService::class.java, arguments) {
playerController = it
playerController.addListener(playerListener)
initializePlayerView()

View File

@ -95,7 +95,6 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
BackgroundHelper.startMediaService(
requireContext(),
if (isOffline) OfflinePlayerService::class.java else OnlinePlayerService::class.java,
bundleOf()
) {
if (_binding == null) {
it.sendCustomCommand(AbstractPlayerService.stopServiceCommand, Bundle.EMPTY)