finish package integration sample

pull/1112/head
deniscerri 5 months ago
parent 388498adb2
commit adca45c63e
No known key found for this signature in database
GPG Key ID: 95C43D517D830350

@ -12,8 +12,8 @@ def properties = new Properties()
def versionMajor = 1
def versionMinor = 8
def versionPatch = 7
def versionBuild = 2 // bump for dogfood builds, public betas, etc.
def isBeta = false
def versionBuild = 3 // bump for dogfood builds, public betas, etc.
def isBeta = true
def versionExt = ""
if (versionBuild > 0) {
@ -47,8 +47,8 @@ android {
applicationId "com.deniscerri.ytdl"
minSdk 24
/*
KEEP 28 TO ALLOW THE APP TO EXECUTE DOWNLOADABLE PLUGINS, IF PLAN TO UPGRADE PRE-BUNDLE plugins in jniLibs
OR LOOK INTO PLUGINS as APK and put the files in their respective jniLibs
KEEP 28 TO ALLOW THE APP TO EXECUTE DOWNLOADABLE PACKAGES, IF PLAN TO UPGRADE PRE-BUNDLE packages in jniLibs
OR LOOK INTO PACKAGES as APK and put the files in their respective jniLibs
* */
//noinspection ExpiredTargetSdkVersion
targetSdk 28
@ -230,7 +230,7 @@ dependencies {
implementation 'androidx.compose.material3:material3-android:1.4.0'
implementation "io.noties.markwon:core:4.6.2"
implementation("org.greenrobot:eventbus:3.3.1")
implementation("com.github.teamnewpipe:newpipeextractor:v0.25.0")
implementation("com.github.teamnewpipe:newpipeextractor:v0.25.2")
implementation("commons-io:commons-io:2.5")
implementation("org.apache.commons:commons-compress:1.12")

@ -6,12 +6,12 @@ import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.core.models.ExecuteException
import com.deniscerri.ytdl.core.models.ExecuteResponse
import com.deniscerri.ytdl.core.models.YTDLRequest
import com.deniscerri.ytdl.core.plugins.Aria2c
import com.deniscerri.ytdl.core.plugins.FFmpeg
import com.deniscerri.ytdl.core.plugins.NodeJS
import com.deniscerri.ytdl.core.plugins.PluginBase
import com.deniscerri.ytdl.core.plugins.Python
import com.deniscerri.ytdl.core.plugins.QuickJS
import com.deniscerri.ytdl.core.packages.Aria2c
import com.deniscerri.ytdl.core.packages.FFmpeg
import com.deniscerri.ytdl.core.packages.NodeJS
import com.deniscerri.ytdl.core.packages.PackageBase
import com.deniscerri.ytdl.core.packages.Python
import com.deniscerri.ytdl.core.packages.QuickJS
import com.deniscerri.ytdl.core.stream.StreamGobbler
import com.deniscerri.ytdl.core.stream.StreamProcessExtractor
import org.apache.commons.io.FileUtils
@ -21,11 +21,11 @@ import java.util.Collections
object RuntimeManager {
val idProcessMap = Collections.synchronizedMap(HashMap<String, Process>())
lateinit var pythonLocation: PluginBase.PluginLocation
lateinit var ffmpegLocation: PluginBase.PluginLocation
lateinit var aria2Location: PluginBase.PluginLocation
lateinit var nodeLocation : PluginBase.PluginLocation
lateinit var quickJsLocation : PluginBase.PluginLocation
lateinit var pythonLocation: PackageBase.PackageLocation
lateinit var ffmpegLocation: PackageBase.PackageLocation
lateinit var aria2Location: PackageBase.PackageLocation
lateinit var nodeLocation : PackageBase.PackageLocation
lateinit var quickJsLocation : PackageBase.PackageLocation
var ytdlpPath: File? = null
const val PREFS_NAME = "runtime_prefs"

@ -1,9 +1,10 @@
package com.deniscerri.ytdl.core.plugins
package com.deniscerri.ytdl.core.packages
object Aria2c : PluginBase() {
object Aria2c : PackageBase() {
override val executableName: String get() = "aria2c"
override val pluginFolderName: String get() = "aria2c"
override val packageFolderName: String get() = "aria2c"
override val bundledZipName: String get() = "libaria2c.zip.so"
override val canUninstall: Boolean = false
override val bundledVersion: String get() = "v1.37.0"
override val githubRepo: String get() = "deniscerri/ytdlnis-plugins"
override val githubPackageName: String get() = "aria2c"

@ -1,9 +1,10 @@
package com.deniscerri.ytdl.core.plugins
package com.deniscerri.ytdl.core.packages
object FFmpeg : PluginBase() {
object FFmpeg : PackageBase() {
override val executableName: String get() = "ffmpeg"
override val pluginFolderName: String get() = "ffmpeg"
override val packageFolderName: String get() = "ffmpeg"
override val bundledZipName: String get() = "libffmpeg.zip.so"
override val canUninstall: Boolean = false
override val bundledVersion: String get() = "v7.0.1"
override val githubRepo: String get() = "deniscerri/ytdlnis-plugins"
override val githubPackageName: String get() = "ffmpeg"

@ -1,9 +1,10 @@
package com.deniscerri.ytdl.core.plugins
package com.deniscerri.ytdl.core.packages
object NodeJS : PluginBase() {
object NodeJS : PackageBase() {
override val executableName: String get() = "node"
override val pluginFolderName: String get() = "node"
override val packageFolderName: String get() = "node"
override val bundledZipName: String get() = "libnode.zip.so"
override val canUninstall: Boolean = true
override val bundledVersion: String get() = ""
override val githubRepo: String get() = "deniscerri/ytdlnis-plugins"
override val githubPackageName: String get() = "nodejs"

@ -1,4 +1,4 @@
package com.deniscerri.ytdl.core.plugins
package com.deniscerri.ytdl.core.packages
import android.content.Context
import android.os.Build
@ -22,19 +22,20 @@ import org.json.JSONObject
import java.io.File
import kotlin.coroutines.cancellation.CancellationException
abstract class PluginBase {
abstract class PackageBase {
protected abstract val executableName: String // e.g., "ffmpeg"
protected abstract val pluginFolderName: String // e.g., "ffmpeg"
protected abstract val packageFolderName: String // e.g., "ffmpeg"
protected abstract val bundledZipName: String // e.g., "libffmpeg.zip.so"
protected abstract val githubRepo: String // e.g deniscerri/ytdlnis-plugins
protected abstract val canUninstall: Boolean // set false if library is essential
protected abstract val githubRepo: String // e.g deniscerri/ytdlnis-packages
protected abstract val githubPackageName: String // e.g ffmpeg
fun getInstance(): PluginBase = this
fun getInstance(): PackageBase = this
abstract val bundledVersion: String?
var downloadedVersion: String? = null
@Serializable
data class PluginRelease(
data class PackageRelease(
@SerializedName(value = "tag_name")
var tag_name: String,
@SerialName("published_at")
@ -46,18 +47,17 @@ abstract class PluginBase {
var version: String = "",
var downloadSize: Long = 0,
var isInstalled: Boolean = false,
var isBundled: Boolean = false,
var isDownloading: Boolean = false,
var downloadProgress: Int = 0
var isBundled: Boolean = false
)
data class PluginLocation(
data class PackageLocation(
val binDir: File,
val ldDir: File,
val executable: File,
val isDownloaded: Boolean,
val isBundled: Boolean,
val isAvailable: Boolean
val isAvailable: Boolean,
val canUninstall: Boolean
)
// Preferences Keys
@ -68,7 +68,7 @@ abstract class PluginBase {
private val downloadedPackagesRoot = "downloaded_packages"
lateinit var location: PluginLocation
lateinit var location: PackageLocation
companion object {
val sharedClient: OkHttpClient by lazy {
@ -79,7 +79,7 @@ abstract class PluginBase {
fun init(context: Context) {
val baseDir = File(context.noBackupFilesDir, RuntimeManager.BASENAME)
val packageDir = File(baseDir, "$packagesRoot/$pluginFolderName")
val packageDir = File(baseDir, "$packagesRoot/$packageFolderName")
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
//try init bundled
initBundled(context, packageDir)
@ -113,10 +113,10 @@ abstract class PluginBase {
private fun getDownloadedDir(context: Context) : File {
val baseDir = File(context.noBackupFilesDir, RuntimeManager.BASENAME)
return File(baseDir, "$downloadedPackagesRoot/$pluginFolderName")
return File(baseDir, "$downloadedPackagesRoot/$packageFolderName")
}
fun getLocation(context: Context, baseDir: File): PluginLocation {
fun getLocation(context: Context, baseDir: File): PackageLocation {
//downloaded
val downloadedDir = getDownloadedDir(context)
val downloadedBinDir = downloadedDir
@ -126,26 +126,27 @@ abstract class PluginBase {
//bundled
val bundledDir = File(baseDir, packagesRoot)
val bundledBinDir = File(context.applicationInfo.nativeLibraryDir)
val bundledLDLibDir = File(bundledDir, pluginFolderName)
val bundledLDLibDir = File(bundledDir, packageFolderName)
val bundledExe = File(bundledBinDir, "lib$executableName.so")
val isDownloaded = downloadedExe.exists()
val isBundled = bundledExe.exists()
return PluginLocation(
return PackageLocation(
binDir = if (isDownloaded) downloadedBinDir else bundledBinDir,
ldDir = if (isDownloaded) downloadedLDLibDir else bundledLDLibDir,
executable = if (isDownloaded) downloadedExe else bundledExe,
isDownloaded,
isBundled,
isDownloaded || isBundled
isDownloaded || isBundled,
canUninstall
)
}
suspend fun downloadRelease(context: Context, release: PluginRelease, onProgress: (Int) -> Unit) : Result<DocumentFile> {
suspend fun downloadRelease(context: Context, release: PackageRelease, onProgress: (Int) -> Unit) : Result<DocumentFile> {
return withContext(Dispatchers.IO) {
try {
val tempZipFile = File(context.cacheDir, "${pluginFolderName}_tmp.zip")
val tempZipFile = File(context.cacheDir, "${packageFolderName}_tmp.zip")
//download
val request = Request.Builder()
@ -220,7 +221,7 @@ abstract class PluginBase {
}
}
fun uninstall(context: Context): Result<Unit> {
fun uninstallDownloaded(context: Context): Result<Unit> {
return kotlin.runCatching {
val runtimeDir = getDownloadedDir(context)
@ -248,7 +249,7 @@ abstract class PluginBase {
}
}
suspend fun getReleases() : Result<List<PluginRelease>> {
suspend fun getReleases() : Result<List<PackageRelease>> {
if (githubRepo.isEmpty()) return Result.success(listOf())
val request = Request.Builder()
@ -263,7 +264,7 @@ abstract class PluginBase {
if (response.isSuccessful && jsonString.isNotEmpty()) {
val supportedArch = getArchSuffix()
val releases = json.decodeFromString<List<PluginRelease>>(jsonString)
val releases = json.decodeFromString<List<PackageRelease>>(jsonString)
.filter {
it.tag_name.contains(githubPackageName)
}

@ -1,10 +1,11 @@
package com.deniscerri.ytdl.core.plugins
package com.deniscerri.ytdl.core.packages
object Python : PluginBase() {
object Python : PackageBase() {
override val executableName: String get() = "python"
override val pluginFolderName: String get() = "python"
override val packageFolderName: String get() = "python"
override val bundledZipName: String get() = "libpython.zip.so"
override val bundledVersion: String get() = "v3.12"
override val canUninstall: Boolean = false
override val githubRepo: String get() = "deniscerri/ytdlnis-plugins"
override val githubPackageName: String get() = "python"
}

@ -1,10 +1,11 @@
package com.deniscerri.ytdl.core.plugins
package com.deniscerri.ytdl.core.packages
object QuickJS : PluginBase() {
object QuickJS : PackageBase() {
override val executableName: String get() = "qjs"
override val pluginFolderName: String get() = "quickjs"
override val packageFolderName: String get() = "quickjs"
override val bundledZipName: String get() = "libqjs.zip.so"
override val bundledVersion: String get() = "2025-04-26"
override val canUninstall: Boolean = false
override val githubRepo: String get() = ""
override val githubPackageName: String get() = ""
}

@ -0,0 +1,10 @@
package com.deniscerri.ytdl.database.models
import com.deniscerri.ytdl.core.packages.PackageBase
data class PackageItem(
val title: String,
val plugin: PackageBase
) {
fun getInstance(): PackageBase = plugin.getInstance()
}

@ -1,10 +0,0 @@
package com.deniscerri.ytdl.database.models
import com.deniscerri.ytdl.core.plugins.PluginBase
data class PluginItem(
val title: String,
val plugin: PluginBase
) {
fun getInstance(): PluginBase = plugin.getInstance()
}

@ -13,17 +13,19 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.core.plugins.PluginBase.PluginRelease
import com.deniscerri.ytdl.core.packages.PackageBase
import com.deniscerri.ytdl.core.packages.PackageBase.PackageRelease
import com.google.android.material.button.MaterialButton
import com.google.android.material.progressindicator.CircularProgressIndicator
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.TimeZone
class PluginReleaseAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<PluginRelease?, PluginReleaseAdapter.ViewHolder>(AsyncDifferConfig.Builder(
class PackageReleaseAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<PackageRelease?, PackageReleaseAdapter.ViewHolder>(AsyncDifferConfig.Builder(
DIFF_CALLBACK
).build()) {
private val activity: Activity
private lateinit var location: PackageBase.PackageLocation
private val onItemClickListener: OnItemClickListener
init {
@ -41,6 +43,10 @@ class PluginReleaseAdapter(onItemClickListener: OnItemClickListener, activity: A
}
}
fun setPackageLocation(location: PackageBase.PackageLocation) {
this.location = location
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cardView = LayoutInflater.from(parent.context)
.inflate(R.layout.plugin_release_item, parent, false)
@ -63,31 +69,19 @@ class PluginReleaseAdapter(onItemClickListener: OnItemClickListener, activity: A
card.findViewById<TextView>(R.id.createdAt).text = parser2.format(date.time)
val actionBtn = card.findViewById<MaterialButton>(R.id.actionBtn)
actionBtn.isVisible = !item.isBundled && item.downloadProgress < 100
actionBtn.isVisible = !item.isBundled
val progress = card.findViewById<CircularProgressIndicator>(R.id.progress)
progress.isVisible = item.isDownloading
if (item.isDownloading) {
actionBtn.setIconResource(R.drawable.ic_cancel)
} else if (item.isInstalled) {
if (item.isInstalled) {
actionBtn.setIconResource(R.drawable.ic_baseline_delete_outline_24)
actionBtn.setOnClickListener {
onItemClickListener.onDeleteDownloadedPackageClick(item)
}
} else {
actionBtn.setIconResource(R.drawable.ic_down)
}
actionBtn.setOnClickListener {
if (!item.isBundled) {
if (item.isDownloading && item.downloadProgress < 100) {
onItemClickListener.onCancelDownloadReleaseClick(item)
} else if (item.isInstalled) {
onItemClickListener.onDeleteReleaseClick(item)
} else {
onItemClickListener.onDownloadReleaseClick(item)
}
actionBtn.setOnClickListener {
onItemClickListener.onDownloadReleaseClick(item)
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
@ -104,21 +98,18 @@ class PluginReleaseAdapter(onItemClickListener: OnItemClickListener, activity: A
}
interface OnItemClickListener {
fun onCancelDownloadReleaseClick(item: PluginRelease)
fun onDownloadReleaseClick(item: PluginRelease)
fun onDeleteReleaseClick(item: PluginRelease)
fun onDownloadReleaseClick(item: PackageRelease)
fun onDeleteDownloadedPackageClick(item: PackageRelease)
}
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<PluginRelease> = object : DiffUtil.ItemCallback<PluginRelease>() {
override fun areItemsTheSame(oldItem: PluginRelease, newItem: PluginRelease): Boolean {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<PackageRelease> = object : DiffUtil.ItemCallback<PackageRelease>() {
override fun areItemsTheSame(oldItem: PackageRelease, newItem: PackageRelease): Boolean {
return oldItem.version == newItem.version
}
override fun areContentsTheSame(oldItem: PluginRelease, newItem: PluginRelease): Boolean {
return oldItem.isInstalled == newItem.isInstalled &&
oldItem.isDownloading == newItem.isDownloading &&
oldItem.downloadProgress == newItem.downloadProgress
override fun areContentsTheSame(oldItem: PackageRelease, newItem: PackageRelease): Boolean {
return oldItem.isInstalled == newItem.isInstalled
}
}
}

@ -1,36 +1,21 @@
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.collection.intSetOf
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.core.plugins.PluginBase
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.GithubRelease
import com.deniscerri.ytdl.database.models.PluginItem
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import java.text.SimpleDateFormat
import java.util.Locale
class PluginsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<PluginItem?, PluginsAdapter.ViewHolder>(AsyncDifferConfig.Builder(
import com.deniscerri.ytdl.core.packages.PackageBase
import com.deniscerri.ytdl.database.models.PackageItem
class PackagesAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<PackageItem?, PackagesAdapter.ViewHolder>(AsyncDifferConfig.Builder(
DIFF_CALLBACK
).build()) {
private val activity: Activity
@ -81,28 +66,30 @@ class PluginsAdapter(onItemClickListener: OnItemClickListener, activity: Activit
card.findViewById<TextView>(R.id.bundledChip).isVisible = isBundled
card.setOnClickListener { cl ->
onItemClickListener.onCardClick(it)
onItemClickListener.onCardClick(it, location)
}
card.setOnLongClickListener { c ->
if (location.isAvailable && location.isDownloaded) {
val canUninstall = location.isAvailable && isDownloaded
if (canUninstall) {
onItemClickListener.onDeleteDownloadedVersion(it, currentVersion)
}
true
}
}
interface OnItemClickListener {
fun onCardClick(item: PluginItem)
fun onDeleteDownloadedVersion(item: PluginItem, currentVersion: String?)
fun onCardClick(item: PackageItem, location: PackageBase.PackageLocation)
fun onDeleteDownloadedVersion(item: PackageItem, currentVersion: String?)
}
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<PluginItem> = object : DiffUtil.ItemCallback<PluginItem>() {
override fun areItemsTheSame(oldItem: PluginItem, newItem: PluginItem): Boolean {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<PackageItem> = object : DiffUtil.ItemCallback<PackageItem>() {
override fun areItemsTheSame(oldItem: PackageItem, newItem: PackageItem): Boolean {
return oldItem.title == newItem.title
}
override fun areContentsTheSame(oldItem: PluginItem, newItem: PluginItem): Boolean {
override fun areContentsTheSame(oldItem: PackageItem, newItem: PackageItem): Boolean {
return oldItem.title == newItem.title
}
}

@ -3,17 +3,11 @@ package com.deniscerri.ytdl.ui.more.settings.updating
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.text.method.LinkMovementMethod
import android.util.DisplayMetrics
import android.view.LayoutInflater
@ -33,14 +27,14 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.core.RuntimeManager
import com.deniscerri.ytdl.core.plugins.Aria2c
import com.deniscerri.ytdl.core.plugins.FFmpeg
import com.deniscerri.ytdl.core.plugins.NodeJS
import com.deniscerri.ytdl.core.plugins.PluginBase
import com.deniscerri.ytdl.core.plugins.Python
import com.deniscerri.ytdl.database.models.PluginItem
import com.deniscerri.ytdl.ui.adapter.PluginReleaseAdapter
import com.deniscerri.ytdl.ui.adapter.PluginsAdapter
import com.deniscerri.ytdl.core.packages.Aria2c
import com.deniscerri.ytdl.core.packages.FFmpeg
import com.deniscerri.ytdl.core.packages.NodeJS
import com.deniscerri.ytdl.core.packages.PackageBase
import com.deniscerri.ytdl.core.packages.Python
import com.deniscerri.ytdl.database.models.PackageItem
import com.deniscerri.ytdl.ui.adapter.PackageReleaseAdapter
import com.deniscerri.ytdl.ui.adapter.PackagesAdapter
import com.deniscerri.ytdl.ui.more.settings.SettingsActivity
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
import com.deniscerri.ytdl.util.FileUtil
@ -56,21 +50,20 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginReleaseAdapter.OnItemClickListener {
class PackagesFragment : Fragment(), PackagesAdapter.OnItemClickListener, PackageReleaseAdapter.OnItemClickListener {
private lateinit var recyclerView: RecyclerView
private lateinit var listAdapter: PluginsAdapter
private lateinit var releaseAdapter: PluginReleaseAdapter
private lateinit var listAdapter: PackagesAdapter
private lateinit var releaseAdapter: PackageReleaseAdapter
private var bottomSheet: BottomSheetDialog? = null
private lateinit var settingsActivity: SettingsActivity
private lateinit var preferences: SharedPreferences
private var tmpItem: PluginItem? = null
private var tmpItem: PackageItem? = null
private var tmpDownloadJob: Job? = null
private var plugins: List<PluginItem> = mutableListOf()
private var pluginReleases: List<PluginBase.PluginRelease> = mutableListOf()
private var packages: List<PackageItem> = mutableListOf()
private var packageReleases: List<PackageBase.PackageRelease> = mutableListOf()
override fun onCreateView(
inflater: LayoutInflater,
@ -78,31 +71,31 @@ class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginRe
savedInstanceState: Bundle?
): View? {
settingsActivity = activity as SettingsActivity
settingsActivity.changeTopAppbarTitle(getString(R.string.plugins))
settingsActivity.changeTopAppbarTitle(getString(R.string.packages))
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
return inflater.inflate(R.layout.fragment_plugins, container, false)
return inflater.inflate(R.layout.fragment_packages, container, false)
}
@SuppressLint("RestrictedApi")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
listAdapter = PluginsAdapter(this, settingsActivity)
listAdapter = PackagesAdapter(this, settingsActivity)
recyclerView = view.findViewById(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = listAdapter
recyclerView.enableFastScroll()
plugins = listOf(
PluginItem("Python", Python),
PluginItem("FFmpeg", FFmpeg),
PluginItem("Aria2c", Aria2c),
PluginItem("NodeJS", NodeJS)
packages = listOf(
PackageItem("Python", Python),
PackageItem("FFmpeg", FFmpeg),
PackageItem("Aria2c", Aria2c),
PackageItem("NodeJS", NodeJS)
)
listAdapter.submitList(plugins)
listAdapter.submitList(packages)
}
override fun onCardClick(item: PluginItem) {
override fun onCardClick(item: PackageItem, location: PackageBase.PackageLocation) {
tmpItem = item
val sheet = BottomSheetDialog(requireContext())
@ -124,8 +117,9 @@ class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginRe
val loader = sheet.findViewById<CircularProgressIndicator>(R.id.loader)
val noResults = sheet.findViewById<View>(R.id.no_results)
pluginReleases = mutableListOf()
releaseAdapter = PluginReleaseAdapter(this@PluginsFragment, requireActivity())
packageReleases = mutableListOf()
releaseAdapter = PackageReleaseAdapter(this@PackagesFragment, requireActivity())
releaseAdapter.setPackageLocation(location)
val releaseRecyclerView = sheet.findViewById<RecyclerView>(R.id.recyclerView)!!
releaseRecyclerView.adapter = releaseAdapter
@ -141,11 +135,11 @@ class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginRe
}
}
pluginReleases = this.getOrElse { listOf() }
releaseAdapter.submitList(pluginReleases)
releaseRecyclerView.isVisible = pluginReleases.isNotEmpty()
packageReleases = this.getOrElse { listOf() }
releaseAdapter.submitList(packageReleases)
releaseRecyclerView.isVisible = packageReleases.isNotEmpty()
loader?.isVisible = false
noResults?.isVisible = pluginReleases.isEmpty()
noResults?.isVisible = packageReleases.isEmpty()
}
}
@ -191,13 +185,21 @@ class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginRe
}
}
private fun deleteDownloadedVersion(item: PluginItem, version: String?) {
override fun onDeleteDownloadedPackageClick(item: PackageBase.PackageRelease) {
deleteDownloadedVersion(tmpItem!!, item.version)
}
override fun onDeleteDownloadedVersion(item: PackageItem, currentVersion: String?) {
deleteDownloadedVersion(item, currentVersion)
}
private fun deleteDownloadedVersion(item: PackageItem, version: String?) {
UiUtil.showGenericDeleteDialog(
requireContext(),
"${item.title} (${version})"
) {
val instance = item.getInstance()
val resp = instance.uninstall(requireContext())
val resp = instance.uninstallDownloaded(requireContext())
resp.onFailure {
Snackbar.make(requireView(), it.message ?: getString(R.string.errored), Snackbar.LENGTH_LONG).show()
}
@ -209,23 +211,7 @@ class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginRe
}
}
override fun onDeleteReleaseClick(item: PluginBase.PluginRelease) {
deleteDownloadedVersion(tmpItem!!, item.version)
}
override fun onDeleteDownloadedVersion(item: PluginItem, currentVersion: String?) {
deleteDownloadedVersion(item, currentVersion)
}
override fun onCancelDownloadReleaseClick(item: PluginBase.PluginRelease) {
tmpDownloadJob?.cancel()
val idx = pluginReleases.indexOf(item)
val list = pluginReleases.toMutableList()
list[idx] = list[idx].copy(isDownloading = false)
releaseAdapter.submitList(list.toList())
}
override fun onDownloadReleaseClick(item: PluginBase.PluginRelease) {
override fun onDownloadReleaseClick(item: PackageBase.PackageRelease) {
var positiveButton: Button? = null
val updateDialog = MaterialAlertDialogBuilder(requireContext())
.setTitle("${item.tag_name} (${FileUtil.convertFileSize(item.downloadSize)})")
@ -259,7 +245,7 @@ class PluginsFragment : Fragment(), PluginsAdapter.OnItemClickListener, PluginRe
val fileResp = instance.downloadRelease(requireContext(), item) { progress ->
lifecycleScope.launch {
withContext(Dispatchers.Main) {
positiveButton?.text = "$progress%"
positiveButton.text = "$progress%"
}
}
}

@ -11,12 +11,6 @@ import androidx.preference.Preference
import androidx.preference.PreferenceManager
import com.deniscerri.ytdl.BuildConfig
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.core.RuntimeManager
import com.deniscerri.ytdl.core.plugins.Aria2c
import com.deniscerri.ytdl.core.plugins.PluginBase
import com.deniscerri.ytdl.core.plugins.FFmpeg
import com.deniscerri.ytdl.core.plugins.NodeJS
import com.deniscerri.ytdl.core.plugins.Python
import com.deniscerri.ytdl.database.viewmodel.SettingsViewModel
import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel
import com.deniscerri.ytdl.ui.more.settings.BaseSettingsFragment
@ -92,11 +86,11 @@ class UpdateSettingsFragment : BaseSettingsFragment() {
false
}
findPreference<Preference>("plugins")?.apply {
findPreference<Preference>("packages")?.apply {
summary = "Python, FFmpeg, Aria2c, NodeJS"
setOnPreferenceClickListener {
findNavController().navigate(R.id.pluginsFragment)
findNavController().navigate(R.id.packagesFragment)
false
}
}

@ -99,16 +99,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:indeterminate="true"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -29,7 +29,7 @@
android:maxLines="2"
android:singleLine="false"
android:textSize="20sp"
android:text="@string/plugins"
android:text="@string/packages"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_import_zip"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

@ -22,8 +22,8 @@
android:id="@+id/action_updateSettingsFragment_to_changeLogFragment"
app:destination="@id/changeLogFragment" />
<action
android:id="@+id/action_updateSettingsFragment_to_pluginsFragment"
app:destination="@id/pluginsFragment" />
android:id="@+id/action_updateSettingsFragment_to_packagesFragment"
app:destination="@id/packagesFragment" />
</fragment>
<fragment
android:id="@+id/downloadSettingsFragment"
@ -76,7 +76,7 @@
android:name="com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.GenerateYoutubePoTokensFragment"
android:label="GenerateYoutubePoTokensFragment" />
<fragment
android:id="@+id/pluginsFragment"
android:name="com.deniscerri.ytdl.ui.more.settings.updating.PluginsFragment"
android:label="PluginsFragment" />
android:id="@+id/packagesFragment"
android:name="com.deniscerri.ytdl.ui.more.settings.updating.PackagesFragment"
android:label="PackagesFragment" />
</navigation>

@ -510,7 +510,7 @@
<string name="show_quick_download_share_menu">Show option to download immediately in the share menu</string>
<string name="quick_download_title">Don\'t fetch data</string>
<string name="sponsorblock_hook">Hook/Greetings</string>
<string name="plugins">Plugins</string>
<string name="packages">Packages</string>
<string name="not_installed">Not installed</string>
<string name="import_zip">Import ZIP</string>
<string name="bundled">Bundled</string>

@ -72,8 +72,8 @@
<Preference
app:icon="@drawable/ic_code"
app:key="plugins"
app:title="@string/plugins" />
app:key="packages"
app:title="@string/packages" />
<Preference
app:icon="@drawable/ic_chapters"

Loading…
Cancel
Save