Remove plugins when repo is deleted

This commit is contained in:
Blatzar 2022-08-08 20:14:57 +02:00
parent 32d9aea02c
commit 72dc24c455
4 changed files with 60 additions and 14 deletions

View file

@ -249,17 +249,25 @@ object PluginManager {
} }
} }
/**
* Spits out a unique and safe filename based on name.
* Used for repo folders (using repo url) and plugin file names (using internalName)
* */
fun getPluginSanitizedFileName(name: String): String {
return sanitizeFilename(
name,
true
) + "." + name.hashCode()
}
suspend fun downloadAndLoadPlugin( suspend fun downloadAndLoadPlugin(
activity: Activity, activity: Activity,
pluginUrl: String, pluginUrl: String,
internalName: String, internalName: String,
repositoryUrl: String repositoryUrl: String
): Boolean { ): Boolean {
val folderName = (sanitizeFilename( val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique
repositoryUrl, val fileName = getPluginSanitizedFileName(internalName)
true
) + "." + repositoryUrl.hashCode()) // Guaranteed unique
val fileName = (sanitizeFilename(internalName, true) + "." + internalName.hashCode())
Log.i(TAG, "Downloading plugin: $pluginUrl to $folderName/$fileName") Log.i(TAG, "Downloading plugin: $pluginUrl to $folderName/$fileName")
// The plugin file needs to be salted with the repository url hash as to allow multiple repositories with the same internal plugin names // 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 file = downloadPluginToFile(activity, pluginUrl, fileName, folderName)

View file

@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.apmapIndexed import com.lagradost.cloudstream3.apmapIndexed
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.plugins.PluginManager.getPluginSanitizedFileName
import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY 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.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
@ -89,7 +90,12 @@ object RepositoryManager {
}.flatten() }.flatten()
} }
suspend fun downloadPluginToFile(context: Context, pluginUrl: String, fileName: String, folder: String): File? { suspend fun downloadPluginToFile(
context: Context,
pluginUrl: String,
fileName: String,
folder: String
): File? {
return suspendSafeApiCall { return suspendSafeApiCall {
val extensionsDir = File(context.filesDir, ONLINE_PLUGINS_FOLDER) val extensionsDir = File(context.filesDir, ONLINE_PLUGINS_FOLDER)
if (!extensionsDir.exists()) if (!extensionsDir.exists())
@ -121,13 +127,23 @@ object RepositoryManager {
} }
} }
suspend fun removeRepository(repository: RepositoryData) { /**
* Also deletes downloaded repository plugins
* */
suspend fun removeRepository(context: Context, repository: RepositoryData) {
val extensionsDir = File(context.filesDir, ONLINE_PLUGINS_FOLDER)
repoLock.withLock { repoLock.withLock {
val currentRepos = getKey<Array<RepositoryData>>(REPOSITORIES_KEY) ?: emptyArray() val currentRepos = getKey<Array<RepositoryData>>(REPOSITORIES_KEY) ?: emptyArray()
// No duplicates // No duplicates
val newRepos = currentRepos.filter { it.url != repository.url } val newRepos = currentRepos.filter { it.url != repository.url }
setKey(REPOSITORIES_KEY, newRepos) setKey(REPOSITORIES_KEY, newRepos)
} }
File(
extensionsDir,
getPluginSanitizedFileName(repository.url)
).delete()
} }
private fun write(stream: InputStream, output: OutputStream) { private fun write(stream: InputStream, output: OutputStream) {

View file

@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.settings.extensions
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -17,13 +18,12 @@ import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.plugins.RepositoryManager import com.lagradost.cloudstream3.plugins.RepositoryManager
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
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.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import kotlinx.android.synthetic.main.add_repo_input.* import kotlinx.android.synthetic.main.add_repo_input.*
import kotlinx.android.synthetic.main.add_repo_input.apply_btt import kotlinx.android.synthetic.main.add_repo_input.apply_btt
import kotlinx.android.synthetic.main.add_repo_input.cancel_btt import kotlinx.android.synthetic.main.add_repo_input.cancel_btt
import kotlinx.android.synthetic.main.fragment_extensions.* import kotlinx.android.synthetic.main.fragment_extensions.*
import kotlinx.android.synthetic.main.stream_input.*
class ExtensionsFragment : Fragment() { class ExtensionsFragment : Fragment() {
override fun onCreateView( override fun onCreateView(
@ -50,9 +50,29 @@ class ExtensionsFragment : Fragment() {
putString(PLUGINS_BUNDLE_URL, it.url) putString(PLUGINS_BUNDLE_URL, it.url)
}) })
}, { repo -> }, { repo ->
ioSafe { // Prompt user before deleting repo
RepositoryManager.removeRepository(repo) main {
extensionViewModel.loadRepositories() val builder = AlertDialog.Builder(context ?: view.context)
val dialogClickListener =
DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
ioSafe {
RepositoryManager.removeRepository(view.context, repo)
extensionViewModel.loadRepositories()
}
}
DialogInterface.BUTTON_NEGATIVE -> {}
}
}
builder.setTitle(R.string.delete_repository)
.setMessage(
context?.getString(R.string.delete_repository_plugins)
)
.setPositiveButton(R.string.delete, dialogClickListener)
.setNegativeButton(R.string.cancel, dialogClickListener)
.show()
} }
}) })

View file

@ -581,6 +581,8 @@
<string name="batch_download_finish_format" formatted="true">Downloaded %d %s successfully</string> <string name="batch_download_finish_format" formatted="true">Downloaded %d %s successfully</string>
<string name="batch_download_nothing_to_download_format" formatted="true">All %s already downloaded</string> <string name="batch_download_nothing_to_download_format" formatted="true">All %s already downloaded</string>
<string name="batch_download">Batch download</string> <string name="batch_download">Batch download</string>
<string name="plugin_singular" formatted="true">plugin</string> <string name="plugin_singular">plugin</string>
<string name="plugin" formatted="true">plugins</string> <string name="plugin">plugins</string>
<string name="delete_repository_plugins">This will also delete all repository plugins</string>
<string name="delete_repository">Delete repository</string>
</resources> </resources>