forked from recloudstream/cloudstream
download resume and stuff
This commit is contained in:
parent
3ef14b93fb
commit
576377e4bb
5 changed files with 136 additions and 24 deletions
|
@ -33,6 +33,19 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".recivers.VideoDownloadRestartReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="restart_service" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<service
|
||||||
|
android:name=".services.VideoDownloadKeepAliveService"
|
||||||
|
android:enabled="true" >
|
||||||
|
</service>
|
||||||
<service
|
<service
|
||||||
android:name=".services.VideoDownloadService"
|
android:name=".services.VideoDownloadService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
|
|
|
@ -1,39 +1,28 @@
|
||||||
package com.lagradost.cloudstream3
|
package com.lagradost.cloudstream3
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.PictureInPictureParams
|
import android.app.PictureInPictureParams
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.ui.AppBarConfiguration
|
import androidx.navigation.ui.AppBarConfiguration
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.anggrayudi.storage.SimpleStorage
|
import com.anggrayudi.storage.SimpleStorage
|
||||||
import com.anggrayudi.storage.callback.StorageAccessCallback
|
|
||||||
import com.anggrayudi.storage.file.StorageId
|
import com.anggrayudi.storage.file.StorageId
|
||||||
import com.anggrayudi.storage.file.StorageType
|
|
||||||
import com.anggrayudi.storage.file.getStorageId
|
|
||||||
import com.google.android.gms.cast.ApplicationMetadata
|
|
||||||
import com.google.android.gms.cast.Cast
|
|
||||||
import com.google.android.gms.cast.LaunchOptions
|
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
|
||||||
import com.google.android.gms.cast.framework.CastSession
|
|
||||||
import com.google.android.gms.cast.framework.SessionManagerListener
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import com.karumi.dexter.Dexter
|
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
|
||||||
import com.karumi.dexter.listener.multi.BaseMultiplePermissionsListener
|
|
||||||
import com.lagradost.cloudstream3.UIHelper.checkWrite
|
import com.lagradost.cloudstream3.UIHelper.checkWrite
|
||||||
import com.lagradost.cloudstream3.UIHelper.hasPIPPermission
|
import com.lagradost.cloudstream3.UIHelper.hasPIPPermission
|
||||||
import com.lagradost.cloudstream3.UIHelper.requestRW
|
import com.lagradost.cloudstream3.UIHelper.requestRW
|
||||||
import com.lagradost.cloudstream3.UIHelper.shouldShowPIPMode
|
import com.lagradost.cloudstream3.UIHelper.shouldShowPIPMode
|
||||||
|
import com.lagradost.cloudstream3.recivers.VideoDownloadRestartReceiver
|
||||||
|
import com.lagradost.cloudstream3.services.RESTART_ALL_DOWNLOADS_AND_QUEUE
|
||||||
|
import com.lagradost.cloudstream3.services.RESTART_NONE
|
||||||
|
import com.lagradost.cloudstream3.services.START_VALUE_KEY
|
||||||
|
import com.lagradost.cloudstream3.services.VideoDownloadKeepAliveService
|
||||||
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,6 +114,14 @@ class MainActivity : AppCompatActivity() {
|
||||||
storage.onRestoreInstanceState(savedInstanceState)
|
storage.onRestoreInstanceState(savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
val broadcastIntent = Intent()
|
||||||
|
broadcastIntent.action = "restart_service"
|
||||||
|
broadcastIntent.setClass(this, VideoDownloadRestartReceiver::class.java)
|
||||||
|
this.sendBroadcast(broadcastIntent)
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
mainContext = this
|
mainContext = this
|
||||||
|
@ -161,6 +158,12 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
CastButtonFactory.setUpMediaRouteButton(this, media_route_button)
|
CastButtonFactory.setUpMediaRouteButton(this, media_route_button)
|
||||||
|
|
||||||
|
if (!VideoDownloadManager.isMyServiceRunning(this, VideoDownloadKeepAliveService::class.java)) {
|
||||||
|
val mYourService = VideoDownloadKeepAliveService()
|
||||||
|
val mServiceIntent = Intent(this, mYourService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE)
|
||||||
|
this.startService(mServiceIntent)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
val castContext = CastContext.getSharedInstance(applicationContext)
|
val castContext = CastContext.getSharedInstance(applicationContext)
|
||||||
fun buildMediaQueueItem(video: String): MediaQueueItem {
|
fun buildMediaQueueItem(video: String): MediaQueueItem {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.lagradost.cloudstream3.recivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import com.lagradost.cloudstream3.services.RESTART_ALL_DOWNLOADS_AND_QUEUE
|
||||||
|
import com.lagradost.cloudstream3.services.START_VALUE_KEY
|
||||||
|
import com.lagradost.cloudstream3.services.VideoDownloadKeepAliveService
|
||||||
|
|
||||||
|
|
||||||
|
class VideoDownloadRestartReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
Log.i("Broadcast Listened", "Service tried to stop")
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
context?.startForegroundService(Intent(context, VideoDownloadKeepAliveService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE))
|
||||||
|
} else {
|
||||||
|
context?.startService(Intent(context, VideoDownloadKeepAliveService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.lagradost.cloudstream3.services
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.IBinder
|
||||||
|
import com.lagradost.cloudstream3.recivers.VideoDownloadRestartReceiver
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStore.getKeys
|
||||||
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
|
|
||||||
|
const val RESTART_ALL_DOWNLOADS_AND_QUEUE = 1
|
||||||
|
const val RESTART_NONE = 0
|
||||||
|
const val START_VALUE_KEY = "start_value"
|
||||||
|
|
||||||
|
class VideoDownloadKeepAliveService : Service() {
|
||||||
|
override fun onBind(p0: Intent?): IBinder? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
val startValue = intent?.getIntExtra(START_VALUE_KEY, RESTART_NONE) ?: RESTART_NONE
|
||||||
|
if (startValue == RESTART_ALL_DOWNLOADS_AND_QUEUE) {
|
||||||
|
val keys = this.getKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)
|
||||||
|
val resumePkg = keys.mapNotNull { k -> this.getKey<VideoDownloadManager.DownloadResumePackage>(k) }
|
||||||
|
|
||||||
|
for (pkg in resumePkg) { // ADD ALL CURRENT DOWNLOADS
|
||||||
|
VideoDownloadManager.downloadFromResume(this, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADD QUEUE
|
||||||
|
val resumeQueue =
|
||||||
|
this.getKey<List<VideoDownloadManager.DownloadQueueResumePackage>>(VideoDownloadManager.KEY_RESUME_QUEUE_PACKAGES)
|
||||||
|
if (resumeQueue != null && resumeQueue.isNotEmpty()) {
|
||||||
|
val sorted = resumeQueue.sortedBy { item -> item.index }
|
||||||
|
for (queueItem in sorted) {
|
||||||
|
VideoDownloadManager.downloadFromResume(this, queueItem.pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return START_STICKY//super.onStartCommand(intent, flags, startId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
val broadcastIntent = Intent()
|
||||||
|
broadcastIntent.action = "restart_service"
|
||||||
|
broadcastIntent.setClass(this, VideoDownloadRestartReceiver::class.java)
|
||||||
|
this.sendBroadcast(broadcastIntent)
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.lagradost.cloudstream3.utils
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
|
import android.app.ActivityManager
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
@ -20,6 +21,9 @@ import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
|
import com.lagradost.cloudstream3.services.RESTART_NONE
|
||||||
|
import com.lagradost.cloudstream3.services.START_VALUE_KEY
|
||||||
|
import com.lagradost.cloudstream3.services.VideoDownloadKeepAliveService
|
||||||
import com.lagradost.cloudstream3.services.VideoDownloadService
|
import com.lagradost.cloudstream3.services.VideoDownloadService
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
|
@ -33,8 +37,7 @@ import java.lang.Thread.sleep
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.net.URLConnection
|
import java.net.URLConnection
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
import kotlin.collections.HashMap
|
|
||||||
|
|
||||||
const val DOWNLOAD_CHANNEL_ID = "cloudstream3.general"
|
const val DOWNLOAD_CHANNEL_ID = "cloudstream3.general"
|
||||||
const val DOWNLOAD_CHANNEL_NAME = "Downloads"
|
const val DOWNLOAD_CHANNEL_NAME = "Downloads"
|
||||||
|
@ -119,6 +122,11 @@ object VideoDownloadManager {
|
||||||
val path: Uri,
|
val path: Uri,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class DownloadQueueResumePackage(
|
||||||
|
val index: Int,
|
||||||
|
val pkg: DownloadResumePackage,
|
||||||
|
)
|
||||||
|
|
||||||
private const val SUCCESS_DOWNLOAD_DONE = 1
|
private const val SUCCESS_DOWNLOAD_DONE = 1
|
||||||
private const val SUCCESS_STOPPED = 2
|
private const val SUCCESS_STOPPED = 2
|
||||||
private const val ERROR_DELETING_FILE = -1
|
private const val ERROR_DELETING_FILE = -1
|
||||||
|
@ -131,8 +139,9 @@ object VideoDownloadManager {
|
||||||
private const val ERROR_CONTENT_RESOLVER_CANT_OPEN_STREAM = -8
|
private const val ERROR_CONTENT_RESOLVER_CANT_OPEN_STREAM = -8
|
||||||
private const val ERROR_CONTENT_RESOLVER_NOT_FOUND = -9
|
private const val ERROR_CONTENT_RESOLVER_NOT_FOUND = -9
|
||||||
|
|
||||||
private const val KEY_RESUME_PACKAGES = "download_resume"
|
const val KEY_RESUME_PACKAGES = "download_resume"
|
||||||
private const val KEY_DOWNLOAD_INFO = "download_info"
|
const val KEY_DOWNLOAD_INFO = "download_info"
|
||||||
|
const val KEY_RESUME_QUEUE_PACKAGES = "download_q_resume"
|
||||||
|
|
||||||
val downloadStatus = HashMap<Int, DownloadType>()
|
val downloadStatus = HashMap<Int, DownloadType>()
|
||||||
val downloadStatusEvent = Event<Pair<Int, DownloadType>>()
|
val downloadStatusEvent = Event<Pair<Int, DownloadType>>()
|
||||||
|
@ -249,7 +258,7 @@ object VideoDownloadManager {
|
||||||
} else if (state == DownloadType.IsDone) {
|
} else if (state == DownloadType.IsDone) {
|
||||||
"Download Done - $rowTwo"
|
"Download Done - $rowTwo"
|
||||||
} else {
|
} else {
|
||||||
"Download Stopped - $rowTwo"
|
"Download Canceled - $rowTwo"
|
||||||
}
|
}
|
||||||
|
|
||||||
val bodyStyle = NotificationCompat.BigTextStyle()
|
val bodyStyle = NotificationCompat.BigTextStyle()
|
||||||
|
@ -263,7 +272,7 @@ object VideoDownloadManager {
|
||||||
} else if (state == DownloadType.IsDone) {
|
} else if (state == DownloadType.IsDone) {
|
||||||
"Download Done - $rowTwo"
|
"Download Done - $rowTwo"
|
||||||
} else {
|
} else {
|
||||||
"Download Stopped - $rowTwo"
|
"Download Canceled - $rowTwo"
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setContentText(txt)
|
builder.setContentText(txt)
|
||||||
|
@ -312,7 +321,7 @@ object VideoDownloadManager {
|
||||||
}, when (i) {
|
}, when (i) {
|
||||||
DownloadActionType.Resume -> "Resume"
|
DownloadActionType.Resume -> "Resume"
|
||||||
DownloadActionType.Pause -> "Pause"
|
DownloadActionType.Pause -> "Pause"
|
||||||
DownloadActionType.Stop -> "Stop"
|
DownloadActionType.Stop -> "Cancel"
|
||||||
}, pending
|
}, pending
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -628,6 +637,9 @@ object VideoDownloadManager {
|
||||||
downloadEvent.invoke(Pair(id, DownloadActionType.Resume))
|
downloadEvent.invoke(Pair(id, DownloadActionType.Resume))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dQueue = downloadQueue.toList().mapIndexed { index, any -> DownloadQueueResumePackage(index, any) }
|
||||||
|
context.setKey(KEY_RESUME_QUEUE_PACKAGES, dQueue)
|
||||||
currentDownloads.add(id)
|
currentDownloads.add(id)
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
@ -722,6 +734,16 @@ object VideoDownloadManager {
|
||||||
downloadCheck(context)
|
downloadCheck(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isMyServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
|
||||||
|
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager?
|
||||||
|
for (service in manager!!.getRunningServices(Int.MAX_VALUE)) {
|
||||||
|
if (serviceClass.name == service.service.className) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun downloadEpisode(
|
fun downloadEpisode(
|
||||||
context: Context,
|
context: Context,
|
||||||
source: String?,
|
source: String?,
|
||||||
|
|
Loading…
Reference in a new issue