mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-16 00:44:51 +02:00
Fix episodeId download issue, add draggable for local tracks
This commit is contained in:
parent
331a3b4a1a
commit
ccba8dc3c7
11 changed files with 150 additions and 15 deletions
|
@ -5,10 +5,7 @@ import com.audiobookshelf.app.MainActivity
|
|||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.server.ApiHandler
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.getcapacitor.JSObject
|
||||
import com.getcapacitor.Plugin
|
||||
import com.getcapacitor.PluginCall
|
||||
import com.getcapacitor.PluginMethod
|
||||
import com.getcapacitor.*
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
@ -202,6 +199,27 @@ class AbsDatabase : Plugin() {
|
|||
}
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun updateLocalTrackOrder(call:PluginCall) {
|
||||
var localLibraryItemId = call.getString("localLibraryItemId", "") ?: ""
|
||||
var localLibraryItem = DeviceManager.dbManager.getLocalLibraryItem(localLibraryItemId)
|
||||
if (localLibraryItem == null) {
|
||||
call.resolve()
|
||||
return
|
||||
}
|
||||
|
||||
var tracks:JSArray = call.getArray("tracks") ?: JSArray()
|
||||
Log.d(tag, "updateLocalTrackOrder $tracks")
|
||||
|
||||
for (i in 0..tracks.length()) {
|
||||
var track = tracks.getJSONObject(i)
|
||||
var localFileId = track.getString("localFileId")
|
||||
Log.d(tag, "LOCAL FILE ID $localFileId")
|
||||
}
|
||||
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
//
|
||||
// Generic Webview calls to db
|
||||
//
|
||||
|
|
|
@ -100,8 +100,9 @@ class AbsDownloader : Plugin() {
|
|||
fun downloadLibraryItem(call: PluginCall) {
|
||||
var libraryItemId = call.data.getString("libraryItemId").toString()
|
||||
var episodeId = call.data.getString("episodeId").toString()
|
||||
if (episodeId == "null") episodeId = ""
|
||||
var localFolderId = call.data.getString("localFolderId").toString()
|
||||
Log.d(tag, "Download library item $libraryItemId to folder $localFolderId")
|
||||
Log.d(tag, "Download library item $libraryItemId to folder $localFolderId / episode: $episodeId")
|
||||
|
||||
var downloadId = if (episodeId.isNullOrEmpty()) libraryItemId else "$libraryItemId-$episodeId"
|
||||
if (downloadQueue.find { it.id == downloadId } != null) {
|
||||
|
|
|
@ -42,11 +42,9 @@
|
|||
</div>
|
||||
|
||||
<!-- Error widget -->
|
||||
<ui-tooltip v-if="showError" :text="errorText" class="absolute bottom-4 left-0 z-10">
|
||||
<div :style="{ height: 1.5 * sizeMultiplier + 'rem', width: 2.5 * sizeMultiplier + 'rem' }" class="bg-error rounded-r-full shadow-md flex items-center justify-end border-r border-b border-red-300">
|
||||
<span class="material-icons text-red-100 pr-1" :style="{ fontSize: 0.875 * sizeMultiplier + 'rem' }">priority_high</span>
|
||||
</div>
|
||||
</ui-tooltip>
|
||||
<div v-if="showError" :style="{ height: 1.5 * sizeMultiplier + 'rem', width: 2.5 * sizeMultiplier + 'rem' }" class="bg-error rounded-r-full shadow-md flex items-center justify-end border-r border-b border-red-300">
|
||||
<span class="material-icons text-red-100 pr-1" :style="{ fontSize: 0.875 * sizeMultiplier + 'rem' }">priority_high</span>
|
||||
</div>
|
||||
|
||||
<!-- Volume number -->
|
||||
<div v-if="seriesSequence && showSequence && !isSelectionMode" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-10" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
|
||||
|
|
|
@ -24,6 +24,11 @@ export default {
|
|||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
script: [
|
||||
{
|
||||
src: '/libs/sortable.js'
|
||||
}
|
||||
],
|
||||
link: [
|
||||
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
|
||||
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Ubuntu+Mono&family=Source+Sans+Pro:wght@300;400;600' },
|
||||
|
|
13
package-lock.json
generated
13
package-lock.json
generated
|
@ -11775,6 +11775,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz",
|
||||
"integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A=="
|
||||
},
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
|
@ -13190,6 +13195,14 @@
|
|||
"resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-1.7.14.tgz",
|
||||
"integrity": "sha512-khZR8t3NWZ/JJ2MZxXLbesHrRJ8AKa75PY5Zq8yMifF9x8lHq8ljYkC0d2PD9yahooygQB5tcFyRDkbbIPx8hw=="
|
||||
},
|
||||
"vuedraggable": {
|
||||
"version": "2.24.3",
|
||||
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz",
|
||||
"integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==",
|
||||
"requires": {
|
||||
"sortablejs": "1.10.2"
|
||||
}
|
||||
},
|
||||
"vuex": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
"libarchive.js": "^1.3.0",
|
||||
"nuxt": "^2.15.7",
|
||||
"socket.io-client": "^4.1.3",
|
||||
"vue-toastification": "^1.7.11"
|
||||
"vue-toastification": "^1.7.11",
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.13.15",
|
||||
|
|
|
@ -18,10 +18,36 @@
|
|||
<div v-if="isScanning" class="w-full text-center p-4">
|
||||
<p>Scanning...</p>
|
||||
</div>
|
||||
<div v-else class="w-full media-item-container overflow-y-auto">
|
||||
<div v-else class="w-full max-w-full media-item-container overflow-y-auto overflow-x-hidden relative">
|
||||
<div v-if="!isPodcast" class="w-full">
|
||||
<p class="text-base mb-2">Audio Tracks ({{ audioTracks.length }})</p>
|
||||
<template v-for="track in audioTracks">
|
||||
|
||||
<draggable v-model="audioTracksCopy" v-bind="dragOptions" handle=".drag-handle" draggable=".item" tag="div" @start="drag = true" @end="drag = false" @update="draggableUpdate">
|
||||
<transition-group type="transition" :name="!drag ? 'dragtrack' : null">
|
||||
<template v-for="track in audioTracksCopy">
|
||||
<div :key="track.localFileId" class="flex items-center my-1 item">
|
||||
<div class="w-8 h-12 flex items-center justify-center" style="min-width: 32px">
|
||||
<span class="material-icons drag-handle text-lg text-white text-opacity-50 hover:text-opacity-100">menu</span>
|
||||
</div>
|
||||
<div class="w-8 h-12 flex items-center justify-center" style="min-width: 32px">
|
||||
<p class="font-mono font-bold text-xl">{{ track.index }}</p>
|
||||
</div>
|
||||
<div class="flex-grow px-2">
|
||||
<p class="text-xs">{{ track.title }}</p>
|
||||
</div>
|
||||
<div class="w-20 text-center text-gray-300" style="min-width: 80px">
|
||||
<p class="text-xs">{{ track.mimeType }}</p>
|
||||
<p class="text-sm">{{ $elapsedPretty(track.duration) }}</p>
|
||||
</div>
|
||||
<div class="w-12 h-12 flex items-center justify-center" style="min-width: 48px">
|
||||
<span class="material-icons" @click="showTrackDialog(track)">more_vert</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
|
||||
<!-- <template v-for="track in audioTracks">
|
||||
<div :key="track.localFileId" class="flex items-center my-1">
|
||||
<div class="w-10 h-12 flex items-center justify-center" style="min-width: 48px">
|
||||
<p class="font-mono font-bold text-xl">{{ track.index }}</p>
|
||||
|
@ -37,7 +63,7 @@
|
|||
<span class="material-icons" @click="showTrackDialog(track)">more_vert</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template> -->
|
||||
</div>
|
||||
<div v-else class="w-full">
|
||||
<p class="text-base mb-2">Episodes ({{ audioTracks.length }})</p>
|
||||
|
@ -87,11 +113,16 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
import { Dialog } from '@capacitor/dialog'
|
||||
import { AbsFileSystem } from '@/plugins/capacitor'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
asyncData({ params }) {
|
||||
return {
|
||||
localLibraryItemId: params.id
|
||||
|
@ -99,8 +130,16 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
drag: false,
|
||||
dragOptions: {
|
||||
animation: 200,
|
||||
group: 'description',
|
||||
delay: 40,
|
||||
delayOnTouchOnly: true
|
||||
},
|
||||
failed: false,
|
||||
localLibraryItem: null,
|
||||
audioTracksCopy: [],
|
||||
removingItem: false,
|
||||
folderId: null,
|
||||
folder: null,
|
||||
|
@ -187,6 +226,15 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
draggableUpdate() {
|
||||
console.log('Draggable update', this.audioTracksCopy)
|
||||
// var copyOfCopy = this.audioTracksCopy.map((at) => ({ ...at }))
|
||||
// const payload = {
|
||||
// localLibraryItemId: this.localLibraryItemId,
|
||||
// tracks: copyOfCopy
|
||||
// }
|
||||
// this.$db.updateLocalTrackOrder(payload)
|
||||
},
|
||||
showItemDialog() {
|
||||
this.selectedAudioTrack = null
|
||||
this.showDialog = true
|
||||
|
@ -322,6 +370,8 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
this.audioTracksCopy = this.audioTracks.map((at) => ({ ...at }))
|
||||
|
||||
this.folderId = this.localLibraryItem.folderId
|
||||
this.folder = await this.$db.getLocalFolder(this.folderId)
|
||||
}
|
||||
|
@ -332,9 +382,21 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style>
|
||||
.media-item-container {
|
||||
height: calc(100vh - 200px);
|
||||
max-height: calc(100vh - 200px);
|
||||
}
|
||||
.sortable-ghost {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.dragtrack-enter-from,
|
||||
.dragtrack-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
.dragtrack-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
|
@ -111,6 +111,30 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
isLocal: true,
|
||||
localFileId: 'lf1',
|
||||
audioProbeResult: {}
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
startOffset: 0,
|
||||
duration: 15000,
|
||||
title: 'Track Title 2',
|
||||
contentUrl: 'test2',
|
||||
mimeType: 'audio/mpeg',
|
||||
metadata: null,
|
||||
isLocal: true,
|
||||
localFileId: 'lf2',
|
||||
audioProbeResult: {}
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
startOffset: 0,
|
||||
duration: 20000,
|
||||
title: 'Track Title 3',
|
||||
contentUrl: 'test3',
|
||||
mimeType: 'audio/mpeg',
|
||||
metadata: null,
|
||||
isLocal: true,
|
||||
localFileId: 'lf3',
|
||||
audioProbeResult: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -170,6 +194,10 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
async syncLocalMediaProgressWithServer() {
|
||||
return null
|
||||
}
|
||||
|
||||
async updateLocalTrackOrder({ localLibraryItemId, tracks }) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const AbsDatabase = registerPlugin('AbsDatabase', {
|
||||
|
|
|
@ -92,6 +92,10 @@ class DbService {
|
|||
syncLocalMediaProgressWithServer() {
|
||||
return AbsDatabase.syncLocalMediaProgressWithServer()
|
||||
}
|
||||
|
||||
updateLocalTrackOrder(payload) {
|
||||
return AbsDatabase.updateLocalTrackOrder(payload)
|
||||
}
|
||||
}
|
||||
|
||||
export default ({ app, store }, inject) => {
|
||||
|
|
2
static/lib/sortable.js
Normal file
2
static/lib/sortable.js
Normal file
File diff suppressed because one or more lines are too long
3
static/lib/sortable.old.js
Normal file
3
static/lib/sortable.old.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue