mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
fixed crashes
This commit is contained in:
parent
e9e4298a7a
commit
0fcb7b8db5
18 changed files with 141 additions and 106 deletions
|
@ -36,7 +36,7 @@ android {
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
|
|
||||||
versionCode 50
|
versionCode 50
|
||||||
versionName "3.1.2"
|
versionName "3.1.3"
|
||||||
|
|
||||||
resValue "string", "app_version",
|
resValue "string", "app_version",
|
||||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||||
|
|
|
@ -71,10 +71,6 @@ object APIHolder {
|
||||||
apiMap = apis.mapIndexed { index, api -> api.name to index }.toMap()
|
apiMap = apis.mapIndexed { index, api -> api.name to index }.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getApiFromName(apiName: String?): MainAPI {
|
|
||||||
return getApiFromNameNull(apiName) ?: apis[defProvider]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getApiFromNameNull(apiName: String?): MainAPI? {
|
fun getApiFromNameNull(apiName: String?): MainAPI? {
|
||||||
if (apiName == null) return null
|
if (apiName == null) return null
|
||||||
initMap()
|
initMap()
|
||||||
|
|
|
@ -6,11 +6,12 @@ import androidx.lifecycle.LiveData
|
||||||
import com.bumptech.glide.load.HttpException
|
import com.bumptech.glide.load.HttpException
|
||||||
import com.lagradost.cloudstream3.BuildConfig
|
import com.lagradost.cloudstream3.BuildConfig
|
||||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.net.ssl.SSLHandshakeException
|
import javax.net.ssl.SSLHandshakeException
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
const val DEBUG_EXCEPTION = "THIS IS A DEBUG EXCEPTION!"
|
const val DEBUG_EXCEPTION = "THIS IS A DEBUG EXCEPTION!"
|
||||||
|
|
||||||
|
@ -44,13 +45,6 @@ fun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
||||||
liveData.observe(this) { it?.let { t -> action(t) } }
|
liveData.observe(this) { it?.let { t -> action(t) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> LifecycleOwner.observeDirectly(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
|
||||||
liveData.observe(this) { it?.let { t -> action(t) } }
|
|
||||||
val currentValue = liveData.value
|
|
||||||
if (currentValue != null)
|
|
||||||
action(currentValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> some(value: T?): Some<T> {
|
inline fun <reified T : Any> some(value: T?): Some<T> {
|
||||||
return if (value == null) {
|
return if (value == null) {
|
||||||
Some.None
|
Some.None
|
||||||
|
@ -125,6 +119,22 @@ fun <T> safeFail(throwable: Throwable): Resource<T> {
|
||||||
return Resource.Failure(false, null, null, stackTraceMsg)
|
return Resource.Failure(false, null, null, stackTraceMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CoroutineScope.launchSafe(
|
||||||
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
|
block: suspend CoroutineScope.() -> Unit
|
||||||
|
): Job {
|
||||||
|
val obj: suspend CoroutineScope.() -> Unit = {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.launch(context, start, obj)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun <T> safeApiCall(
|
suspend fun <T> safeApiCall(
|
||||||
apiCall: suspend () -> T,
|
apiCall: suspend () -> T,
|
||||||
): Resource<T> {
|
): Resource<T> {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY
|
||||||
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
|
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
||||||
import com.lagradost.cloudstream3.APIHolder.removePluginMapping
|
import com.lagradost.cloudstream3.APIHolder.removePluginMapping
|
||||||
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
import com.lagradost.cloudstream3.utils.extractorApis
|
import com.lagradost.cloudstream3.utils.extractorApis
|
||||||
|
@ -335,7 +336,7 @@ object PluginManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all registered apis
|
// remove all registered apis
|
||||||
APIHolder.apis.filter { it -> it.sourcePlugin == plugin.__filename }.forEach {
|
APIHolder.apis.filter { api -> api.sourcePlugin == plugin.__filename }.forEach {
|
||||||
removePluginMapping(it)
|
removePluginMapping(it)
|
||||||
}
|
}
|
||||||
APIHolder.allProviders.removeIf { provider: MainAPI -> provider.sourcePlugin == plugin.__filename }
|
APIHolder.allProviders.removeIf { provider: MainAPI -> provider.sourcePlugin == plugin.__filename }
|
||||||
|
@ -363,6 +364,7 @@ object PluginManager {
|
||||||
internalName: String,
|
internalName: String,
|
||||||
repositoryUrl: String
|
repositoryUrl: String
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
try {
|
||||||
val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique
|
val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique
|
||||||
val fileName = getPluginSanitizedFileName(internalName)
|
val fileName = getPluginSanitizedFileName(internalName)
|
||||||
Log.i(TAG, "Downloading plugin: $pluginUrl to $folderName/$fileName")
|
Log.i(TAG, "Downloading plugin: $pluginUrl to $folderName/$fileName")
|
||||||
|
@ -373,6 +375,10 @@ object PluginManager {
|
||||||
file ?: return false,
|
file ?: return false,
|
||||||
PluginData(internalName, pluginUrl, true, file.absolutePath, PLUGIN_VERSION_NOT_SET)
|
PluginData(internalName, pluginUrl, true, file.absolutePath, PLUGIN_VERSION_NOT_SET)
|
||||||
)
|
)
|
||||||
|
} catch (e : Exception) {
|
||||||
|
logError(e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.isMovieType
|
import com.lagradost.cloudstream3.isMovieType
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
||||||
|
@ -38,7 +39,7 @@ class DownloadViewModel : ViewModel() {
|
||||||
val availableBytes: LiveData<Long> = _availableBytes
|
val availableBytes: LiveData<Long> = _availableBytes
|
||||||
val downloadBytes: LiveData<Long> = _downloadBytes
|
val downloadBytes: LiveData<Long> = _downloadBytes
|
||||||
|
|
||||||
fun updateList(context: Context) = viewModelScope.launch {
|
fun updateList(context: Context) = viewModelScope.launchSafe {
|
||||||
val children = withContext(Dispatchers.IO) {
|
val children = withContext(Dispatchers.IO) {
|
||||||
val headers = context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
val headers = context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
||||||
headers.mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) }
|
headers.mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) }
|
||||||
|
|
|
@ -229,7 +229,7 @@ class EasyDownloadButton : IDisposable {
|
||||||
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent += it }
|
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent += it }
|
||||||
|
|
||||||
downloadView.setOnClickListener {
|
downloadView.setOnClickListener {
|
||||||
if (currentBytes <= 0) {
|
if (currentBytes <= 0 || totalBytes <= 0) {
|
||||||
_clickCallback?.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data))
|
_clickCallback?.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data))
|
||||||
} else {
|
} else {
|
||||||
val list = arrayListOf(
|
val list = arrayListOf(
|
||||||
|
|
|
@ -15,10 +15,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.HomePageList
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
import com.lagradost.cloudstream3.MainAPI
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
|
||||||
import com.lagradost.cloudstream3.mvvm.debugWarning
|
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
||||||
|
@ -63,7 +60,7 @@ class HomeViewModel : ViewModel() {
|
||||||
private val _resumeWatching = MutableLiveData<List<SearchResponse>>()
|
private val _resumeWatching = MutableLiveData<List<SearchResponse>>()
|
||||||
val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching
|
val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching
|
||||||
|
|
||||||
fun loadResumeWatching() = viewModelScope.launch {
|
fun loadResumeWatching() = viewModelScope.launchSafe {
|
||||||
val resumeWatching = withContext(Dispatchers.IO) {
|
val resumeWatching = withContext(Dispatchers.IO) {
|
||||||
getAllResumeStateIds()?.mapNotNull { id ->
|
getAllResumeStateIds()?.mapNotNull { id ->
|
||||||
getLastWatched(id)
|
getLastWatched(id)
|
||||||
|
@ -99,12 +96,12 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadStoredData(preferredWatchStatus: EnumSet<WatchType>?) = viewModelScope.launch {
|
fun loadStoredData(preferredWatchStatus: EnumSet<WatchType>?) = viewModelScope.launchSafe {
|
||||||
val watchStatusIds = withContext(Dispatchers.IO) {
|
val watchStatusIds = withContext(Dispatchers.IO) {
|
||||||
getAllWatchStateIds()?.map { id ->
|
getAllWatchStateIds()?.map { id ->
|
||||||
Pair(id, getResultWatchState(id))
|
Pair(id, getResultWatchState(id))
|
||||||
}
|
}
|
||||||
}?.distinctBy { it.first } ?: return@launch
|
}?.distinctBy { it.first } ?: return@launchSafe
|
||||||
|
|
||||||
val length = WatchType.values().size
|
val length = WatchType.values().size
|
||||||
val currentWatchTypes = EnumSet.noneOf(WatchType::class.java)
|
val currentWatchTypes = EnumSet.noneOf(WatchType::class.java)
|
||||||
|
@ -120,7 +117,7 @@ class HomeViewModel : ViewModel() {
|
||||||
|
|
||||||
if (currentWatchTypes.size <= 0) {
|
if (currentWatchTypes.size <= 0) {
|
||||||
_bookmarks.postValue(Pair(false, ArrayList()))
|
_bookmarks.postValue(Pair(false, ArrayList()))
|
||||||
return@launch
|
return@launchSafe
|
||||||
}
|
}
|
||||||
|
|
||||||
val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())
|
val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())
|
||||||
|
@ -204,11 +201,11 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is soo over engineered, but idk how I can make it clean without making the main api harder to use :pensive:
|
// this is soo over engineered, but idk how I can make it clean without making the main api harder to use :pensive:
|
||||||
fun expand(name: String) = viewModelScope.launch {
|
fun expand(name: String) = viewModelScope.launchSafe {
|
||||||
expandAndReturn(name)
|
expandAndReturn(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun load(api: MainAPI?) = viewModelScope.launch {
|
private fun load(api: MainAPI?) = viewModelScope.launchSafe {
|
||||||
repo = if (api != null) {
|
repo = if (api != null) {
|
||||||
APIRepository(api)
|
APIRepository(api)
|
||||||
} else {
|
} else {
|
||||||
|
@ -267,7 +264,7 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadAndCancel(preferredApiName: String?) = viewModelScope.launch {
|
fun loadAndCancel(preferredApiName: String?) = viewModelScope.launchSafe {
|
||||||
val api = getApiFromNameNull(preferredApiName)
|
val api = getApiFromNameNull(preferredApiName)
|
||||||
if (preferredApiName == noneApi.name){
|
if (preferredApiName == noneApi.name){
|
||||||
setKey(USER_SELECTED_HOMEPAGE_API, noneApi.name)
|
setKey(USER_SELECTED_HOMEPAGE_API, noneApi.name)
|
||||||
|
|
|
@ -734,6 +734,8 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
if ((currentMeta as? ResultEpisode)?.tvType?.isLiveStream() == true) return
|
if ((currentMeta as? ResultEpisode)?.tvType?.isLiveStream() == true) return
|
||||||
|
|
||||||
val (position, duration) = posDur
|
val (position, duration) = posDur
|
||||||
|
if(duration == 0L) return // idk how you achieved this, but div by zero crash
|
||||||
|
|
||||||
viewModel.getId()?.let {
|
viewModel.getId()?.let {
|
||||||
DataStoreHelper.setViewPos(it, position, duration)
|
DataStoreHelper.setViewPos(it, position, duration)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
@ -61,7 +62,7 @@ class PlayerGeneratorViewModel : ViewModel() {
|
||||||
fun preLoadNextLinks() {
|
fun preLoadNextLinks() {
|
||||||
Log.i(TAG, "preLoadNextLinks")
|
Log.i(TAG, "preLoadNextLinks")
|
||||||
currentJob?.cancel()
|
currentJob?.cancel()
|
||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launchSafe {
|
||||||
if (generator?.hasCache == true && generator?.hasNext() == true) {
|
if (generator?.hasCache == true && generator?.hasNext() == true) {
|
||||||
safeApiCall {
|
safeApiCall {
|
||||||
generator?.generateLinks(
|
generator?.generateLinks(
|
||||||
|
@ -116,7 +117,7 @@ class PlayerGeneratorViewModel : ViewModel() {
|
||||||
fun loadLinks(clearCache: Boolean = false, isCasting: Boolean = false) {
|
fun loadLinks(clearCache: Boolean = false, isCasting: Boolean = false) {
|
||||||
Log.i(TAG, "loadLinks")
|
Log.i(TAG, "loadLinks")
|
||||||
currentJob?.cancel()
|
currentJob?.cancel()
|
||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launchSafe {
|
||||||
val currentLinks = mutableSetOf<Pair<ExtractorLink?, ExtractorUri?>>()
|
val currentLinks = mutableSetOf<Pair<ExtractorLink?, ExtractorUri?>>()
|
||||||
val currentSubs = mutableSetOf<SubtitleData>()
|
val currentSubs = mutableSetOf<SubtitleData>()
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,9 @@ import android.text.Editable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.AbsListView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -19,14 +21,10 @@ import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
|
||||||
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.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
|
||||||
import com.lagradost.cloudstream3.DubStatus
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
@ -43,10 +41,9 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
|
@ -95,13 +92,8 @@ import kotlinx.android.synthetic.main.fragment_result.result_title
|
||||||
import kotlinx.android.synthetic.main.fragment_result.result_vpn
|
import kotlinx.android.synthetic.main.fragment_result.result_vpn
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
|
||||||
import kotlinx.android.synthetic.main.result_sync.*
|
import kotlinx.android.synthetic.main.result_sync.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import android.widget.EditText
|
|
||||||
|
|
||||||
import android.widget.AbsListView
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
|
||||||
|
|
||||||
|
|
||||||
const val START_ACTION_RESUME_LATEST = 1
|
const val START_ACTION_RESUME_LATEST = 1
|
||||||
|
@ -346,7 +338,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
|
|
||||||
main {
|
main {
|
||||||
val file =
|
val file =
|
||||||
ioWork {
|
ioWorkSafe {
|
||||||
context?.let {
|
context?.let {
|
||||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||||
it,
|
it,
|
||||||
|
@ -360,11 +352,11 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
downloadButton?.setUpMoreButton(
|
downloadButton?.setUpMoreButton(
|
||||||
file?.fileLength,
|
file?.fileLength,
|
||||||
file?.totalBytes,
|
file?.totalBytes,
|
||||||
result_movie_progress_downloaded,
|
result_movie_progress_downloaded ?: return@main,
|
||||||
result_movie_download_icon,
|
result_movie_download_icon ?: return@main,
|
||||||
result_movie_download_text,
|
result_movie_download_text ?: return@main,
|
||||||
result_movie_download_text_precentage,
|
result_movie_download_text_precentage ?: return@main,
|
||||||
result_download_movie,
|
result_download_movie ?: return@main,
|
||||||
true,
|
true,
|
||||||
VideoDownloadHelper.DownloadEpisodeCached(
|
VideoDownloadHelper.DownloadEpisodeCached(
|
||||||
ep.name,
|
ep.name,
|
||||||
|
|
|
@ -41,6 +41,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast
|
||||||
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
||||||
|
@ -831,7 +832,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
text,
|
text,
|
||||||
options
|
options
|
||||||
) { value ->
|
) { value ->
|
||||||
viewModelScope.launch {
|
viewModelScope.launchSafe {
|
||||||
_selectPopup.postValue(Some.None)
|
_selectPopup.postValue(Some.None)
|
||||||
callback.invoke(value)
|
callback.invoke(value)
|
||||||
}
|
}
|
||||||
|
@ -850,7 +851,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
text,
|
text,
|
||||||
options,
|
options,
|
||||||
) { value ->
|
) { value ->
|
||||||
viewModelScope.launch {
|
viewModelScope.launchSafe {
|
||||||
_selectPopup.value = Some.None
|
_selectPopup.value = Some.None
|
||||||
callback.invoke(value)
|
callback.invoke(value)
|
||||||
}
|
}
|
||||||
|
@ -858,7 +859,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadLinks(
|
private fun loadLinks(
|
||||||
result: ResultEpisode,
|
result: ResultEpisode,
|
||||||
isVisible: Boolean,
|
isVisible: Boolean,
|
||||||
isCasting: Boolean,
|
isCasting: Boolean,
|
||||||
|
@ -910,7 +911,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun CoroutineScope.loadLinks(
|
private suspend fun CoroutineScope.loadLinks(
|
||||||
result: ResultEpisode,
|
result: ResultEpisode,
|
||||||
isVisible: Boolean,
|
isVisible: Boolean,
|
||||||
isCasting: Boolean,
|
isCasting: Boolean,
|
||||||
|
@ -1006,7 +1007,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleAction(activity: Activity?, click: EpisodeClickEvent) = viewModelScope.launch {
|
fun handleAction(activity: Activity?, click: EpisodeClickEvent) = viewModelScope.launchSafe {
|
||||||
handleEpisodeClickEvent(activity, click)
|
handleEpisodeClickEvent(activity, click)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,7 +1315,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Log.i(TAG, "setMeta")
|
Log.i(TAG, "setMeta")
|
||||||
viewModelScope.launch {
|
viewModelScope.launchSafe {
|
||||||
currentMeta = meta
|
currentMeta = meta
|
||||||
currentSync = syncs
|
currentSync = syncs
|
||||||
val (value, updateEpisodes) = ioWork {
|
val (value, updateEpisodes) = ioWork {
|
||||||
|
@ -1325,9 +1326,9 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
postSuccessful(
|
postSuccessful(
|
||||||
value ?: return@launch,
|
value ?: return@launchSafe,
|
||||||
currentRepo ?: return@launch,
|
currentRepo ?: return@launchSafe,
|
||||||
updateEpisodes ?: return@launch,
|
updateEpisodes ?: return@launchSafe,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1336,13 +1337,8 @@ class ResultViewModel2 : ViewModel() {
|
||||||
|
|
||||||
private suspend fun updateFillers(name: String) {
|
private suspend fun updateFillers(name: String) {
|
||||||
fillers =
|
fillers =
|
||||||
ioWork {
|
ioWorkSafe {
|
||||||
try {
|
|
||||||
FillerEpisodeCheck.getFillerEpisodes(name)
|
FillerEpisodeCheck.getFillerEpisodes(name)
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1799,8 +1795,8 @@ class ResultViewModel2 : ViewModel() {
|
||||||
fun hasLoaded() = currentResponse != null
|
fun hasLoaded() = currentResponse != null
|
||||||
|
|
||||||
private fun handleAutoStart(activity: Activity?, autostart: AutoResume?) =
|
private fun handleAutoStart(activity: Activity?, autostart: AutoResume?) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launchSafe {
|
||||||
if (autostart == null || activity == null) return@launch
|
if (autostart == null || activity == null) return@launchSafe
|
||||||
|
|
||||||
when (autostart.startAction) {
|
when (autostart.startAction) {
|
||||||
START_ACTION_RESUME_LATEST -> {
|
START_ACTION_RESUME_LATEST -> {
|
||||||
|
@ -1823,7 +1819,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
currentEpisodes[currentIndex]?.firstOrNull { it.episode == ep && it.season == autostart.episode }
|
currentEpisodes[currentIndex]?.firstOrNull { it.episode == ep && it.season == autostart.episode }
|
||||||
?: all.firstOrNull { it.episode == ep && it.season == autostart.episode }
|
?: all.firstOrNull { it.episode == ep && it.season == autostart.episode }
|
||||||
}
|
}
|
||||||
?: return@launch
|
?: return@launchSafe
|
||||||
handleAction(
|
handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episode)
|
EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episode)
|
||||||
|
@ -1840,7 +1836,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
dubStatus: DubStatus,
|
dubStatus: DubStatus,
|
||||||
autostart: AutoResume?,
|
autostart: AutoResume?,
|
||||||
) =
|
) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launchSafe {
|
||||||
_page.postValue(Resource.Loading(url))
|
_page.postValue(Resource.Loading(url))
|
||||||
_episodes.postValue(ResourceSome.Loading())
|
_episodes.postValue(ResourceSome.Loading())
|
||||||
|
|
||||||
|
@ -1858,12 +1854,12 @@ class ResultViewModel2 : ViewModel() {
|
||||||
"This provider does not exist"
|
"This provider does not exist"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return@launch
|
return@launchSafe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// validate url
|
// validate url
|
||||||
var validUrlResource = safeApiCall {
|
val validUrlResource = safeApiCall {
|
||||||
SyncRedirector.redirect(
|
SyncRedirector.redirect(
|
||||||
url,
|
url,
|
||||||
api.mainUrl
|
api.mainUrl
|
||||||
|
@ -1882,7 +1878,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
_page.postValue(validUrlResource)
|
_page.postValue(validUrlResource)
|
||||||
}
|
}
|
||||||
|
|
||||||
return@launch
|
return@launchSafe
|
||||||
}
|
}
|
||||||
val validUrl = validUrlResource.value
|
val validUrl = validUrlResource.value
|
||||||
val repo = APIRepository(api)
|
val repo = APIRepository(api)
|
||||||
|
@ -1893,11 +1889,11 @@ class ResultViewModel2 : ViewModel() {
|
||||||
_page.postValue(data)
|
_page.postValue(data)
|
||||||
}
|
}
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
if (!isActive) return@launch
|
if (!isActive) return@launchSafe
|
||||||
val loadResponse = ioWork {
|
val loadResponse = ioWork {
|
||||||
applyMeta(data.value, currentMeta, currentSync).first
|
applyMeta(data.value, currentMeta, currentSync).first
|
||||||
}
|
}
|
||||||
if (!isActive) return@launch
|
if (!isActive) return@launchSafe
|
||||||
val mainId = loadResponse.getId()
|
val mainId = loadResponse.getId()
|
||||||
|
|
||||||
preferDubStatus = getDub(mainId) ?: preferDubStatus
|
preferDubStatus = getDub(mainId) ?: preferDubStatus
|
||||||
|
@ -1924,7 +1920,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
updateFillers = showFillers,
|
updateFillers = showFillers,
|
||||||
apiRepository = repo
|
apiRepository = repo
|
||||||
)
|
)
|
||||||
if (!isActive) return@launch
|
if (!isActive) return@launchSafe
|
||||||
handleAutoStart(activity, autostart)
|
handleAutoStart(activity, autostart)
|
||||||
}
|
}
|
||||||
is Resource.Loading -> {
|
is Resource.Loading -> {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
import com.lagradost.cloudstream3.apmap
|
import com.lagradost.cloudstream3.apmap
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -76,11 +77,11 @@ class SearchViewModel : ViewModel() {
|
||||||
ignoreSettings: Boolean = false,
|
ignoreSettings: Boolean = false,
|
||||||
isQuickSearch: Boolean = false,
|
isQuickSearch: Boolean = false,
|
||||||
) =
|
) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launchSafe {
|
||||||
val currentIndex = currentSearchIndex
|
val currentIndex = currentSearchIndex
|
||||||
if (query.length <= 1) {
|
if (query.length <= 1) {
|
||||||
clearSearch()
|
clearSearch()
|
||||||
return@launch
|
return@launchSafe
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isQuickSearch) {
|
if (!isQuickSearch) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.apmap
|
import com.lagradost.cloudstream3.apmap
|
||||||
import com.lagradost.cloudstream3.mvvm.Some
|
import com.lagradost.cloudstream3.mvvm.Some
|
||||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||||
import com.lagradost.cloudstream3.plugins.PluginManager.getPluginsOnline
|
import com.lagradost.cloudstream3.plugins.PluginManager.getPluginsOnline
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||||
|
@ -45,7 +46,7 @@ class ExtensionsViewModel : ViewModel() {
|
||||||
val pluginStats: LiveData<Some<PluginStats>> = _pluginStats
|
val pluginStats: LiveData<Some<PluginStats>> = _pluginStats
|
||||||
|
|
||||||
//TODO CACHE GET REQUESTS
|
//TODO CACHE GET REQUESTS
|
||||||
fun loadStats() = viewModelScope.launch {
|
fun loadStats() = viewModelScope.launchSafe {
|
||||||
val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)
|
val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)
|
||||||
?: emptyArray()) + PREBUILT_REPOSITORIES
|
?: emptyArray()) + PREBUILT_REPOSITORIES
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,17 @@ import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN
|
import com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||||
import com.lagradost.cloudstream3.utils.GlideApp
|
import com.lagradost.cloudstream3.utils.GlideApp
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
|
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||||
import kotlinx.android.synthetic.main.repository_item.view.*
|
import kotlinx.android.synthetic.main.repository_item.view.*
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,6 +95,15 @@ class PluginAdapter(
|
||||||
iconClickCallback.invoke(data.plugin)
|
iconClickCallback.invoke(data.plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if (itemView.context?.isTrueTvSettings() == false) {
|
||||||
|
// val siteUrl = metadata.repositoryUrl
|
||||||
|
// if (siteUrl != null && siteUrl.isNotBlank() && siteUrl != "NONE") {
|
||||||
|
// itemView.setOnClickListener {
|
||||||
|
// openBrowser(siteUrl)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
if (data.isDownloaded) {
|
if (data.isDownloaded) {
|
||||||
val plugin = PluginManager.urlPlugins[metadata.url]
|
val plugin = PluginManager.urlPlugins[metadata.url]
|
||||||
if (plugin?.openSettings != null) {
|
if (plugin?.openSettings != null) {
|
||||||
|
@ -117,7 +128,12 @@ class PluginAdapter(
|
||||||
itemView.action_settings?.isVisible = false
|
itemView.action_settings?.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemView.entry_icon?.setImage(metadata.iconUrl, null) != true) {
|
if (itemView.entry_icon?.setImage(
|
||||||
|
metadata.iconUrl?.replace("&sz=24", "&sz=128"), // lazy fix for better resolution
|
||||||
|
null,
|
||||||
|
errorImageDrawable = R.drawable.ic_baseline_extension_24
|
||||||
|
) != true
|
||||||
|
) {
|
||||||
itemView.entry_icon?.setImageResource(R.drawable.ic_baseline_extension_24)
|
itemView.entry_icon?.setImageResource(R.drawable.ic_baseline_extension_24)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +148,8 @@ class PluginAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.main_text?.text = metadata.name
|
itemView.main_text?.text = metadata.name
|
||||||
itemView.sub_text?.text = metadata.description
|
itemView.sub_text?.isGone = metadata.description.isNullOrBlank()
|
||||||
|
itemView.sub_text?.text = metadata.description.html()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.apmap
|
import com.lagradost.cloudstream3.apmap
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.plugins.PluginData
|
import com.lagradost.cloudstream3.plugins.PluginData
|
||||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||||
|
@ -199,7 +200,7 @@ class PluginsViewModel : ViewModel() {
|
||||||
_filteredPlugins.postValue(false to plugins.filterTvTypes().sortByQuery(currentQuery))
|
_filteredPlugins.postValue(false to plugins.filterTvTypes().sortByQuery(currentQuery))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePluginList(repositoryUrl: String) = viewModelScope.launch {
|
fun updatePluginList(repositoryUrl: String) = viewModelScope.launchSafe {
|
||||||
Log.i(TAG, "updatePluginList = $repositoryUrl")
|
Log.i(TAG, "updatePluginList = $repositoryUrl")
|
||||||
updatePluginListPrivate(repositoryUrl)
|
updatePluginListPrivate(repositoryUrl)
|
||||||
}
|
}
|
||||||
|
@ -212,7 +213,7 @@ class PluginsViewModel : ViewModel() {
|
||||||
/**
|
/**
|
||||||
* Update the list but only with the local data. Used for file management.
|
* Update the list but only with the local data. Used for file management.
|
||||||
* */
|
* */
|
||||||
fun updatePluginListLocal() = viewModelScope.launch {
|
fun updatePluginListLocal() = viewModelScope.launchSafe {
|
||||||
Log.i(TAG, "updatePluginList = local")
|
Log.i(TAG, "updatePluginList = local")
|
||||||
|
|
||||||
val downloadedPlugins = (PluginManager.getPluginsOnline() + PluginManager.getPluginsLocal())
|
val downloadedPlugins = (PluginManager.getPluginsOnline() + PluginManager.getPluginsLocal())
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
|
@ -10,7 +11,7 @@ import kotlinx.coroutines.*
|
||||||
object Coroutines {
|
object Coroutines {
|
||||||
fun <T> T.main(work: suspend ((T) -> Unit)): Job {
|
fun <T> T.main(work: suspend ((T) -> Unit)): Job {
|
||||||
val value = this
|
val value = this
|
||||||
return CoroutineScope(Dispatchers.Main).launch {
|
return CoroutineScope(Dispatchers.Main).launchSafe {
|
||||||
work(value)
|
work(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +19,19 @@ object Coroutines {
|
||||||
fun <T> T.ioSafe(work: suspend (CoroutineScope.(T) -> Unit)): Job {
|
fun <T> T.ioSafe(work: suspend (CoroutineScope.(T) -> Unit)): Job {
|
||||||
val value = this
|
val value = this
|
||||||
|
|
||||||
return CoroutineScope(Dispatchers.IO).launch {
|
return CoroutineScope(Dispatchers.IO).launchSafe {
|
||||||
|
work(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T, V> V.ioWorkSafe(work: suspend (CoroutineScope.(V) -> T)): T? {
|
||||||
|
val value = this
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
work(value)
|
work(value)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:nextFocusRight="@id/action_button"
|
android:nextFocusRight="@id/action_button"
|
||||||
android:background="@drawable/outline_drawable"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:padding="20dp">
|
android:padding="20dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -16,16 +16,18 @@
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_gravity="start|center_vertical"
|
android:layout_gravity="start|center_vertical"
|
||||||
android:layout_marginEnd="20dp"
|
android:layout_marginEnd="20dp"
|
||||||
android:scaleType="centerInside"
|
android:scaleType="fitCenter"
|
||||||
app:srcCompat="@drawable/ic_github_logo" />
|
app:srcCompat="@drawable/ic_github_logo" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
@ -78,6 +80,7 @@
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/action_settings"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -85,11 +88,12 @@
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:srcCompat="@drawable/ic_baseline_tune_24"
|
app:srcCompat="@drawable/ic_baseline_tune_24"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible"
|
||||||
|
android:contentDescription="@string/title_settings" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
android:background="@drawable/outline_drawable"
|
|
||||||
android:nextFocusLeft="@id/repository_item_root"
|
android:nextFocusLeft="@id/repository_item_root"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:id="@+id/action_button"
|
android:id="@+id/action_button"
|
||||||
|
@ -98,6 +102,7 @@
|
||||||
android:layout_gravity="center_vertical|end"
|
android:layout_gravity="center_vertical|end"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
tools:src="@drawable/ic_baseline_add_24"
|
tools:src="@drawable/ic_baseline_add_24"
|
||||||
android:focusable="true" />
|
android:focusable="true"
|
||||||
|
android:contentDescription="@string/download" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
Loading…
Reference in a new issue