mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Fix internal plugin updater
This commit is contained in:
		
							parent
							
								
									7a640b58cb
								
							
						
					
					
						commit
						c4295f55ae
					
				
					 3 changed files with 69 additions and 20 deletions
				
			
		|  | @ -15,6 +15,7 @@ import kotlin.coroutines.CoroutineContext | |||
| import kotlin.coroutines.EmptyCoroutineContext | ||||
| 
 | ||||
| const val DEBUG_EXCEPTION = "THIS IS A DEBUG EXCEPTION!" | ||||
| const val DEBUG_PRINT = "DEBUG PRINT" | ||||
| 
 | ||||
| class DebugException(message: String) : Exception("$DEBUG_EXCEPTION\n$message") | ||||
| 
 | ||||
|  | @ -24,6 +25,12 @@ inline fun debugException(message: () -> String) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| inline fun debugPrint(tag: String = DEBUG_PRINT, message: () -> String) { | ||||
|     if (BuildConfig.DEBUG) { | ||||
|         Log.d(tag, message.invoke()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| inline fun debugWarning(message: () -> String) { | ||||
|     if (BuildConfig.DEBUG) { | ||||
|         logError(DebugException(message.invoke())) | ||||
|  |  | |||
|  | @ -8,12 +8,10 @@ import android.content.res.Resources | |||
| import android.os.Environment | ||||
| import android.widget.Toast | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.os.Build | ||||
| import android.util.Log | ||||
| import androidx.core.app.NotificationCompat | ||||
| import androidx.core.app.NotificationManagerCompat | ||||
| import androidx.core.net.toUri | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.getKey | ||||
|  | @ -28,6 +26,7 @@ import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData | |||
| import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename | ||||
| import com.lagradost.cloudstream3.APIHolder.removePluginMapping | ||||
| import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent | ||||
| import com.lagradost.cloudstream3.mvvm.debugPrint | ||||
| import com.lagradost.cloudstream3.mvvm.logError | ||||
| import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | ||||
|  | @ -37,7 +36,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute | |||
| import com.lagradost.cloudstream3.utils.extractorApis | ||||
| import kotlinx.coroutines.sync.Mutex | ||||
| import kotlinx.coroutines.sync.withLock | ||||
| import org.acra.log.debug | ||||
| import java.io.File | ||||
| import java.io.InputStreamReader | ||||
| import java.util.* | ||||
|  | @ -223,13 +221,14 @@ object PluginManager { | |||
| 
 | ||||
|         // Iterates over all offline plugins, compares to remote repo and returns the plugins which are outdated | ||||
|         val outdatedPlugins = getPluginsOnline().map { savedData -> | ||||
|             onlinePlugins.filter { onlineData -> savedData.internalName == onlineData.second.internalName } | ||||
|             onlinePlugins | ||||
|                 .filter { onlineData -> savedData.internalName == onlineData.second.internalName } | ||||
|                 .map { onlineData -> | ||||
|                     OnlinePluginData(savedData, onlineData) | ||||
|                 } | ||||
|         }.flatten().distinctBy { it.onlineData.second.url } | ||||
| 
 | ||||
|         debug { | ||||
|         debugPrint { | ||||
|             "Outdated plugins: ${outdatedPlugins.filter { it.isOutdated }}" | ||||
|         } | ||||
| 
 | ||||
|  | @ -244,7 +243,7 @@ object PluginManager { | |||
|                     activity, | ||||
|                     pluginData.onlineData.second.url, | ||||
|                     pluginData.savedData.internalName, | ||||
|                     pluginData.onlineData.first | ||||
|                     File(pluginData.savedData.filePath) | ||||
|                 ).let { success -> | ||||
|                     if (success) | ||||
|                         updatedPlugins.add(pluginData.onlineData.second.name) | ||||
|  | @ -417,24 +416,45 @@ object PluginManager { | |||
|         ) + "." + name.hashCode() | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Used for fresh installs | ||||
|      * */ | ||||
|     suspend fun downloadAndLoadPlugin( | ||||
|         activity: Activity, | ||||
|         pluginUrl: String, | ||||
|         internalName: String, | ||||
|         repositoryUrl: String | ||||
|     ): Boolean { | ||||
|         try { | ||||
|             val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique | ||||
|             val fileName = getPluginSanitizedFileName(internalName) | ||||
|             unloadPlugin("${activity.filesDir}/${ONLINE_PLUGINS_FOLDER}/${folderName}/$fileName.cs3") | ||||
|         val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique | ||||
|         val fileName = getPluginSanitizedFileName(internalName) | ||||
|         val file = File("${activity.filesDir}/${ONLINE_PLUGINS_FOLDER}/${folderName}/$fileName.cs3") | ||||
|         downloadAndLoadPlugin(activity, pluginUrl, internalName, file) | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|             Log.d(TAG, "Downloading plugin: $pluginUrl to $folderName/$fileName") | ||||
|     /** | ||||
|      * Used for updates. | ||||
|      * | ||||
|      * Uses a file instead of repository url, as extensions can get moved it is better to directly | ||||
|      * update the files instead of getting the filepath from repo url. | ||||
|      * */ | ||||
|     private suspend fun downloadAndLoadPlugin( | ||||
|         activity: Activity, | ||||
|         pluginUrl: String, | ||||
|         internalName: String, | ||||
|         file: File, | ||||
|     ): Boolean { | ||||
|         try { | ||||
|             unloadPlugin(file.absolutePath) | ||||
| 
 | ||||
|             Log.d(TAG, "Downloading plugin: $pluginUrl to ${file.absolutePath}") | ||||
|             // The plugin file needs to be salted with the repository url hash as to allow multiple repositories with the same internal plugin names | ||||
|             val file = downloadPluginToFile(activity, pluginUrl, fileName, folderName) | ||||
|             val newFile = downloadPluginToFile(pluginUrl, file) | ||||
|             return loadPlugin( | ||||
|                 activity, | ||||
|                 file ?: return false, | ||||
|                 PluginData(internalName, pluginUrl, true, file.absolutePath, PLUGIN_VERSION_NOT_SET) | ||||
|                 newFile ?: return false, | ||||
|                 PluginData(internalName, pluginUrl, true, newFile.absolutePath, PLUGIN_VERSION_NOT_SET) | ||||
|             ) | ||||
|         } catch (e: Exception) { | ||||
|             logError(e) | ||||
|  | @ -468,7 +488,8 @@ object PluginManager { | |||
|         // the NotificationChannel class is new and not in the support library | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             val name = EXTENSIONS_CHANNEL_NAME //getString(R.string.channel_name) | ||||
|             val descriptionText = EXTENSIONS_CHANNEL_DESCRIPT//getString(R.string.channel_description) | ||||
|             val descriptionText = | ||||
|                 EXTENSIONS_CHANNEL_DESCRIPT//getString(R.string.channel_description) | ||||
|             val importance = NotificationManager.IMPORTANCE_LOW | ||||
|             val channel = NotificationChannel(EXTENSIONS_CHANNEL_ID, name, importance).apply { | ||||
|                 description = descriptionText | ||||
|  | @ -479,10 +500,11 @@ object PluginManager { | |||
|             notificationManager.createNotificationChannel(channel) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun createNotification( | ||||
|         context: Context, | ||||
|         extensionNames: List<String> | ||||
|         ): Notification? { | ||||
|     ): Notification? { | ||||
|         try { | ||||
|             if (extensionNames.isEmpty()) return null | ||||
| 
 | ||||
|  | @ -497,8 +519,10 @@ object PluginManager { | |||
|                 .setColor(context.colorFromAttribute(R.attr.colorPrimary)) | ||||
|                 .setContentTitle(context.getString(R.string.plugins_updated, extensionNames.size)) | ||||
|                 .setSmallIcon(R.drawable.ic_baseline_extension_24) | ||||
|                 .setStyle(NotificationCompat.BigTextStyle() | ||||
|                     .bigText(content)) | ||||
|                 .setStyle( | ||||
|                     NotificationCompat.BigTextStyle() | ||||
|                         .bigText(content) | ||||
|                 ) | ||||
|                 .setContentText(content) | ||||
| 
 | ||||
|             if (!hasCreatedNotChanel) { | ||||
|  | @ -508,7 +532,7 @@ object PluginManager { | |||
|             val notification = builder.build() | ||||
|             with(NotificationManagerCompat.from(context)) { | ||||
|                 // notificationId is a unique int for each notification that you must define | ||||
|                 notify((System.currentTimeMillis()/1000).toInt(), notification) | ||||
|                 notify((System.currentTimeMillis() / 1000).toInt(), notification) | ||||
|             } | ||||
|             return notification | ||||
|         } catch (e: Exception) { | ||||
|  |  | |||
|  | @ -84,7 +84,7 @@ object RepositoryManager { | |||
|             // Normal parsed function not working? | ||||
|             // return response.parsedSafe() | ||||
|             tryParseJson<Array<SitePlugin>>(response.text)?.toList() ?: emptyList() | ||||
|         } catch (t : Throwable) { | ||||
|         } catch (t: Throwable) { | ||||
|             logError(t) | ||||
|             emptyList() | ||||
|         } | ||||
|  | @ -102,9 +102,27 @@ object RepositoryManager { | |||
|         }.flatten() | ||||
|     } | ||||
| 
 | ||||
|     suspend fun downloadPluginToFile( | ||||
|         pluginUrl: String, | ||||
|         file: File | ||||
|     ): File? { | ||||
|         return suspendSafeApiCall { | ||||
|             file.mkdirs() | ||||
| 
 | ||||
|             // Overwrite if exists | ||||
|             if (file.exists()) { file.delete() } | ||||
|             file.createNewFile() | ||||
| 
 | ||||
|             val body = app.get(pluginUrl).okhttpResponse.body | ||||
|             write(body.byteStream(), file.outputStream()) | ||||
|             file | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     suspend fun downloadPluginToFile( | ||||
|         context: Context, | ||||
|         pluginUrl: String, | ||||
|         /** Filename without .cs3 */ | ||||
|         fileName: String, | ||||
|         folder: String | ||||
|     ): File? { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue