Downloads go into sub-directory, fix text overflow in downloads modal

This commit is contained in:
advplyr
2021-09-16 19:41:07 -05:00
parent 8232cfb796
commit 87f1deff19
6 changed files with 69 additions and 84 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ android {
applicationId "com.audiobookshelf.app" applicationId "com.audiobookshelf.app"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 10 versionCode 11
versionName "0.8.1-beta" versionName "0.8.2-beta"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions { aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
@@ -7,7 +7,6 @@ import android.net.Uri
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log import android.util.Log
import android.widget.Toast
import com.getcapacitor.JSObject import com.getcapacitor.JSObject
import com.getcapacitor.Plugin import com.getcapacitor.Plugin
import com.getcapacitor.PluginCall import com.getcapacitor.PluginCall
@@ -23,10 +22,10 @@ class AudioDownloader : Plugin() {
lateinit var mainActivity:MainActivity lateinit var mainActivity:MainActivity
lateinit var downloadManager:DownloadManager lateinit var downloadManager:DownloadManager
data class AudiobookDownload(val url: String, val filename:String, val downloadId: Long) data class AudiobookDownload(val url: String, val filename: String, val downloadId: Long)
var downloads:MutableList<AudiobookDownload> = mutableListOf() var downloads:MutableList<AudiobookDownload> = mutableListOf()
data class CoverItem(val name:String, val coverUrl:String) data class CoverItem(val name: String, val coverUrl: String)
data class AudiobookItem(val id: Long, val uri: Uri, val name: String, val size: Int, val duration: Int, val coverUrl: String) { data class AudiobookItem(val id: Long, val uri: Uri, val name: String, val size: Int, val duration: Int, val coverUrl: String) {
fun toJSObject() : JSObject { fun toJSObject() : JSObject {
var obj = JSObject() var obj = JSObject()
@@ -76,7 +75,8 @@ class AudioDownloader : Plugin() {
MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.SIZE, MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.IS_AUDIOBOOK MediaStore.Audio.Media.IS_AUDIOBOOK,
MediaStore.Audio.Media.RELATIVE_PATH
) )
var _audiobookItems:MutableList<AudiobookItem> = mutableListOf() var _audiobookItems:MutableList<AudiobookItem> = mutableListOf()
@@ -99,6 +99,7 @@ class AudioDownloader : Plugin() {
cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION) cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE) val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)
val isAudiobookColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_AUDIOBOOK) val isAudiobookColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_AUDIOBOOK)
var relativePathColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.RELATIVE_PATH)
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn) val id = cursor.getLong(idColumn)
@@ -106,6 +107,7 @@ class AudioDownloader : Plugin() {
val duration = cursor.getInt(durationColumn) val duration = cursor.getInt(durationColumn)
val size = cursor.getInt(sizeColumn) val size = cursor.getInt(sizeColumn)
var isAudiobook = cursor.getInt(isAudiobookColumn) var isAudiobook = cursor.getInt(isAudiobookColumn)
var relativePath = cursor.getString(relativePathColumn)
if (isAudiobook == 1) { if (isAudiobook == 1) {
val contentUri: Uri = ContentUris.withAppendedId( val contentUri: Uri = ContentUris.withAppendedId(
@@ -113,7 +115,7 @@ class AudioDownloader : Plugin() {
id id
) )
Log.d(tag, "Got Content FRom MEdia STORE $id $contentUri, Name: $name, Dur: $duration, Size: $size") Log.d(tag, "Got Content FRom MEdia STORE $id $contentUri, Name: $name, Dur: $duration, Size: $size, relativePath: $relativePath")
var audiobookId = File(name).nameWithoutExtension var audiobookId = File(name).nameWithoutExtension
var coverItem:CoverItem? = covers.find{it.name == audiobookId} var coverItem:CoverItem? = covers.find{it.name == audiobookId}
var coverUrl = coverItem?.coverUrl ?: "" var coverUrl = coverItem?.coverUrl ?: ""
@@ -177,6 +179,7 @@ class AudioDownloader : Plugin() {
@PluginMethod @PluginMethod
fun downloadCover(call: PluginCall) { fun downloadCover(call: PluginCall) {
var audiobookId = call.data.getString("audiobookId", "audiobook").toString()
var url = call.data.getString("downloadUrl", "unknown").toString() var url = call.data.getString("downloadUrl", "unknown").toString()
var title = call.data.getString("title", "Cover").toString() var title = call.data.getString("title", "Cover").toString()
var filename = call.data.getString("filename", "audiobook.jpg").toString() var filename = call.data.getString("filename", "audiobook.jpg").toString()
@@ -187,7 +190,10 @@ class AudioDownloader : Plugin() {
dlRequest.setTitle("Cover Art: $title") dlRequest.setTitle("Cover Art: $title")
dlRequest.setDescription("Cover art for audiobook") dlRequest.setDescription("Cover art for audiobook")
dlRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION) dlRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION)
dlRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_AUDIOBOOKS, filename)
var file:File = File(audiobookId, filename)
Log.d(tag, "FILE ${file.path} | ${file.canonicalPath}")
dlRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_AUDIOBOOKS, file.path)
var downloadId = downloadManager.enqueue(dlRequest) var downloadId = downloadManager.enqueue(dlRequest)
var progressReceiver : (prog: Long) -> Unit = { prog: Long -> var progressReceiver : (prog: Long) -> Unit = { prog: Long ->
@@ -212,6 +218,7 @@ class AudioDownloader : Plugin() {
@PluginMethod @PluginMethod
fun download(call: PluginCall) { fun download(call: PluginCall) {
var audiobookId = call.data.getString("audiobookId", "audiobook").toString()
var url = call.data.getString("downloadUrl", "unknown").toString() var url = call.data.getString("downloadUrl", "unknown").toString()
var title = call.data.getString("title", "Audiobook").toString() var title = call.data.getString("title", "Audiobook").toString()
var filename = call.data.getString("filename", "audiobook.mp3").toString() var filename = call.data.getString("filename", "audiobook.mp3").toString()
@@ -223,7 +230,9 @@ class AudioDownloader : Plugin() {
dlRequest.setDescription("Downloading to Audiobooks directory") dlRequest.setDescription("Downloading to Audiobooks directory")
dlRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION) dlRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION)
dlRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_AUDIOBOOKS, filename) var file:File = File(audiobookId, filename)
Log.d(tag, "FILE ${file.path} | ${file.canonicalPath}")
dlRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_AUDIOBOOKS, file.path)
var downloadId = downloadManager.enqueue(dlRequest) var downloadId = downloadManager.enqueue(dlRequest)
@@ -251,12 +260,31 @@ class AudioDownloader : Plugin() {
} }
@PluginMethod @PluginMethod
fun delete(call:PluginCall) { fun delete(call: PluginCall) {
var audiobookId = call.data.getString("audiobookId", "audiobook").toString()
var filename = call.data.getString("filename", "audiobook.mp3").toString() var filename = call.data.getString("filename", "audiobook.mp3").toString()
var url = call.data.getString("url", "").toString() var url = call.data.getString("url", "").toString()
var coverUrl = call.data.getString("coverUrl", "").toString() var coverUrl = call.data.getString("coverUrl", "").toString()
Log.d(tag, "Called delete file $filename $url") // Does Not Work
// var audiobookDirRoot = activity.applicationContext.getExternalFilesDir(Environment.DIRECTORY_AUDIOBOOKS)
// Log.d(tag, "AUDIOBOOK DIR ROOT $audiobookDirRoot")
// var result = audiobookDirRoot?.deleteRecursively()
// Log.d(tag, "DONE DELETING FOLDER $result")
// Does Not Work
// var audiobookDir = File(audiobookDirRoot, audiobookId + "/")
// Log.d(tag, "Delete Audiobook DIR ${audiobookDir.path} is dir ${audiobookDir.isDirectory}")
// var result = audiobookDir.deleteRecursively()
//
// Does Not Work
// var audiobookDir = activity.applicationContext.getExternalFilesDir(Environment.DIRECTORY_AUDIOBOOKS)
// Log.d(tag, "AUDIOBOOK DIR ${audiobookDir?.path}")
// var dir = File(audiobookDir, "$audiobookId/")
// Log.d(tag, "DIR DIR ${dir.path}")
// var res = dir.delete()
// Log.d(tag, "DELETED $res")
var contentResolver = activity.applicationContext.contentResolver var contentResolver = activity.applicationContext.contentResolver
contentResolver.delete(Uri.parse(url), null, null) contentResolver.delete(Uri.parse(url), null, null)
@@ -268,7 +296,7 @@ class AudioDownloader : Plugin() {
call.resolve() call.resolve()
} }
internal class DownloadProgressUpdater(private val manager: DownloadManager, private val downloadId: Long, private var receiver:(Long) -> Unit, private var doneReceiver:(Boolean) -> Unit) : Thread() { internal class DownloadProgressUpdater(private val manager: DownloadManager, private val downloadId: Long, private var receiver: (Long) -> Unit, private var doneReceiver: (Boolean) -> Unit) : Thread() {
private val query: DownloadManager.Query = DownloadManager.Query() private val query: DownloadManager.Query = DownloadManager.Query()
private var totalBytes: Int = 0 private var totalBytes: Int = 0
private var TAG = "DownloadProgressUpdater" private var TAG = "DownloadProgressUpdater"
+25 -13
View File
@@ -11,7 +11,7 @@
<template v-for="download in downloadsDownloading"> <template v-for="download in downloadsDownloading">
<li :key="download.id" class="text-gray-400 select-none relative px-4 py-5 border-b border-white border-opacity-10 bg-black bg-opacity-10"> <li :key="download.id" class="text-gray-400 select-none relative px-4 py-5 border-b border-white border-opacity-10 bg-black bg-opacity-10">
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<div> <div class="w-3/4">
<span class="text-xs">({{ downloadingProgress[download.id] || 0 }}%) {{ download.isPreparing ? 'Preparing' : 'Downloading' }}...</span> <span class="text-xs">({{ downloadingProgress[download.id] || 0 }}%) {{ download.isPreparing ? 'Preparing' : 'Downloading' }}...</span>
<p class="font-normal truncate text-sm">{{ download.audiobook.book.title }}</p> <p class="font-normal truncate text-sm">{{ download.audiobook.book.title }}</p>
</div> </div>
@@ -28,7 +28,7 @@
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<img v-if="download.cover" :src="download.cover" class="w-10 h-16 object-contain" /> <img v-if="download.cover" :src="download.cover" class="w-10 h-16 object-contain" />
<img v-else src="/book_placeholder.jpg" class="w-10 h-16 object-contain" /> <img v-else src="/book_placeholder.jpg" class="w-10 h-16 object-contain" />
<div class="pl-2"> <div class="pl-2 w-1/2">
<p class="font-normal truncate text-sm">{{ download.audiobook.book.title }}</p> <p class="font-normal truncate text-sm">{{ download.audiobook.book.title }}</p>
<p class="font-normal truncate text-xs text-gray-400">{{ download.audiobook.book.author }}</p> <p class="font-normal truncate text-xs text-gray-400">{{ download.audiobook.book.author }}</p>
</div> </div>
@@ -48,7 +48,11 @@
<template v-for="download in orphanDownloads"> <template v-for="download in orphanDownloads">
<li :key="download.id" class="text-gray-50 select-none relative cursor-pointer px-4 py-5 border-b border-white border-opacity-10"> <li :key="download.id" class="text-gray-50 select-none relative cursor-pointer px-4 py-5 border-b border-white border-opacity-10">
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<span class="font-normal block truncate text-sm">{{ download.filename }}</span> <div class="w-3/4">
<span class="text-xs text-gray-400">Unknown Audio File</span>
<p class="font-normal truncate text-sm">{{ download.filename }}</p>
</div>
<!-- <span class="font-normal block truncate text-sm pr-2">{{ download.filename }}</span> -->
<div class="flex-grow" /> <div class="flex-grow" />
<div class="shadow-sm text-warning flex items-center justify-center rounded-full"> <div class="shadow-sm text-warning flex items-center justify-center rounded-full">
<span class="material-icons">error_outline</span> <span class="material-icons">error_outline</span>
@@ -94,27 +98,35 @@ export default {
}, },
orphanDownloads() { orphanDownloads() {
return this.$store.state.downloads.orphanDownloads return this.$store.state.downloads.orphanDownloads
// return [
// {
// id: 'asdf',
// filename: 'Test Title 1 another long title on the downloading widget.jpg'
// }
// ]
}, },
downloads() { downloads() {
return this.$store.state.downloads.downloads return this.$store.state.downloads.downloads
// return [ // return [
// { // {
// id: 'asdf1', // id: 'asdf1',
// title: 'Test Title 1', // audiobook: {
// author: 'Test Author 1', // book: {
// title: 'Test Title 1 another long title on the downloading widget',
// author: 'Test Author 1'
// }
// },
// isDownloading: true // isDownloading: true
// }, // },
// { // {
// id: 'asdf2', // id: 'asdf2',
// title: 'Test Title 2', // audiobook: {
// author: 'Author 2', // book: {
// title: 'Test Title 2',
// author: 'Test Author 2 long test author to test the overflow capabilities'
// }
// },
// isReady: true // isReady: true
// },
// {
// id: 'asdf3',
// name: 'asdf.mp3',
// isReady: false,
// isDownloading: false
// } // }
// ] // ]
} }
+1 -58
View File
@@ -247,7 +247,7 @@ export default {
} }
if (download.contentUrl) { if (download.contentUrl) {
await AudioDownloader.delete({ filename: download.filename, url: download.contentUrl, coverUrl: download.coverUrl }) await AudioDownloader.delete({ audiobookId: download.id, filename: download.filename, url: download.contentUrl, coverUrl: download.coverUrl })
} }
this.$store.commit('downloads/removeDownload', download) this.$store.commit('downloads/removeDownload', download)
}, },
@@ -268,63 +268,6 @@ export default {
}) })
AudioDownloader.load() AudioDownloader.load()
}, },
// parseSemver(ver) {
// if (!ver) return null
// var groups = ver.match(/^v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)$/)
// if (groups && groups.length > 6) {
// var total = Number(groups[3]) * 100 + Number(groups[4]) * 10 + Number(groups[5])
// if (isNaN(total)) {
// console.warn('Invalid version total', groups[3], groups[4], groups[5])
// return null
// }
// return {
// total,
// version: groups[2],
// major: Number(groups[3]),
// minor: Number(groups[4]),
// patch: Number(groups[5]),
// preRelease: groups[6] || null
// }
// } else {
// console.warn('Invalid semver string', ver)
// }
// return null
// },
// checkForUpdateWebVersion() {
// if (!this.$config.version) {
// return
// }
// var currVerObj = this.parseSemver(this.$config.version)
// if (!currVerObj) {
// console.error('Invalid version', this.$config.version)
// return
// }
// console.log('Check for update, your version:', currVerObj.version)
// this.$store.commit('setCurrentVersion', currVerObj)
// var largestVer = null
// this.$axios.$get(`https://api.github.com/repos/advplyr/audiobookshelf-app/tags`).then((tags) => {
// if (tags && tags.length) {
// tags.forEach((tag) => {
// var verObj = this.parseSemver(tag.name)
// if (verObj) {
// if (!largestVer || largestVer.total < verObj.total) {
// largestVer = verObj
// }
// }
// })
// }
// })
// if (!largestVer) {
// console.error('No valid version tags to compare with')
// return
// }
// this.$store.commit('setLatestVersion', largestVer)
// if (largestVer.total > currVerObj.total) {
// console.log('Has Update!', largestVer.version)
// this.$store.commit('setHasUpdate', true)
// }
// }
async setupNetworkListener() { async setupNetworkListener() {
var status = await Network.getStatus() var status = await Network.getStatus()
console.log('Network status', status.connected, status.connectionType) console.log('Network status', status.connected, status.connectionType)
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf-app", "name": "audiobookshelf-app",
"version": "v0.8.1-beta", "version": "v0.8.2-beta",
"author": "advplyr", "author": "advplyr",
"scripts": { "scripts": {
"dev": "nuxt --hostname localhost --port 1337", "dev": "nuxt --hostname localhost --port 1337",
+2
View File
@@ -286,6 +286,7 @@ export default {
var extname = Path.extname(coverUrl) || '.jpg' var extname = Path.extname(coverUrl) || '.jpg'
var downloadRequestPayload = { var downloadRequestPayload = {
audiobookId: download.id,
downloadUrl: coverUrl, downloadUrl: coverUrl,
filename: `${download.id}${extname}`, filename: `${download.id}${extname}`,
title: download.audiobook.book.title title: download.audiobook.book.title
@@ -310,6 +311,7 @@ export default {
console.log('Starting Download URL', url) console.log('Starting Download URL', url)
var downloadRequestPayload = { var downloadRequestPayload = {
audiobookId: download.id,
filename: download.filename, filename: download.filename,
downloadUrl: url, downloadUrl: url,
title: download.audiobook.book.title title: download.audiobook.book.title