forked from recloudstream/cloudstream
Remove plugins when repo is deleted
This commit is contained in:
parent
32d9aea02c
commit
72dc24c455
4 changed files with 60 additions and 14 deletions
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue