Add start of new local media page for adding folders and scanning local media items

This commit is contained in:
advplyr
2022-03-31 20:23:38 -05:00
parent a8de03b82d
commit a259883979
14 changed files with 698 additions and 73 deletions
@@ -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