diff --git a/.dockerignore b/.dockerignore index 16527338..24993ca3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,6 +8,6 @@ npm-debug.log /audiobooks2 /metadata dev.js -/test/ +test/ /client/.nuxt/ /client/dist/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index cee07aab..2ba35300 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,6 @@ node_modules/ /audiobooks/ /audiobooks2/ /metadata/ -/test/ +test/ /client/.nuxt/ /client/dist/ \ No newline at end of file diff --git a/client/assets/app.css b/client/assets/app.css index 328fb97b..377dd0e1 100644 --- a/client/assets/app.css +++ b/client/assets/app.css @@ -62,6 +62,14 @@ border-right: 6px solid transparent; border-top: 6px solid white; } +.triangle-right { + width: 0; + height: 0; + border-left: 8px solid transparent; + border-bottom: 8px solid transparent; + border-top: 8px solid rgb(34,127,35); + border-right: 8px solid rgb(34,127,35); +} .icon-text { font-size: 1.1rem; diff --git a/client/components/app/Appbar.vue b/client/components/app/Appbar.vue index f54fbd59..fe8c6ee2 100644 --- a/client/components/app/Appbar.vue +++ b/client/components/app/Appbar.vue @@ -6,7 +6,7 @@ arrow_back -

AudioBookshelf

+

AudioBookshelf

diff --git a/client/components/cards/BookCard.vue b/client/components/cards/BookCard.vue index 0df78850..0fdc123f 100644 --- a/client/components/cards/BookCard.vue +++ b/client/components/cards/BookCard.vue @@ -1,31 +1,41 @@ @@ -51,6 +61,12 @@ export default { } }, computed: { + isNew() { + return this.tags.includes('new') + }, + tags() { + return this.audiobook.tags || [] + }, audiobookId() { return this.audiobook.id }, diff --git a/client/components/controls/FilterSelect.vue b/client/components/controls/FilterSelect.vue index fba24bd4..a87fb3d8 100644 --- a/client/components/controls/FilterSelect.vue +++ b/client/components/controls/FilterSelect.vue @@ -115,9 +115,6 @@ export default { if (!_sel) return '' return _sel.text }, - authors() { - return this.$store.getters['audiobooks/getUniqueAuthors'] - }, genres() { return this.$store.state.audiobooks.genres }, diff --git a/client/components/ui/MultiSelect.vue b/client/components/ui/MultiSelect.vue index 8c9519d2..1b7ccc75 100644 --- a/client/components/ui/MultiSelect.vue +++ b/client/components/ui/MultiSelect.vue @@ -103,7 +103,6 @@ export default { this.menu.style.top = boundingBox.y + boundingBox.height - 4 + 'px' this.menu.style.left = boundingBox.x + 'px' this.menu.style.width = boundingBox.width + 'px' - console.log('Recalc menu pos', boundingBox.height) }, unmountMountMenu() { if (!this.$refs.menu) return @@ -138,8 +137,10 @@ export default { if (this.$refs.input) this.$refs.input.blur() }, clickedOption(e, itemValue) { - e.stopPropagation() - e.preventDefault() + if (e) { + e.stopPropagation() + e.preventDefault() + } if (this.$refs.input) this.$refs.input.focus() var newSelected = null @@ -187,7 +188,7 @@ export default { return i === cleaned || cleanedKebab === i }) if (matchesItem) { - this.clickedOption(matchesItem.value) + this.clickedOption(null, matchesItem) } else { this.insertNewItem(this.textInput) } diff --git a/client/nuxt.config.js b/client/nuxt.config.js index c1703017..517a08a6 100644 --- a/client/nuxt.config.js +++ b/client/nuxt.config.js @@ -36,6 +36,7 @@ module.exports = { link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Fira+Mono&family=Ubuntu+Mono&family=Open+Sans:wght@400;600&family=Gentium+Book+Basic' }, + { rel: 'stylesheet', href: "https://fonts.googleapis.com/css2?family=Fondamento&family=Gentium+Book+Basic&family=Kurale&family=Lateef&family=Mate+SC&family=Merienda&display=swap" }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/icon?family=Material+Icons' } ] }, diff --git a/client/package.json b/client/package.json index 69a1ad6e..f4c7dac9 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-client", - "version": "0.9.86-beta", + "version": "0.9.87-beta", "description": "Audiobook manager and player", "main": "index.js", "scripts": { diff --git a/client/tailwind.config.js b/client/tailwind.config.js index 41643a0b..8436bb35 100644 --- a/client/tailwind.config.js +++ b/client/tailwind.config.js @@ -23,6 +23,7 @@ module.exports = { info: '#2196F3', success: '#4CAF50', warning: '#FB8C00', + darkgreen: 'rgb(34,127,35)', 'black-50': '#bbbbbb', 'black-100': '#666666', 'black-200': '#555555', @@ -38,7 +39,12 @@ module.exports = { fontFamily: { sans: ['Open Sans', ...defaultTheme.fontFamily.sans], mono: ['Ubuntu Mono', ...defaultTheme.fontFamily.mono], - book: ['Gentium Book Basic', 'serif'] + book: ['Gentium Book Basic', 'serif'], + fondamento: 'Fondamento', + gentium: 'Gentium Book Basic', + kurale: 'Kurale', + mate: 'Mate SC', + merienda: 'Merienda' } } }, diff --git a/package.json b/package.json index 6e66a91e..966d513a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf", - "version": "0.9.86-beta", + "version": "0.9.87-beta", "description": "Self-hosted audiobook server for managing and playing audiobooks.", "main": "index.js", "scripts": { diff --git a/server/HlsController.js b/server/HlsController.js index bacc60bd..4ac0f30e 100644 --- a/server/HlsController.js +++ b/server/HlsController.js @@ -30,6 +30,12 @@ class HlsController { var streamId = req.params.stream var fullFilePath = Path.join(this.MetadataPath, streamId, req.params.file) + // development test stream - ignore + if (streamId === 'test') { + Logger.debug('Test Stream Request', streamId, req.headers, fullFilePath) + return res.sendFile(fullFilePath) + } + var exists = await fs.pathExists(fullFilePath) if (!exists) { Logger.warn('File path does not exist', fullFilePath) diff --git a/server/RssFeeds.js b/server/RssFeeds.js index 2f98d26a..be446515 100644 --- a/server/RssFeeds.js +++ b/server/RssFeeds.js @@ -3,6 +3,7 @@ const express = require('express') const ip = require('ip') const Logger = require('./Logger') +// Not functional at the moment - just an idea class RssFeeds { constructor(Port, db) { this.Port = Port diff --git a/server/Server.js b/server/Server.js index 9761b00a..44545b63 100644 --- a/server/Server.js +++ b/server/Server.js @@ -133,6 +133,7 @@ class Server { app.use('/api', this.authMiddleware.bind(this), this.apiController.router) app.use('/hls', this.authMiddleware.bind(this), this.hlsController.router) + // app.use('/hls', this.hlsController.router) app.use('/feeds', this.rssFeeds.router) app.post('/login', (req, res) => this.auth.login(req, res)) @@ -142,6 +143,21 @@ class Server { res.json({ success: true }) }) + + // Used in development to set-up streams without authentication + if (process.env.NODE_ENV !== 'production') { + app.use('/test-hls', this.hlsController.router) + app.get('/test-stream/:id', async (req, res) => { + var uri = await this.streamManager.openTestStream(this.MetadataPath, req.params.id) + res.send(uri) + }) + app.get('/catalog.json', (req, res) => { + Logger.error('Catalog request made', req.headers) + res.json() + }) + } + + this.server.listen(this.Port, this.Host, () => { Logger.info(`Running on http://${this.Host}:${this.Port}`) }) diff --git a/server/StreamManager.js b/server/StreamManager.js index d020d039..a0e5bbb2 100644 --- a/server/StreamManager.js +++ b/server/StreamManager.js @@ -1,4 +1,5 @@ const Stream = require('./Stream') +const StreamTest = require('./test/StreamTest') const Logger = require('./Logger') const fs = require('fs-extra') const Path = require('path') @@ -100,6 +101,23 @@ class StreamManager { this.db.updateUserStream(client.user.id, null) } + async openTestStream(streamPath, audiobookId) { + Logger.info('Open Stream Test Request', audiobookId) + var audiobook = this.audiobooks.find(ab => ab.id === audiobookId) + var stream = new StreamTest(streamPath, audiobook) + + stream.on('closed', () => { + console.log('Stream closed') + }) + + var playlistUri = await stream.generatePlaylist() + stream.start() + + Logger.info('Stream Playlist', playlistUri) + Logger.info('Test Stream Opened for audiobook', audiobook.title, 'with streamId', stream.id) + return playlistUri + } + streamUpdate(socket, { currentTime, streamId }) { var client = socket.sheepClient if (!client || !client.stream) {