add plugin unloading

This commit is contained in:
C10udburst 2022-08-09 10:33:16 +02:00
parent 08d7f3444f
commit bceeec849d
4 changed files with 70 additions and 4 deletions

View File

@ -342,6 +342,9 @@ abstract class MainAPI {
/**Used for testing and can be used to disable the providers if WebView is not available*/
open val usesWebView = false
/** Determines which plugin a given provider is from */
var sourcePlugin: String? = null
open val hasMainPage = false
open val hasQuickSearch = false

View File

@ -3,6 +3,13 @@ package com.lagradost.cloudstream3.plugins
import android.content.Context
import android.content.res.Resources
import kotlin.Throws
import com.lagradost.cloudstream3.MainAPI
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.extractorApis
import android.util.Log
const val PLUGIN_TAG = "PluginInstance"
abstract class Plugin {
/**
@ -13,6 +20,33 @@ abstract class Plugin {
open fun load(context: Context) {
}
/**
* Called when your Plugin is being unloaded
*/
@Throws(Throwable::class)
open fun beforeUnload() {
}
/**
* Used to register providers instances of MainAPI
* @param element MainAPI provider you want to register
*/
fun registerMainAPI(element: MainAPI) {
Log.i(PLUGIN_TAG, "Adding ${element.name} (${element.mainUrl}) MainAPI")
element.sourcePlugin = this.`__filename`
APIHolder.allProviders.add(element)
}
/**
* Used to register extractor instances of ExtractorApi
* @param element ExtractorApi provider you want to register
*/
fun registerExtractorAPI(element: ExtractorApi) {
Log.i(PLUGIN_TAG, "Adding ${element.name} (${element.mainUrl}) ExtractorApi")
element.sourcePlugin = this.`__filename`
extractorApis.add(element)
}
class Manifest {
var name: String? = null
var pluginClassName: String? = null

View File

@ -23,6 +23,10 @@ import com.lagradost.cloudstream3.plugins.RepositoryManager.getRepoPlugins
import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.MainAPI
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.extractorApis
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.File
@ -99,8 +103,7 @@ object PluginManager {
private val classLoaders: MutableMap<PathClassLoader, Plugin> =
HashMap<PathClassLoader, Plugin>()
private val failedToLoad: MutableMap<File, Any> = LinkedHashMap()
private var loadedLocalPlugins = false
private val gson = Gson()
@ -112,6 +115,8 @@ object PluginManager {
file,
PluginData(name, null, false, file.absolutePath, PLUGIN_VERSION_NOT_SET)
)
} else {
Log.i(TAG, "Skipping invalid plugin file: $file")
}
}
@ -197,6 +202,8 @@ object PluginManager {
val sortedPlugins = dir.listFiles()
// Always sort plugins alphabetically for reproducible results
Log.d(TAG, "Files in '${LOCAL_PLUGINS_PATH}' folder: ${sortedPlugins}")
sortedPlugins?.sortedBy { it.name }?.apmap { file ->
maybeLoadPlugin(activity, file)
}
@ -217,7 +224,6 @@ object PluginManager {
var manifest: Plugin.Manifest
loader.getResourceAsStream("manifest.json").use { stream ->
if (stream == null) {
failedToLoad[file] = "No manifest found"
Log.e(TAG, "Failed to load plugin $fileName: No manifest found")
return false
}
@ -263,7 +269,6 @@ object PluginManager {
Log.i(TAG, "Loaded plugin ${data.internalName} successfully")
true
} catch (e: Throwable) {
failedToLoad[file] = e
Log.e(TAG, "Failed to load $file: ${Log.getStackTraceString(e)}")
showToast(
activity,
@ -274,6 +279,26 @@ object PluginManager {
}
}
private suspend fun unloadPlugin(absolutePath: String) {
var plugin = plugins.get(absolutePath)
if (plugin == null) {
Log.w(TAG, "Couldn't find plugin $absolutePath")
return
}
try {
plugin.beforeUnload()
} catch (e: Throwable) {
Log.e(TAG, "Failed to run beforeUnload $absolutePath: ${Log.getStackTraceString(e)}")
}
// remove all registered apis
APIHolder.allProviders.removeIf { provider: MainAPI -> provider.sourcePlugin == plugin.`__filename` }
extractorApis.removeIf { provider: ExtractorApi -> provider.sourcePlugin == plugin.`__filename` }
plugins.remove(absolutePath)
}
/**
* Spits out a unique and safe filename based on name.
* Used for repo folders (using repo url) and plugin file names (using internalName)
@ -309,6 +334,7 @@ object PluginManager {
?: return false
return try {
if (File(data.filePath).delete()) {
unloadPlugin(data.filePath)
deletePluginData(data)
return true
}

View File

@ -247,6 +247,9 @@ abstract class ExtractorApi {
abstract val mainUrl: String
abstract val requiresReferer: Boolean
/** Determines which plugin a given extractor is from */
var sourcePlugin: String? = null
//suspend fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? {
// return suspendSafeApiCall { getUrl(url, referer) }
//}