This commit is contained in:
Mark Cooper
2021-09-01 20:07:11 -05:00
commit 0fef23e47b
106 changed files with 18798 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
<template>
<div class="w-full h-full p-4">
<div class="w-full max-w-xs mx-auto">
<ui-text-input-with-label :value="serverUrl" label="Server Url" disabled class="my-4" />
<ui-text-input-with-label :value="username" label="Username" disabled class="my-4" />
</div>
<div class="flex items-center pt-4">
<div class="flex-grow" />
<p class="pr-2 text-sm font-book text-yellow-400">Report bugs, request features, provide feedback, and contribute on <a class="underline" href="https://github.com/advplyr/audiobookshelf" target="_blank">github</a>.</p>
<a href="https://github.com/advplyr/audiobookshelf" target="_blank" class="text-white hover:text-gray-200 hover:scale-150 hover:rotate-6 transform duration-500">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="24" height="24" viewBox="0 0 24 24">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
</a>
</div>
<p class="font-mono pt-1 pb-4">v{{ $config.version }}</p>
</div>
</template>
<script>
export default {
data() {
return {}
},
computed: {
username() {
return this.user.username
},
user() {
return this.$store.state.user.user
},
serverUrl() {
return this.$server.url
}
},
methods: {},
mounted() {}
}
</script>
+89
View File
@@ -0,0 +1,89 @@
<template>
<div class="w-full h-full px-3 py-4 overflow-y-auto">
<div class="flex">
<div class="w-32">
<cards-book-cover :audiobook="audiobook" :width="128" />
</div>
<div class="flex-grow px-3">
<h1 class="text-lg">{{ title }}</h1>
<h3 v-if="series" class="font-book text-gray-300 text-lg leading-7">{{ seriesText }}</h3>
<p class="text-sm text-gray-400">by {{ author }}</p>
<p class="text-gray-300 text-sm my-1">
{{ durationPretty }}<span class="px-4">{{ sizePretty }}</span>
</p>
<ui-btn color="success" class="flex items-center justify-center w-full mt-2" :padding-x="4" @click="playClick">
<span class="material-icons">play_arrow</span>
<span class="px-1">Play</span>
</ui-btn>
<div class="flex my-4"></div>
</div>
</div>
<div class="w-full py-4">
<p>{{ description }}</p>
</div>
</div>
</template>
<script>
export default {
async asyncData({ params, redirect, app }) {
var audiobookId = params.id
var audiobook = await app.$axios.$get(`/api/audiobook/${audiobookId}`).catch((error) => {
console.error('Failed', error)
return false
})
if (!audiobook) {
console.error('No audiobook...', params.id)
return redirect('/')
}
return {
audiobook
}
},
data() {
return {}
},
computed: {
book() {
return this.audiobook.book || {}
},
title() {
return this.book.title
},
author() {
return this.book.author || 'Unknown'
},
description() {
return this.book.description || 'No Description'
},
series() {
return this.book.series || null
},
volumeNumber() {
return this.book.volumeNumber || null
},
seriesText() {
if (!this.series) return ''
if (!this.volumeNumber) return this.series
return `${this.series} #${this.volumeNumber}`
},
durationPretty() {
return this.audiobook.durationPretty
},
duration() {
return this.audiobook.duration
},
sizePretty() {
return this.audiobook.sizePretty
}
},
methods: {
playClick() {
this.$store.commit('setPlayOnLoad', true)
this.$store.commit('setStreamAudiobook', this.audiobook)
this.$server.socket.emit('open_stream', this.audiobook.id)
}
},
mounted() {}
}
</script>
+164
View File
@@ -0,0 +1,164 @@
<template>
<div class="w-full h-full">
<div class="relative flex items-center justify-center min-h-screen sm:pt-0">
<div class="absolute top-0 left-0 w-full p-6 flex items-center flex-col justify-center z-0 short:hidden">
<img src="/Logo.png" class="h-20 w-20 mb-2" />
<h1 class="text-2xl font-book">AudioBookshelf</h1>
</div>
<p class="hidden absolute short:block top-0 left-0 p-2 font-book text-xl">AudioBookshelf</p>
<div class="max-w-sm mx-auto sm:px-6 lg:px-8 z-10">
<div v-show="loggedIn" class="mt-8 bg-primary overflow-hidden shadow rounded-lg p-6 text-center">
<p class="text-success text-xl mb-2">Login Success!</p>
<p>Connecting socket..</p>
</div>
<div v-show="!loggedIn" class="mt-8 bg-primary overflow-hidden shadow rounded-lg p-6">
<h2 class="text-xl leading-7 mb-4">Enter an <span class="font-book font-normal">AudioBookshelf</span><br />server address:</h2>
<form v-show="!showAuth" @submit.prevent="submit">
<ui-text-input v-model="serverUrl" :disabled="processing" placeholder="http://55.55.55.55:13378" type="url" class="w-60 sm:w-72 h-10" />
<ui-btn :disabled="processing" type="submit" :padding-x="3" class="h-10">Submit</ui-btn>
</form>
<template v-if="showAuth">
<div class="flex items-center">
<p class="">{{ serverUrl }}</p>
<div class="flex-grow" />
<span class="material-icons" style="font-size: 1.1rem" @click="editServerUrl">edit</span>
</div>
<div class="w-full h-px bg-gray-200 my-2" />
<form @submit.prevent="submitAuth" class="pt-3">
<ui-text-input v-model="username" :disabled="processing" placeholder="username" class="w-full my-1 text-lg" />
<ui-text-input v-model="password" type="password" :disabled="processing" placeholder="password" class="w-full my-1 text-lg" />
<ui-btn :disabled="processing" type="submit" class="mt-1 h-10">Submit</ui-btn>
</form>
</template>
<div v-show="error" class="w-full rounded-lg bg-red-600 bg-opacity-10 border border-error border-opacity-50 py-3 px-2 flex items-center mt-4">
<span class="material-icons mr-2 text-error" style="font-size: 1.1rem">warning</span>
<p class="text-error">{{ error }}</p>
</div>
</div>
</div>
</div>
<div :class="processing ? 'opacity-100' : 'opacity-0 pointer-events-none'" class="fixed w-full h-full top-0 left-0 bg-black bg-opacity-75 flex items-center justify-center z-30 transition-opacity duration-500">
<div>
<div class="absolute top-0 left-0 w-full p-6 flex items-center flex-col justify-center z-0 short:hidden">
<img src="/Logo.png" class="h-20 w-20 mb-2" />
</div>
<svg class="animate-spin w-16 h-16" viewBox="0 0 24 24">
<path fill="currentColor" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" />
</svg>
</div>
</div>
<div class="flex items-center justify-center pt-4 fixed bottom-4 left-0 right-0">
<a href="https://github.com/advplyr/audiobookshelf" target="_blank" class="text-sm pr-2">Follow the project on Github</a>
<a href="https://github.com/advplyr/audiobookshelf" target="_blank"
><svg class="w-8 h-8 text-gray-100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">
<path
d="M12 2.247a10 10 0 0 0-3.162 19.487c.5.088.687-.212.687-.475c0-.237-.012-1.025-.012-1.862c-2.513.462-3.163-.613-3.363-1.175a3.636 3.636 0 0 0-1.025-1.413c-.35-.187-.85-.65-.013-.662a2.001 2.001 0 0 1 1.538 1.025a2.137 2.137 0 0 0 2.912.825a2.104 2.104 0 0 1 .638-1.338c-2.225-.25-4.55-1.112-4.55-4.937a3.892 3.892 0 0 1 1.025-2.688a3.594 3.594 0 0 1 .1-2.65s.837-.262 2.75 1.025a9.427 9.427 0 0 1 5 0c1.912-1.3 2.75-1.025 2.75-1.025a3.593 3.593 0 0 1 .1 2.65a3.869 3.869 0 0 1 1.025 2.688c0 3.837-2.338 4.687-4.563 4.937a2.368 2.368 0 0 1 .675 1.85c0 1.338-.012 2.413-.012 2.75c0 .263.187.575.687.475A10.005 10.005 0 0 0 12 2.247z"
fill="currentColor"
/></svg
></a>
</div>
</div>
</template>
<script>
export default {
layout: 'blank',
data() {
return {
serverUrl: null,
processing: false,
showAuth: false,
username: null,
password: null,
error: null,
loggedIn: false
}
},
methods: {
async submit() {
this.processing = true
this.error = null
var success = await this.$server.check(this.serverUrl)
this.processing = false
if (!success) {
console.error('Server invalid')
this.error = 'Invalid Server'
} else {
this.showAuth = true
}
},
async submitAuth() {
if (!this.username) {
this.error = 'Invalid username'
return
}
this.error = null
this.processing = true
var response = await this.$server.login(this.serverUrl, this.username, this.password)
this.processing = false
if (response.error) {
console.error('Login failed')
this.error = response.error
} else {
console.log('Login Success!')
this.loggedIn = true
}
},
editServerUrl() {
this.error = null
this.showAuth = false
},
redirect() {
if (this.$route.query && this.$route.query.redirect) {
this.$router.replace(this.$route.query.redirect)
} else {
this.$router.replace('/')
}
},
socketConnected() {
console.log('Socket connected')
this.redirect()
},
async init() {
if (!this.$server) {
console.error('Invalid server not initialized')
return
}
if (this.$server.connected) {
console.warn('Server already connected')
return this.redirect()
}
this.$server.on('connected', this.socketConnected)
var localServerUrl = localStorage.getItem('serverUrl')
var localUserToken = localStorage.getItem('userToken')
if (localServerUrl) {
this.serverUrl = localServerUrl
if (localUserToken) {
this.processing = true
var success = await this.$server.connect(localServerUrl, localUserToken)
if (!success && !this.$server.url) {
this.processing = false
this.serverUrl = null
this.showAuth = false
} else if (!success) {
console.log('Server connect success')
this.processing = false
}
this.showAuth = true
} else {
this.submit()
}
}
}
},
mounted() {
this.init()
}
}
</script>
+66
View File
@@ -0,0 +1,66 @@
<template>
<div class="w-full h-full">
<div class="w-full h-12 relative z-20">
<div id="toolbar" class="asolute top-0 left-0 w-full h-full bg-bg flex items-center px-2">
<p class="font-book">{{ numAudiobooks }} Audiobooks</p>
<div class="flex-grow" />
<span class="material-icons px-2" @click="showFilterModal = true">filter_alt</span>
<span class="material-icons px-2" @click="showSortModal = true">sort</span>
</div>
</div>
<app-bookshelf />
<modals-order-modal v-model="showSortModal" :order-by.sync="settings.orderBy" :descending.sync="settings.orderDesc" @change="updateOrder" />
<modals-filter-modal v-model="showFilterModal" :filter-by.sync="settings.filterBy" @change="updateFilter" />
</div>
</template>
<script>
export default {
data() {
return {
showSortModal: false,
showFilterModal: false,
settings: {}
}
},
computed: {
numAudiobooks() {
return this.$store.getters['audiobooks/getFiltered']().length
}
},
methods: {
updateOrder() {
this.saveSettings()
},
updateFilter() {
this.saveSettings()
},
saveSettings() {
this.$store.commit('user/setSettings', this.settings) // Immediate update
this.$store.dispatch('user/updateUserSettings', this.settings)
},
init() {
this.settings = { ...this.$store.state.user.settings }
},
settingsUpdated(settings) {
for (const key in settings) {
this.settings[key] = settings[key]
}
}
},
mounted() {
this.init()
this.$store.commit('user/addSettingsListener', { id: 'bookshelftoolbar', meth: this.settingsUpdated })
},
beforeDestroy() {
this.$store.commit('user/removeSettingsListener', 'bookshelftoolbar')
}
}
</script>
<style>
#toolbar {
box-shadow: 0px 5px 5px #11111155;
}
</style>