mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 15:30:31 +05:30
Merge pull request #7262 from Bnyro/master
refactor: merge OfflinePlayerService with VideoOfflinePlayerService
This commit is contained in:
commit
a0a6694017
@ -17,7 +17,6 @@ import com.github.libretube.parcelable.PlayerData
|
|||||||
import com.github.libretube.services.AbstractPlayerService
|
import com.github.libretube.services.AbstractPlayerService
|
||||||
import com.github.libretube.services.OfflinePlayerService
|
import com.github.libretube.services.OfflinePlayerService
|
||||||
import com.github.libretube.services.OnlinePlayerService
|
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.MainActivity
|
||||||
import com.github.libretube.ui.activities.NoInternetActivity
|
import com.github.libretube.ui.activities.NoInternetActivity
|
||||||
import com.github.libretube.ui.fragments.DownloadTab
|
import com.github.libretube.ui.fragments.DownloadTab
|
||||||
@ -65,8 +64,7 @@ object BackgroundHelper {
|
|||||||
fun stopBackgroundPlay(context: Context) {
|
fun stopBackgroundPlay(context: Context) {
|
||||||
arrayOf(
|
arrayOf(
|
||||||
OnlinePlayerService::class.java,
|
OnlinePlayerService::class.java,
|
||||||
OfflinePlayerService::class.java,
|
OfflinePlayerService::class.java
|
||||||
VideoOfflinePlayerService::class.java
|
|
||||||
).forEach {
|
).forEach {
|
||||||
val intent = Intent(context, it)
|
val intent = Intent(context, it)
|
||||||
context.stopService(intent)
|
context.stopService(intent)
|
||||||
@ -104,7 +102,8 @@ object BackgroundHelper {
|
|||||||
IntentData.videoId to videoId,
|
IntentData.videoId to videoId,
|
||||||
IntentData.shuffle to shuffle,
|
IntentData.shuffle to shuffle,
|
||||||
IntentData.downloadTab to downloadTab,
|
IntentData.downloadTab to downloadTab,
|
||||||
IntentData.noInternet to noInternet
|
IntentData.noInternet to noInternet,
|
||||||
|
IntentData.audioOnly to true
|
||||||
)
|
)
|
||||||
|
|
||||||
startMediaService(context, OfflinePlayerService::class.java, arguments)
|
startMediaService(context, OfflinePlayerService::class.java, arguments)
|
||||||
|
@ -15,7 +15,6 @@ import androidx.media3.common.ForwardingPlayer
|
|||||||
import androidx.media3.common.MediaMetadata
|
import androidx.media3.common.MediaMetadata
|
||||||
import androidx.media3.common.PlaybackException
|
import androidx.media3.common.PlaybackException
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.common.util.Log
|
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
@ -119,13 +118,6 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
onServiceCreated(args)
|
onServiceCreated(args)
|
||||||
notificationProvider?.intentActivity = getIntentActivity()
|
notificationProvider?.intentActivity = getIntentActivity()
|
||||||
|
|
||||||
if (isAudioOnlyPlayer) {
|
|
||||||
trackSelector?.updateParameters {
|
|
||||||
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.e("custom start", "custom start")
|
|
||||||
if (::videoId.isInitialized) startPlayback()
|
if (::videoId.isInitialized) startPlayback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,16 @@ package com.github.libretube.services
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.MediaItem
|
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.Player
|
||||||
import androidx.media3.common.util.UnstableApi
|
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.constants.IntentData
|
||||||
import com.github.libretube.db.DatabaseHelper
|
import com.github.libretube.db.DatabaseHelper
|
||||||
import com.github.libretube.db.DatabaseHolder.Database
|
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.serializable
|
||||||
import com.github.libretube.extensions.setMetadata
|
import com.github.libretube.extensions.setMetadata
|
||||||
import com.github.libretube.extensions.toAndroidUri
|
import com.github.libretube.extensions.toAndroidUri
|
||||||
|
import com.github.libretube.extensions.updateParameters
|
||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
import com.github.libretube.ui.activities.NoInternetActivity
|
import com.github.libretube.ui.activities.NoInternetActivity
|
||||||
@ -65,6 +73,7 @@ open class OfflinePlayerService : AbstractPlayerService() {
|
|||||||
downloadTab = args.serializable(IntentData.downloadTab)!!
|
downloadTab = args.serializable(IntentData.downloadTab)!!
|
||||||
shuffle = args.getBoolean(IntentData.shuffle, false)
|
shuffle = args.getBoolean(IntentData.shuffle, false)
|
||||||
noInternetService = args.getBoolean(IntentData.noInternet, false)
|
noInternetService = args.getBoolean(IntentData.noInternet, false)
|
||||||
|
isAudioOnlyPlayer = args.getBoolean(IntentData.audioOnly, false)
|
||||||
|
|
||||||
val videoId = if (shuffle) {
|
val videoId = if (shuffle) {
|
||||||
runBlocking(Dispatchers.IO) {
|
runBlocking(Dispatchers.IO) {
|
||||||
@ -75,10 +84,12 @@ open class OfflinePlayerService : AbstractPlayerService() {
|
|||||||
} ?: return
|
} ?: return
|
||||||
setVideoId(videoId)
|
setVideoId(videoId)
|
||||||
|
|
||||||
PlayingQueue.clear()
|
|
||||||
|
|
||||||
exoPlayer?.addListener(playerListener)
|
exoPlayer?.addListener(playerListener)
|
||||||
|
trackSelector?.updateParameters {
|
||||||
|
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, isAudioOnlyPlayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayingQueue.clear()
|
||||||
fillQueue()
|
fillQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,23 +127,71 @@ open class OfflinePlayerService : AbstractPlayerService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setMediaItem(downloadWithItems: DownloadWithItems) {
|
private fun setMediaItem(downloadWithItems: DownloadWithItems) {
|
||||||
val audioItem = downloadWithItems.downloadItems.filter { it.path.exists() }
|
val downloadFiles = 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 }
|
|
||||||
|
|
||||||
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()
|
stopSelf()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val mediaItem = MediaItem.Builder()
|
val subtitleInfo = downloadFiles.firstOrNull { it.type == FileType.SUBTITLE }
|
||||||
.setUri(audioItem.path.toAndroidUri())
|
|
||||||
.setMetadata(downloadWithItems)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
exoPlayer?.setMediaItem(mediaItem)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fillQueue() {
|
private suspend fun fillQueue() {
|
||||||
|
@ -4,6 +4,7 @@ import android.net.Uri
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||||
import androidx.media3.common.MimeTypes
|
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.setMetadata
|
||||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||||
import com.github.libretube.extensions.toastFromMainThread
|
import com.github.libretube.extensions.toastFromMainThread
|
||||||
|
import com.github.libretube.extensions.updateParameters
|
||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.helpers.PlayerHelper.checkForSegments
|
import com.github.libretube.helpers.PlayerHelper.checkForSegments
|
||||||
import com.github.libretube.helpers.PlayerHelper.getSubtitleRoleFlags
|
import com.github.libretube.helpers.PlayerHelper.getSubtitleRoleFlags
|
||||||
@ -112,13 +114,14 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
if (!playerData.keepQueue) PlayingQueue.clear()
|
if (!playerData.keepQueue) PlayingQueue.clear()
|
||||||
|
|
||||||
exoPlayer?.addListener(playerListener)
|
exoPlayer?.addListener(playerListener)
|
||||||
|
trackSelector?.updateParameters {
|
||||||
|
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, isAudioOnlyPlayer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun startPlayback() {
|
override suspend fun startPlayback() {
|
||||||
super.startPlayback()
|
super.startPlayback()
|
||||||
|
|
||||||
Log.e("start", "playback")
|
|
||||||
|
|
||||||
val timestampMs = startTimestampSeconds?.times(1000) ?: 0L
|
val timestampMs = startTimestampSeconds?.times(1000) ?: 0L
|
||||||
startTimestampSeconds = null
|
startTimestampSeconds = null
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,7 +32,7 @@ import com.github.libretube.helpers.BackgroundHelper
|
|||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.helpers.WindowHelper
|
import com.github.libretube.helpers.WindowHelper
|
||||||
import com.github.libretube.services.AbstractPlayerService
|
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.base.BaseActivity
|
||||||
import com.github.libretube.ui.fragments.DownloadTab
|
import com.github.libretube.ui.fragments.DownloadTab
|
||||||
import com.github.libretube.ui.interfaces.TimeFrameReceiver
|
import com.github.libretube.ui.interfaces.TimeFrameReceiver
|
||||||
@ -139,9 +139,10 @@ class OfflinePlayerActivity : BaseActivity() {
|
|||||||
|
|
||||||
val arguments = bundleOf(
|
val arguments = bundleOf(
|
||||||
IntentData.downloadTab to DownloadTab.VIDEO,
|
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 = it
|
||||||
playerController.addListener(playerListener)
|
playerController.addListener(playerListener)
|
||||||
initializePlayerView()
|
initializePlayerView()
|
||||||
|
@ -95,7 +95,6 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
|
|||||||
BackgroundHelper.startMediaService(
|
BackgroundHelper.startMediaService(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
if (isOffline) OfflinePlayerService::class.java else OnlinePlayerService::class.java,
|
if (isOffline) OfflinePlayerService::class.java else OnlinePlayerService::class.java,
|
||||||
bundleOf()
|
|
||||||
) {
|
) {
|
||||||
if (_binding == null) {
|
if (_binding == null) {
|
||||||
it.sendCustomCommand(AbstractPlayerService.stopServiceCommand, Bundle.EMPTY)
|
it.sendCustomCommand(AbstractPlayerService.stopServiceCommand, Bundle.EMPTY)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user