mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-08-25 21:04:02 +02:00
Add start of new local media page for adding folders and scanning local media items
This commit is contained in:
@@ -5,6 +5,7 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.server.ApiHandler
|
||||
import com.capacitorjs.plugins.app.AppPlugin
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
@@ -80,6 +81,23 @@ class MyNativeAudio : Plugin() {
|
||||
}
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun playLocalLibraryItem(call:PluginCall) {
|
||||
var localMediaItemId = call.getString("localMediaItemId", "").toString()
|
||||
var playWhenReady = call.getBoolean("playWhenReady") == true
|
||||
|
||||
DeviceManager.dbManager.loadLocalMediaItem(localMediaItemId)?.let {
|
||||
Handler(Looper.getMainLooper()).post() {
|
||||
Log.d(tag, "Preparing Local Media item ${jacksonObjectMapper().writeValueAsString(it)}")
|
||||
playerNotificationService.playLocalMediaItem(it, playWhenReady)
|
||||
}
|
||||
return call.resolve(JSObject())
|
||||
}
|
||||
var errObj = JSObject()
|
||||
errObj.put("error", "Item Not Found")
|
||||
call.resolve(errObj)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun getLibraryItems(call: PluginCall) {
|
||||
var libraryId = call.getString("libraryId", "").toString()
|
||||
|
||||
@@ -24,6 +24,7 @@ import androidx.media.MediaBrowserServiceCompat
|
||||
import androidx.media.utils.MediaConstants
|
||||
import com.anggrayudi.storage.file.isExternalStorageDocument
|
||||
import com.audiobookshelf.app.data.DbManager
|
||||
import com.audiobookshelf.app.data.LocalMediaItem
|
||||
import com.audiobookshelf.app.data.PlaybackSession
|
||||
import com.getcapacitor.Bridge
|
||||
import com.getcapacitor.JSObject
|
||||
@@ -706,6 +707,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||
currentPlayer.setPlaybackSpeed(1f) // TODO: Playback speed should come from settings
|
||||
}
|
||||
|
||||
fun playLocalMediaItem(localMediaItem: LocalMediaItem, playWhenReady:Boolean) {
|
||||
Log.d(tag, "playLocalMediaItem ${localMediaItem}")
|
||||
}
|
||||
|
||||
fun initPlayer(audiobookStreamData: AudiobookStreamData) {
|
||||
currentAudiobookStreamData = audiobookStreamData
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ 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.data.LocalFolder
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.device.FolderScanner
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.getcapacitor.*
|
||||
@@ -21,30 +23,6 @@ class StorageManager : Plugin() {
|
||||
|
||||
lateinit var mainActivity:MainActivity
|
||||
|
||||
data class MediaFile(val uri: Uri, val name: String, val simplePath: String, val size: Long, val type: String, val isAudio: Boolean) {
|
||||
fun toJSObject() : JSObject {
|
||||
var obj = JSObject()
|
||||
obj.put("uri", this.uri)
|
||||
obj.put("name", this.name)
|
||||
obj.put("simplePath", this.simplePath)
|
||||
obj.put("size", this.size)
|
||||
obj.put("type", this.type)
|
||||
obj.put("isAudio", this.isAudio)
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
data class MediaFolder(val uri: Uri, val name: String, val simplePath: String, val mediaFiles:List<MediaFile>) {
|
||||
fun toJSObject() : JSObject {
|
||||
var obj = JSObject()
|
||||
obj.put("uri", this.uri)
|
||||
obj.put("name", this.name)
|
||||
obj.put("simplePath", this.simplePath)
|
||||
obj.put("files", this.mediaFiles.map { it.toJSObject() })
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
override fun load() {
|
||||
mainActivity = (activity as MainActivity)
|
||||
|
||||
@@ -79,24 +57,19 @@ class StorageManager : Plugin() {
|
||||
|
||||
@PluginMethod
|
||||
fun selectFolder(call: PluginCall) {
|
||||
var mediaType = call.data.getString("mediaType", "book").toString()
|
||||
|
||||
mainActivity.storage.folderPickerCallback = object : FolderPickerCallback {
|
||||
override fun onFolderSelected(requestCode: Int, folder: DocumentFile) {
|
||||
Log.d(TAG, "ON FOLDER SELECTED ${folder.uri} ${folder.name}")
|
||||
|
||||
var absolutePath = folder.getAbsolutePath(activity)
|
||||
var storageId = folder.getStorageId(activity)
|
||||
var storageType = folder.getStorageType(activity)
|
||||
var simplePath = folder.getSimplePath(activity)
|
||||
var basePath = folder.getBasePath(activity)
|
||||
|
||||
var jsobj = JSObject()
|
||||
jsobj.put("uri", folder.uri)
|
||||
jsobj.put("absolutePath", absolutePath)
|
||||
jsobj.put("storageId", storageId)
|
||||
jsobj.put("storageType", storageType)
|
||||
jsobj.put("simplePath", simplePath)
|
||||
jsobj.put("basePath", basePath)
|
||||
call.resolve(jsobj)
|
||||
var localFolder = LocalFolder(folder.id, folder.name, folder.uri.toString(),absolutePath, simplePath, storageType.toString(), mediaType)
|
||||
|
||||
DeviceManager.dbManager.saveLocalFolder(localFolder)
|
||||
call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(localFolder)))
|
||||
}
|
||||
|
||||
override fun onStorageAccessDenied(requestCode: Int, folder: DocumentFile?, storageType: StorageType) {
|
||||
@@ -155,19 +128,22 @@ class StorageManager : Plugin() {
|
||||
|
||||
@PluginMethod
|
||||
fun searchFolder(call: PluginCall) {
|
||||
var folderUrl = call.data.getString("folderUrl", "").toString()
|
||||
var mediaType = call.data.getString("mediaType", "book").toString()
|
||||
Log.d(TAG, "Searching folder $folderUrl")
|
||||
|
||||
var folderScanner = FolderScanner(context)
|
||||
var folderScanResult = folderScanner.scanForMediaItems(folderUrl, mediaType)
|
||||
if (folderScanResult == null) {
|
||||
Log.d(TAG, "NO Scan DATA")
|
||||
call.resolve(JSObject())
|
||||
} else {
|
||||
Log.d(TAG, "Scan DATA ${jacksonObjectMapper().writeValueAsString(folderScanResult)}")
|
||||
call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(folderScanResult)))
|
||||
var folderId = call.data.getString("folderId", "").toString()
|
||||
var folder: LocalFolder? = DeviceManager.dbManager.loadLocalFolder(folderId)
|
||||
folder?.let {
|
||||
Log.d(TAG, "Searching folder ${it.contentUrl}")
|
||||
var folderScanner = FolderScanner(context)
|
||||
var folderScanResult = folderScanner.scanForMediaItems(it.contentUrl, it.mediaType)
|
||||
if (folderScanResult == null) {
|
||||
Log.d(TAG, "NO Scan DATA")
|
||||
return call.resolve(JSObject())
|
||||
} else {
|
||||
Log.d(TAG, "Scan DATA ${jacksonObjectMapper().writeValueAsString(folderScanResult)}")
|
||||
return call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(folderScanResult)))
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "Folder not found $folderId")
|
||||
call.resolve(JSObject())
|
||||
|
||||
//
|
||||
// var df: DocumentFile? = DocumentFileCompat.fromUri(context, Uri.parse(folderUrl))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.audiobookshelf.app.data
|
||||
|
||||
import android.util.Log
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.getcapacitor.JSObject
|
||||
import com.getcapacitor.Plugin
|
||||
import com.getcapacitor.PluginCall
|
||||
@@ -13,15 +14,54 @@ import org.json.JSONObject
|
||||
class DbManager : Plugin() {
|
||||
val tag = "DbManager"
|
||||
|
||||
fun loadDeviceData():DeviceData {
|
||||
var deviceData:DeviceData? = Paper.book("device").read("data")
|
||||
return deviceData ?: DeviceData(mutableListOf(),null)
|
||||
fun loadDeviceData(): DeviceData {
|
||||
return Paper.book("device").read("data") ?: DeviceData(mutableListOf(), null)
|
||||
}
|
||||
|
||||
fun saveDeviceData(deviceData:DeviceData) {
|
||||
Paper.book("device").write("data", deviceData)
|
||||
}
|
||||
|
||||
fun loadLocalMediaItems():List<LocalMediaItem> {
|
||||
var localMediaItems:MutableList<LocalMediaItem> = mutableListOf()
|
||||
Paper.book("localMediaItems").allKeys.forEach {
|
||||
var localMediaItem:LocalMediaItem? = Paper.book("localMediaItems").read(it)
|
||||
if (localMediaItem != null) {
|
||||
localMediaItems.add(localMediaItem)
|
||||
}
|
||||
}
|
||||
return localMediaItems
|
||||
}
|
||||
|
||||
fun loadLocalMediaItem(localMediaItemId:String):LocalMediaItem? {
|
||||
return Paper.book("localMediaItems").read(localMediaItemId)
|
||||
}
|
||||
|
||||
fun saveLocalMediaItems(localMediaItems:List<LocalMediaItem>) {
|
||||
localMediaItems.map {
|
||||
Paper.book("localMediaItems").write(it.id, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveLocalFolder(localFolder:LocalFolder) {
|
||||
Paper.book("localFolders").write(localFolder.id,localFolder)
|
||||
}
|
||||
|
||||
fun loadLocalFolder(folderId:String):LocalFolder? {
|
||||
return Paper.book("localFolders").read(folderId)
|
||||
}
|
||||
|
||||
fun getAllLocalFolders():List<LocalFolder> {
|
||||
var localFolders:MutableList<LocalFolder> = mutableListOf()
|
||||
Paper.book("localFolders").allKeys.forEach {
|
||||
var localFolder:LocalFolder? = Paper.book("localFolders").read(it)
|
||||
if (localFolder != null) {
|
||||
localFolders.add(localFolder)
|
||||
}
|
||||
}
|
||||
return localFolders
|
||||
}
|
||||
|
||||
fun saveObject(db:String, key:String, value:JSONObject) {
|
||||
Log.d(tag, "Saving Object $key ${value.toString()}")
|
||||
Paper.book(db).write(key, value)
|
||||
@@ -60,4 +100,26 @@ class DbManager : Plugin() {
|
||||
var jsobj = JSObject.fromJSONObject(json)
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun localFoldersFromWebView(call:PluginCall) {
|
||||
var folders = getAllLocalFolders()
|
||||
var folderObjArray = jacksonObjectMapper().writeValueAsString(folders)
|
||||
var jsobj = JSObject()
|
||||
jsobj.put("folders", folderObjArray)
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun loadMediaItemsInFolder(call:PluginCall) {
|
||||
var folderId = call.getString("folderId", "").toString()
|
||||
var localMediaItems = loadLocalMediaItems().filter {
|
||||
it.folderId == folderId
|
||||
}
|
||||
|
||||
var mediaItemsArray = jacksonObjectMapper().writeValueAsString(localMediaItems)
|
||||
var jsobj = JSObject()
|
||||
jsobj.put("localMediaItems", mediaItemsArray)
|
||||
call.resolve(jsobj)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ data class DeviceData(
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class LocalMediaItem(
|
||||
var id:String,
|
||||
var name: String,
|
||||
var mediaType:String,
|
||||
var folderId:String,
|
||||
var contentUrl:String,
|
||||
var simplePath: String,
|
||||
var absolutePath:String,
|
||||
@@ -39,3 +42,14 @@ data class LocalFile(
|
||||
var mimeType:String?,
|
||||
var size:Long
|
||||
)
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class LocalFolder(
|
||||
var id:String,
|
||||
var name:String?,
|
||||
var contentUrl:String,
|
||||
var absolutePath:String,
|
||||
var simplePath:String,
|
||||
var storageType:String,
|
||||
var mediaType:String
|
||||
)
|
||||
|
||||
@@ -20,6 +20,10 @@ class FolderScanner(var ctx: Context) {
|
||||
Log.e(tag, "Folder Doc File Invalid $folderUrl")
|
||||
return null
|
||||
}
|
||||
var folderName = df.name ?: ""
|
||||
var folderPath = df.getAbsolutePath(ctx)
|
||||
var folderUrl = df.uri.toString()
|
||||
var folderId = df.id
|
||||
|
||||
var foldersFound = df.search(false, DocumentFileType.FOLDER)
|
||||
|
||||
@@ -27,7 +31,7 @@ class FolderScanner(var ctx: Context) {
|
||||
|
||||
foldersFound.forEach {
|
||||
Log.d(tag, "Iterating over Folder Found ${it.name} | ${it.getSimplePath(ctx)} | URI: ${it.uri}")
|
||||
var folderName = it.name ?: ""
|
||||
var itemFolderName = it.name ?: ""
|
||||
|
||||
var audioTracks = mutableListOf<AudioTrack>()
|
||||
var localFiles = mutableListOf<LocalFile>()
|
||||
@@ -40,7 +44,7 @@ class FolderScanner(var ctx: Context) {
|
||||
var mimeType = it2?.mimeType ?: ""
|
||||
var filename = it2?.name ?: ""
|
||||
var isAudio = mimeType.startsWith("audio")
|
||||
Log.d(tag, "Found $mimeType file $filename in folder $folderName")
|
||||
Log.d(tag, "Found $mimeType file $filename in folder $itemFolderName")
|
||||
|
||||
var localFile = LocalFile(it2.id,it2.name,it2.uri.toString(),it2.getAbsolutePath(ctx),it2.getSimplePath(ctx),it2.mimeType,it2.length())
|
||||
localFiles.add(localFile)
|
||||
@@ -70,15 +74,16 @@ class FolderScanner(var ctx: Context) {
|
||||
}
|
||||
}
|
||||
if (audioTracks.size > 0) {
|
||||
Log.d(tag, "Found local media item named $folderName with ${audioTracks.size} tracks")
|
||||
var localMediaItem = LocalMediaItem(folderName, it.uri.toString(), it.getSimplePath(ctx), it.getAbsolutePath(ctx),audioTracks,localFiles,coverPath)
|
||||
Log.d(tag, "Found local media item named $itemFolderName with ${audioTracks.size} tracks")
|
||||
var localMediaItem = LocalMediaItem(it.id, itemFolderName, mediaType, folderId, it.uri.toString(), it.getSimplePath(ctx), it.getAbsolutePath(ctx),audioTracks,localFiles,coverPath)
|
||||
mediaItems.add(localMediaItem)
|
||||
}
|
||||
}
|
||||
|
||||
return if (mediaItems.size > 0) {
|
||||
Log.d(tag, "Found ${mediaItems.size} Media Items")
|
||||
FolderScanResult(df.name, df.getAbsolutePath(ctx), mediaType, df.uri.toString(), mediaItems)
|
||||
DeviceManager.dbManager.saveLocalMediaItems(mediaItems)
|
||||
FolderScanResult(folderName, folderPath, mediaType, folderUrl, mediaItems)
|
||||
} else {
|
||||
Log.d(tag, "No Media Items Found")
|
||||
null
|
||||
|
||||
Reference in New Issue
Block a user