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…
Reference in a new issue