2023-04-10 19:24:09 +05:30
|
|
|
package com.github.libretube.services
|
|
|
|
|
|
|
|
import android.content.Intent
|
2023-04-11 13:22:43 +05:30
|
|
|
import android.os.IBinder
|
2023-04-10 19:24:09 +05:30
|
|
|
import androidx.core.app.NotificationCompat
|
|
|
|
import androidx.core.app.ServiceCompat
|
2023-04-11 13:22:43 +05:30
|
|
|
import androidx.lifecycle.LifecycleService
|
|
|
|
import androidx.lifecycle.lifecycleScope
|
2023-04-10 19:24:09 +05:30
|
|
|
import com.github.libretube.R
|
|
|
|
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
|
|
|
import com.github.libretube.constants.IntentData
|
|
|
|
import com.github.libretube.constants.PLAYER_NOTIFICATION_ID
|
|
|
|
import com.github.libretube.db.DatabaseHolder
|
|
|
|
import com.github.libretube.db.obj.DownloadWithItems
|
|
|
|
import com.github.libretube.enums.FileType
|
|
|
|
import com.github.libretube.extensions.toAndroidUri
|
|
|
|
import com.github.libretube.helpers.PlayerHelper
|
|
|
|
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
|
|
|
import com.github.libretube.obj.PlayerNotificationData
|
|
|
|
import com.github.libretube.util.NowPlayingNotification
|
|
|
|
import com.google.android.exoplayer2.ExoPlayer
|
|
|
|
import com.google.android.exoplayer2.MediaItem
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.withContext
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A service to play downloaded audio in the background
|
|
|
|
*/
|
2023-04-11 13:22:43 +05:30
|
|
|
class OfflinePlayerService : LifecycleService() {
|
2023-04-10 19:24:09 +05:30
|
|
|
private var player: ExoPlayer? = null
|
|
|
|
private var nowPlayingNotification: NowPlayingNotification? = null
|
|
|
|
|
|
|
|
override fun onCreate() {
|
|
|
|
super.onCreate()
|
|
|
|
|
|
|
|
val notification = NotificationCompat.Builder(this, BACKGROUND_CHANNEL_ID)
|
|
|
|
.setContentTitle(getString(R.string.app_name))
|
|
|
|
.setContentText(getString(R.string.playingOnBackground))
|
|
|
|
.setSmallIcon(R.drawable.ic_launcher_lockscreen)
|
|
|
|
.build()
|
|
|
|
|
|
|
|
startForeground(PLAYER_NOTIFICATION_ID, notification)
|
|
|
|
}
|
|
|
|
|
2023-04-11 13:22:43 +05:30
|
|
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
|
|
val videoId = intent?.getStringExtra(IntentData.videoId)
|
2023-04-10 19:24:09 +05:30
|
|
|
|
2023-04-11 13:22:43 +05:30
|
|
|
lifecycleScope.launch(Dispatchers.IO) {
|
2023-04-10 19:24:09 +05:30
|
|
|
val downloadWithItems = DatabaseHolder.Database.downloadDao().findById(videoId!!)
|
|
|
|
withContext(Dispatchers.Main) {
|
|
|
|
if (startAudioPlayer(downloadWithItems)) {
|
|
|
|
nowPlayingNotification = NowPlayingNotification(
|
|
|
|
this@OfflinePlayerService,
|
|
|
|
player!!,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
val notificationData = PlayerNotificationData(
|
|
|
|
title = downloadWithItems.download.title,
|
|
|
|
uploaderName = downloadWithItems.download.uploader,
|
|
|
|
thumbnailPath = downloadWithItems.download.thumbnailPath
|
|
|
|
)
|
|
|
|
nowPlayingNotification?.updatePlayerNotification(videoId, notificationData)
|
|
|
|
} else {
|
|
|
|
onDestroy()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return super.onStartCommand(intent, flags, startId)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempt to start an audio player with the given download items
|
|
|
|
* @param downloadWithItem The database download to play from
|
|
|
|
* @return whether starting the audio player succeeded
|
|
|
|
*/
|
|
|
|
private fun startAudioPlayer(downloadWithItem: DownloadWithItems): Boolean {
|
|
|
|
player = ExoPlayer.Builder(this)
|
|
|
|
.setUsePlatformDiagnostics(false)
|
|
|
|
.setHandleAudioBecomingNoisy(true)
|
|
|
|
.setAudioAttributes(PlayerHelper.getAudioAttributes(), true)
|
|
|
|
.setLoadControl(PlayerHelper.getLoadControl())
|
|
|
|
.build()
|
|
|
|
.loadPlaybackParams(isBackgroundMode = true).apply {
|
|
|
|
playWhenReady = true
|
|
|
|
}
|
|
|
|
|
|
|
|
val audioItem = downloadWithItem.downloadItems.firstOrNull { it.type == FileType.AUDIO }
|
|
|
|
?: // in some rare cases, video files can contain audio
|
|
|
|
downloadWithItem.downloadItems.firstOrNull { it.type == FileType.VIDEO } ?: return false
|
|
|
|
|
|
|
|
val mediaItem = MediaItem.Builder()
|
|
|
|
.setUri(audioItem.path.toAndroidUri())
|
|
|
|
.build()
|
|
|
|
|
|
|
|
player?.setMediaItem(mediaItem)
|
|
|
|
player?.prepare()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDestroy() {
|
|
|
|
nowPlayingNotification?.destroySelfAndPlayer()
|
|
|
|
|
|
|
|
player = null
|
|
|
|
nowPlayingNotification = null
|
|
|
|
|
|
|
|
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
|
|
|
stopSelf()
|
|
|
|
|
|
|
|
super.onDestroy()
|
|
|
|
}
|
|
|
|
|
2023-04-11 13:22:43 +05:30
|
|
|
override fun onBind(intent: Intent): IBinder? {
|
|
|
|
super.onBind(intent)
|
|
|
|
return null
|
|
|
|
}
|
2023-04-10 19:24:09 +05:30
|
|
|
}
|