forked from recloudstream/cloudstream
download stuff
This commit is contained in:
parent
b5f913cc72
commit
bd34c66592
6 changed files with 261 additions and 138 deletions
|
@ -5,6 +5,7 @@ import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
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.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.ui.AppBarConfiguration
|
import androidx.navigation.ui.AppBarConfiguration
|
||||||
|
@ -21,6 +22,9 @@ import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
|
||||||
import com.lagradost.cloudstream3.services.RESTART_ALL_DOWNLOADS_AND_QUEUE
|
import com.lagradost.cloudstream3.services.RESTART_ALL_DOWNLOADS_AND_QUEUE
|
||||||
import com.lagradost.cloudstream3.services.START_VALUE_KEY
|
import com.lagradost.cloudstream3.services.START_VALUE_KEY
|
||||||
import com.lagradost.cloudstream3.services.VideoDownloadKeepAliveService
|
import com.lagradost.cloudstream3.services.VideoDownloadKeepAliveService
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStore.getKeys
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStore.removeKeys
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
|
||||||
|
@ -126,7 +130,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
mainContext = this
|
mainContext = this
|
||||||
setupSimpleStorage()
|
setupSimpleStorage()
|
||||||
|
|
||||||
if(!storage.isStorageAccessGranted(StorageId.PRIMARY)) {
|
if (!storage.isStorageAccessGranted(StorageId.PRIMARY)) {
|
||||||
storage.requestStorageAccess(REQUEST_CODE_STORAGE_ACCESS)
|
storage.requestStorageAccess(REQUEST_CODE_STORAGE_ACCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +167,29 @@ class MainActivity : AppCompatActivity() {
|
||||||
// val mServiceIntent = Intent(this, mYourService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE)
|
// val mServiceIntent = Intent(this, mYourService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE)
|
||||||
// this.startService(mServiceIntent)
|
// this.startService(mServiceIntent)
|
||||||
//}
|
//}
|
||||||
|
//settingsManager.getBoolean("disable_automatic_data_downloads", true) &&
|
||||||
|
if ( isUsingMobileData()) {
|
||||||
|
Toast.makeText(this, "Downloads not resumed on mobile data", Toast.LENGTH_LONG).show()
|
||||||
|
} else {
|
||||||
|
val keys = getKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)
|
||||||
|
val resumePkg = keys.mapNotNull { k -> getKey<VideoDownloadManager.DownloadResumePackage>(k) }
|
||||||
|
|
||||||
|
// To remove a bug where this is permanent
|
||||||
|
removeKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)
|
||||||
|
|
||||||
|
for (pkg in resumePkg) { // ADD ALL CURRENT DOWNLOADS
|
||||||
|
VideoDownloadManager.downloadFromResume(this, pkg, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADD QUEUE
|
||||||
|
// array needed because List gets cast exception to linkedList for some unknown reason
|
||||||
|
val resumeQueue =
|
||||||
|
getKey<Array<VideoDownloadManager.DownloadQueueResumePackage>>(VideoDownloadManager.KEY_RESUME_QUEUE_PACKAGES)
|
||||||
|
|
||||||
|
resumeQueue?.sortedBy { it.index }?.forEach {
|
||||||
|
VideoDownloadManager.downloadFromResume(this, it.pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
val castContext = CastContext.getSharedInstance(applicationContext)
|
val castContext = CastContext.getSharedInstance(applicationContext)
|
||||||
fun buildMediaQueueItem(video: String): MediaQueueItem {
|
fun buildMediaQueueItem(video: String): MediaQueueItem {
|
||||||
|
|
|
@ -76,6 +76,7 @@ import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.VIDEO_PLAYER_BRIGHTNESS
|
||||||
import com.lagradost.cloudstream3.utils.getId
|
import com.lagradost.cloudstream3.utils.getId
|
||||||
import kotlinx.android.synthetic.main.fragment_player.*
|
import kotlinx.android.synthetic.main.fragment_player.*
|
||||||
import kotlinx.android.synthetic.main.player_custom_layout.*
|
import kotlinx.android.synthetic.main.player_custom_layout.*
|
||||||
|
@ -413,6 +414,8 @@ class PlayerFragment : Fragment() {
|
||||||
) // 0.05f *if (diffY > 0) 1 else -1
|
) // 0.05f *if (diffY > 0) 1 else -1
|
||||||
brightness_overlay?.alpha = alpha
|
brightness_overlay?.alpha = alpha
|
||||||
|
|
||||||
|
context?.setKey(VIDEO_PLAYER_BRIGHTNESS, alpha)
|
||||||
|
|
||||||
progressBarRight?.max = 100 * 100
|
progressBarRight?.max = 100 * 100
|
||||||
progressBarRight?.progress = ((1f - alpha) * 100 * 100).toInt()
|
progressBarRight?.progress = ((1f - alpha) * 100 * 100).toInt()
|
||||||
}
|
}
|
||||||
|
@ -764,6 +767,8 @@ class PlayerFragment : Fragment() {
|
||||||
playerResizeEnabled = settingsManager.getBoolean("player_resize_enabled", true)
|
playerResizeEnabled = settingsManager.getBoolean("player_resize_enabled", true)
|
||||||
doubleTapEnabled = settingsManager.getBoolean("double_tap_enabled", false)
|
doubleTapEnabled = settingsManager.getBoolean("double_tap_enabled", false)
|
||||||
|
|
||||||
|
brightness_overlay?.alpha = context?.getKey(VIDEO_PLAYER_BRIGHTNESS, 0f) ?: 0f
|
||||||
|
|
||||||
isInPlayer = true // NEED REFERENCE TO MAIN ACTIVITY FOR PIP
|
isInPlayer = true // NEED REFERENCE TO MAIN ACTIVITY FOR PIP
|
||||||
|
|
||||||
navigationBarHeight = requireContext().getNavigationBarHeight()
|
navigationBarHeight = requireContext().getNavigationBarHeight()
|
||||||
|
|
|
@ -21,6 +21,7 @@ import com.google.android.gms.cast.framework.CastState
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.UIHelper.hideSystemUI
|
import com.lagradost.cloudstream3.UIHelper.hideSystemUI
|
||||||
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
||||||
|
import com.lagradost.cloudstream3.UIHelper.isConnectedToChromecast
|
||||||
import com.lagradost.cloudstream3.utils.getId
|
import com.lagradost.cloudstream3.utils.getId
|
||||||
import kotlinx.android.synthetic.main.result_episode.view.episode_holder
|
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.view.episode_text
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.*
|
||||||
import android.content.Intent
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
|
import android.content.Intent.*
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
|
@ -16,6 +17,8 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.text.color
|
import androidx.core.text.color
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
@ -31,6 +34,7 @@ import com.google.android.gms.cast.framework.CastState
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
|
import com.lagradost.cloudstream3.UIHelper.checkWrite
|
||||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
|
||||||
import com.lagradost.cloudstream3.UIHelper.getStatusBarHeight
|
import com.lagradost.cloudstream3.UIHelper.getStatusBarHeight
|
||||||
|
@ -39,6 +43,7 @@ import com.lagradost.cloudstream3.UIHelper.isConnectedToChromecast
|
||||||
import com.lagradost.cloudstream3.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons
|
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons
|
||||||
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringres
|
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringres
|
||||||
|
import com.lagradost.cloudstream3.UIHelper.requestRW
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
|
@ -54,6 +59,7 @@ import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
||||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
const val MAX_SYNO_LENGH = 300
|
const val MAX_SYNO_LENGH = 300
|
||||||
|
@ -268,13 +274,16 @@ class ResultFragment : Fragment() {
|
||||||
var currentLinks: ArrayList<ExtractorLink>? = null
|
var currentLinks: ArrayList<ExtractorLink>? = null
|
||||||
var currentSubs: ArrayList<SubtitleFile>? = null
|
var currentSubs: ArrayList<SubtitleFile>? = null
|
||||||
|
|
||||||
suspend fun requireLinks(isCasting: Boolean = false): Boolean {
|
val showTitle = episodeClick.data.name ?: "Episode ${episodeClick.data.episode}"
|
||||||
|
|
||||||
|
suspend fun requireLinks(isCasting: Boolean): Boolean {
|
||||||
val currentLinksTemp =
|
val currentLinksTemp =
|
||||||
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
|
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
|
||||||
val currentSubsTemp =
|
val currentSubsTemp =
|
||||||
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
|
if (allEpisodesSubs.containsKey(episodeClick.data.id)) allEpisodesSubs[episodeClick.data.id] else null
|
||||||
if (currentLinksTemp != null && currentLinksTemp.size > 0) {
|
if (currentLinksTemp != null && currentLinksTemp.size > 0) {
|
||||||
currentLinks = currentLinksTemp
|
currentLinks = currentLinksTemp
|
||||||
|
currentSubs = currentSubsTemp
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,11 +327,105 @@ class ResultFragment : Fragment() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun aquireSingeExtractorLink(links: List<ExtractorLink>, title: String, callback: (ExtractorLink) -> Unit) {
|
||||||
|
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
||||||
|
|
||||||
|
builder.setTitle(title)
|
||||||
|
builder.setItems(links.map { it.name }.toTypedArray()) { dia, which ->
|
||||||
|
callback.invoke(links[which])
|
||||||
|
dia?.dismiss()
|
||||||
|
}
|
||||||
|
builder.create().show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun aquireSingeExtractorLink(title: String, callback: (ExtractorLink) -> Unit) {
|
||||||
|
aquireSingeExtractorLink(currentLinks ?: return, title, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startChromecast(startIndex: Int) {
|
||||||
|
val eps = currentEpisodes ?: return
|
||||||
|
context?.startCast(
|
||||||
|
apiName ?: return,
|
||||||
|
currentIsMovie ?: return,
|
||||||
|
currentHeaderName,
|
||||||
|
currentPoster,
|
||||||
|
episodeClick.data.index,
|
||||||
|
eps,
|
||||||
|
sortUrls(currentLinks ?: return),
|
||||||
|
currentSubs ?: return,
|
||||||
|
startTime = episodeClick.data.getRealPosition(),
|
||||||
|
startIndex = startIndex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startDownload(links: List<ExtractorLink>) {
|
||||||
|
val isMovie = currentIsMovie ?: return
|
||||||
|
val titleName = sanitizeFilename(currentHeaderName ?: return)
|
||||||
|
|
||||||
|
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
|
||||||
|
episodeClick.data.id,
|
||||||
|
titleName,
|
||||||
|
apiName ?: return,
|
||||||
|
episodeClick.data.poster ?: currentPoster,
|
||||||
|
episodeClick.data.name,
|
||||||
|
if (isMovie) null else episodeClick.data.season,
|
||||||
|
if (isMovie) null else episodeClick.data.episode
|
||||||
|
)
|
||||||
|
|
||||||
|
val folder = when (currentType) {
|
||||||
|
TvType.Anime -> "Anime/$titleName"
|
||||||
|
TvType.Movie -> "Movies"
|
||||||
|
TvType.TvSeries -> "TVSeries/$titleName"
|
||||||
|
TvType.ONA -> "ONA"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
context?.let { ctx ->
|
||||||
|
// SET VISUAL KEYS
|
||||||
|
ctx.setKey(
|
||||||
|
DOWNLOAD_HEADER_CACHE, (currentId ?: return@let).toString(),
|
||||||
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
|
apiName,
|
||||||
|
url ?: return@let,
|
||||||
|
currentType ?: return@let,
|
||||||
|
currentHeaderName ?: return@let,
|
||||||
|
currentPoster ?: return@let,
|
||||||
|
currentId ?: return@let
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val epData = episodeClick.data
|
||||||
|
ctx.setKey(
|
||||||
|
DOWNLOAD_EPISODE_CACHE,
|
||||||
|
epData.id.toString(),
|
||||||
|
VideoDownloadHelper.DownloadEpisodeCached(
|
||||||
|
epData.name,
|
||||||
|
epData.poster,
|
||||||
|
epData.episode,
|
||||||
|
epData.season,
|
||||||
|
epData.id,
|
||||||
|
currentId ?: return@let,
|
||||||
|
epData.rating,
|
||||||
|
epData.descript
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// DOWNLOAD VIDEO
|
||||||
|
VideoDownloadManager.downloadEpisode(
|
||||||
|
ctx,
|
||||||
|
url ?: return,
|
||||||
|
folder,
|
||||||
|
meta,
|
||||||
|
links
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val isLoaded = when (episodeClick.action) {
|
val isLoaded = when (episodeClick.action) {
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER -> true
|
ACTION_PLAY_EPISODE_IN_PLAYER -> true
|
||||||
ACTION_CHROME_CAST_EPISODE -> requireLinks(true)
|
ACTION_CHROME_CAST_EPISODE -> requireLinks(true)
|
||||||
ACTION_CHROME_CAST_MIRROR -> requireLinks(true)
|
ACTION_CHROME_CAST_MIRROR -> requireLinks(true)
|
||||||
else -> requireLinks()
|
else -> requireLinks(false)
|
||||||
}
|
}
|
||||||
if (!isLoaded) return@main // CANT LOAD
|
if (!isLoaded) return@main // CANT LOAD
|
||||||
|
|
||||||
|
@ -330,7 +433,7 @@ class ResultFragment : Fragment() {
|
||||||
ACTION_SHOW_OPTIONS -> {
|
ACTION_SHOW_OPTIONS -> {
|
||||||
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
||||||
var dialog: AlertDialog? = null
|
var dialog: AlertDialog? = null
|
||||||
builder.setTitle(episodeClick.data.name)
|
builder.setTitle(showTitle)
|
||||||
val options = requireContext().resources.getStringArray(R.array.episode_long_click_options)
|
val options = requireContext().resources.getStringArray(R.array.episode_long_click_options)
|
||||||
val optionsValues =
|
val optionsValues =
|
||||||
requireContext().resources.getIntArray(R.array.episode_long_click_options_values)
|
requireContext().resources.getIntArray(R.array.episode_long_click_options_values)
|
||||||
|
@ -364,22 +467,96 @@ class ResultFragment : Fragment() {
|
||||||
dialog = builder.create()
|
dialog = builder.create()
|
||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
ACTION_COPY_LINK -> {
|
||||||
|
aquireSingeExtractorLink("Copy Link") { link ->
|
||||||
|
val serviceClipboard =
|
||||||
|
(requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager?)
|
||||||
|
?: return@aquireSingeExtractorLink
|
||||||
|
val clip = ClipData.newPlainText(link.name, link.url)
|
||||||
|
serviceClipboard.setPrimaryClip(clip)
|
||||||
|
Toast.makeText(requireContext(), "Text Copied", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTION_PLAY_EPISODE_IN_BROWSER -> {
|
||||||
|
aquireSingeExtractorLink("Play in Browser") { link ->
|
||||||
|
val i = Intent(Intent.ACTION_VIEW)
|
||||||
|
i.data = Uri.parse(link.url)
|
||||||
|
startActivity(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTION_CHROME_CAST_MIRROR -> {
|
||||||
|
aquireSingeExtractorLink("Cast Mirror") { link ->
|
||||||
|
val mirrorIndex = currentLinks?.indexOf(link) ?: -1
|
||||||
|
startChromecast(if (mirrorIndex == -1) 0 else mirrorIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ACTION_CHROME_CAST_EPISODE -> {
|
ACTION_CHROME_CAST_EPISODE -> {
|
||||||
|
startChromecast(0)
|
||||||
|
}
|
||||||
|
|
||||||
val eps = currentEpisodes ?: return@main
|
ACTION_PLAY_EPISODE_IN_EXTERNAL_PLAYER -> {
|
||||||
context?.startCast(
|
if (activity?.checkWrite() != true) {
|
||||||
apiName ?: return@main,
|
activity?.requestRW()
|
||||||
currentIsMovie ?: return@main,
|
if (activity?.checkWrite() == true) return@main
|
||||||
currentHeaderName,
|
}
|
||||||
currentPoster,
|
val data = currentLinks ?: return@main
|
||||||
episodeClick.data.index,
|
val subs = currentSubs
|
||||||
eps,
|
|
||||||
sortUrls(currentLinks ?: return@main),
|
val outputDir = requireContext().cacheDir
|
||||||
currentSubs ?: return@main,
|
val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
||||||
startTime = episodeClick.data.getRealPosition(),
|
var text = "#EXTM3U"
|
||||||
|
if (subs != null) {
|
||||||
|
for (sub in subs) {
|
||||||
|
text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.lang}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.lang}\",URI=\"${sub.url}\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (link in data.sortedBy { -it.quality }) {
|
||||||
|
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
||||||
|
}
|
||||||
|
outputFile.writeText(text)
|
||||||
|
val VLC_PACKAGE = "org.videolan.vlc"
|
||||||
|
val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result"
|
||||||
|
val VLC_COMPONENT: ComponentName =
|
||||||
|
ComponentName(VLC_PACKAGE, "org.videolan.vlc.gui.video.VideoPlayerActivity")
|
||||||
|
val REQUEST_CODE = 42
|
||||||
|
|
||||||
|
val FROM_START = -1
|
||||||
|
val FROM_PROGRESS = -2
|
||||||
|
|
||||||
|
val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT)
|
||||||
|
|
||||||
|
vlcIntent.setPackage(VLC_PACKAGE)
|
||||||
|
vlcIntent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||||
|
vlcIntent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION)
|
||||||
|
vlcIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
vlcIntent.addFlags(FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
|
||||||
|
vlcIntent.setDataAndType(
|
||||||
|
FileProvider.getUriForFile(
|
||||||
|
requireActivity(),
|
||||||
|
requireActivity().applicationContext.packageName + ".provider",
|
||||||
|
outputFile
|
||||||
|
), "video/*"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val startId = FROM_PROGRESS
|
||||||
|
|
||||||
|
var position = startId
|
||||||
|
if (startId == FROM_START) {
|
||||||
|
position = 1
|
||||||
|
} else if (startId == FROM_PROGRESS) {
|
||||||
|
position = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
vlcIntent.putExtra("position", position)
|
||||||
|
|
||||||
|
vlcIntent.component = VLC_COMPONENT
|
||||||
|
|
||||||
|
activity?.startActivityForResult(vlcIntent, REQUEST_CODE)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
||||||
|
@ -401,69 +578,21 @@ class ResultFragment : Fragment() {
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_RELOAD_EPISODE -> {
|
ACTION_RELOAD_EPISODE -> {
|
||||||
viewModel.loadEpisode(episodeClick.data, false)
|
viewModel.loadEpisode(episodeClick.data, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_DOWNLOAD_EPISODE -> {
|
ACTION_DOWNLOAD_EPISODE -> {
|
||||||
val isMovie = currentIsMovie ?: return@main
|
startDownload(currentLinks ?: return@main)
|
||||||
val titleName = sanitizeFilename(currentHeaderName ?: return@main)
|
}
|
||||||
|
|
||||||
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
|
ACTION_DOWNLOAD_MIRROR -> {
|
||||||
episodeClick.data.id,
|
aquireSingeExtractorLink(
|
||||||
titleName,
|
(currentLinks ?: return@main).filter { !it.isM3u8 },
|
||||||
apiName ?: return@main,
|
"Download Mirror"
|
||||||
episodeClick.data.poster ?: currentPoster,
|
) { link ->
|
||||||
episodeClick.data.name,
|
startDownload(listOf(link))
|
||||||
if (isMovie) null else episodeClick.data.season,
|
|
||||||
if (isMovie) null else episodeClick.data.episode
|
|
||||||
)
|
|
||||||
|
|
||||||
val folder = when (currentType) {
|
|
||||||
TvType.Anime -> "Anime/$titleName"
|
|
||||||
TvType.Movie -> "Movies"
|
|
||||||
TvType.TvSeries -> "TVSeries/$titleName"
|
|
||||||
TvType.ONA -> "ONA"
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
context?.let { ctx ->
|
|
||||||
// SET VISUAL KEYS
|
|
||||||
ctx.setKey(
|
|
||||||
DOWNLOAD_HEADER_CACHE, (currentId ?: return@let).toString(),
|
|
||||||
VideoDownloadHelper.DownloadHeaderCached(
|
|
||||||
apiName,
|
|
||||||
url ?: return@let,
|
|
||||||
currentType ?: return@let,
|
|
||||||
currentHeaderName ?: return@let,
|
|
||||||
currentPoster ?: return@let,
|
|
||||||
currentId ?: return@let
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val epData = episodeClick.data
|
|
||||||
ctx.setKey(
|
|
||||||
DOWNLOAD_EPISODE_CACHE,
|
|
||||||
epData.id.toString(),
|
|
||||||
VideoDownloadHelper.DownloadEpisodeCached(
|
|
||||||
epData.name,
|
|
||||||
epData.poster,
|
|
||||||
epData.episode,
|
|
||||||
epData.season,
|
|
||||||
epData.id,
|
|
||||||
currentId ?: return@let,
|
|
||||||
epData.rating,
|
|
||||||
epData.descript
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// DOWNLOAD VIDEO
|
|
||||||
VideoDownloadManager.downloadEpisode(
|
|
||||||
ctx,
|
|
||||||
url ?: return@main,
|
|
||||||
folder,
|
|
||||||
meta,
|
|
||||||
currentLinks ?: return@main
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -620,63 +749,6 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playEpisode(data: ArrayList<ExtractorLink>?, episodeIndex: Int) {
|
|
||||||
if (data != null) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (activity?.checkWrite() != true) {
|
|
||||||
activity?.requestRW()
|
|
||||||
if (activity?.checkWrite() == true) return
|
|
||||||
}
|
|
||||||
|
|
||||||
val outputDir = context!!.cacheDir
|
|
||||||
val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
|
||||||
var text = "#EXTM3U";
|
|
||||||
for (link in data.sortedBy { -it.quality }) {
|
|
||||||
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
|
||||||
}
|
|
||||||
outputFile.writeText(text)
|
|
||||||
val VLC_PACKAGE = "org.videolan.vlc"
|
|
||||||
val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result"
|
|
||||||
val VLC_COMPONENT: ComponentName =
|
|
||||||
ComponentName(VLC_PACKAGE, "org.videolan.vlc.gui.video.VideoPlayerActivity")
|
|
||||||
val REQUEST_CODE = 42
|
|
||||||
|
|
||||||
val FROM_START = -1
|
|
||||||
val FROM_PROGRESS = -2
|
|
||||||
|
|
||||||
val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT)
|
|
||||||
|
|
||||||
vlcIntent.setPackage(VLC_PACKAGE)
|
|
||||||
vlcIntent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
||||||
|
|
||||||
vlcIntent.setDataAndType(FileProvider.getUriForFile(activity!!,
|
|
||||||
activity!!.applicationContext.packageName + ".provider",
|
|
||||||
outputFile), "video/*")
|
|
||||||
|
|
||||||
val startId = FROM_PROGRESS
|
|
||||||
|
|
||||||
var position = startId
|
|
||||||
if (startId == FROM_START) {
|
|
||||||
position = 1
|
|
||||||
} else if (startId == FROM_PROGRESS) {
|
|
||||||
position = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
vlcIntent.putExtra("position", position)
|
|
||||||
//vlcIntent.putExtra("title", episodeName)
|
|
||||||
|
|
||||||
vlcIntent.setComponent(VLC_COMPONENT)
|
|
||||||
|
|
||||||
activity?.startActivityForResult(vlcIntent, REQUEST_CODE)
|
|
||||||
*/
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d.plot != null) {
|
if (d.plot != null) {
|
||||||
var syno = d.plot!!
|
var syno = d.plot!!
|
||||||
if (syno.length > MAX_SYNO_LENGH) {
|
if (syno.length > MAX_SYNO_LENGH) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
|
|
||||||
const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
|
const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
|
||||||
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
|
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
|
||||||
|
const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha"
|
||||||
|
|
||||||
const val PREFERENCES_NAME: String = "rebuild_preference"
|
const val PREFERENCES_NAME: String = "rebuild_preference"
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
@ -638,8 +639,6 @@ object VideoDownloadManager {
|
||||||
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 {
|
||||||
|
@ -729,9 +728,28 @@ object VideoDownloadManager {
|
||||||
return context.getKey(KEY_RESUME_PACKAGES, id.toString())
|
return context.getKey(KEY_RESUME_PACKAGES, id.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadFromResume(context: Context, pkg: DownloadResumePackage) {
|
fun downloadFromResume(context: Context, pkg: DownloadResumePackage, setKey: Boolean = true) {
|
||||||
downloadQueue.addLast(pkg)
|
if (!currentDownloads.any { it == pkg.item.ep.id }) {
|
||||||
downloadCheck(context)
|
if (currentDownloads.size == maxConcurrentDownloads) {
|
||||||
|
main {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"${pkg.item.ep.mainName}${pkg.item.ep.episode?.let { " Episode $it " } ?: " "}queued",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
downloadQueue.addLast(pkg)
|
||||||
|
downloadCheck(context)
|
||||||
|
if (setKey) saveQueue(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveQueue(context: Context) {
|
||||||
|
val dQueue =
|
||||||
|
downloadQueue.toList().mapIndexed { index, any -> DownloadQueueResumePackage(index, any) }
|
||||||
|
.toTypedArray()
|
||||||
|
context.setKey(KEY_RESUME_QUEUE_PACKAGES, dQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isMyServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
|
fun isMyServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
|
||||||
|
|
Loading…
Reference in a new issue