mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-04 18:15:01 +02:00
Remove file copy
This commit is contained in:
parent
e6aaccfc74
commit
9acf695802
1 changed files with 0 additions and 300 deletions
|
@ -1,300 +0,0 @@
|
|||
package com.audiobookshelf.app.plugins
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.anggrayudi.storage.SimpleStorage
|
||||
import com.anggrayudi.storage.callback.FolderPickerCallback
|
||||
import com.anggrayudi.storage.callback.StorageAccessCallback
|
||||
import com.anggrayudi.storage.file.*
|
||||
import com.audiobookshelf.app.MainActivity
|
||||
import com.audiobookshelf.app.data.LocalFolder
|
||||
import com.audiobookshelf.app.data.LocalLibraryItem
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.device.FolderScanner
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.getcapacitor.*
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
@CapacitorPlugin(name = "AbsFileSystem")
|
||||
class AbsFileSystem : Plugin() {
|
||||
private val TAG = "AbsFileSystem"
|
||||
private val tag = "AbsFileSystem"
|
||||
private var jacksonMapper = jacksonObjectMapper().enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature())
|
||||
|
||||
lateinit var mainActivity: MainActivity
|
||||
|
||||
override fun load() {
|
||||
mainActivity = (activity as MainActivity)
|
||||
|
||||
mainActivity.storage.storageAccessCallback = object : StorageAccessCallback {
|
||||
override fun onRootPathNotSelected(
|
||||
requestCode: Int,
|
||||
rootPath: String,
|
||||
uri: Uri,
|
||||
selectedStorageType: StorageType,
|
||||
expectedStorageType: StorageType
|
||||
) {
|
||||
Log.d(TAG, "STORAGE ACCESS CALLBACK")
|
||||
}
|
||||
|
||||
override fun onCanceledByUser(requestCode: Int) {
|
||||
Log.d(TAG, "STORAGE ACCESS CALLBACK")
|
||||
}
|
||||
|
||||
override fun onExpectedStorageNotSelected(requestCode: Int, selectedFolder: DocumentFile, selectedStorageType: StorageType, expectedBasePath: String, expectedStorageType: StorageType) {
|
||||
Log.d(TAG, "STORAGE ACCESS CALLBACK")
|
||||
}
|
||||
|
||||
override fun onStoragePermissionDenied(requestCode: Int) {
|
||||
Log.d(TAG, "STORAGE ACCESS CALLBACK")
|
||||
}
|
||||
|
||||
override fun onRootPathPermissionGranted(requestCode: Int, root: DocumentFile) {
|
||||
Log.d(TAG, "STORAGE ACCESS CALLBACK")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun selectFolder(call: PluginCall) {
|
||||
val mediaType = call.data.getString("mediaType", "book").toString()
|
||||
val REQUEST_CODE_SELECT_FOLDER = 6
|
||||
val REQUEST_CODE_SDCARD_ACCESS = 7
|
||||
|
||||
mainActivity.storage.folderPickerCallback = object : FolderPickerCallback {
|
||||
override fun onFolderSelected(requestCode: Int, folder: DocumentFile) {
|
||||
Log.d(TAG, "ON FOLDER SELECTED ${folder.uri} ${folder.name}")
|
||||
val absolutePath = folder.getAbsolutePath(activity)
|
||||
val storageType = folder.getStorageType(activity)
|
||||
val simplePath = folder.getSimplePath(activity)
|
||||
val basePath = folder.getBasePath(activity)
|
||||
val folderId = android.util.Base64.encodeToString(folder.id.toByteArray(), android.util.Base64.DEFAULT)
|
||||
|
||||
val localFolder = LocalFolder(folderId, folder.name ?: "", folder.uri.toString(),basePath,absolutePath, simplePath, storageType.toString(), mediaType)
|
||||
|
||||
DeviceManager.dbManager.saveLocalFolder(localFolder)
|
||||
call.resolve(JSObject(jacksonMapper.writeValueAsString(localFolder)))
|
||||
}
|
||||
|
||||
override fun onStorageAccessDenied(
|
||||
requestCode: Int,
|
||||
folder: DocumentFile?,
|
||||
storageType: StorageType,
|
||||
storageId: String
|
||||
) {
|
||||
Log.e(tag, "Storage Access Denied ${folder?.getAbsolutePath(mainActivity)}")
|
||||
|
||||
val jsobj = JSObject()
|
||||
if (requestCode == REQUEST_CODE_SELECT_FOLDER) {
|
||||
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(mainActivity)
|
||||
builder.setMessage(
|
||||
"You have no write access to this storage, thus selecting this folder is useless." +
|
||||
"\nWould you like to grant access to this folder?")
|
||||
builder.setNegativeButton("Dont Allow") { _, _ ->
|
||||
run {
|
||||
jsobj.put("error", "User Canceled, Access Denied")
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
}
|
||||
builder.setPositiveButton("Allow.") { _, _ -> mainActivity.storageHelper.requestStorageAccess(REQUEST_CODE_SDCARD_ACCESS, initialPath = FileFullPath(mainActivity, storageId, "")) }
|
||||
builder.show()
|
||||
} else {
|
||||
Log.d(TAG, "STORAGE ACCESS DENIED $requestCode")
|
||||
jsobj.put("error", "Access Denied")
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onStoragePermissionDenied(requestCode: Int) {
|
||||
Log.d(TAG, "STORAGE PERMISSION DENIED $requestCode")
|
||||
val jsobj = JSObject()
|
||||
jsobj.put("error", "Permission Denied")
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mainActivity.storage.openFolderPicker(REQUEST_CODE_SELECT_FOLDER)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@PluginMethod
|
||||
fun requestStoragePermission(call: PluginCall) {
|
||||
Log.d(TAG, "Request Storage Permissions")
|
||||
mainActivity.storageHelper.requestStorageAccess()
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun checkStoragePermission(call: PluginCall) {
|
||||
val res: Boolean
|
||||
if (Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.P) {
|
||||
res = SimpleStorage.hasStoragePermission(context)
|
||||
Log.d(TAG, "checkStoragePermission: Check Storage Access $res")
|
||||
} else {
|
||||
Log.d(TAG, "checkStoragePermission: Has permission on Android 10 or up")
|
||||
res = true
|
||||
}
|
||||
|
||||
val jsobj = JSObject()
|
||||
jsobj.put("value", res)
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun checkFolderPermissions(call: PluginCall) {
|
||||
val folderUrl = call.data.getString("folderUrl", "").toString()
|
||||
Log.d(TAG, "Check Folder Permissions for $folderUrl")
|
||||
|
||||
val hasAccess = SimpleStorage.hasStorageAccess(context,folderUrl,true)
|
||||
|
||||
val jsobj = JSObject()
|
||||
jsobj.put("value", hasAccess)
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun scanFolder(call: PluginCall) {
|
||||
val folderId = call.data.getString("folderId", "").toString()
|
||||
val forceAudioProbe = call.data.getBoolean("forceAudioProbe")
|
||||
Log.d(TAG, "Scan Folder $folderId | Force Audio Probe $forceAudioProbe")
|
||||
|
||||
val folder: LocalFolder? = DeviceManager.dbManager.getLocalFolder(folderId)
|
||||
folder?.let {
|
||||
val folderScanner = FolderScanner(context)
|
||||
val folderScanResult = folderScanner.scanForMediaItems(it, forceAudioProbe)
|
||||
if (folderScanResult == null) {
|
||||
Log.d(TAG, "NO Scan DATA")
|
||||
return call.resolve(JSObject())
|
||||
} else {
|
||||
Log.d(TAG, "Scan DATA ${jacksonMapper.writeValueAsString(folderScanResult)}")
|
||||
return call.resolve(JSObject(jacksonMapper.writeValueAsString(folderScanResult)))
|
||||
}
|
||||
} ?: call.resolve(JSObject())
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun removeFolder(call: PluginCall) {
|
||||
val folderId = call.data.getString("folderId", "").toString()
|
||||
DeviceManager.dbManager.removeLocalFolder(folderId)
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun removeLocalLibraryItem(call: PluginCall) {
|
||||
val localLibraryItemId = call.data.getString("localLibraryItemId", "").toString()
|
||||
DeviceManager.dbManager.removeLocalLibraryItem(localLibraryItemId)
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun scanLocalLibraryItem(call: PluginCall) {
|
||||
val localLibraryItemId = call.data.getString("localLibraryItemId", "").toString()
|
||||
val forceAudioProbe = call.data.getBoolean("forceAudioProbe")
|
||||
Log.d(TAG, "Scan Local library item $localLibraryItemId | Force Audio Probe $forceAudioProbe")
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val localLibraryItem: LocalLibraryItem? = DeviceManager.dbManager.getLocalLibraryItem(localLibraryItemId)
|
||||
localLibraryItem?.let {
|
||||
val folderScanner = FolderScanner(context)
|
||||
val scanResult = folderScanner.scanLocalLibraryItem(it, forceAudioProbe)
|
||||
if (scanResult == null) {
|
||||
Log.d(TAG, "NO Scan DATA")
|
||||
call.resolve(JSObject())
|
||||
} else {
|
||||
Log.d(TAG, "Scan DATA ${jacksonMapper.writeValueAsString(scanResult)}")
|
||||
call.resolve(JSObject(jacksonMapper.writeValueAsString(scanResult)))
|
||||
}
|
||||
} ?: call.resolve(JSObject())
|
||||
}
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun deleteItem(call: PluginCall) {
|
||||
val localLibraryItemId = call.data.getString("id", "").toString()
|
||||
val absolutePath = call.data.getString("absolutePath", "").toString()
|
||||
val contentUrl = call.data.getString("contentUrl", "").toString()
|
||||
Log.d(tag, "deleteItem $absolutePath | $contentUrl")
|
||||
|
||||
// Check if should delete subfolder
|
||||
val localLibraryItem = DeviceManager.dbManager.getLocalLibraryItem(localLibraryItemId)
|
||||
|
||||
val success: Boolean
|
||||
|
||||
// If internal library item use File to delete
|
||||
if (localLibraryItem?.folderId?.startsWith("internal-") == true) {
|
||||
Log.d(tag, "Deleting internal library item at absolutePath $absolutePath")
|
||||
val file = File(absolutePath)
|
||||
success = file.deleteRecursively()
|
||||
} else {
|
||||
var subfolderPathToDelete = ""
|
||||
localLibraryItem?.folderId?.let { folderId ->
|
||||
val folder = DeviceManager.dbManager.getLocalFolder(folderId)
|
||||
folder?.absolutePath?.let { folderPath ->
|
||||
val splitAbsolutePath = absolutePath.split("/")
|
||||
val fullSubDir = splitAbsolutePath.subList(0, splitAbsolutePath.size - 1).joinToString("/")
|
||||
if (fullSubDir != folderPath) {
|
||||
val subdirHasAnItem = DeviceManager.dbManager.getLocalLibraryItems().any { _localLibraryItem ->
|
||||
if (_localLibraryItem.id == localLibraryItemId) {
|
||||
false
|
||||
} else {
|
||||
_localLibraryItem.absolutePath.startsWith(fullSubDir)
|
||||
}
|
||||
}
|
||||
subfolderPathToDelete = if (subdirHasAnItem) "" else fullSubDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val docfile = DocumentFileCompat.fromUri(mainActivity, Uri.parse(contentUrl))
|
||||
success = docfile?.delete() == true
|
||||
|
||||
if (subfolderPathToDelete != "") {
|
||||
Log.d(tag, "Deleting empty subfolder at $subfolderPathToDelete")
|
||||
val docfilesub = DocumentFileCompat.fromFullPath(mainActivity, subfolderPathToDelete)
|
||||
docfilesub?.delete()
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
DeviceManager.dbManager.removeLocalLibraryItem(localLibraryItemId)
|
||||
}
|
||||
call.resolve(JSObject("{\"success\":$success}"))
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun deleteTrackFromItem(call: PluginCall) {
|
||||
val localLibraryItemId = call.data.getString("id", "").toString()
|
||||
val trackLocalFileId = call.data.getString("trackLocalFileId", "").toString()
|
||||
val contentUrl = call.data.getString("trackContentUrl", "").toString()
|
||||
Log.d(tag, "deleteTrackFromItem $contentUrl")
|
||||
|
||||
val localLibraryItem = DeviceManager.dbManager.getLocalLibraryItem(localLibraryItemId)
|
||||
if (localLibraryItem == null) {
|
||||
Log.e(tag, "deleteTrackFromItem: LLI does not exist $localLibraryItemId")
|
||||
return call.resolve(JSObject("{\"success\":false}"))
|
||||
}
|
||||
|
||||
val docfile = DocumentFileCompat.fromUri(mainActivity, Uri.parse(contentUrl))
|
||||
val success = docfile?.delete() == true
|
||||
if (success) {
|
||||
localLibraryItem.media.removeAudioTrack(trackLocalFileId)
|
||||
localLibraryItem.removeLocalFile(trackLocalFileId)
|
||||
DeviceManager.dbManager.saveLocalLibraryItem(localLibraryItem)
|
||||
call.resolve(JSObject(jacksonMapper.writeValueAsString(localLibraryItem)))
|
||||
} else {
|
||||
call.resolve(JSObject("{\"success\":false}"))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue