mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-08-25 21:04:02 +02:00
Support for android 8+, selectable download location, permissions check, recursive delete
This commit is contained in:
+170
-77
@@ -55,14 +55,16 @@ export default {
|
||||
if (localAudiobooks[audiobookId].lastUpdate > userAudiobooks[audiobookId].lastUpdate) {
|
||||
// Local progress is more recent than user progress
|
||||
this.updateAudiobookProgressOnServer(localAudiobooks[audiobookId])
|
||||
} else {
|
||||
} else if (localAudiobooks[audiobookId].lastUpdate < userAudiobooks[audiobookId].lastUpdate) {
|
||||
// Server is more recent than local
|
||||
newestLocal[audiobookId] = userAudiobooks[audiobookId]
|
||||
console.log('SYNCUSERPROGRESS Server IS MORE RECENT for', audiobookId)
|
||||
localHasUpdates = true
|
||||
}
|
||||
} else {
|
||||
// Not on local yet - store on local
|
||||
newestLocal[audiobookId] = userAudiobooks[audiobookId]
|
||||
console.log('SYNCUSERPROGRESS LOCAL Is NOT Stored YET for', audiobookId, JSON.stringify(newestLocal[audiobookId]))
|
||||
localHasUpdates = true
|
||||
}
|
||||
}
|
||||
@@ -111,22 +113,19 @@ export default {
|
||||
this.$store.commit('setAppUpdateInfo', result)
|
||||
if (result.updateAvailability === 2) {
|
||||
setTimeout(() => {
|
||||
this.$toast.info(`Update is available!`, {
|
||||
this.$toast.info(`Update is available! Click to update.`, {
|
||||
draggable: false,
|
||||
hideProgressBar: false,
|
||||
timeout: 4000,
|
||||
closeButton: false,
|
||||
onClick: this.clickUpdateToast()
|
||||
timeout: 20000,
|
||||
closeButton: true,
|
||||
onClick: this.clickUpdateToast
|
||||
})
|
||||
// this.showUpdateToast(result.availableVersion, !!result.immediateUpdateAllowed)
|
||||
}, 5000)
|
||||
}
|
||||
},
|
||||
onDownloadProgress(data) {
|
||||
// var downloadId = data.downloadId
|
||||
var progress = data.progress
|
||||
var filename = data.filename
|
||||
var audiobookId = filename ? Path.basename(filename, Path.extname(filename)) : ''
|
||||
var audiobookId = data.audiobookId
|
||||
|
||||
var downloadObj = this.$store.getters['downloads/getDownload'](audiobookId)
|
||||
if (downloadObj) {
|
||||
@@ -136,31 +135,70 @@ export default {
|
||||
this.$toast.update(downloadObj.toastId, { content: `${progress}% Downloading ${downloadObj.audiobook.book.title}` })
|
||||
}
|
||||
},
|
||||
onDownloadFailed(data) {
|
||||
if (!data.audiobookId) {
|
||||
console.error('Download failed invalid audiobook id', data)
|
||||
return
|
||||
}
|
||||
var downloadObj = this.$store.getters['downloads/getDownload'](data.audiobookId)
|
||||
if (!downloadObj) {
|
||||
console.error('Failed to find download for audiobook', data.audiobookId)
|
||||
return
|
||||
}
|
||||
var message = data.error || 'Unknown Error'
|
||||
this.$toast.update(downloadObj.toastId, { content: `Failed. ${message}.`, options: { timeout: 5000, type: 'error' } }, true)
|
||||
this.$store.commit('downloads/removeDownload', downloadObj)
|
||||
},
|
||||
onDownloadComplete(data) {
|
||||
if (!data.audiobookId) {
|
||||
console.error('Download compelte invalid audiobook id', data)
|
||||
return
|
||||
}
|
||||
var downloadId = data.downloadId
|
||||
var contentUrl = data.contentUrl
|
||||
var folderUrl = data.folderUrl
|
||||
var folderName = data.folderName
|
||||
var storageId = data.storageId
|
||||
var storageType = data.storageType
|
||||
var simplePath = data.simplePath
|
||||
var filename = data.filename
|
||||
var audiobookId = filename ? Path.basename(filename, Path.extname(filename)) : ''
|
||||
var audiobookId = data.audiobookId
|
||||
var size = data.size || 0
|
||||
var isCover = !!data.isCover
|
||||
|
||||
if (audiobookId) {
|
||||
console.log('Download complete', filename, downloadId, contentUrl, 'AudiobookId:', audiobookId, 'Is Cover:', isCover)
|
||||
var downloadObj = this.$store.getters['downloads/getDownload'](audiobookId)
|
||||
if (!downloadObj) {
|
||||
console.error('Failed to find download for audiobook', audiobookId)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isCover) {
|
||||
// Notify server to remove prepared download
|
||||
if (this.$server.socket) {
|
||||
this.$server.socket.emit('remove_download', audiobookId)
|
||||
}
|
||||
|
||||
console.log('Download complete', filename, downloadId, contentUrl, 'AudiobookId:', audiobookId)
|
||||
var downloadObj = this.$store.getters['downloads/getDownload'](audiobookId)
|
||||
if (!downloadObj) {
|
||||
console.error('Could not find download...')
|
||||
} else {
|
||||
this.$toast.update(downloadObj.toastId, { content: `Success! ${downloadObj.audiobook.book.title} downloaded.`, options: { timeout: 5000, type: 'success' } }, true)
|
||||
this.$toast.update(downloadObj.toastId, { content: `Success! ${downloadObj.audiobook.book.title} downloaded.`, options: { timeout: 5000, type: 'success' } }, true)
|
||||
|
||||
console.log('Found download, update with content url')
|
||||
delete downloadObj.isDownloading
|
||||
delete downloadObj.isPreparing
|
||||
downloadObj.contentUrl = contentUrl
|
||||
this.$store.commit('downloads/addUpdateDownload', downloadObj)
|
||||
}
|
||||
delete downloadObj.isDownloading
|
||||
delete downloadObj.isPreparing
|
||||
downloadObj.contentUrl = contentUrl
|
||||
downloadObj.simplePath = simplePath
|
||||
downloadObj.folderUrl = folderUrl
|
||||
downloadObj.folderName = folderName
|
||||
downloadObj.storageType = storageType
|
||||
downloadObj.storageId = storageId
|
||||
downloadObj.basePath = data.basePath || null
|
||||
downloadObj.size = size
|
||||
this.$store.commit('downloads/addUpdateDownload', downloadObj)
|
||||
} else {
|
||||
downloadObj.coverUrl = contentUrl
|
||||
downloadObj.cover = Capacitor.convertFileSrc(contentUrl)
|
||||
downloadObj.coverSize = size
|
||||
downloadObj.coverBasePath = data.basePath || null
|
||||
console.log('Updating download with cover', downloadObj.cover)
|
||||
this.$store.commit('downloads/addUpdateDownload', downloadObj)
|
||||
}
|
||||
},
|
||||
async checkLoadCurrent() {
|
||||
@@ -176,59 +214,38 @@ export default {
|
||||
this.$localStore.setCurrent(null)
|
||||
}
|
||||
},
|
||||
onMediaLoaded(items) {
|
||||
async onMediaLoaded(items) {
|
||||
var jsitems = JSON.parse(items)
|
||||
jsitems = jsitems.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
size: item.size,
|
||||
duration: item.duration,
|
||||
filename: item.name,
|
||||
audiobookId: item.name ? Path.basename(item.name, Path.extname(item.name)) : '',
|
||||
contentUrl: item.uri.replace(/\\\//g, '/'),
|
||||
size: item.size,
|
||||
contentUrl: item.uri,
|
||||
coverUrl: item.coverUrl || null
|
||||
}
|
||||
})
|
||||
jsitems.forEach((item) => {
|
||||
var download = this.$store.getters['downloads/getDownload'](item.audiobookId)
|
||||
if (!download) {
|
||||
console.error(`Unknown media item found for filename ${item.filename}`)
|
||||
console.log('onMediaLoaded Items', JSON.stringify(jsitems))
|
||||
|
||||
var orphanDownload = {
|
||||
id: `orphan-${item.id}`,
|
||||
contentUrl: item.contentUrl,
|
||||
coverUrl: item.coverUrl,
|
||||
cover: item.coverUrl ? Capacitor.convertFileSrc(item.coverUrl) : null,
|
||||
mediaId: item.id,
|
||||
filename: item.filename,
|
||||
size: item.size,
|
||||
duration: item.duration,
|
||||
isOrphan: true
|
||||
}
|
||||
this.$store.commit('downloads/addUpdateDownload', orphanDownload)
|
||||
} else {
|
||||
console.log(`Found media item for audiobook ${download.audiobook.book.title} (${item.audiobookId})`)
|
||||
download.contentUrl = item.contentUrl
|
||||
download.coverUrl = item.coverUrl
|
||||
download.cover = item.coverUrl ? Capacitor.convertFileSrc(item.coverUrl) : null
|
||||
download.size = item.size
|
||||
download.duration = item.duration
|
||||
var downloads = await this.$sqlStore.getAllDownloads()
|
||||
for (let i = 0; i < downloads.length; i++) {
|
||||
var download = downloads[i]
|
||||
var jsitem = jsitems.find((item) => item.contentUrl === download.contentUrl)
|
||||
if (!jsitem) {
|
||||
console.error('Removing download was not found', JSON.stringify(download))
|
||||
await this.$sqlStore.removeDownload(download.id)
|
||||
} else if (download.coverUrl && !jsitem.coverUrl) {
|
||||
console.error('Removing cover for download was not found')
|
||||
download.cover = null
|
||||
download.coverUrl = null
|
||||
download.size = jsitem.size || 0
|
||||
this.$store.commit('downloads/addUpdateDownload', download)
|
||||
this.$store.commit('audiobooks/addUpdate', download.audiobook)
|
||||
} else {
|
||||
download.size = jsitem.size || 0
|
||||
this.$store.commit('downloads/addUpdateDownload', download)
|
||||
|
||||
download.audiobook.isDownloaded = true
|
||||
this.$store.commit('audiobooks/addUpdate', download.audiobook)
|
||||
}
|
||||
})
|
||||
|
||||
var downloads = this.$store.state.downloads.downloads
|
||||
|
||||
downloads.forEach((download) => {
|
||||
var matchingItem = jsitems.find((item) => item.audiobookId === download.id)
|
||||
if (!matchingItem) {
|
||||
console.error(`Saved download not in media store ${download.audiobook.book.title} (${download.id})`)
|
||||
this.$store.commit('downloads/removeDownload', download)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.checkLoadCurrent()
|
||||
},
|
||||
@@ -245,32 +262,95 @@ export default {
|
||||
this.$refs.streamContainer.cancelStream()
|
||||
}
|
||||
}
|
||||
|
||||
if (download.contentUrl) {
|
||||
await AudioDownloader.delete({ audiobookId: download.id, filename: download.filename, url: download.contentUrl, coverUrl: download.coverUrl })
|
||||
await AudioDownloader.delete(download)
|
||||
}
|
||||
this.$store.commit('downloads/removeDownload', download)
|
||||
},
|
||||
async initMediaStore() {
|
||||
// Load local database of downloads
|
||||
await this.$store.dispatch('downloads/loadFromStorage')
|
||||
await this.$localStore.loadUserAudiobooks()
|
||||
async onPermissionUpdate(data) {
|
||||
var val = data.value
|
||||
console.log('Permission Update', val)
|
||||
if (val === 'required') {
|
||||
console.log('Permission Required - Making Request')
|
||||
this.$store.commit('setHasStoragePermission', false)
|
||||
} else if (val === 'canceled' || val === 'denied') {
|
||||
console.error('Permission denied by user')
|
||||
this.$store.commit('setHasStoragePermission', false)
|
||||
} else if (val === 'granted') {
|
||||
console.log('User Granted permission')
|
||||
this.$store.commit('setHasStoragePermission', true)
|
||||
|
||||
var folder = data
|
||||
delete folder.value
|
||||
console.log('Setting folder', JSON.stringify(folder))
|
||||
await this.$localStore.setDownloadFolder(folder)
|
||||
} else {
|
||||
console.warn('Other permisiso update', val)
|
||||
}
|
||||
},
|
||||
async initMediaStore() {
|
||||
// Request and setup listeners for media files on native
|
||||
console.log('Permissino SET LISTENER')
|
||||
AudioDownloader.addListener('permission', (data) => {
|
||||
this.onPermissionUpdate(data)
|
||||
})
|
||||
AudioDownloader.addListener('onDownloadComplete', (data) => {
|
||||
this.onDownloadComplete(data)
|
||||
})
|
||||
AudioDownloader.addListener('onDownloadFailed', (data) => {
|
||||
this.onDownloadFailed(data)
|
||||
})
|
||||
AudioDownloader.addListener('onMediaLoaded', (data) => {
|
||||
this.onMediaLoaded(data.items)
|
||||
})
|
||||
AudioDownloader.addListener('onDownloadProgress', (data) => {
|
||||
this.onDownloadProgress(data)
|
||||
})
|
||||
AudioDownloader.load()
|
||||
|
||||
await this.$localStore.loadUserAudiobooks()
|
||||
await this.$localStore.getDownloadFolder()
|
||||
|
||||
var userSavedSettings = await this.$localStore.getUserSettings()
|
||||
if (userSavedSettings) {
|
||||
this.$store.commit('user/setSettings', userSavedSettings)
|
||||
}
|
||||
|
||||
var downloads = await this.$sqlStore.getAllDownloads()
|
||||
if (downloads.length) {
|
||||
var urls = downloads
|
||||
.map((d) => {
|
||||
return {
|
||||
contentUrl: d.contentUrl,
|
||||
coverUrl: d.coverUrl || '',
|
||||
storageId: d.storageId,
|
||||
basePath: d.basePath,
|
||||
coverBasePath: d.coverBasePath || ''
|
||||
}
|
||||
})
|
||||
.filter((d) => {
|
||||
if (!d.contentUrl) {
|
||||
console.error('Invalid Download no Content URL', JSON.stringify(d))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
AudioDownloader.load({
|
||||
audiobookUrls: urls
|
||||
})
|
||||
}
|
||||
|
||||
var checkPermission = await AudioDownloader.checkStoragePermission()
|
||||
console.log('Storage Permission is', checkPermission.value)
|
||||
if (!checkPermission.value) {
|
||||
console.log('Will require permissions')
|
||||
} else {
|
||||
console.log('Has Storage Permission')
|
||||
this.$store.commit('setHasStoragePermission', true)
|
||||
}
|
||||
},
|
||||
async setupNetworkListener() {
|
||||
var status = await Network.getStatus()
|
||||
console.log('Network status', status.connected, status.connectionType)
|
||||
this.$store.commit('setNetworkStatus', status)
|
||||
|
||||
Network.addListener('networkStatusChange', (status) => {
|
||||
@@ -282,12 +362,26 @@ export default {
|
||||
mounted() {
|
||||
if (!this.$server) return console.error('No Server')
|
||||
|
||||
console.log('Default Mounted')
|
||||
|
||||
this.$server.on('connected', this.connected)
|
||||
this.$server.on('initialStream', this.initialStream)
|
||||
|
||||
this.setupNetworkListener()
|
||||
this.checkForUpdate()
|
||||
this.initMediaStore()
|
||||
if (this.$store.state.isFirstLoad) {
|
||||
this.$store.commit('setIsFirstLoad', false)
|
||||
this.setupNetworkListener()
|
||||
this.checkForUpdate()
|
||||
this.initMediaStore()
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.$server) {
|
||||
console.error('No Server beforeDestroy')
|
||||
return
|
||||
}
|
||||
console.log('Default Before Destroy remove listeners')
|
||||
this.$server.off('connected', this.connected)
|
||||
this.$server.off('initialStream', this.initialStream)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -297,7 +391,6 @@ export default {
|
||||
height: calc(100vh - 64px);
|
||||
}
|
||||
#content.playerOpen {
|
||||
/* height: calc(100vh - 204px); */
|
||||
height: calc(100vh - 240px);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user