diff --git a/android/app/src/main/java/com/audiobookshelf/app/StorageManager.kt b/android/app/src/main/java/com/audiobookshelf/app/StorageManager.kt index 52be4b46..c8cd79ec 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/StorageManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/StorageManager.kt @@ -1,20 +1,17 @@ package com.audiobookshelf.app -import android.Manifest -import android.content.pm.PackageManager import android.database.Cursor import android.net.Uri import android.os.Build import android.util.Log import androidx.annotation.RequiresApi -import androidx.core.app.ActivityCompat 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.device.FolderScanner +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.getcapacitor.* import com.getcapacitor.annotation.CapacitorPlugin @@ -159,12 +156,19 @@ 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 data = folderScanner.scanForAudiobooks(folderUrl) - Log.d(TAG, "Scan DATA $data") - call.resolve(JSObject()) + 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 df: DocumentFile? = DocumentFileCompat.fromUri(context, Uri.parse(folderUrl)) // diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt index 8fe06dba..fc8593f3 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt @@ -150,5 +150,6 @@ data class AudioTrack( var title:String, var contentUrl:String, var mimeType:String, - var isLocal:Boolean + var isLocal:Boolean, + var audioProbeResult:AudioProbeResult? ) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt index 8af0a744..052ba958 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt @@ -1,6 +1,7 @@ package com.audiobookshelf.app.data import android.net.Uri +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.getcapacitor.JSObject data class ServerConfig( @@ -17,8 +18,24 @@ data class DeviceData( var lastServerConfigId:String? ) +@JsonIgnoreProperties(ignoreUnknown = true) data class LocalMediaItem( - val name: String, - val simplePath: String, - val audioTracks:MutableList + var name: String, + var contentUrl:String, + var simplePath: String, + var absolutePath:String, + var audioTracks:MutableList, + var localFiles:MutableList, + var coverPath:String? +) + +@JsonIgnoreProperties(ignoreUnknown = true) +data class LocalFile( + var id:String, + var filename:String?, + var contentUrl:String, + var absolutePath:String, + var simplePath:String, + var mimeType:String?, + var size:Long ) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt b/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt new file mode 100644 index 00000000..927f74cb --- /dev/null +++ b/android/app/src/main/java/com/audiobookshelf/app/data/FolderScanResult.kt @@ -0,0 +1,9 @@ +package com.audiobookshelf.app.data + +data class FolderScanResult( + val name:String?, + val absolutePath:String, + val mediaType:String, + val contentUrl:String, + val localMediaItems:MutableList, +) diff --git a/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt b/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt index 143643d1..cb39c283 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/device/FolderScanner.kt @@ -5,39 +5,35 @@ import android.net.Uri import android.util.Log import androidx.documentfile.provider.DocumentFile import com.anggrayudi.storage.file.* -import com.arthenica.ffmpegkit.FFmpegKitConfig import com.arthenica.ffmpegkit.FFprobeKit -import com.arthenica.ffmpegkit.FFprobeSession -import com.arthenica.ffmpegkit.Level -import com.audiobookshelf.app.data.AudioProbeResult -import com.audiobookshelf.app.data.AudioTrack -import com.audiobookshelf.app.data.LocalMediaItem -import com.audiobookshelf.app.data.PlaybackSession +import com.audiobookshelf.app.data.* import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue - class FolderScanner(var ctx: Context) { private val tag = "FolderScanner" - fun scanForAudiobooks(folderUrl: String):MutableList { + fun scanForMediaItems(folderUrl: String, mediaType:String):FolderScanResult? { var df: DocumentFile? = DocumentFileCompat.fromUri(ctx, Uri.parse(folderUrl)) if (df == null) { Log.e(tag, "Folder Doc File Invalid $folderUrl") - return mutableListOf() + return null } - var mediaFolders = mutableListOf() var foldersFound = df.search(false, DocumentFileType.FOLDER) + var mediaItems = mutableListOf() + foldersFound.forEach { Log.d(tag, "Iterating over Folder Found ${it.name} | ${it.getSimplePath(ctx)} | URI: ${it.uri}") var folderName = it.name ?: "" - var mediaFiles = mutableListOf() var audioTracks = mutableListOf() + var localFiles = mutableListOf() var index = 1 + var startOffset = 0.0 + var coverPath:String? = null var filesInFolder = it.search(false, DocumentFileType.FILE, arrayOf("audio/*", "image/*")) filesInFolder.forEach { it2 -> @@ -46,12 +42,16 @@ class FolderScanner(var ctx: Context) { var isAudio = mimeType.startsWith("audio") Log.d(tag, "Found $mimeType file $filename in folder $folderName") + var localFile = LocalFile(it2.id,it2.name,it2.uri.toString(),it2.getAbsolutePath(ctx),it2.getSimplePath(ctx),it2.mimeType,it2.length()) + localFiles.add(localFile) + + Log.d(tag, "File attributes Id:${it2.id}|ContentUrl:${localFile.contentUrl}|isDownloadsDocument:${it2.isDownloadsDocument}") + if (isAudio) { - var absolutePath = it2.getAbsolutePath(ctx) - Log.d(tag, "Audio File Path $absolutePath") + Log.d(tag, "Scanning Audio File Path ${localFile.absolutePath}") // TODO: Make asynchronous - var session = FFprobeKit.execute("-i \"$absolutePath\" -print_format json -show_format -show_streams -select_streams a -show_chapters -loglevel quiet") + var session = FFprobeKit.execute("-i \"${localFile.absolutePath}\" -print_format json -show_format -show_streams -select_streams a -show_chapters -loglevel quiet") var sessionData = session.output Log.d(tag, "AFTER FFPROBE STRING $sessionData") @@ -59,19 +59,29 @@ class FolderScanner(var ctx: Context) { val audioProbeResult = mapper.readValue(sessionData) Log.d(tag, "Probe Result DATA ${audioProbeResult.duration} | ${audioProbeResult.size} | ${audioProbeResult.title} | ${audioProbeResult.artist}") - var track = AudioTrack(index, 0.0, 0.0, filename, absolutePath, mimeType, true) + var track = AudioTrack(index, startOffset, audioProbeResult.duration, filename, localFile.contentUrl, mimeType, true, audioProbeResult) audioTracks.add(track) + startOffset += audioProbeResult.duration } else { - Log.d(tag, "Found non audio file $filename") + // First image file use as cover path + if (coverPath == null) { + coverPath = localFile.absolutePath + } } -// var imageFile = StorageManager.MediaFile(it2.uri, filename, it2.getSimplePath(context), it2.length(), mimeType, isAudio) -// mediaFiles.add(imageFile) } - if (mediaFiles.size > 0) { - + 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) + mediaItems.add(localMediaItem) } } - return mediaFolders + return if (mediaItems.size > 0) { + Log.d(tag, "Found ${mediaItems.size} Media Items") + FolderScanResult(df.name, df.getAbsolutePath(ctx), mediaType, df.uri.toString(), mediaItems) + } else { + Log.d(tag, "No Media Items Found") + null + } } } diff --git a/pages/downloads.vue b/pages/downloads.vue index be1ca975..90994969 100644 --- a/pages/downloads.vue +++ b/pages/downloads.vue @@ -56,6 +56,18 @@ Change Folder Reset + + +
+
+ +
+
+

{{ mediaItem.name }}

+

{{ mediaItem.audioTracks.length }} Tracks

+
+
+

Scanning Folder..

No Files Found

@@ -83,6 +95,7 @@