mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-01-07 18:10:31 +05:30
Convert DownloadService and BackgroundMode to lifecycle services.
This commit is contained in:
parent
0173ace37e
commit
5e6d171675
@ -3,7 +3,6 @@ package com.github.libretube.services
|
|||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.Service
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@ -13,10 +12,11 @@ import android.os.Looper
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
|
import androidx.lifecycle.LifecycleService
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.JsonHelper
|
import com.github.libretube.api.JsonHelper
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
import com.github.libretube.api.obj.Segment
|
|
||||||
import com.github.libretube.api.obj.SegmentData
|
import com.github.libretube.api.obj.SegmentData
|
||||||
import com.github.libretube.api.obj.Streams
|
import com.github.libretube.api.obj.Streams
|
||||||
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
||||||
@ -37,15 +37,15 @@ import com.google.android.exoplayer2.ExoPlayer
|
|||||||
import com.google.android.exoplayer2.MediaItem
|
import com.google.android.exoplayer2.MediaItem
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
import com.google.android.exoplayer2.PlaybackException
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.android.exoplayer2.Player
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the selected videos audio in background mode with a notification area.
|
* Loads the selected videos audio in background mode with a notification area.
|
||||||
*/
|
*/
|
||||||
class BackgroundMode : Service() {
|
class BackgroundMode : LifecycleService() {
|
||||||
/**
|
/**
|
||||||
* VideoId of the video
|
* VideoId of the video
|
||||||
*/
|
*/
|
||||||
@ -171,7 +171,7 @@ class BackgroundMode : Service() {
|
|||||||
seekToPosition: Long = 0,
|
seekToPosition: Long = 0,
|
||||||
keepQueue: Boolean = false
|
keepQueue: Boolean = false
|
||||||
) {
|
) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
streams = runCatching {
|
streams = runCatching {
|
||||||
RetrofitInstance.api.getStreams(videoId)
|
RetrofitInstance.api.getStreams(videoId)
|
||||||
}.getOrNull() ?: return@launch
|
}.getOrNull() ?: return@launch
|
||||||
@ -186,7 +186,7 @@ class BackgroundMode : Service() {
|
|||||||
PlayingQueue.updateCurrent(it)
|
PlayingQueue.updateCurrent(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.post {
|
withContext(Dispatchers.Main) {
|
||||||
playAudio(seekToPosition)
|
playAudio(seekToPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,18 +292,12 @@ class BackgroundMode : Service() {
|
|||||||
* Sets the [MediaItem] with the [streams] into the [player]
|
* Sets the [MediaItem] with the [streams] into the [player]
|
||||||
*/
|
*/
|
||||||
private fun setMediaItem() {
|
private fun setMediaItem() {
|
||||||
|
val streams = streams
|
||||||
streams ?: return
|
streams ?: return
|
||||||
|
|
||||||
val uri = if (streams!!.audioStreams.orEmpty().isNotEmpty()) {
|
val uri = if (streams.audioStreams.isNotEmpty()) {
|
||||||
PlayerHelper.getAudioSource(
|
PlayerHelper.getAudioSource(this, streams.audioStreams)
|
||||||
this,
|
} else streams.hls ?: return
|
||||||
streams!!.audioStreams!!
|
|
||||||
)
|
|
||||||
} else if (streams!!.hls != null) {
|
|
||||||
streams!!.hls
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val mediaItem = MediaItem.Builder()
|
val mediaItem = MediaItem.Builder()
|
||||||
.setUri(uri)
|
.setUri(uri)
|
||||||
@ -315,7 +309,7 @@ class BackgroundMode : Service() {
|
|||||||
* fetch the segments for SponsorBlock
|
* fetch the segments for SponsorBlock
|
||||||
*/
|
*/
|
||||||
private fun fetchSponsorBlockSegments() {
|
private fun fetchSponsorBlockSegments() {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val categories = PlayerHelper.getSponsorBlockCategories()
|
val categories = PlayerHelper.getSponsorBlockCategories()
|
||||||
if (categories.isEmpty()) return@runCatching
|
if (categories.isEmpty()) return@runCatching
|
||||||
@ -336,7 +330,7 @@ class BackgroundMode : Service() {
|
|||||||
|
|
||||||
if (segmentData == null || segmentData!!.segments.isEmpty()) return
|
if (segmentData == null || segmentData!!.segments.isEmpty()) return
|
||||||
|
|
||||||
segmentData!!.segments.forEach { segment: Segment ->
|
segmentData!!.segments.forEach { segment ->
|
||||||
val segmentStart = (segment.segment[0] * 1000f).toLong()
|
val segmentStart = (segment.segment[0] * 1000f).toLong()
|
||||||
val segmentEnd = (segment.segment[1] * 1000f).toLong()
|
val segmentEnd = (segment.segment[1] * 1000f).toLong()
|
||||||
val currentPosition = player?.currentPosition
|
val currentPosition = player?.currentPosition
|
||||||
@ -399,7 +393,8 @@ class BackgroundMode : Service() {
|
|||||||
fun getService(): BackgroundMode = this@BackgroundMode
|
fun getService(): BackgroundMode = this@BackgroundMode
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(p0: Intent?): IBinder {
|
override fun onBind(intent: Intent): IBinder {
|
||||||
|
super.onBind(intent)
|
||||||
return binder
|
return binder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package com.github.libretube.services
|
|||||||
|
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.Service
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
@ -11,6 +10,8 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
import androidx.core.util.set
|
import androidx.core.util.set
|
||||||
import androidx.core.util.valueIterator
|
import androidx.core.util.valueIterator
|
||||||
|
import androidx.lifecycle.LifecycleService
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.CronetHelper
|
import com.github.libretube.api.CronetHelper
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
@ -40,13 +41,9 @@ import java.io.File
|
|||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -59,12 +56,8 @@ import okio.source
|
|||||||
/**
|
/**
|
||||||
* Download service with custom implementation of downloading using [HttpURLConnection].
|
* Download service with custom implementation of downloading using [HttpURLConnection].
|
||||||
*/
|
*/
|
||||||
class DownloadService : Service() {
|
class DownloadService : LifecycleService() {
|
||||||
|
|
||||||
private val binder = LocalBinder()
|
private val binder = LocalBinder()
|
||||||
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
|
||||||
private val jobMain = SupervisorJob()
|
|
||||||
private val scope = CoroutineScope(dispatcher + jobMain)
|
|
||||||
|
|
||||||
private lateinit var notificationManager: NotificationManager
|
private lateinit var notificationManager: NotificationManager
|
||||||
private lateinit var summaryNotificationBuilder: NotificationCompat.Builder
|
private lateinit var summaryNotificationBuilder: NotificationCompat.Builder
|
||||||
@ -81,6 +74,7 @@ class DownloadService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
super.onStartCommand(intent, flags, startId)
|
||||||
when (intent?.action) {
|
when (intent?.action) {
|
||||||
ACTION_DOWNLOAD_RESUME -> resume(intent.getIntExtra("id", -1))
|
ACTION_DOWNLOAD_RESUME -> resume(intent.getIntExtra("id", -1))
|
||||||
ACTION_DOWNLOAD_PAUSE -> pause(intent.getIntExtra("id", -1))
|
ACTION_DOWNLOAD_PAUSE -> pause(intent.getIntExtra("id", -1))
|
||||||
@ -94,9 +88,11 @@ class DownloadService : Service() {
|
|||||||
val audioQuality = intent.getStringExtra(IntentData.audioQuality)
|
val audioQuality = intent.getStringExtra(IntentData.audioQuality)
|
||||||
val subtitleCode = intent.getStringExtra(IntentData.subtitleCode)
|
val subtitleCode = intent.getStringExtra(IntentData.subtitleCode)
|
||||||
|
|
||||||
scope.launch {
|
lifecycleScope.launch {
|
||||||
try {
|
try {
|
||||||
val streams = RetrofitInstance.api.getStreams(videoId)
|
val streams = withContext(Dispatchers.IO) {
|
||||||
|
RetrofitInstance.api.getStreams(videoId)
|
||||||
|
}
|
||||||
|
|
||||||
val thumbnailTargetFile = getDownloadFile(DownloadHelper.THUMBNAIL_DIR, fileName)
|
val thumbnailTargetFile = getDownloadFile(DownloadHelper.THUMBNAIL_DIR, fileName)
|
||||||
|
|
||||||
@ -153,7 +149,7 @@ class DownloadService : Service() {
|
|||||||
Database.downloadDao().insertDownloadItem(item)
|
Database.downloadDao().insertDownloadItem(item)
|
||||||
}.toInt()
|
}.toInt()
|
||||||
|
|
||||||
scope.launch {
|
lifecycleScope.launch {
|
||||||
downloadFile(item)
|
downloadFile(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,7 +293,7 @@ class DownloadService : Service() {
|
|||||||
val downloadCount = downloadQueue.valueIterator().asSequence().count { it }
|
val downloadCount = downloadQueue.valueIterator().asSequence().count { it }
|
||||||
if (downloadCount >= DownloadHelper.getMaxConcurrentDownloads()) {
|
if (downloadCount >= DownloadHelper.getMaxConcurrentDownloads()) {
|
||||||
toastFromMainThread(getString(R.string.concurrent_downloads_limit_reached))
|
toastFromMainThread(getString(R.string.concurrent_downloads_limit_reached))
|
||||||
scope.launch {
|
lifecycleScope.launch {
|
||||||
_downloadFlow.emit(id to DownloadStatus.Paused)
|
_downloadFlow.emit(id to DownloadStatus.Paused)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -306,7 +302,7 @@ class DownloadService : Service() {
|
|||||||
val downloadItem = awaitQuery {
|
val downloadItem = awaitQuery {
|
||||||
Database.downloadDao().findDownloadItemById(id)
|
Database.downloadDao().findDownloadItemById(id)
|
||||||
}
|
}
|
||||||
scope.launch {
|
lifecycleScope.launch {
|
||||||
downloadFile(downloadItem)
|
downloadFile(downloadItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,9 +464,9 @@ class DownloadService : Service() {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder {
|
override fun onBind(intent: Intent): IBinder {
|
||||||
val ids = intent?.getIntArrayExtra("ids")
|
super.onBind(intent)
|
||||||
ids?.forEach { id -> resume(id) }
|
intent.getIntArrayExtra("ids")?.forEach { resume(it) }
|
||||||
return binder
|
return binder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user