reverted sflix to old system because of complaints, make cache for all links, made downloads more reliable

This commit is contained in:
LagradOst 2022-02-02 23:12:52 +01:00
parent c35364fb82
commit 1804484860
4 changed files with 226 additions and 136 deletions

View file

@ -294,7 +294,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
ignoreCase = true ignoreCase = true
) || this.equals("RapidStream", ignoreCase = true) ) || this.equals("RapidStream", ignoreCase = true)
) return true ) return true
return true return false
} }
// For re-use in Zoro // For re-use in Zoro

View file

@ -556,7 +556,11 @@ class GeneratorPlayer : FullScreenPlayer() {
observe(viewModel.currentLinks) { observe(viewModel.currentLinks) {
currentLinks = it currentLinks = it
overlay_loading_skip_button?.isVisible = it.isNotEmpty() val turnVisible = it.isNotEmpty()
if (turnVisible && overlay_loading_skip_button?.isGone == true) {
overlay_loading_skip_button?.requestFocus()
}
overlay_loading_skip_button?.isVisible = turnVisible
} }
observe(viewModel.currentSubs) { set -> observe(viewModel.currentSubs) { set ->

View file

@ -14,7 +14,8 @@ class RepoLinkGenerator(
private var currentIndex: Int = 0 private var currentIndex: Int = 0
) : IGenerator { ) : IGenerator {
companion object { companion object {
val TAG = "RepoLink" const val TAG = "RepoLink"
val cache: HashMap<Int, Pair<MutableSet<ExtractorLink>, MutableSet<SubtitleData>>> = hashMapOf()
} }
override val hasCache = true override val hasCache = true
@ -54,8 +55,8 @@ class RepoLinkGenerator(
} }
// this is a simple array that is used to instantly load links if they are already loaded // this is a simple array that is used to instantly load links if they are already loaded
var linkCache = Array<Set<ExtractorLink>>(size = episodes.size, init = { setOf() }) //var linkCache = Array<Set<ExtractorLink>>(size = episodes.size, init = { setOf() })
var subsCache = Array<Set<SubtitleData>>(size = episodes.size, init = { setOf() }) //var subsCache = Array<Set<SubtitleData>>(size = episodes.size, init = { setOf() })
override suspend fun generateLinks( override suspend fun generateLinks(
clearCache: Boolean, clearCache: Boolean,
@ -67,8 +68,14 @@ class RepoLinkGenerator(
val index = currentIndex val index = currentIndex
val current = episodes.getOrNull(index + offset) ?: return false val current = episodes.getOrNull(index + offset) ?: return false
val currentLinkCache = if (clearCache) mutableSetOf() else linkCache[index].toMutableSet() val (currentLinkCache, currentSubsCache) = if (clearCache) {
val currentSubsCache = if (clearCache) mutableSetOf() else subsCache[index].toMutableSet() Pair(mutableSetOf(), mutableSetOf())
} else {
cache[current.id] ?: Pair(mutableSetOf(), mutableSetOf())
}
//val currentLinkCache = if (clearCache) mutableSetOf() else linkCache[index].toMutableSet()
//val currentSubsCache = if (clearCache) mutableSetOf() else subsCache[index].toMutableSet()
val currentLinks = mutableSetOf<String>() // makes all urls unique val currentLinks = mutableSetOf<String>() // makes all urls unique
val currentSubsUrls = mutableSetOf<String>() // makes all subs urls unique val currentSubsUrls = mutableSetOf<String>() // makes all subs urls unique
@ -91,7 +98,7 @@ class RepoLinkGenerator(
return true return true
} }
return APIRepository( val result = APIRepository(
getApiFromNameNull(current.apiName) ?: throw Exception("This provider does not exist") getApiFromNameNull(current.apiName) ?: throw Exception("This provider does not exist")
).loadLinks(current.data, ).loadLinks(current.data,
isCasting, isCasting,
@ -114,7 +121,7 @@ class RepoLinkGenerator(
if (!currentSubsCache.contains(updatedFile)) { if (!currentSubsCache.contains(updatedFile)) {
subtitleCallback(updatedFile) subtitleCallback(updatedFile)
currentSubsCache.add(updatedFile) currentSubsCache.add(updatedFile)
subsCache[index] = currentSubsCache //subsCache[index] = currentSubsCache
} }
} }
}, },
@ -124,10 +131,13 @@ class RepoLinkGenerator(
currentLinks.add(link.url) currentLinks.add(link.url)
callback(Pair(link, null)) callback(Pair(link, null))
currentLinkCache.add(link) currentLinkCache.add(link)
linkCache[index] = currentLinkCache //linkCache[index] = currentLinkCache
} }
} }
} }
) )
cache[current.id] = Pair(currentLinkCache, currentSubsCache)
return result
} }
} }

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.ui.result package com.lagradost.cloudstream3.ui.result
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context.CLIPBOARD_SERVICE import android.content.Context.CLIPBOARD_SERVICE
@ -35,6 +36,8 @@ 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.APIHolder.getId import com.lagradost.cloudstream3.APIHolder.getId
import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.getCastSession import com.lagradost.cloudstream3.CommonActivity.getCastSession
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.mvvm.*
@ -46,6 +49,7 @@ import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.ui.search.SearchAdapter
@ -193,6 +197,167 @@ class ResultFragment : Fragment() {
} }
private var updateUIListener: (() -> Unit)? = null private var updateUIListener: (() -> Unit)? = null
suspend fun startDownload(
episode: ResultEpisode,
currentIsMovie: Boolean,
currentHeaderName: String,
currentType: TvType,
currentPoster: String,
apiName: String,
parentId: Int,
url: String,
links: List<ExtractorLink>,
subs: List<SubtitleData>?
) {
val titleName = sanitizeFilename(currentHeaderName)
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
episode.id,
titleName,
apiName,
episode.poster ?: currentPoster,
episode.name,
if (currentIsMovie) null else episode.season,
if (currentIsMovie) null else episode.episode
)
val folder = when (currentType) {
TvType.Anime -> "Anime/$titleName"
TvType.Movie -> "Movies"
TvType.AnimeMovie -> "Movies"
TvType.TvSeries -> "TVSeries/$titleName"
TvType.OVA -> "OVA"
TvType.Cartoon -> "Cartoons/$titleName"
TvType.Torrent -> "Torrent"
TvType.Documentary -> "Documentaries"
}
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
// SET VISUAL KEYS
setKey(
DOWNLOAD_HEADER_CACHE,
parentId.toString(),
VideoDownloadHelper.DownloadHeaderCached(
apiName,
url,
currentType,
currentHeaderName,
currentPoster,
parentId,
System.currentTimeMillis(),
)
)
setKey(
getFolderName(
DOWNLOAD_EPISODE_CACHE,
parentId.toString()
), // 3 deep folder for faster acess
episode.id.toString(),
VideoDownloadHelper.DownloadEpisodeCached(
episode.name,
episode.poster,
episode.episode,
episode.season,
episode.id,
parentId,
episode.rating,
episode.description,
System.currentTimeMillis(),
)
)
// DOWNLOAD VIDEO
VideoDownloadManager.downloadEpisodeUsingWorker(
context ?: return,
src,//url ?: return,
folder,
meta,
links
)
// 1. Checks if the lang should be downloaded
// 2. Makes it into the download format
// 3. Downloads it as a .vtt file
val downloadList = getDownloadSubsLanguageISO639_1()
subs?.let { subsList ->
subsList.filter {
downloadList.contains(
SubtitleHelper.fromLanguageToTwoLetters(
it.name,
true
)
)
}
.map { ExtractorSubtitleLink(it.name, it.url, "") }
.forEach { link ->
val epName = meta.name
?: "${context?.getString(R.string.episode)} ${meta.episode}"
val fileName =
sanitizeFilename(epName + if (downloadList.size > 1) " ${link.name}" else "")
withContext(Dispatchers.IO) {
normalSafeApiCall {
VideoDownloadManager.downloadThing(
context ?: return@normalSafeApiCall,
link,
fileName,
folder,
"vtt",
false,
null
) {
// no notification
}
}
}
}
}
}
suspend fun downloadEpisode(
activity: Activity?,
episode: ResultEpisode,
currentIsMovie: Boolean,
currentHeaderName: String,
currentType: TvType,
currentPoster: String,
apiName: String,
parentId: Int,
url: String,
) {
safeApiCall {
val generator = RepoLinkGenerator(listOf(episode))
val currentLinks = mutableSetOf<ExtractorLink>()
val currentSubs = mutableSetOf<SubtitleData>()
generator.generateLinks(clearCache = false, isCasting = false, callback = {
it.first?.let { link ->
currentLinks.add(link)
}
}, subtitleCallback = { sub ->
currentSubs.add(sub)
})
if (currentLinks.isEmpty()) {
showToast(activity, R.string.no_links_found_toast, Toast.LENGTH_SHORT)
return@safeApiCall
}
startDownload(
episode,
currentIsMovie,
currentHeaderName,
currentType,
currentPoster,
apiName,
parentId,
url,
sortUrls(currentLinks),
sortSubs(currentSubs),
)
}
}
} }
private var currentLoadingCount = private var currentLoadingCount =
@ -449,6 +614,28 @@ class ResultFragment : Fragment() {
} }
fun handleAction(episodeClick: EpisodeClickEvent): Job = main { fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
if (episodeClick.action == ACTION_DOWNLOAD_EPISODE) {
val isMovie = currentIsMovie ?: return@main
val headerName = currentHeaderName ?: return@main
val tvType = currentType ?: return@main
val poster = currentPoster ?: return@main
val id = currentId ?: return@main
val curl = url ?: return@main
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
downloadEpisode(
activity,
episodeClick.data,
isMovie,
headerName,
tvType,
poster,
apiName,
id,
curl,
)
return@main
}
var currentLinks: Set<ExtractorLink>? = null var currentLinks: Set<ExtractorLink>? = null
var currentSubs: Set<SubtitleData>? = null var currentSubs: Set<SubtitleData>? = null
@ -498,121 +685,6 @@ class ResultFragment : Fragment() {
) )
} }
fun startDownload(links: List<ExtractorLink>, subs: List<SubtitleData>?) {
val isMovie = currentIsMovie ?: return
val titleName = sanitizeFilename(currentHeaderName ?: return)
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
episodeClick.data.id,
titleName,
apiName,
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.AnimeMovie -> "Movies"
TvType.TvSeries -> "TVSeries/$titleName"
TvType.OVA -> "OVA"
TvType.Cartoon -> "Cartoons/$titleName"
TvType.Torrent -> "Torrent"
TvType.Documentary -> "Documentaries"
null -> null
}
context?.let { ctx ->
val parentId = currentId ?: return@let
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
// SET VISUAL KEYS
ctx.setKey(
DOWNLOAD_HEADER_CACHE,
parentId.toString(),
VideoDownloadHelper.DownloadHeaderCached(
apiName,
url ?: return@let,
currentType ?: return@let,
currentHeaderName ?: return@let,
currentPoster,
currentId ?: return@let,
System.currentTimeMillis(),
)
)
val epData = episodeClick.data
ctx.setKey(
getFolderName(
DOWNLOAD_EPISODE_CACHE,
parentId.toString()
), // 3 deep folder for faster acess
epData.id.toString(),
VideoDownloadHelper.DownloadEpisodeCached(
epData.name,
epData.poster,
epData.episode,
epData.season,
epData.id,
parentId,
epData.rating,
epData.description,
System.currentTimeMillis(),
)
)
// DOWNLOAD VIDEO
VideoDownloadManager.downloadEpisodeUsingWorker(
ctx,
src,//url ?: return,
folder,
meta,
links
)
// 1. Checks if the lang should be downloaded
// 2. Makes it into the download format
// 3. Downloads it as a .vtt file
val downloadList = getDownloadSubsLanguageISO639_1()
main {
subs?.let { subsList ->
subsList.filter {
downloadList.contains(
SubtitleHelper.fromLanguageToTwoLetters(
it.name,
true
)
)
}
.map { ExtractorSubtitleLink(it.name, it.url, "") }
.forEach { link ->
val epName = meta.name
?: "${context?.getString(R.string.episode)} ${meta.episode}"
val fileName =
sanitizeFilename(epName + if (downloadList.size > 1) " ${link.name}" else "")
val topFolder = "$folder"
withContext(Dispatchers.IO) {
normalSafeApiCall {
VideoDownloadManager.downloadThing(
ctx,
link,
fileName,
topFolder,
"vtt",
false,
null
) {
// no notification
}
}
}
}
}
}
}
}
suspend fun requireLinks(isCasting: Boolean, displayLoading: Boolean = true): Boolean { suspend fun requireLinks(isCasting: Boolean, displayLoading: Boolean = true): Boolean {
val skipLoading = getApiFromName(apiName).instantLinkLoading val skipLoading = getApiFromName(apiName).instantLinkLoading
@ -864,12 +936,6 @@ class ResultFragment : Fragment() {
viewModel.loadEpisode(episodeClick.data, false) viewModel.loadEpisode(episodeClick.data, false)
} }
ACTION_DOWNLOAD_EPISODE -> {
startDownload(
sortUrls(currentLinks ?: return@main),
sortSubs(currentSubs ?: return@main)
)
}
ACTION_DOWNLOAD_MIRROR -> { ACTION_DOWNLOAD_MIRROR -> {
acquireSingleExtractorLink( acquireSingleExtractorLink(
@ -878,11 +944,21 @@ class ResultFragment : Fragment() {
),//(currentLinks ?: return@main).filter { !it.isM3u8 }, ),//(currentLinks ?: return@main).filter { !it.isM3u8 },
getString(R.string.episode_action_download_mirror) getString(R.string.episode_action_download_mirror)
) { link -> ) { link ->
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT) main {
startDownload( startDownload(
episodeClick.data,
currentIsMovie ?: return@main,
currentHeaderName ?: return@main,
currentType ?: return@main,
currentPoster ?: return@main,
apiName,
currentId ?: return@main,
url ?: return@main,
listOf(link), listOf(link),
sortSubs(currentSubs ?: return@acquireSingleExtractorLink) sortSubs(currentSubs ?: return@main)
) )
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
}
} }
} }
} }