Update:Android download to internal storage option #635

This commit is contained in:
advplyr 2023-06-04 14:59:55 -05:00
parent fbcb8620f9
commit 373221703d
12 changed files with 126 additions and 71 deletions

View file

@ -233,7 +233,7 @@ class AbsDownloader : Plugin() {
val fileSize = audioTrack?.metadata?.size ?: 0
Log.d(tag, "Starting podcast episode download")
val itemFolderPath = localFolder.absolutePath + "/" + podcastTitle
val itemFolderPath = if (isInternal) "$tempFolderPath" else "${localFolder.absolutePath}/$podcastTitle"
val downloadItemId = "${libraryItem.id}-${episode?.id}"
val downloadItem = DownloadItem(downloadItemId, libraryItem.id, episode?.id, libraryItem.userMediaProgress, DeviceManager.serverConnectionConfig?.id ?: "", DeviceManager.serverAddress, DeviceManager.serverUserId, libraryItem.mediaType, itemFolderPath, localFolder, podcastTitle, podcastTitle, libraryItem.media, mutableListOf())

View file

@ -1,7 +1,6 @@
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
@ -165,6 +164,13 @@ class AbsFileSystem : Plugin() {
call.resolve(jsobj)
}
@PluginMethod
fun getSDKVersion(call: PluginCall) {
val jsObject = JSObject()
jsObject.put("version", Build.VERSION.SDK_INT)
call.resolve(jsObject)
}
@PluginMethod
fun scanFolder(call: PluginCall) {
val folderId = call.data.getString("folderId", "").toString()

View file

@ -1,8 +1,8 @@
<template>
<modals-modal v-model="show" :width="300" height="100%">
<template #outer>
<div class="absolute top-8 left-4 z-40" style="max-width: 80%">
<p class="text-white text-lg truncate">Select Local Folder</p>
<div class="absolute top-10 left-4 z-40" style="max-width: 80%">
<p class="text-white text-lg truncate">Select Download Location</p>
</div>
</template>
@ -25,36 +25,48 @@
<script>
export default {
props: {
value: Boolean,
mediaType: String
},
data() {
return {
localFolders: []
}
},
watch: {
value(newVal) {
show(newVal) {
if (newVal) {
this.$nextTick(this.init)
}
}
},
computed: {
show: {
get() {
return this.value
return this.$store.state.globals.showSelectLocalFolderModal
},
set(val) {
this.$emit('input', val)
this.$store.commit('globals/setShowSelectLocalFolderModal', val)
}
},
modalData() {
return this.$store.state.globals.localFolderSelectData || {}
},
callback() {
return this.modalData.callback
},
mediaType() {
return this.modalData.mediaType
}
},
methods: {
clickedOption(folder) {
this.$emit('select', folder)
this.show = false
if (!this.callback) {
console.error('Callback not set')
return
}
this.callback(folder)
},
async init() {
var localFolders = (await this.$db.getLocalFolders()) || []
const localFolders = (await this.$db.getLocalFolders()) || []
if (!localFolders.some((lf) => lf.id === `internal-${this.mediaType}`)) {
localFolders.push({

View file

@ -186,28 +186,32 @@ export default {
}
},
async download(selectedLocalFolder = null) {
var localFolder = selectedLocalFolder
let localFolder = selectedLocalFolder
if (!localFolder) {
var localFolders = (await this.$db.getLocalFolders()) || []
const localFolders = (await this.$db.getLocalFolders()) || []
console.log('Local folders loaded', localFolders.length)
var foldersWithMediaType = localFolders.filter((lf) => {
const foldersWithMediaType = localFolders.filter((lf) => {
console.log('Checking local folder', lf.mediaType)
return lf.mediaType == this.mediaType
})
console.log('Folders with media type', this.mediaType, foldersWithMediaType.length)
const internalStorageFolder = foldersWithMediaType.find((f) => f.id === `internal-${this.mediaType}`)
if (!foldersWithMediaType.length) {
// No local folders or no local folders with this media type
localFolder = await this.selectFolder()
} else if (foldersWithMediaType.length == 1) {
console.log('Only 1 local folder with this media type - auto select it')
localFolder = foldersWithMediaType[0]
} else {
console.log('Multiple folders with media type')
// this.showSelectLocalFolder = true
return
localFolder = {
id: `internal-${this.mediaType}`,
name: 'Internal App Storage',
mediaType: this.mediaType
}
if (!localFolder) {
return this.$toast.error('Invalid download folder')
} else if (foldersWithMediaType.length === 1 && internalStorageFolder) {
localFolder = internalStorageFolder
} else {
this.$store.commit('globals/showSelectLocalFolderModal', {
mediaType: this.mediaType,
callback: (folder) => {
this.download(folder)
}
})
return
}
}

View file

@ -192,28 +192,32 @@ export default {
}
},
async download(selectedLocalFolder = null) {
var localFolder = selectedLocalFolder
let localFolder = selectedLocalFolder
if (!localFolder) {
var localFolders = (await this.$db.getLocalFolders()) || []
const localFolders = (await this.$db.getLocalFolders()) || []
console.log('Local folders loaded', localFolders.length)
var foldersWithMediaType = localFolders.filter((lf) => {
const foldersWithMediaType = localFolders.filter((lf) => {
console.log('Checking local folder', lf.mediaType)
return lf.mediaType == this.mediaType
})
console.log('Folders with media type', this.mediaType, foldersWithMediaType.length)
const internalStorageFolder = foldersWithMediaType.find((f) => f.id === `internal-${this.mediaType}`)
if (!foldersWithMediaType.length) {
// No local folders or no local folders with this media type
localFolder = await this.selectFolder()
} else if (foldersWithMediaType.length == 1) {
console.log('Only 1 local folder with this media type - auto select it')
localFolder = foldersWithMediaType[0]
} else {
console.log('Multiple folders with media type')
// this.showSelectLocalFolder = true
return
localFolder = {
id: `internal-${this.mediaType}`,
name: 'Internal App Storage',
mediaType: this.mediaType
}
if (!localFolder) {
return this.$toast.error('Invalid download folder')
} else if (foldersWithMediaType.length === 1 && internalStorageFolder) {
localFolder = internalStorageFolder
} else {
this.$store.commit('globals/showSelectLocalFolderModal', {
mediaType: this.mediaType,
callback: (folder) => {
this.download(folder)
}
})
return
}
}

View file

@ -11,6 +11,7 @@
<app-audio-player-container ref="streamContainer" />
<modals-libraries-modal />
<modals-playlists-add-create-modal />
<modals-select-local-folder-modal />
<app-side-drawer />
<readers-reader />
</div>

View file

@ -346,19 +346,23 @@ export default {
return lf.mediaType == this.mediaType
})
console.log('Folders with media type', this.mediaType, foldersWithMediaType.length)
const internalStorageFolder = foldersWithMediaType.find((f) => f.id === `internal-${this.mediaType}`)
if (!foldersWithMediaType.length) {
// No local folders or no local folders with this media type
localFolder = await this.selectFolder()
} else if (foldersWithMediaType.length == 1) {
console.log('Only 1 local folder with this media type - auto select it')
localFolder = foldersWithMediaType[0]
} else {
console.log('Multiple folders with media type')
// this.showSelectLocalFolder = true
return
localFolder = {
id: `internal-${this.mediaType}`,
name: 'Internal App Storage',
mediaType: this.mediaType
}
if (!localFolder) {
return this.$toast.error('Invalid download folder')
} else if (foldersWithMediaType.length === 1 && internalStorageFolder) {
localFolder = internalStorageFolder
} else {
this.$store.commit('globals/showSelectLocalFolderModal', {
mediaType: this.mediaType,
callback: (folder) => {
this.download(folder)
}
})
return
}
}

View file

@ -622,38 +622,32 @@ export default {
},
async download(selectedLocalFolder = null) {
// Get the local folder to download to
var localFolder = selectedLocalFolder
let localFolder = selectedLocalFolder
if (!localFolder) {
var localFolders = (await this.$db.getLocalFolders()) || []
const localFolders = (await this.$db.getLocalFolders()) || []
console.log('Local folders loaded', localFolders.length)
var foldersWithMediaType = localFolders.filter((lf) => {
const foldersWithMediaType = localFolders.filter((lf) => {
console.log('Checking local folder', lf.mediaType)
return lf.mediaType == this.mediaType
})
console.log('Folders with media type', this.mediaType, foldersWithMediaType.length)
const internalStorageFolder = foldersWithMediaType.find((f) => f.id === `internal-${this.mediaType}`)
if (!foldersWithMediaType.length) {
localFolder = {
id: `internal-${this.mediaType}`,
name: 'App Storage',
name: 'Internal App Storage',
mediaType: this.mediaType
}
} else if (foldersWithMediaType.length === 1 && internalStorageFolder) {
localFolder = internalStorageFolder
} else {
this.showSelectLocalFolder = true
return
this.$store.commit('globals/showSelectLocalFolderModal', {
mediaType: this.mediaType,
callback: (folder) => {
this.download(folder)
}
// if (!foldersWithMediaType.length) {
// // No local folders or no local folders with this media type
// localFolder = await this.selectFolder()
// } else if (foldersWithMediaType.length == 1) {
// console.log('Only 1 local folder with this media type - auto select it')
// localFolder = foldersWithMediaType[0]
// } else {
// console.log('Multiple folders with media type')
// this.showSelectLocalFolder = true
// return
// }
if (!localFolder) {
return this.$toast.error('Invalid download folder')
})
return
}
}

View file

@ -15,12 +15,18 @@
<div v-if="!localFolders.length" class="flex justify-center">
<p class="text-center">No Media Folders</p>
</div>
<div class="flex border-t border-white border-opacity-10 my-4 py-4">
<div v-if="!isAndroid10OrBelow || overrideFolderRestriction" class="flex border-t border-white border-opacity-10 my-4 py-4">
<div class="flex-grow pr-1">
<ui-dropdown v-model="newFolderMediaType" placeholder="Select media type" :items="mediaTypeItems" />
</div>
<ui-btn small class="w-28" color="success" @click="selectFolder">New Folder</ui-btn>
</div>
<div v-else class="flex border-t border-white border-opacity-10 my-4 py-4">
<div class="flex-grow pr-1">
<p class="text-sm">Android 10 and below will use internal app storage for downloads.</p>
</div>
<ui-btn small class="w-28" color="primary" @click="overrideFolderRestriction = true">Override</ui-btn>
</div>
</div>
</div>
</template>
@ -44,7 +50,9 @@ export default {
text: 'Podcasts'
}
],
syncing: false
syncing: false,
isAndroid10OrBelow: false,
overrideFolderRestriction: false
}
},
computed: {
@ -82,6 +90,10 @@ export default {
this.$router.push(`/localMedia/folders/${folderObj.id}?scan=1`)
},
async init() {
const androidSdkVersion = await this.$getAndroidSDKVersion()
this.isAndroid10OrBelow = !!androidSdkVersion && androidSdkVersion <= 29
console.log(`androidSdkVersion=${androidSdkVersion}, isAndroid10OrBelow=${this.isAndroid10OrBelow}`)
this.localFolders = (await this.$db.getLocalFolders()) || []
this.localLibraryItems = await this.$db.getLocalLibraryItems()
}

View file

@ -272,6 +272,7 @@ export default {
},
showItemDialog() {
this.selectedAudioTrack = null
this.selectedEpisode = null
this.showDialog = true
},
showTrackDialog(track) {

View file

@ -2,6 +2,7 @@ import Vue from 'vue'
import vClickOutside from 'v-click-outside'
import { App } from '@capacitor/app'
import { Dialog } from '@capacitor/dialog'
import { AbsFileSystem } from '@/plugins/capacitor'
import { StatusBar, Style } from '@capacitor/status-bar';
import { formatDistance, format, addDays, isDate } from 'date-fns'
import { Capacitor } from '@capacitor/core'
@ -17,6 +18,13 @@ if (Capacitor.getPlatform() != 'web') {
Vue.prototype.$isDev = process.env.NODE_ENV !== 'production'
Vue.prototype.$getAndroidSDKVersion = async () => {
if (Capacitor.getPlatform() !== 'android') return null
const data = await AbsFileSystem.getSDKVersion()
if (isNaN(data?.version)) return null
return Number(data.version)
}
Vue.prototype.$encodeUriPath = (path) => {
return path.replace(/\\/g, '/').replace(/%/g, '%25').replace(/#/g, '%23')
}

View file

@ -36,6 +36,8 @@ export const state = () => ({
libraryIcons: ['database', 'audiobookshelf', 'books-1', 'books-2', 'book-1', 'microphone-1', 'microphone-3', 'radio', 'podcast', 'rss', 'headphones', 'music', 'file-picture', 'rocket', 'power', 'star', 'heart'],
selectedPlaylistItems: [],
showPlaylistsAddCreateModal: false,
showSelectLocalFolderModal: false,
localFolderSelectData: null,
hapticFeedback: 'LIGHT'
})
@ -181,6 +183,13 @@ export const mutations = {
setShowPlaylistsAddCreateModal(state, val) {
state.showPlaylistsAddCreateModal = val
},
showSelectLocalFolderModal(state, data) {
state.localFolderSelectData = data
state.showSelectLocalFolderModal = true
},
setShowSelectLocalFolderModal(state, val) {
state.showSelectLocalFolderModal = val
},
setHapticFeedback(state, val) {
state.hapticFeedback = val || 'LIGHT'
}