mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	add plugin unloading
This commit is contained in:
		
							parent
							
								
									08d7f3444f
								
							
						
					
					
						commit
						bceeec849d
					
				
					 4 changed files with 70 additions and 4 deletions
				
			
		|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|             } | ||||
|  |  | |||
|  | @ -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) } | ||||
|     //} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue