mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Update:New EBook API endpoint
This commit is contained in:
		
							parent
							
								
									b3f19ef628
								
							
						
					
					
						commit
						4f75a89633
					
				| @ -57,7 +57,6 @@ Archive.init({ | |||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   props: { |   props: { | ||||||
|     url: String, |  | ||||||
|     libraryItem: { |     libraryItem: { | ||||||
|       type: Object, |       type: Object, | ||||||
|       default: () => {} |       default: () => {} | ||||||
| @ -88,6 +87,15 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|  |     userToken() { | ||||||
|  |       return this.$store.getters['user/getToken'] | ||||||
|  |     }, | ||||||
|  |     libraryItemId() { | ||||||
|  |       return this.libraryItem?.id | ||||||
|  |     }, | ||||||
|  |     ebookUrl() { | ||||||
|  |       return `/api/items/${this.libraryItemId}/ebook` | ||||||
|  |     }, | ||||||
|     comicMetadataKeys() { |     comicMetadataKeys() { | ||||||
|       return this.comicMetadata ? Object.keys(this.comicMetadata) : [] |       return this.comicMetadata ? Object.keys(this.comicMetadata) : [] | ||||||
|     }, |     }, | ||||||
| @ -146,10 +154,11 @@ export default { | |||||||
|     }, |     }, | ||||||
|     async extract() { |     async extract() { | ||||||
|       this.loading = true |       this.loading = true | ||||||
|       console.log('Extracting', this.url) |       var buff = await this.$axios.$get(this.ebookUrl, { | ||||||
| 
 |         responseType: 'blob', | ||||||
|       var buff = await this.$axios.$get(this.url, { |         headers: { | ||||||
|         responseType: 'blob' |           Authorization: `Bearer ${this.userToken}` | ||||||
|  |         } | ||||||
|       }) |       }) | ||||||
|       const archive = await Archive.open(buff) |       const archive = await Archive.open(buff) | ||||||
|       const originalFilesObject = await archive.getFilesObject() |       const originalFilesObject = await archive.getFilesObject() | ||||||
|  | |||||||
| @ -24,7 +24,6 @@ import ePub from 'epubjs' | |||||||
|  */ |  */ | ||||||
| export default { | export default { | ||||||
|   props: { |   props: { | ||||||
|     url: String, |  | ||||||
|     libraryItem: { |     libraryItem: { | ||||||
|       type: Object, |       type: Object, | ||||||
|       default: () => {} |       default: () => {} | ||||||
| @ -47,6 +46,9 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|  |     userToken() { | ||||||
|  |       return this.$store.getters['user/getToken'] | ||||||
|  |     }, | ||||||
|     /** @returns {string} */ |     /** @returns {string} */ | ||||||
|     libraryItemId() { |     libraryItemId() { | ||||||
|       return this.libraryItem?.id |       return this.libraryItem?.id | ||||||
| @ -75,6 +77,9 @@ export default { | |||||||
|     readerHeight() { |     readerHeight() { | ||||||
|       if (this.windowHeight < 400 || !this.playerOpen) return this.windowHeight |       if (this.windowHeight < 400 || !this.playerOpen) return this.windowHeight | ||||||
|       return this.windowHeight - 164 |       return this.windowHeight - 164 | ||||||
|  |     }, | ||||||
|  |     epubUrl() { | ||||||
|  |       return `/api/items/${this.libraryItemId}/ebook` | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
| @ -212,9 +217,13 @@ export default { | |||||||
|       const reader = this |       const reader = this | ||||||
| 
 | 
 | ||||||
|       /** @type {ePub.Book} */ |       /** @type {ePub.Book} */ | ||||||
|       reader.book = new ePub(reader.url, { |       reader.book = new ePub(reader.epubUrl, { | ||||||
|         width: this.readerWidth, |         width: this.readerWidth, | ||||||
|         height: this.readerHeight - 50 |         height: this.readerHeight - 50, | ||||||
|  |         openAs: 'epub', | ||||||
|  |         requestHeaders: { | ||||||
|  |           Authorization: `Bearer ${this.userToken}` | ||||||
|  |         } | ||||||
|       }) |       }) | ||||||
| 
 | 
 | ||||||
|       /** @type {ePub.Rendition} */ |       /** @type {ePub.Rendition} */ | ||||||
|  | |||||||
| @ -15,7 +15,6 @@ import defaultCss from '@/assets/ebooks/basic.js' | |||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   props: { |   props: { | ||||||
|     url: String, |  | ||||||
|     libraryItem: { |     libraryItem: { | ||||||
|       type: Object, |       type: Object, | ||||||
|       default: () => {} |       default: () => {} | ||||||
| @ -25,7 +24,17 @@ export default { | |||||||
|   data() { |   data() { | ||||||
|     return {} |     return {} | ||||||
|   }, |   }, | ||||||
|   computed: {}, |   computed: { | ||||||
|  |     userToken() { | ||||||
|  |       return this.$store.getters['user/getToken'] | ||||||
|  |     }, | ||||||
|  |     libraryItemId() { | ||||||
|  |       return this.libraryItem?.id | ||||||
|  |     }, | ||||||
|  |     ebookUrl() { | ||||||
|  |       return `/api/items/${this.libraryItemId}/ebook` | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     addHtmlCss() { |     addHtmlCss() { | ||||||
|       let iframe = document.getElementsByTagName('iframe')[0] |       let iframe = document.getElementsByTagName('iframe')[0] | ||||||
| @ -83,8 +92,11 @@ export default { | |||||||
|     }, |     }, | ||||||
|     async initMobi() { |     async initMobi() { | ||||||
|       // Fetch mobi file as blob |       // Fetch mobi file as blob | ||||||
|       var buff = await this.$axios.$get(this.url, { |       var buff = await this.$axios.$get(this.ebookUrl, { | ||||||
|         responseType: 'blob' |         responseType: 'blob', | ||||||
|  |         headers: { | ||||||
|  |           Authorization: `Bearer ${this.userToken}` | ||||||
|  |         } | ||||||
|       }) |       }) | ||||||
|       var reader = new FileReader() |       var reader = new FileReader() | ||||||
|       reader.onload = async (event) => { |       reader.onload = async (event) => { | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
|       <div class="flex items-center justify-center"> |       <div class="flex items-center justify-center"> | ||||||
|         <div :style="{ width: pdfWidth + 'px', height: pdfHeight + 'px' }" class="overflow-auto"> |         <div :style="{ width: pdfWidth + 'px', height: pdfHeight + 'px' }" class="overflow-auto"> | ||||||
|           <div v-if="loadedRatio > 0 && loadedRatio < 1" style="background-color: green; color: white; text-align: center" :style="{ width: loadedRatio * 100 + '%' }">{{ Math.floor(loadedRatio * 100) }}%</div> |           <div v-if="loadedRatio > 0 && loadedRatio < 1" style="background-color: green; color: white; text-align: center" :style="{ width: loadedRatio * 100 + '%' }">{{ Math.floor(loadedRatio * 100) }}%</div> | ||||||
|           <pdf ref="pdf" class="m-auto z-10 border border-black border-opacity-20 shadow-md" :src="url" :page="page" :rotate="rotate" @progress="progressEvt" @error="error" @num-pages="numPagesLoaded" @link-clicked="page = $event" @loaded="loadedEvt"></pdf> |           <pdf ref="pdf" class="m-auto z-10 border border-black border-opacity-20 shadow-md" :src="pdfDocInitParams" :page="page" :rotate="rotate" @progress="progressEvt" @error="error" @num-pages="numPagesLoaded" @link-clicked="page = $event" @loaded="loadedEvt"></pdf> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
| @ -41,7 +41,6 @@ export default { | |||||||
|     pdf |     pdf | ||||||
|   }, |   }, | ||||||
|   props: { |   props: { | ||||||
|     url: String, |  | ||||||
|     libraryItem: { |     libraryItem: { | ||||||
|       type: Object, |       type: Object, | ||||||
|       default: () => {} |       default: () => {} | ||||||
| @ -60,6 +59,9 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|  |     userToken() { | ||||||
|  |       return this.$store.getters['user/getToken'] | ||||||
|  |     }, | ||||||
|     libraryItemId() { |     libraryItemId() { | ||||||
|       return this.libraryItem?.id |       return this.libraryItem?.id | ||||||
|     }, |     }, | ||||||
| @ -94,6 +96,14 @@ export default { | |||||||
|     }, |     }, | ||||||
|     savedPage() { |     savedPage() { | ||||||
|       return Number(this.userMediaProgress?.ebookLocation || 0) |       return Number(this.userMediaProgress?.ebookLocation || 0) | ||||||
|  |     }, | ||||||
|  |     pdfDocInitParams() { | ||||||
|  |       return { | ||||||
|  |         url: `/api/items/${this.libraryItemId}/ebook`, | ||||||
|  |         httpHeaders: { | ||||||
|  |           Authorization: `Bearer ${this.userToken}` | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ | |||||||
|       <span class="material-icons cursor-pointer text-2xl" @click="close">close</span> |       <span class="material-icons cursor-pointer text-2xl" @click="close">close</span> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <component v-if="componentName" ref="readerComponent" :is="componentName" :url="ebookUrl" :library-item="selectedLibraryItem" :player-open="!!streamLibraryItem" /> |     <component v-if="componentName" ref="readerComponent" :is="componentName" :library-item="selectedLibraryItem" :player-open="!!streamLibraryItem" /> | ||||||
| 
 | 
 | ||||||
|     <!-- TOC side nav --> |     <!-- TOC side nav --> | ||||||
|     <div v-if="tocOpen" class="w-full h-full fixed inset-0 bg-black/20 z-20" @click.stop.prevent="toggleToC"></div> |     <div v-if="tocOpen" class="w-full h-full fixed inset-0 bg-black/20 z-20" @click.stop.prevent="toggleToC"></div> | ||||||
| @ -128,21 +128,6 @@ export default { | |||||||
|     isComic() { |     isComic() { | ||||||
|       return this.ebookFormat == 'cbz' || this.ebookFormat == 'cbr' |       return this.ebookFormat == 'cbz' || this.ebookFormat == 'cbr' | ||||||
|     }, |     }, | ||||||
|     ebookUrl() { |  | ||||||
|       if (!this.ebookFile) return null |  | ||||||
|       let filepath = '' |  | ||||||
|       if (this.selectedLibraryItem.isFile) { |  | ||||||
|         filepath = this.$encodeUriPath(this.ebookFile.metadata.filename) |  | ||||||
|       } else { |  | ||||||
|         const itemRelPath = this.selectedLibraryItem.relPath |  | ||||||
|         if (itemRelPath.startsWith('/')) itemRelPath = itemRelPath.slice(1) |  | ||||||
|         const relPath = this.ebookFile.metadata.relPath |  | ||||||
|         if (relPath.startsWith('/')) relPath = relPath.slice(1) |  | ||||||
| 
 |  | ||||||
|         filepath = this.$encodeUriPath(`${itemRelPath}/${relPath}`) |  | ||||||
|       } |  | ||||||
|       return `/ebook/${this.libraryId}/${this.folderId}/${filepath}` |  | ||||||
|     }, |  | ||||||
|     userToken() { |     userToken() { | ||||||
|       return this.$store.getters['user/getToken'] |       return this.$store.getters['user/getToken'] | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -71,9 +71,8 @@ module.exports = { | |||||||
|   ], |   ], | ||||||
| 
 | 
 | ||||||
|   proxy: { |   proxy: { | ||||||
|     '/dev/': { target: 'http://localhost:3333', pathRewrite: { '^/dev/': '' } }, |     '/s/': { target: process.env.NODE_ENV !== 'production' ? 'http://localhost:3333' : '/' }, | ||||||
|     '/ebook/': { target: process.env.NODE_ENV !== 'production' ? 'http://localhost:3333' : '/' }, |     '/api/': { target: process.env.NODE_ENV !== 'production' ? 'http://localhost:3333' : '/' } | ||||||
|     '/s/': { target: process.env.NODE_ENV !== 'production' ? 'http://localhost:3333' + process.env : '/' }, |  | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   io: { |   io: { | ||||||
|  | |||||||
| @ -7,15 +7,10 @@ export default function ({ $axios, store, $config }) { | |||||||
|     if (config.url.startsWith('http:') || config.url.startsWith('https:')) { |     if (config.url.startsWith('http:') || config.url.startsWith('https:')) { | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
|     var bearerToken = store.state.user.user ? store.state.user.user.token : null |     const bearerToken = store.state.user.user?.token || null | ||||||
|     if (bearerToken) { |     if (bearerToken) { | ||||||
|       config.headers.common['Authorization'] = `Bearer ${bearerToken}` |       config.headers.common['Authorization'] = `Bearer ${bearerToken}` | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     if (process.env.NODE_ENV === 'development') { |  | ||||||
|       config.url = `/dev${config.url}` |  | ||||||
|       console.log('Making request to ' + config.url) |  | ||||||
|     } |  | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   $axios.onError(error => { |   $axios.onError(error => { | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ export const getters = { | |||||||
|   getIsRoot: (state) => state.user && state.user.type === 'root', |   getIsRoot: (state) => state.user && state.user.type === 'root', | ||||||
|   getIsAdminOrUp: (state) => state.user && (state.user.type === 'admin' || state.user.type === 'root'), |   getIsAdminOrUp: (state) => state.user && (state.user.type === 'admin' || state.user.type === 'root'), | ||||||
|   getToken: (state) => { |   getToken: (state) => { | ||||||
|     return state.user ? state.user.token : null |     return state.user?.token || null | ||||||
|   }, |   }, | ||||||
|   getUserMediaProgress: (state) => (libraryItemId, episodeId = null) => { |   getUserMediaProgress: (state) => (libraryItemId, episodeId = null) => { | ||||||
|     if (!state.user.mediaProgress) return null |     if (!state.user.mediaProgress) return null | ||||||
|  | |||||||
| @ -165,6 +165,7 @@ class Server { | |||||||
|     router.use('/s', this.authMiddleware.bind(this), this.staticRouter.router) |     router.use('/s', this.authMiddleware.bind(this), this.staticRouter.router) | ||||||
| 
 | 
 | ||||||
|     // EBook static file routes
 |     // EBook static file routes
 | ||||||
|  |     // TODO: Deprecated as of 2.2.21 edge
 | ||||||
|     router.get('/ebook/:library/:folder/*', (req, res) => { |     router.get('/ebook/:library/:folder/*', (req, res) => { | ||||||
|       const library = this.db.libraries.find(lib => lib.id === req.params.library) |       const library = this.db.libraries.find(lib => lib.id === req.params.library) | ||||||
|       if (!library) return res.sendStatus(404) |       if (!library) return res.sendStatus(404) | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | const Path = require('path') | ||||||
| const fs = require('../libs/fsExtra') | const fs = require('../libs/fsExtra') | ||||||
| const Logger = require('../Logger') | const Logger = require('../Logger') | ||||||
| const SocketAuthority = require('../SocketAuthority') | const SocketAuthority = require('../SocketAuthority') | ||||||
| @ -552,6 +553,16 @@ class LibraryItemController { | |||||||
|     res.sendStatus(200) |     res.sendStatus(200) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   async getEBookFile(req, res) { | ||||||
|  |     const ebookFile = req.libraryItem.media.ebookFile | ||||||
|  |     if (!ebookFile) { | ||||||
|  |       Logger.error(`[LibraryItemController] No ebookFile for library item "${req.libraryItem.media.metadata.title}"`) | ||||||
|  |       return res.sendStatus(404) | ||||||
|  |     } | ||||||
|  |     const ebookFilePath = ebookFile.metadata.path | ||||||
|  |     res.sendFile(ebookFilePath) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   middleware(req, res, next) { |   middleware(req, res, next) { | ||||||
|     const item = this.db.libraryItems.find(li => li.id === req.params.id) |     const item = this.db.libraryItems.find(li => li.id === req.params.id) | ||||||
|     if (!item || !item.media) return res.sendStatus(404) |     if (!item || !item.media) return res.sendStatus(404) | ||||||
|  | |||||||
| @ -121,6 +121,7 @@ class ApiRouter { | |||||||
|     this.router.post('/items/:id/chapters', LibraryItemController.middleware.bind(this), LibraryItemController.updateMediaChapters.bind(this)) |     this.router.post('/items/:id/chapters', LibraryItemController.middleware.bind(this), LibraryItemController.updateMediaChapters.bind(this)) | ||||||
|     this.router.post('/items/:id/tone-scan/:index?', LibraryItemController.middleware.bind(this), LibraryItemController.toneScan.bind(this)) |     this.router.post('/items/:id/tone-scan/:index?', LibraryItemController.middleware.bind(this), LibraryItemController.toneScan.bind(this)) | ||||||
|     this.router.delete('/items/:id/file/:ino', LibraryItemController.middleware.bind(this), LibraryItemController.deleteLibraryFile.bind(this)) |     this.router.delete('/items/:id/file/:ino', LibraryItemController.middleware.bind(this), LibraryItemController.deleteLibraryFile.bind(this)) | ||||||
|  |     this.router.get('/items/:id/ebook', LibraryItemController.middleware.bind(this), LibraryItemController.getEBookFile.bind(this)) | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|     // User Routes
 |     // User Routes
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user