forked from recloudstream/cloudstream
download not working
This commit is contained in:
parent
2c312cd9b4
commit
672dc8c8d1
15 changed files with 559 additions and 6 deletions
|
@ -4,6 +4,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.lagradost.cloudstream3
|
||||
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -36,6 +37,7 @@ class MainActivity : AppCompatActivity() {
|
|||
var isInPlayer: Boolean = false
|
||||
var canShowPipMode: Boolean = false
|
||||
var isInPIPMode: Boolean = false
|
||||
lateinit var mainContext : MainActivity
|
||||
}
|
||||
|
||||
private fun enterPIPMode() {
|
||||
|
@ -83,6 +85,8 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mainContext = this
|
||||
|
||||
setContentView(R.layout.activity_main)
|
||||
val navView: BottomNavigationView = findViewById(R.id.nav_view)
|
||||
|
||||
|
|
|
@ -22,9 +22,10 @@ import kotlinx.android.synthetic.main.result_episode.view.episode_holder
|
|||
import kotlinx.android.synthetic.main.result_episode.view.episode_text
|
||||
import kotlinx.android.synthetic.main.result_episode_large.view.*
|
||||
|
||||
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
|
||||
const val ACTION_RELOAD_EPISODE = 4
|
||||
const val ACTION_CHROME_CAST_EPISODE = 2
|
||||
const val ACTION_DOWNLOAD_EPISODE = 3
|
||||
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
|
||||
|
||||
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
||||
|
||||
|
@ -145,10 +146,12 @@ class EpisodeAdapter(
|
|||
if (castContext.castState == CastState.CONNECTED) {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card))
|
||||
} else {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
||||
// clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card))
|
||||
}
|
||||
} else {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
||||
// clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,9 @@ import com.lagradost.cloudstream3.ui.player.PlayerData
|
|||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
|
||||
|
@ -258,7 +260,6 @@ class ResultFragment : Fragment() {
|
|||
currentLoadingCount++
|
||||
when (episodeClick.action) {
|
||||
ACTION_CHROME_CAST_EPISODE -> {
|
||||
|
||||
val skipLoading = if (apiName != null) {
|
||||
getApiFromName(apiName).instantLinkLoading
|
||||
} else false
|
||||
|
@ -327,7 +328,19 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
ACTION_DOWNLOAD_EPISODE -> {
|
||||
val tempUrl = url
|
||||
if (tempUrl != null) {
|
||||
viewModel.loadEpisode(episodeClick.data, true) { data ->
|
||||
if (data is Resource.Success) {
|
||||
VideoDownloadManager.DownloadEpisode(requireContext(),
|
||||
tempUrl,
|
||||
episodeClick.data,
|
||||
data.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ class SearchFragment : Fragment() {
|
|||
allApi.providersActive = requireActivity().getApiSettings()
|
||||
|
||||
//searchViewModel.search("iron man")
|
||||
//(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
||||
(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
||||
/*
|
||||
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.enter_anim,
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import com.google.android.exoplayer2.offline.DownloadRequest
|
||||
import com.google.android.exoplayer2.offline.DownloadService
|
||||
import com.google.android.exoplayer2.offline.DownloadService.sendAddDownload
|
||||
import com.google.android.exoplayer2.offline.StreamKey
|
||||
import com.google.android.exoplayer2.scheduler.Requirements
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||
import com.lagradost.cloudstream3.USER_AGENT
|
||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||
import java.io.File
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
|
||||
const val CHANNEL_ID = "cloudstream3.general"
|
||||
const val CHANNEL_NAME = "Downloads"
|
||||
const val CHANNEL_DESCRIPT = "The download notification channel"
|
||||
|
||||
object VideoDownloadManager {
|
||||
@DrawableRes
|
||||
const val imgDone = R.drawable.rddone
|
||||
|
||||
@DrawableRes
|
||||
const val imgDownloading = R.drawable.rdload
|
||||
|
||||
@DrawableRes
|
||||
const val imgPaused = R.drawable.rdpause
|
||||
|
||||
@DrawableRes
|
||||
const val imgStopped = R.drawable.rderror
|
||||
|
||||
@DrawableRes
|
||||
const val imgError = R.drawable.rderror
|
||||
|
||||
@DrawableRes
|
||||
const val pressToPauseIcon = R.drawable.ic_baseline_pause_24
|
||||
|
||||
@DrawableRes
|
||||
const val pressToResumeIcon = R.drawable.ic_baseline_play_arrow_24
|
||||
|
||||
@DrawableRes
|
||||
const val pressToStopIcon = R.drawable.exo_icon_stop
|
||||
|
||||
enum class DownloadType {
|
||||
IsPaused,
|
||||
IsDownloading,
|
||||
IsDone,
|
||||
IsFailed,
|
||||
IsStopped,
|
||||
}
|
||||
|
||||
enum class DownloadActionType {
|
||||
Pause,
|
||||
Resume,
|
||||
Stop,
|
||||
}
|
||||
|
||||
private var hasCreatedNotChanel = false
|
||||
private fun Context.createNotificationChannel() {
|
||||
hasCreatedNotChanel = true
|
||||
// Create the NotificationChannel, but only on API 26+ because
|
||||
// the NotificationChannel class is new and not in the support library
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val name = CHANNEL_NAME //getString(R.string.channel_name)
|
||||
val descriptionText = CHANNEL_DESCRIPT//getString(R.string.channel_description)
|
||||
val importance = NotificationManager.IMPORTANCE_DEFAULT
|
||||
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
|
||||
description = descriptionText
|
||||
}
|
||||
// Register the channel with the system
|
||||
val notificationManager: NotificationManager =
|
||||
this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
private val cachedBitmaps = hashMapOf<String, Bitmap>()
|
||||
private fun Context.getImageBitmapFromUrl(url: String): Bitmap? {
|
||||
if (cachedBitmaps.containsKey(url)) {
|
||||
return cachedBitmaps[url]
|
||||
}
|
||||
|
||||
val bitmap = Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(url).into(720, 720)
|
||||
.get()
|
||||
if (bitmap != null) {
|
||||
cachedBitmaps[url] = bitmap
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun createNotification(
|
||||
context: Context,
|
||||
text: String,
|
||||
source: String,
|
||||
ep: ResultEpisode,
|
||||
state: DownloadType,
|
||||
progress: Long,
|
||||
total: Long,
|
||||
) {
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
data = source.toUri()
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
|
||||
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setAutoCancel(true)
|
||||
.setColorized(true)
|
||||
.setAutoCancel(true)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setColor(context.colorFromAttribute(R.attr.colorPrimary))
|
||||
.setContentText(text)
|
||||
.setSmallIcon(
|
||||
when (state) {
|
||||
DownloadType.IsDone -> imgDone
|
||||
DownloadType.IsDownloading -> imgDownloading
|
||||
DownloadType.IsPaused -> imgPaused
|
||||
DownloadType.IsFailed -> imgError
|
||||
DownloadType.IsStopped -> imgStopped
|
||||
}
|
||||
)
|
||||
.setContentIntent(pendingIntent)
|
||||
|
||||
if (state == DownloadType.IsDownloading || state == DownloadType.IsPaused) {
|
||||
builder.setProgress(total.toInt(), progress.toInt(), false)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (ep.poster != null) {
|
||||
val poster = context.getImageBitmapFromUrl(ep.poster)
|
||||
if (poster != null)
|
||||
builder.setLargeIcon(poster)
|
||||
}
|
||||
}
|
||||
if ((state == DownloadType.IsDownloading || state == DownloadType.IsPaused) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val actionTypes: MutableList<DownloadActionType> = ArrayList()
|
||||
// INIT
|
||||
if (state == DownloadType.IsDownloading) {
|
||||
actionTypes.add(DownloadActionType.Pause)
|
||||
actionTypes.add(DownloadActionType.Stop)
|
||||
}
|
||||
|
||||
if (state == DownloadType.IsPaused) {
|
||||
actionTypes.add(DownloadActionType.Resume)
|
||||
actionTypes.add(DownloadActionType.Stop)
|
||||
}
|
||||
|
||||
// ADD ACTIONS
|
||||
for ((index, i) in actionTypes.withIndex()) {
|
||||
val _resultIntent = Intent(context, DownloadService::class.java)
|
||||
|
||||
_resultIntent.putExtra(
|
||||
"type", when (i) {
|
||||
DownloadActionType.Resume -> "resume"
|
||||
DownloadActionType.Pause -> "pause"
|
||||
DownloadActionType.Stop -> "stop"
|
||||
}
|
||||
)
|
||||
|
||||
_resultIntent.putExtra("id", ep.id)
|
||||
|
||||
val pending: PendingIntent = PendingIntent.getService(
|
||||
context, 4337 + index + ep.id,
|
||||
_resultIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
builder.addAction(
|
||||
NotificationCompat.Action(
|
||||
when (i) {
|
||||
DownloadActionType.Resume -> pressToResumeIcon
|
||||
DownloadActionType.Pause -> pressToPauseIcon
|
||||
DownloadActionType.Stop -> pressToStopIcon
|
||||
}, when (i) {
|
||||
DownloadActionType.Resume -> "Resume"
|
||||
DownloadActionType.Pause -> "Pause"
|
||||
DownloadActionType.Stop -> "Stop"
|
||||
}, pending
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasCreatedNotChanel) {
|
||||
context.createNotificationChannel()
|
||||
}
|
||||
|
||||
with(NotificationManagerCompat.from(context)) {
|
||||
// notificationId is a unique int for each notification that you must define
|
||||
notify(ep.id, builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
//https://exoplayer.dev/downloading-media.html
|
||||
fun DownloadSingleEpisode(context: Context, source: String, ep: ResultEpisode, link: ExtractorLink) {
|
||||
val url = link.url
|
||||
val headers = mapOf("User-Agent" to USER_AGENT, "Referer" to link.referer)
|
||||
|
||||
// Note: This should be a singleton in your app.
|
||||
val databaseProvider = ExoDatabaseProvider(context)
|
||||
|
||||
val downloadDirectory = File(Environment.getExternalStorageDirectory().path + "/Download/" + (ep.name ?: "Episode ${ep.episode}")) // File(context.cacheDir, "video_${ep.id}")
|
||||
|
||||
// A download cache should not evict media, so should use a NoopCacheEvictor.
|
||||
val downloadCache = SimpleCache(
|
||||
downloadDirectory,
|
||||
NoOpCacheEvictor(),
|
||||
databaseProvider)
|
||||
|
||||
// Create a factory for reading the data from the network.
|
||||
val dataSourceFactory = DefaultHttpDataSourceFactory()
|
||||
|
||||
// Choose an executor for downloading data. Using Runnable::run will cause each download task to
|
||||
// download data on its own thread. Passing an executor that uses multiple threads will speed up
|
||||
// download tasks that can be split into smaller parts for parallel execution. Applications that
|
||||
// already have an executor for background downloads may wish to reuse their existing executor.
|
||||
val downloadExecutor = Executor { obj: Runnable -> obj.run() }
|
||||
|
||||
|
||||
// Create the download manager.
|
||||
val downloadManager = DownloadManager(
|
||||
context,
|
||||
databaseProvider,
|
||||
downloadCache,
|
||||
dataSourceFactory,
|
||||
downloadExecutor)
|
||||
|
||||
val requirements = Requirements(Requirements.NETWORK)
|
||||
// Optionally, setters can be called to configure the download manager.
|
||||
downloadManager.requirements = requirements
|
||||
downloadManager.maxParallelDownloads = 3
|
||||
val builder = DownloadRequest.Builder(ep.id.toString(), link.url.toUri())
|
||||
|
||||
val downloadRequest: DownloadRequest = builder.build()
|
||||
|
||||
DownloadService.sendAddDownload(
|
||||
context,
|
||||
VideoDownloadService::class.java,
|
||||
downloadRequest,
|
||||
/* foreground= */ true)
|
||||
/*
|
||||
val disposable = url.download(header = headers)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy(
|
||||
onNext = { progress ->
|
||||
createNotification(
|
||||
context,
|
||||
"Downloading ${progress.downloadSizeStr()}/${progress.totalSizeStr()}",
|
||||
source,
|
||||
ep,
|
||||
DownloadType.IsDownloading,
|
||||
progress.downloadSize,
|
||||
progress.totalSize
|
||||
)
|
||||
},
|
||||
onComplete = {
|
||||
createNotification(
|
||||
context,
|
||||
"Download Done",
|
||||
source,
|
||||
ep,
|
||||
DownloadType.IsDone,
|
||||
0, 0
|
||||
)
|
||||
},
|
||||
onError = {
|
||||
createNotification(
|
||||
context,
|
||||
"Download Failed",
|
||||
source,
|
||||
ep,
|
||||
DownloadType.IsFailed,
|
||||
0, 0
|
||||
)
|
||||
}
|
||||
)*/
|
||||
}
|
||||
|
||||
public fun DownloadEpisode(context: Context, source: String, ep: ResultEpisode, links: List<ExtractorLink>) {
|
||||
val validLinks = links.filter { !it.isM3u8 }
|
||||
if (validLinks.isNotEmpty()) {
|
||||
DownloadSingleEpisode(context, source, ep, validLinks.first())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.app.IntentService
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.exoplayer2.offline.Download
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import com.google.android.exoplayer2.offline.DownloadService
|
||||
import com.google.android.exoplayer2.scheduler.PlatformScheduler
|
||||
import com.google.android.exoplayer2.scheduler.Scheduler
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||
import java.lang.Exception
|
||||
|
||||
private const val JOB_ID = 1
|
||||
private const val FOREGROUND_NOTIFICATION_ID = 1
|
||||
|
||||
class VideoDownloadService : DownloadService(
|
||||
FOREGROUND_NOTIFICATION_ID,
|
||||
DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL,
|
||||
CHANNEL_ID,
|
||||
R.string.exo_download_notification_channel_name, /* channelDescriptionResourceId= */
|
||||
0) {
|
||||
override fun getDownloadManager(): DownloadManager {
|
||||
val ctx = this
|
||||
return ExoPlayerHelper.downloadManager.apply {
|
||||
requirements = DownloadManager.DEFAULT_REQUIREMENTS
|
||||
maxParallelDownloads = 3
|
||||
addListener(
|
||||
object : DownloadManager.Listener {
|
||||
|
||||
override fun onDownloadChanged(
|
||||
downloadManager: DownloadManager,
|
||||
download: Download,
|
||||
finalException: Exception?,
|
||||
) {
|
||||
val intent = Intent(ctx, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(ctx, 0, intent, 0)
|
||||
val builder = NotificationCompat.Builder(ctx, CHANNEL_ID)
|
||||
.setAutoCancel(true)
|
||||
.setColorized(true)
|
||||
.setAutoCancel(true)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setColor(colorFromAttribute(R.attr.colorPrimary))
|
||||
.setContentText("${download.bytesDownloaded} / ${download.contentLength}")
|
||||
.setSmallIcon(
|
||||
VideoDownloadManager.imgDownloading
|
||||
)
|
||||
.setProgress((download.bytesDownloaded / 1000).toInt(),
|
||||
(download.contentLength / 1000).toInt(),
|
||||
false) // in case the size is over 2gb / 1000
|
||||
.setContentIntent(pendingIntent)
|
||||
builder.build()
|
||||
with(NotificationManagerCompat.from(ctx)) {
|
||||
// notificationId is a unique int for each notification that you must define
|
||||
notify(download.request.id.hashCode(), builder.build())
|
||||
}
|
||||
super.onDownloadChanged(downloadManager, download, finalException)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScheduler(): Scheduler =
|
||||
PlatformScheduler(this, JOB_ID)
|
||||
|
||||
override fun getForegroundNotification(downloads: MutableList<Download>): Notification {
|
||||
val intent = Intent(this, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
|
||||
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setAutoCancel(true)
|
||||
.setColorized(true)
|
||||
.setAutoCancel(true)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setColor(colorFromAttribute(R.attr.colorPrimary))
|
||||
.setContentText("Downloading ${downloads.size} item${if (downloads.size == 1) "" else "s"}")
|
||||
.setSmallIcon(
|
||||
VideoDownloadManager.imgDownloading
|
||||
)
|
||||
.setContentIntent(pendingIntent)
|
||||
return builder.build()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
object ExoPlayerHelper {
|
||||
private val context = MainActivity.mainContext
|
||||
val databaseProvider = ExoDatabaseProvider(context)
|
||||
val downloadExecutor = Executor { obj: Runnable -> obj.run() }
|
||||
val dataSourceFactory = DefaultHttpDataSourceFactory()
|
||||
|
||||
val downloadCache: SimpleCache by lazy {
|
||||
SimpleCache(
|
||||
context.cacheDir,
|
||||
LeastRecentlyUsedCacheEvictor(20 * 1024 * 1024),
|
||||
databaseProvider
|
||||
)
|
||||
}
|
||||
|
||||
val downloadManager: DownloadManager by lazy {
|
||||
DownloadManager(context,
|
||||
databaseProvider,
|
||||
downloadCache,
|
||||
dataSourceFactory,
|
||||
downloadExecutor)
|
||||
}
|
||||
|
||||
}
|
6
app/src/main/res/drawable/.idea/misc.xml
Normal file
6
app/src/main/res/drawable/.idea/misc.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
app/src/main/res/drawable/.idea/modules.xml
Normal file
8
app/src/main/res/drawable/.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/drawable.iml" filepath="$PROJECT_DIR$/.idea/drawable.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
app/src/main/res/drawable/.idea/vcs.xml
Normal file
6
app/src/main/res/drawable/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../../../../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
24
app/src/main/res/drawable/rddone.xml
Normal file
24
app/src/main/res/drawable/rddone.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorPrimary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 7.488 13.004 L 9.132 11.36 L 12.492 14.72 L 10.848 16.364 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 10.848 16.364 L 9.203 14.72 L 14.894 9.029 L 16.539 10.673 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
24
app/src/main/res/drawable/rderror.xml
Normal file
24
app/src/main/res/drawable/rderror.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorPrimary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z M 10.101 13.289 L 10.513 10.311 L 9.848 9.33 L 9.496 8.867 L 11 13 L 9.706 13 L 9.745 15.93 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 15.801 14.763 L 14.157 16.407 L 7.873 10.124 L 9.518 8.479 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 14.157 8.479 L 15.801 10.124 L 9.518 16.407 L 7.873 14.763 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/rdload.xml
Normal file
5
app/src/main/res/drawable/rdload.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="?attr/colorPrimary"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z"/>
|
||||
</vector>
|
19
app/src/main/res/drawable/rdpause.xml
Normal file
19
app/src/main/res/drawable/rdpause.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorPrimary"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z M 10.101 13.289 L 10.513 10.311 L 9.848 9.33 L 9.496 8.867 L 11 13 L 9.706 13 L 9.745 15.93 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 9.104 8.931 L 11.129 8.931 L 11.129 15.956 L 9.104 15.956 Z M 12.871 8.931 L 14.896 8.931 L 14.896 15.956 L 12.871 15.956 Z"
|
||||
android:fillColor="@color/white"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
Loading…
Reference in a new issue