mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Fixing scanner inodes, select all fix, starting ebook reader
This commit is contained in:
		
							parent
							
								
									01fdca4bf9
								
							
						
					
					
						commit
						3e5338ec8e
					
				| @ -37,7 +37,9 @@ | |||||||
| 
 | 
 | ||||||
|       <div v-show="numAudiobooksSelected" class="absolute top-0 left-0 w-full h-full px-4 bg-primary flex items-center"> |       <div v-show="numAudiobooksSelected" class="absolute top-0 left-0 w-full h-full px-4 bg-primary flex items-center"> | ||||||
|         <h1 class="text-2xl px-4">{{ numAudiobooksSelected }} Selected</h1> |         <h1 class="text-2xl px-4">{{ numAudiobooksSelected }} Selected</h1> | ||||||
|         <ui-btn small class="text-sm mx-2" @click="toggleSelectAll">{{ isAllSelected ? 'Select None' : 'Select All' }}</ui-btn> |         <ui-btn small class="text-sm mx-2" @click="toggleSelectAll" | ||||||
|  |           >{{ isAllSelected ? 'Select None' : 'Select All' }}<span class="pl-2">({{ audiobooksShowing.length }})</span></ui-btn | ||||||
|  |         > | ||||||
| 
 | 
 | ||||||
|         <div class="flex-grow" /> |         <div class="flex-grow" /> | ||||||
| 
 | 
 | ||||||
| @ -87,7 +89,8 @@ export default { | |||||||
|       return this.$store.state.user.user.audiobooks || {} |       return this.$store.state.user.user.audiobooks || {} | ||||||
|     }, |     }, | ||||||
|     audiobooksShowing() { |     audiobooksShowing() { | ||||||
|       return this.$store.getters['audiobooks/getFiltered']() |       // return this.$store.getters['audiobooks/getFiltered']() | ||||||
|  |       return this.$store.getters['audiobooks/getEntitiesShowing']() | ||||||
|     }, |     }, | ||||||
|     userCanUpdate() { |     userCanUpdate() { | ||||||
|       return this.$store.getters['user/getUserCanUpdate'] |       return this.$store.getters['user/getUserCanUpdate'] | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
|             <template v-for="entity in shelf"> |             <template v-for="entity in shelf"> | ||||||
|               <cards-group-card v-if="showGroups" :key="entity.id" :width="bookCoverWidth" :group="entity" @click="clickGroup" /> |               <cards-group-card v-if="showGroups" :key="entity.id" :width="bookCoverWidth" :group="entity" @click="clickGroup" /> | ||||||
|               <!-- <cards-book-3d :key="entity.id" v-else :width="100" :src="$store.getters['audiobooks/getBookCoverSrc'](entity.book)" /> --> |               <!-- <cards-book-3d :key="entity.id" v-else :width="100" :src="$store.getters['audiobooks/getBookCoverSrc'](entity.book)" /> --> | ||||||
|               <cards-book-card v-else :key="entity.id" :show-volume-number="selectedSeries" :width="bookCoverWidth" :user-progress="userAudiobooks[entity.id]" :audiobook="entity" /> |               <cards-book-card v-else :key="entity.id" :show-volume-number="!!selectedSeries" :width="bookCoverWidth" :user-progress="userAudiobooks[entity.id]" :audiobook="entity" /> | ||||||
|             </template> |             </template> | ||||||
|           </div> |           </div> | ||||||
|           <div class="bookshelfDivider h-4 w-full absolute bottom-0 left-0 right-0 z-10" /> |           <div class="bookshelfDivider h-4 w-full absolute bottom-0 left-0 right-0 z-10" /> | ||||||
|  | |||||||
| @ -33,6 +33,10 @@ | |||||||
|             <p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">#{{ volumeNumber }}</p> |             <p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">#{{ volumeNumber }}</p> | ||||||
|           </div> |           </div> | ||||||
| 
 | 
 | ||||||
|  |           <!-- <div v-if="true && hasEbook" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md" :style="{ bottom: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }"> | ||||||
|  |             <p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">EBook</p> | ||||||
|  |           </div> --> | ||||||
|  | 
 | ||||||
|           <div v-show="!isSelectionMode" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full" :class="userIsRead ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div> |           <div v-show="!isSelectionMode" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full" :class="userIsRead ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div> | ||||||
| 
 | 
 | ||||||
|           <ui-tooltip v-if="showError" :text="errorText" class="absolute bottom-4 left-0"> |           <ui-tooltip v-if="showError" :text="errorText" class="absolute bottom-4 left-0"> | ||||||
| @ -78,6 +82,9 @@ export default { | |||||||
|     audiobookId() { |     audiobookId() { | ||||||
|       return this.audiobook.id |       return this.audiobook.id | ||||||
|     }, |     }, | ||||||
|  |     hasEbook() { | ||||||
|  |       return this.audiobook.numEbooks | ||||||
|  |     }, | ||||||
|     isSelectionMode() { |     isSelectionMode() { | ||||||
|       return this.$store.getters['getNumAudiobooksSelected'] |       return this.$store.getters['getNumAudiobooksSelected'] | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
|           <template v-for="track in files"> |           <template v-for="track in files"> | ||||||
|             <tr :key="track.path"> |             <tr :key="track.path"> | ||||||
|               <td class="font-book pl-2"> |               <td class="font-book pl-2"> | ||||||
|                 {{ track.filename }} |                 {{ track.filename }}<span class="text-white text-opacity-50 pl-4">({{ track.ino }})</span> | ||||||
|               </td> |               </td> | ||||||
|               <td class="font-mono"> |               <td class="font-mono"> | ||||||
|                 {{ $bytesPretty(track.size) }} |                 {{ $bytesPretty(track.size) }} | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ | |||||||
|           <template v-for="file in files"> |           <template v-for="file in files"> | ||||||
|             <tr :key="file.path"> |             <tr :key="file.path"> | ||||||
|               <td class="font-book pl-2"> |               <td class="font-book pl-2"> | ||||||
|                 {{ file.path }} |                 {{ file.path }}<span class="text-white text-opacity-50 pl-4">({{ file.ino }})</span> | ||||||
|               </td> |               </td> | ||||||
|               <td class="text-xs"> |               <td class="text-xs"> | ||||||
|                 <p>{{ file.filetype }}</p> |                 <p>{{ file.filetype }}</p> | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ | |||||||
|                 <p>{{ track.index }}</p> |                 <p>{{ track.index }}</p> | ||||||
|               </td> |               </td> | ||||||
|               <td class="font-book"> |               <td class="font-book"> | ||||||
|                 {{ track.filename }} |                 {{ track.filename }}<span class="text-white text-opacity-50 pl-4">({{ track.ino }})</span> | ||||||
|               </td> |               </td> | ||||||
|               <td class="font-mono"> |               <td class="font-mono"> | ||||||
|                 {{ $bytesPretty(track.size) }} |                 {{ $bytesPretty(track.size) }} | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| export default function ({ store, redirect, route, app }) { | export default function ({ store, redirect, route, app }) { | ||||||
|   // If the user is not authenticated
 |   // If the user is not authenticated
 | ||||||
|   if (!store.state.user.user) { |   if (!store.state.user.user) { | ||||||
|     if (route.name === 'batch') return redirect('/login') |     if (route.name === 'batch' || route.name === 'index') return redirect('/login') | ||||||
|     return redirect(`/login?redirect=${route.fullPath}`) |     return redirect(`/login?redirect=${route.fullPath}`) | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										2
									
								
								client/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								client/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "audiobookshelf-client", |   "name": "audiobookshelf-client", | ||||||
|   "version": "1.1.13", |   "version": "1.2.4", | ||||||
|   "lockfileVersion": 1, |   "lockfileVersion": 1, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "audiobookshelf-client", |   "name": "audiobookshelf-client", | ||||||
|   "version": "1.2.4", |   "version": "1.2.5", | ||||||
|   "description": "Audiobook manager and player", |   "description": "Audiobook manager and player", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  | |||||||
| @ -42,6 +42,11 @@ | |||||||
|               Missing |               Missing | ||||||
|             </ui-btn> |             </ui-btn> | ||||||
| 
 | 
 | ||||||
|  |             <!-- <ui-btn v-if="ebooks.length" color="info" :padding-x="4" small class="flex items-center h-9 mr-2" @click="openEbook"> | ||||||
|  |               <span class="material-icons -ml-2 pr-2 text-white">auto_stories</span> | ||||||
|  |               Read | ||||||
|  |             </ui-btn> --> | ||||||
|  | 
 | ||||||
|             <ui-tooltip v-if="userCanUpdate" text="Edit" direction="top"> |             <ui-tooltip v-if="userCanUpdate" text="Edit" direction="top"> | ||||||
|               <ui-icon-btn icon="edit" class="mx-0.5" @click="editClick" /> |               <ui-icon-btn icon="edit" class="mx-0.5" @click="editClick" /> | ||||||
|             </ui-tooltip> |             </ui-tooltip> | ||||||
| @ -86,6 +91,8 @@ | |||||||
|           <tables-other-files-table v-if="otherFiles.length" :audiobook-id="audiobook.id" :files="otherFiles" class="mt-6" /> |           <tables-other-files-table v-if="otherFiles.length" :audiobook-id="audiobook.id" :files="otherFiles" class="mt-6" /> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|  | 
 | ||||||
|  |       <div id="area"></div> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| @ -223,6 +230,9 @@ export default { | |||||||
|     audioFiles() { |     audioFiles() { | ||||||
|       return this.audiobook.audioFiles || [] |       return this.audiobook.audioFiles || [] | ||||||
|     }, |     }, | ||||||
|  |     ebooks() { | ||||||
|  |       return this.audiobook.ebooks | ||||||
|  |     }, | ||||||
|     description() { |     description() { | ||||||
|       return this.book.description || '' |       return this.book.description || '' | ||||||
|     }, |     }, | ||||||
| @ -261,6 +271,18 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     openEbook() { | ||||||
|  |       var ebook = this.ebooks[0] | ||||||
|  |       console.log('Ebook', ebook) | ||||||
|  |       this.$axios | ||||||
|  |         .$get(`/ebook/open/${this.audiobookId}/${ebook.ino}`) | ||||||
|  |         .then(() => { | ||||||
|  |           console.log('opened') | ||||||
|  |         }) | ||||||
|  |         .catch((error) => { | ||||||
|  |           console.error('failed', error) | ||||||
|  |         }) | ||||||
|  |     }, | ||||||
|     toggleRead() { |     toggleRead() { | ||||||
|       var updatePayload = { |       var updatePayload = { | ||||||
|         isRead: !this.isRead |         isRead: !this.isRead | ||||||
|  | |||||||
| @ -24,12 +24,18 @@ export default { | |||||||
|         console.error('Search error', error) |         console.error('Search error', error) | ||||||
|         return [] |         return [] | ||||||
|       }) |       }) | ||||||
|  |       store.commit('audiobooks/setSearchResults', searchResults) | ||||||
|     } |     } | ||||||
|  |     var selectedSeries = query.series ? app.$decode(query.series) : null | ||||||
|  |     store.commit('audiobooks/setSelectedSeries', selectedSeries) | ||||||
|  |     var libraryPage = params.id || '' | ||||||
|  |     store.commit('audiobooks/setLibraryPage', libraryPage) | ||||||
|  | 
 | ||||||
|     return { |     return { | ||||||
|       id: params.id, |       id: libraryPage, | ||||||
|       searchQuery, |       searchQuery, | ||||||
|       searchResults, |       searchResults, | ||||||
|       selectedSeries: query.series ? app.$decode(query.series) : null |       selectedSeries | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   data() { |   data() { | ||||||
|  | |||||||
| @ -77,7 +77,6 @@ export default { | |||||||
|         if (token) { |         if (token) { | ||||||
|           this.processing = true |           this.processing = true | ||||||
| 
 | 
 | ||||||
|           console.log('Authorize', token) |  | ||||||
|           this.$axios |           this.$axios | ||||||
|             .$post('/api/authorize', null, { |             .$post('/api/authorize', null, { | ||||||
|               headers: { |               headers: { | ||||||
|  | |||||||
| @ -10,13 +10,32 @@ export const state = () => ({ | |||||||
|   genres: [...STANDARD_GENRES], |   genres: [...STANDARD_GENRES], | ||||||
|   tags: [], |   tags: [], | ||||||
|   series: [], |   series: [], | ||||||
|   keywordFilter: null |   keywordFilter: null, | ||||||
|  |   selectedSeries: null, | ||||||
|  |   libraryPage: null, | ||||||
|  |   searchResults: [] | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| export const getters = { | export const getters = { | ||||||
|   getAudiobook: (state) => id => { |   getAudiobook: (state) => id => { | ||||||
|     return state.audiobooks.find(ab => ab.id === id) |     return state.audiobooks.find(ab => ab.id === id) | ||||||
|   }, |   }, | ||||||
|  |   getEntitiesShowing: (state, getters, rootState, rootGetters) => () => { | ||||||
|  |     if (!state.libraryPage) { | ||||||
|  |       return getters.getFiltered() | ||||||
|  |     } else if (state.libraryPage === 'search') { | ||||||
|  |       return state.searchResults | ||||||
|  |     } else if (state.libraryPage === 'series') { | ||||||
|  |       var series = getters.getSeriesGroups() | ||||||
|  |       if (state.selectedSeries) { | ||||||
|  |         var _series = series.find(__series => __series.name === state.selectedSeries) | ||||||
|  |         if (!_series) return [] | ||||||
|  |         return _series.books || [] | ||||||
|  |       } | ||||||
|  |       return series | ||||||
|  |     } | ||||||
|  |     return [] | ||||||
|  |   }, | ||||||
|   getFiltered: (state, getters, rootState, rootGetters) => () => { |   getFiltered: (state, getters, rootState, rootGetters) => () => { | ||||||
|     var filtered = state.audiobooks |     var filtered = state.audiobooks | ||||||
|     var settings = rootState.user.settings || {} |     var settings = rootState.user.settings || {} | ||||||
| @ -159,6 +178,15 @@ export const mutations = { | |||||||
|   setKeywordFilter(state, val) { |   setKeywordFilter(state, val) { | ||||||
|     state.keywordFilter = val |     state.keywordFilter = val | ||||||
|   }, |   }, | ||||||
|  |   setSelectedSeries(state, val) { | ||||||
|  |     state.selectedSeries = val | ||||||
|  |   }, | ||||||
|  |   setLibraryPage(state, val) { | ||||||
|  |     state.libraryPage = val | ||||||
|  |   }, | ||||||
|  |   setSearchResults(state, val) { | ||||||
|  |     state.searchResults = val | ||||||
|  |   }, | ||||||
|   set(state, audiobooks) { |   set(state, audiobooks) { | ||||||
|     // GENRES
 |     // GENRES
 | ||||||
|     var genres = [...state.genres] |     var genres = [...state.genres] | ||||||
|  | |||||||
							
								
								
									
										427
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										427
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "audiobookshelf", |   "name": "audiobookshelf", | ||||||
|   "version": "1.1.13", |   "version": "1.2.4", | ||||||
|   "lockfileVersion": 1, |   "lockfileVersion": 1, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
| @ -69,6 +69,12 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "abbrev": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "aborter": { |     "aborter": { | ||||||
|       "version": "1.1.0", |       "version": "1.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/aborter/-/aborter-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/aborter/-/aborter-1.1.0.tgz", | ||||||
| @ -83,6 +89,23 @@ | |||||||
|         "negotiator": "0.6.2" |         "negotiator": "0.6.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "adm-zip": { | ||||||
|  |       "version": "0.4.16", | ||||||
|  |       "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", | ||||||
|  |       "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==" | ||||||
|  |     }, | ||||||
|  |     "ansi-regex": { | ||||||
|  |       "version": "2.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", | ||||||
|  |       "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "aproba": { | ||||||
|  |       "version": "1.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", | ||||||
|  |       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "archiver": { |     "archiver": { | ||||||
|       "version": "5.3.0", |       "version": "5.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", |       "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", | ||||||
| @ -138,6 +161,33 @@ | |||||||
|         "is-primitive": "^3.0.1" |         "is-primitive": "^3.0.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "are-we-there-yet": { | ||||||
|  |       "version": "1.1.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", | ||||||
|  |       "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "delegates": "^1.0.0", | ||||||
|  |         "readable-stream": "^2.0.6" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "readable-stream": { | ||||||
|  |           "version": "2.3.7", | ||||||
|  |           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", | ||||||
|  |           "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", | ||||||
|  |           "optional": true, | ||||||
|  |           "requires": { | ||||||
|  |             "core-util-is": "~1.0.0", | ||||||
|  |             "inherits": "~2.0.3", | ||||||
|  |             "isarray": "~1.0.0", | ||||||
|  |             "process-nextick-args": "~2.0.0", | ||||||
|  |             "safe-buffer": "~5.1.1", | ||||||
|  |             "string_decoder": "~1.1.1", | ||||||
|  |             "util-deprecate": "~1.0.1" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "array-back": { |     "array-back": { | ||||||
|       "version": "3.1.0", |       "version": "3.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", |       "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", | ||||||
| @ -285,6 +335,12 @@ | |||||||
|         "responselike": "^2.0.0" |         "responselike": "^2.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "chownr": { | ||||||
|  |       "version": "1.1.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", | ||||||
|  |       "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "clone-response": { |     "clone-response": { | ||||||
|       "version": "1.0.2", |       "version": "1.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", | ||||||
| @ -293,6 +349,12 @@ | |||||||
|         "mimic-response": "^1.0.0" |         "mimic-response": "^1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "code-point-at": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", | ||||||
|  |       "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "command-line-args": { |     "command-line-args": { | ||||||
|       "version": "5.2.0", |       "version": "5.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", |       "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", | ||||||
| @ -325,6 +387,12 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", |       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | ||||||
|       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" |       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | ||||||
|     }, |     }, | ||||||
|  |     "console-control-strings": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", | ||||||
|  |       "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "content-disposition": { |     "content-disposition": { | ||||||
|       "version": "0.5.3", |       "version": "0.5.3", | ||||||
|       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", |       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", | ||||||
| @ -417,11 +485,23 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "deep-extend": { | ||||||
|  |       "version": "0.6.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", | ||||||
|  |       "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "defer-to-connect": { |     "defer-to-connect": { | ||||||
|       "version": "2.0.1", |       "version": "2.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", |       "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", | ||||||
|       "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" |       "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" | ||||||
|     }, |     }, | ||||||
|  |     "delegates": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", | ||||||
|  |       "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "depd": { |     "depd": { | ||||||
|       "version": "1.1.2", |       "version": "1.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", | ||||||
| @ -432,6 +512,12 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", |       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", | ||||||
|       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" |       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" | ||||||
|     }, |     }, | ||||||
|  |     "detect-libc": { | ||||||
|  |       "version": "1.0.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", | ||||||
|  |       "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "dicer": { |     "dicer": { | ||||||
|       "version": "0.3.0", |       "version": "0.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", |       "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", | ||||||
| @ -629,11 +715,36 @@ | |||||||
|         "universalify": "^2.0.0" |         "universalify": "^2.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "fs-minipass": { | ||||||
|  |       "version": "1.2.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", | ||||||
|  |       "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "minipass": "^2.6.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "fs.realpath": { |     "fs.realpath": { | ||||||
|       "version": "1.0.0", |       "version": "1.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", | ||||||
|       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" |       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" | ||||||
|     }, |     }, | ||||||
|  |     "gauge": { | ||||||
|  |       "version": "2.7.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", | ||||||
|  |       "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "aproba": "^1.0.3", | ||||||
|  |         "console-control-strings": "^1.0.0", | ||||||
|  |         "has-unicode": "^2.0.0", | ||||||
|  |         "object-assign": "^4.1.0", | ||||||
|  |         "signal-exit": "^3.0.0", | ||||||
|  |         "string-width": "^1.0.1", | ||||||
|  |         "strip-ansi": "^3.0.1", | ||||||
|  |         "wide-align": "^1.1.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "get-stream": { |     "get-stream": { | ||||||
|       "version": "5.2.0", |       "version": "5.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", |       "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", | ||||||
| @ -679,6 +790,12 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", |       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", | ||||||
|       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" |       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" | ||||||
|     }, |     }, | ||||||
|  |     "has-unicode": { | ||||||
|  |       "version": "2.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", | ||||||
|  |       "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "http-cache-semantics": { |     "http-cache-semantics": { | ||||||
|       "version": "4.1.0", |       "version": "4.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", |       "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", | ||||||
| @ -718,6 +835,15 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", |       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", | ||||||
|       "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" |       "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" | ||||||
|     }, |     }, | ||||||
|  |     "ignore-walk": { | ||||||
|  |       "version": "3.0.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", | ||||||
|  |       "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "minimatch": "^3.0.4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "inflight": { |     "inflight": { | ||||||
|       "version": "1.0.6", |       "version": "1.0.6", | ||||||
|       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", |       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", | ||||||
| @ -732,6 +858,12 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", |       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", | ||||||
|       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" |       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" | ||||||
|     }, |     }, | ||||||
|  |     "ini": { | ||||||
|  |       "version": "1.3.8", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", | ||||||
|  |       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "ip": { |     "ip": { | ||||||
|       "version": "1.1.5", |       "version": "1.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", |       "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", | ||||||
| @ -742,6 +874,15 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", |       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", | ||||||
|       "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" |       "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" | ||||||
|     }, |     }, | ||||||
|  |     "is-fullwidth-code-point": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", | ||||||
|  |       "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "number-is-nan": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "is-primitive": { |     "is-primitive": { | ||||||
|       "version": "3.0.1", |       "version": "3.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", |       "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", | ||||||
| @ -965,11 +1106,79 @@ | |||||||
|         "brace-expansion": "^1.1.7" |         "brace-expansion": "^1.1.7" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "minimist": { | ||||||
|  |       "version": "1.2.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | ||||||
|  |       "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "minipass": { | ||||||
|  |       "version": "2.9.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", | ||||||
|  |       "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "safe-buffer": "^5.1.2", | ||||||
|  |         "yallist": "^3.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "minizlib": { | ||||||
|  |       "version": "1.3.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", | ||||||
|  |       "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "minipass": "^2.9.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "mkdirp": { | ||||||
|  |       "version": "0.5.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", | ||||||
|  |       "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "minimist": "^1.2.5" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "ms": { |     "ms": { | ||||||
|       "version": "2.0.0", |       "version": "2.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||||
|       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" |       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" | ||||||
|     }, |     }, | ||||||
|  |     "nan": { | ||||||
|  |       "version": "2.10.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", | ||||||
|  |       "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "needle": { | ||||||
|  |       "version": "2.9.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", | ||||||
|  |       "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "debug": "^3.2.6", | ||||||
|  |         "iconv-lite": "^0.4.4", | ||||||
|  |         "sax": "^1.2.4" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "debug": { | ||||||
|  |           "version": "3.2.7", | ||||||
|  |           "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", | ||||||
|  |           "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", | ||||||
|  |           "optional": true, | ||||||
|  |           "requires": { | ||||||
|  |             "ms": "^2.1.1" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "ms": { | ||||||
|  |           "version": "2.1.3", | ||||||
|  |           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | ||||||
|  |           "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "negotiator": { |     "negotiator": { | ||||||
|       "version": "0.6.2", |       "version": "0.6.2", | ||||||
|       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", |       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", | ||||||
| @ -991,6 +1200,34 @@ | |||||||
|         "minimatch": "^3.0.2" |         "minimatch": "^3.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node-pre-gyp": { | ||||||
|  |       "version": "0.10.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", | ||||||
|  |       "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "detect-libc": "^1.0.2", | ||||||
|  |         "mkdirp": "^0.5.1", | ||||||
|  |         "needle": "^2.2.1", | ||||||
|  |         "nopt": "^4.0.1", | ||||||
|  |         "npm-packlist": "^1.1.6", | ||||||
|  |         "npmlog": "^4.0.2", | ||||||
|  |         "rc": "^1.2.7", | ||||||
|  |         "rimraf": "^2.6.1", | ||||||
|  |         "semver": "^5.3.0", | ||||||
|  |         "tar": "^4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "nopt": { | ||||||
|  |       "version": "4.0.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", | ||||||
|  |       "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "abbrev": "1", | ||||||
|  |         "osenv": "^0.1.4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "normalize-path": { |     "normalize-path": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", |       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", | ||||||
| @ -1001,6 +1238,50 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", |       "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", | ||||||
|       "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" |       "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" | ||||||
|     }, |     }, | ||||||
|  |     "npm-bundled": { | ||||||
|  |       "version": "1.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", | ||||||
|  |       "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "npm-normalize-package-bin": "^1.0.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "npm-normalize-package-bin": { | ||||||
|  |       "version": "1.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", | ||||||
|  |       "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "npm-packlist": { | ||||||
|  |       "version": "1.4.8", | ||||||
|  |       "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", | ||||||
|  |       "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "ignore-walk": "^3.0.1", | ||||||
|  |         "npm-bundled": "^1.0.1", | ||||||
|  |         "npm-normalize-package-bin": "^1.0.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "npmlog": { | ||||||
|  |       "version": "4.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", | ||||||
|  |       "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "are-we-there-yet": "~1.1.2", | ||||||
|  |         "console-control-strings": "~1.1.0", | ||||||
|  |         "gauge": "~2.7.3", | ||||||
|  |         "set-blocking": "~2.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "number-is-nan": { | ||||||
|  |       "version": "1.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", | ||||||
|  |       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "object-assign": { |     "object-assign": { | ||||||
|       "version": "4.1.1", |       "version": "4.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", |       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||||
| @ -1022,6 +1303,28 @@ | |||||||
|         "wrappy": "1" |         "wrappy": "1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "os-homedir": { | ||||||
|  |       "version": "1.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", | ||||||
|  |       "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "os-tmpdir": { | ||||||
|  |       "version": "1.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", | ||||||
|  |       "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "osenv": { | ||||||
|  |       "version": "0.1.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", | ||||||
|  |       "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "os-homedir": "^1.0.0", | ||||||
|  |         "os-tmpdir": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "p-cancelable": { |     "p-cancelable": { | ||||||
|       "version": "2.1.1", |       "version": "2.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", |       "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", | ||||||
| @ -1119,6 +1422,18 @@ | |||||||
|         "unpipe": "1.0.0" |         "unpipe": "1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "rc": { | ||||||
|  |       "version": "1.2.8", | ||||||
|  |       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", | ||||||
|  |       "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "deep-extend": "^0.6.0", | ||||||
|  |         "ini": "~1.3.0", | ||||||
|  |         "minimist": "^1.2.0", | ||||||
|  |         "strip-json-comments": "~2.0.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "readable-stream": { |     "readable-stream": { | ||||||
|       "version": "3.6.0", |       "version": "3.6.0", | ||||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", |       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", | ||||||
| @ -1155,6 +1470,15 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", |       "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", | ||||||
|       "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" |       "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" | ||||||
|     }, |     }, | ||||||
|  |     "rimraf": { | ||||||
|  |       "version": "2.7.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", | ||||||
|  |       "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "glob": "^7.1.3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "ripstat": { |     "ripstat": { | ||||||
|       "version": "1.1.1", |       "version": "1.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/ripstat/-/ripstat-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/ripstat/-/ripstat-1.1.1.tgz", | ||||||
| @ -1197,6 +1521,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", |       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | ||||||
|       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" |       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" | ||||||
|     }, |     }, | ||||||
|  |     "sax": { | ||||||
|  |       "version": "1.2.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", | ||||||
|  |       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" | ||||||
|  |     }, | ||||||
|     "semver": { |     "semver": { | ||||||
|       "version": "5.7.1", |       "version": "5.7.1", | ||||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", |       "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", | ||||||
| @ -1240,6 +1569,12 @@ | |||||||
|         "send": "0.17.1" |         "send": "0.17.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "set-blocking": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", | ||||||
|  |       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "setprototypeof": { |     "setprototypeof": { | ||||||
|       "version": "1.1.1", |       "version": "1.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", | ||||||
| @ -1326,6 +1661,17 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/string-indexes/-/string-indexes-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/string-indexes/-/string-indexes-1.0.0.tgz", | ||||||
|       "integrity": "sha512-RUlx+2YydZJNlRAvoh1siPYWj/Xfk6t1sQLkA5n1tMGRCKkRLzkRtJhHk4qRmKergEBh8R3pWhsUsDqia/bolw==" |       "integrity": "sha512-RUlx+2YydZJNlRAvoh1siPYWj/Xfk6t1sQLkA5n1tMGRCKkRLzkRtJhHk4qRmKergEBh8R3pWhsUsDqia/bolw==" | ||||||
|     }, |     }, | ||||||
|  |     "string-width": { | ||||||
|  |       "version": "1.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", | ||||||
|  |       "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "code-point-at": "^1.0.0", | ||||||
|  |         "is-fullwidth-code-point": "^1.0.0", | ||||||
|  |         "strip-ansi": "^3.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "string_decoder": { |     "string_decoder": { | ||||||
|       "version": "1.1.1", |       "version": "1.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", | ||||||
| @ -1334,6 +1680,44 @@ | |||||||
|         "safe-buffer": "~5.1.0" |         "safe-buffer": "~5.1.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "strip-ansi": { | ||||||
|  |       "version": "3.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", | ||||||
|  |       "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "ansi-regex": "^2.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "strip-json-comments": { | ||||||
|  |       "version": "2.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", | ||||||
|  |       "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "tar": { | ||||||
|  |       "version": "4.4.19", | ||||||
|  |       "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", | ||||||
|  |       "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "chownr": "^1.1.4", | ||||||
|  |         "fs-minipass": "^1.2.7", | ||||||
|  |         "minipass": "^2.9.0", | ||||||
|  |         "minizlib": "^1.3.3", | ||||||
|  |         "mkdirp": "^0.5.5", | ||||||
|  |         "safe-buffer": "^5.2.1", | ||||||
|  |         "yallist": "^3.1.1" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "safe-buffer": { | ||||||
|  |           "version": "5.2.1", | ||||||
|  |           "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | ||||||
|  |           "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "tar-stream": { |     "tar-stream": { | ||||||
|       "version": "2.2.0", |       "version": "2.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", |       "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", | ||||||
| @ -1419,6 +1803,15 @@ | |||||||
|         "isexe": "^2.0.0" |         "isexe": "^2.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "wide-align": { | ||||||
|  |       "version": "1.1.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", | ||||||
|  |       "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "string-width": "^1.0.2 || 2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "wrappy": { |     "wrappy": { | ||||||
|       "version": "1.0.2", |       "version": "1.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | ||||||
| @ -1434,6 +1827,26 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", | ||||||
|       "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" |       "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" | ||||||
|     }, |     }, | ||||||
|  |     "xml2js": { | ||||||
|  |       "version": "0.4.23", | ||||||
|  |       "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", | ||||||
|  |       "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", | ||||||
|  |       "requires": { | ||||||
|  |         "sax": ">=0.6.0", | ||||||
|  |         "xmlbuilder": "~11.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "xmlbuilder": { | ||||||
|  |       "version": "11.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", | ||||||
|  |       "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" | ||||||
|  |     }, | ||||||
|  |     "yallist": { | ||||||
|  |       "version": "3.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", | ||||||
|  |       "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|     "zip-stream": { |     "zip-stream": { | ||||||
|       "version": "4.1.0", |       "version": "4.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", |       "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", | ||||||
| @ -1443,6 +1856,16 @@ | |||||||
|         "compress-commons": "^4.1.0", |         "compress-commons": "^4.1.0", | ||||||
|         "readable-stream": "^3.6.0" |         "readable-stream": "^3.6.0" | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     "zipfile": { | ||||||
|  |       "version": "0.5.12", | ||||||
|  |       "resolved": "https://registry.npmjs.org/zipfile/-/zipfile-0.5.12.tgz", | ||||||
|  |       "integrity": "sha512-zA60gW+XgQBu/Q4qV3BCXNIDRald6Xi5UOPj3jWGlnkjmBHaKDwIz7kyXWV3kq7VEsQN/2t/IWjdXdKeVNm6Eg==", | ||||||
|  |       "optional": true, | ||||||
|  |       "requires": { | ||||||
|  |         "nan": "~2.10.0", | ||||||
|  |         "node-pre-gyp": "~0.10.2" | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "audiobookshelf", |   "name": "audiobookshelf", | ||||||
|   "version": "1.2.4", |   "version": "1.2.5", | ||||||
|   "description": "Self-hosted audiobook server for managing and playing audiobooks", |   "description": "Self-hosted audiobook server for managing and playing audiobooks", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  | |||||||
							
								
								
									
										42
									
								
								server/EbookReader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								server/EbookReader.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | // const express = require('express')
 | ||||||
|  | // const EPub = require('epub')
 | ||||||
|  | // const Logger = require('./Logger')
 | ||||||
|  | 
 | ||||||
|  | // class EbookReader {
 | ||||||
|  | //   constructor(db, MetadataPath, AudiobookPath) {
 | ||||||
|  | //     this.db = db
 | ||||||
|  | //     this.MetadataPath = MetadataPath
 | ||||||
|  | //     this.AudiobookPath = AudiobookPath
 | ||||||
|  | 
 | ||||||
|  | //     this.router = express()
 | ||||||
|  | //     this.init()
 | ||||||
|  | //   }
 | ||||||
|  | 
 | ||||||
|  | //   init() {
 | ||||||
|  | //     this.router.get('/open/:id/:ino', this.openRequest.bind(this))
 | ||||||
|  | //   }
 | ||||||
|  | 
 | ||||||
|  | //   openRequest(req, res) {
 | ||||||
|  | //     Logger.info('Open request received', req.params)
 | ||||||
|  | //     var audiobookId = req.params.id
 | ||||||
|  | //     var fileIno = req.params.ino
 | ||||||
|  | //     var audiobook = this.db.audiobooks.find(ab => ab.id === audiobookId)
 | ||||||
|  | //     if (!audiobook) {
 | ||||||
|  | //       return res.sendStatus(404)
 | ||||||
|  | //     }
 | ||||||
|  | //     var ebook = audiobook.ebooks.find(eb => eb.ino === fileIno)
 | ||||||
|  | //     if (!ebook) {
 | ||||||
|  | //       Logger.error('Ebook file not found', fileIno)
 | ||||||
|  | //       return res.sendStatus(404)
 | ||||||
|  | //     }
 | ||||||
|  | //     Logger.info('Ebook found', ebook)
 | ||||||
|  | //     this.open(ebook.fullPath)
 | ||||||
|  | //     res.sendStatus(200)
 | ||||||
|  | //   }
 | ||||||
|  | 
 | ||||||
|  | //   open(path) {
 | ||||||
|  | //     var epub = new EPub(path)
 | ||||||
|  | //     console.log('epub', epub)
 | ||||||
|  | //   }
 | ||||||
|  | // }
 | ||||||
|  | // module.exports = EbookReader
 | ||||||
| @ -25,25 +25,6 @@ class Scanner { | |||||||
|     return this.db.audiobooks |     return this.db.audiobooks | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async setAudiobookDataInos(audiobookData) { |  | ||||||
|     for (let i = 0; i < audiobookData.length; i++) { |  | ||||||
|       var abd = audiobookData[i] |  | ||||||
|       var matchingAB = this.db.audiobooks.find(_ab => comparePaths(_ab.path, abd.path)) |  | ||||||
|       if (matchingAB) { |  | ||||||
|         if (!matchingAB.ino) { |  | ||||||
|           matchingAB.ino = await getIno(matchingAB.fullPath) |  | ||||||
|         } |  | ||||||
|         abd.ino = matchingAB.ino |  | ||||||
|       } else { |  | ||||||
|         abd.ino = await getIno(abd.fullPath) |  | ||||||
|         if (!abd.ino) { |  | ||||||
|           Logger.error('[Scanner] Invalid ino - ignoring audiobook data', abd.path) |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return audiobookData.filter(abd => !!abd.ino) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   async setAudioFileInos(audiobookDataAudioFiles, audiobookAudioFiles) { |   async setAudioFileInos(audiobookDataAudioFiles, audiobookAudioFiles) { | ||||||
|     for (let i = 0; i < audiobookDataAudioFiles.length; i++) { |     for (let i = 0; i < audiobookDataAudioFiles.length; i++) { | ||||||
|       var abdFile = audiobookDataAudioFiles[i] |       var abdFile = audiobookDataAudioFiles[i] | ||||||
| @ -68,7 +49,6 @@ class Scanner { | |||||||
|     Logger.debug(`[Scanner] Scanning "${audiobookData.title}" (${audiobookData.ino}) - ${!!existingAudiobook ? 'Exists' : 'New'}`) |     Logger.debug(`[Scanner] Scanning "${audiobookData.title}" (${audiobookData.ino}) - ${!!existingAudiobook ? 'Exists' : 'New'}`) | ||||||
| 
 | 
 | ||||||
|     if (existingAudiobook) { |     if (existingAudiobook) { | ||||||
| 
 |  | ||||||
|       // REMOVE: No valid audio files
 |       // REMOVE: No valid audio files
 | ||||||
|       // TODO: Label as incomplete, do not actually delete
 |       // TODO: Label as incomplete, do not actually delete
 | ||||||
|       if (!audiobookData.audioFiles.length) { |       if (!audiobookData.audioFiles.length) { | ||||||
| @ -80,7 +60,10 @@ class Scanner { | |||||||
|         return ScanResult.REMOVED |         return ScanResult.REMOVED | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       audiobookData.audioFiles = await this.setAudioFileInos(audiobookData.audioFiles, existingAudiobook.audioFiles) |       // ino is now set for every file in scandir
 | ||||||
|  |       audiobookData.audioFiles = audiobookData.audioFiles.filter(af => af.ino) | ||||||
|  |       // audiobookData.audioFiles = await this.setAudioFileInos(audiobookData.audioFiles, existingAudiobook.audioFiles)
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|       // Check for audio files that were removed
 |       // Check for audio files that were removed
 | ||||||
|       var abdAudioFileInos = audiobookData.audioFiles.map(af => af.ino) |       var abdAudioFileInos = audiobookData.audioFiles.map(af => af.ino) | ||||||
| @ -90,6 +73,14 @@ class Scanner { | |||||||
|         removedAudioFiles.forEach((af) => existingAudiobook.removeAudioFile(af)) |         removedAudioFiles.forEach((af) => existingAudiobook.removeAudioFile(af)) | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       // Check for mismatched audio tracks - tracks with no matching audio file
 | ||||||
|  |       var removedAudioTracks = existingAudiobook.tracks.filter(track => !abdAudioFileInos.includes(track.ino)) | ||||||
|  |       if (removedAudioTracks.length) { | ||||||
|  |         Logger.info(`[Scanner] ${removedAudioTracks.length} tracks removed no matching audio file for audiobook "${existingAudiobook.title}"`) | ||||||
|  |         removedAudioTracks.forEach((at) => existingAudiobook.removeAudioTrack(at)) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|       // Check for new audio files and sync existing audio files
 |       // Check for new audio files and sync existing audio files
 | ||||||
|       var newAudioFiles = [] |       var newAudioFiles = [] | ||||||
|       var hasUpdatedAudioFiles = false |       var hasUpdatedAudioFiles = false | ||||||
| @ -124,7 +115,7 @@ class Scanner { | |||||||
|         return ScanResult.REMOVED |         return ScanResult.REMOVED | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       var hasUpdates = removedAudioFiles.length || newAudioFiles.length || hasUpdatedAudioFiles |       var hasUpdates = removedAudioFiles.length || removedAudioTracks.length || newAudioFiles.length || hasUpdatedAudioFiles | ||||||
| 
 | 
 | ||||||
|       if (existingAudiobook.checkUpdateMissingParts()) { |       if (existingAudiobook.checkUpdateMissingParts()) { | ||||||
|         Logger.info(`[Scanner] "${existingAudiobook.title}" missing parts updated`) |         Logger.info(`[Scanner] "${existingAudiobook.title}" missing parts updated`) | ||||||
| @ -187,27 +178,28 @@ class Scanner { | |||||||
|     // TODO: This temporary fix from pre-release should be removed soon, including the "fixRelativePath" and "checkUpdateInos"
 |     // TODO: This temporary fix from pre-release should be removed soon, including the "fixRelativePath" and "checkUpdateInos"
 | ||||||
|     // TEMP - fix relative file paths
 |     // TEMP - fix relative file paths
 | ||||||
|     // TEMP - update ino for each audiobook
 |     // TEMP - update ino for each audiobook
 | ||||||
|     // if (this.audiobooks.length) {
 |     if (this.audiobooks.length) { | ||||||
|     //   for (let i = 0; i < this.audiobooks.length; i++) {
 |       for (let i = 0; i < this.audiobooks.length; i++) { | ||||||
|     //     var ab = this.audiobooks[i]
 |         var ab = this.audiobooks[i] | ||||||
|     //     var shouldUpdate = ab.fixRelativePath(this.AudiobookPath) || !ab.ino
 |         // var shouldUpdate = ab.fixRelativePath(this.AudiobookPath) || !ab.ino
 | ||||||
| 
 | 
 | ||||||
|     //     // Update ino if an audio file has the same ino as the audiobook
 |         // Update ino if inos are not set
 | ||||||
|     //     var shouldUpdateIno = !ab.ino || (ab.audioFiles || []).find(abf => abf.ino === ab.ino)
 |         var shouldUpdateIno = ab.hasMissingIno | ||||||
|     //     if (shouldUpdateIno) {
 |         if (shouldUpdateIno) { | ||||||
|     //       await ab.checkUpdateInos()
 |           Logger.debug(`Updating inos for ${ab.title}`) | ||||||
|     //     }
 |           var hasUpdates = await ab.checkUpdateInos() | ||||||
|     //     if (shouldUpdate) {
 |           if (hasUpdates) { | ||||||
|     //       await this.db.updateAudiobook(ab)
 |             await this.db.updateAudiobook(ab) | ||||||
|     //     }
 |           } | ||||||
|     //   }
 |         } | ||||||
|     // }
 |       } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     const scanStart = Date.now() |     const scanStart = Date.now() | ||||||
|     var audiobookDataFound = await scanRootDir(this.AudiobookPath, this.db.serverSettings) |     var audiobookDataFound = await scanRootDir(this.AudiobookPath, this.db.serverSettings) | ||||||
| 
 | 
 | ||||||
|     // Set ino for each ab data as a string
 |     // Remove audiobooks with no inode
 | ||||||
|     audiobookDataFound = await this.setAudiobookDataInos(audiobookDataFound) |     audiobookDataFound = audiobookDataFound.filter(abd => abd.ino) | ||||||
| 
 | 
 | ||||||
|     if (this.cancelScan) { |     if (this.cancelScan) { | ||||||
|       this.cancelScan = false |       this.cancelScan = false | ||||||
| @ -323,7 +315,11 @@ class Scanner { | |||||||
|   async filesChanged(filepaths) { |   async filesChanged(filepaths) { | ||||||
|     if (!filepaths.length) return ScanResult.NOTHING |     if (!filepaths.length) return ScanResult.NOTHING | ||||||
|     var relfilepaths = filepaths.map(path => path.replace(this.AudiobookPath, '')) |     var relfilepaths = filepaths.map(path => path.replace(this.AudiobookPath, '')) | ||||||
|     var fileGroupings = groupFilesIntoAudiobookPaths(relfilepaths) |     var fileGroupings = groupFilesIntoAudiobookPaths(relfilepaths, true) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     Logger.debug(`[Scanner] fileGroupings `, filepaths, fileGroupings) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     var results = [] |     var results = [] | ||||||
|     for (const dir in fileGroupings) { |     for (const dir in fileGroupings) { | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ const HlsController = require('./HlsController') | |||||||
| const StreamManager = require('./StreamManager') | const StreamManager = require('./StreamManager') | ||||||
| const RssFeeds = require('./RssFeeds') | const RssFeeds = require('./RssFeeds') | ||||||
| const DownloadManager = require('./DownloadManager') | const DownloadManager = require('./DownloadManager') | ||||||
|  | // const EbookReader = require('./EbookReader')
 | ||||||
| const Logger = require('./Logger') | const Logger = require('./Logger') | ||||||
| 
 | 
 | ||||||
| class Server { | class Server { | ||||||
| @ -37,6 +38,7 @@ class Server { | |||||||
|     this.downloadManager = new DownloadManager(this.db, this.MetadataPath, this.AudiobookPath, this.emitter.bind(this)) |     this.downloadManager = new DownloadManager(this.db, this.MetadataPath, this.AudiobookPath, this.emitter.bind(this)) | ||||||
|     this.apiController = new ApiController(this.MetadataPath, this.db, this.scanner, this.auth, this.streamManager, this.rssFeeds, this.downloadManager, this.emitter.bind(this), this.clientEmitter.bind(this)) |     this.apiController = new ApiController(this.MetadataPath, this.db, this.scanner, this.auth, this.streamManager, this.rssFeeds, this.downloadManager, this.emitter.bind(this), this.clientEmitter.bind(this)) | ||||||
|     this.hlsController = new HlsController(this.db, this.scanner, this.auth, this.streamManager, this.emitter.bind(this), this.streamManager.StreamsPath) |     this.hlsController = new HlsController(this.db, this.scanner, this.auth, this.streamManager, this.emitter.bind(this), this.streamManager.StreamsPath) | ||||||
|  |     // this.ebookReader = new EbookReader(this.db, this.MetadataPath, this.AudiobookPath)
 | ||||||
| 
 | 
 | ||||||
|     this.server = null |     this.server = null | ||||||
|     this.io = null |     this.io = null | ||||||
| @ -204,7 +206,7 @@ class Server { | |||||||
| 
 | 
 | ||||||
|     app.use('/api', this.authMiddleware.bind(this), this.apiController.router) |     app.use('/api', this.authMiddleware.bind(this), this.apiController.router) | ||||||
|     app.use('/hls', this.authMiddleware.bind(this), this.hlsController.router) |     app.use('/hls', this.authMiddleware.bind(this), this.hlsController.router) | ||||||
|     // app.use('/hls', this.hlsController.router)
 |     // app.use('/ebook', this.ebookReader.router)
 | ||||||
|     app.use('/feeds', this.rssFeeds.router) |     app.use('/feeds', this.rssFeeds.router) | ||||||
| 
 | 
 | ||||||
|     app.post('/upload', this.authMiddleware.bind(this), this.handleUpload.bind(this)) |     app.post('/upload', this.authMiddleware.bind(this), this.handleUpload.bind(this)) | ||||||
|  | |||||||
| @ -106,6 +106,14 @@ class Audiobook { | |||||||
|     return (this.audioFiles || []).filter(af => af.invalid).map(af => ({ filename: af.filename, error: af.error || 'Unknown Error' })) |     return (this.audioFiles || []).filter(af => af.invalid).map(af => ({ filename: af.filename, error: af.error || 'Unknown Error' })) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   get ebooks() { | ||||||
|  |     return this.otherFiles.filter(file => file.filetype === 'ebook') | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   get hasMissingIno() { | ||||||
|  |     return !this.ino || (this.audioFiles || []).find(abf => !abf.ino) || (this.otherFiles || []).find(f => !f.ino) || (this.tracks || []).find(t => !t.ino) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   bookToJSON() { |   bookToJSON() { | ||||||
|     return this.book ? this.book.toJSON() : null |     return this.book ? this.book.toJSON() : null | ||||||
|   } |   } | ||||||
| @ -152,6 +160,7 @@ class Audiobook { | |||||||
|       hasBookMatch: !!this.book, |       hasBookMatch: !!this.book, | ||||||
|       hasMissingParts: this.missingParts ? this.missingParts.length : 0, |       hasMissingParts: this.missingParts ? this.missingParts.length : 0, | ||||||
|       hasInvalidParts: this.invalidParts ? this.invalidParts.length : 0, |       hasInvalidParts: this.invalidParts ? this.invalidParts.length : 0, | ||||||
|  |       numEbooks: this.ebooks.length, | ||||||
|       numTracks: this.tracks.length, |       numTracks: this.tracks.length, | ||||||
|       chapters: this.chapters || [], |       chapters: this.chapters || [], | ||||||
|       isMissing: !!this.isMissing |       isMissing: !!this.isMissing | ||||||
| @ -173,6 +182,7 @@ class Audiobook { | |||||||
|       invalidParts: this.invalidParts, |       invalidParts: this.invalidParts, | ||||||
|       audioFiles: (this.audioFiles || []).map(audioFile => audioFile.toJSON()), |       audioFiles: (this.audioFiles || []).map(audioFile => audioFile.toJSON()), | ||||||
|       otherFiles: (this.otherFiles || []).map(otherFile => otherFile.toJSON()), |       otherFiles: (this.otherFiles || []).map(otherFile => otherFile.toJSON()), | ||||||
|  |       ebooks: (this.ebooks || []).map(ebook => ebook.toJSON()), | ||||||
|       tags: this.tags, |       tags: this.tags, | ||||||
|       book: this.bookToJSON(), |       book: this.bookToJSON(), | ||||||
|       tracks: this.tracksToJSON(), |       tracks: this.tracksToJSON(), | ||||||
| @ -195,7 +205,8 @@ class Audiobook { | |||||||
|     return false |     return false | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Update was made to add ino values, ensure they are set
 |   // Originally files did not store the inode value
 | ||||||
|  |   // this function checks all files and sets the inode
 | ||||||
|   async checkUpdateInos() { |   async checkUpdateInos() { | ||||||
|     var hasUpdates = false |     var hasUpdates = false | ||||||
|     if (!this.ino) { |     if (!this.ino) { | ||||||
| @ -204,15 +215,55 @@ class Audiobook { | |||||||
|     } |     } | ||||||
|     for (let i = 0; i < this.audioFiles.length; i++) { |     for (let i = 0; i < this.audioFiles.length; i++) { | ||||||
|       var af = this.audioFiles[i] |       var af = this.audioFiles[i] | ||||||
|  |       var at = this.tracks.find(t => t.ino === af.ino) | ||||||
|  |       if (!at) { | ||||||
|  |         at = this.tracks.find(t => comparePaths(t.path, af.path)) | ||||||
|  |       } | ||||||
|       if (!af.ino || af.ino === this.ino) { |       if (!af.ino || af.ino === this.ino) { | ||||||
|         af.ino = await getIno(af.fullPath) |         af.ino = await getIno(af.fullPath) | ||||||
|         if (!af.ino) { |         if (!af.ino) { | ||||||
|           Logger.error('[Audiobook] checkUpdateInos: Failed to set ino for audio file', af.fullPath) |           Logger.error('[Audiobook] checkUpdateInos: Failed to set ino for audio file', af.fullPath) | ||||||
|         } else { |         } else { | ||||||
|           var track = this.tracks.find(t => comparePaths(t.path, af.path)) |           Logger.debug(`[Audiobook] Set INO For audio file ${af.path}`) | ||||||
|           if (track) { |           if (at) at.ino = af.ino | ||||||
|             track.ino = af.ino |         } | ||||||
|  |         hasUpdates = true | ||||||
|  |       } else if (at && at.ino !== af.ino) { | ||||||
|  |         at.ino = af.ino | ||||||
|  |         hasUpdates = true | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for (let i = 0; i < this.tracks.length; i++) { | ||||||
|  |       var at = this.tracks[i] | ||||||
|  |       if (!at.ino) { | ||||||
|  |         Logger.debug(`[Audiobook] Track ${at.filename} still does not have ino`) | ||||||
|  |         var atino = await getIno(at.fullPath) | ||||||
|  |         var af = this.audioFiles.find(_af => _af.ino === atino) | ||||||
|  |         if (!af) { | ||||||
|  |           Logger.debug(`[Audiobook] Track ${at.filename} no matching audio file with ino ${atino}`) | ||||||
|  |           af = this.audioFiles.find(_af => _af.filename === at.filename) | ||||||
|  |           if (!af) { | ||||||
|  |             Logger.debug(`[Audiobook] Track ${at.filename} no matching audio file with filename`) | ||||||
|  |           } else { | ||||||
|  |             Logger.debug(`[Audiobook] Track ${at.filename} found matching filename but mismatch ino ${atino}/${af.ino}`) | ||||||
|  |             // at.ino = af.ino
 | ||||||
|  |             // at.path = af.path
 | ||||||
|  |             // at.fullPath = af.fullPath
 | ||||||
|  |             // hasUpdates = true
 | ||||||
|           } |           } | ||||||
|  |         } else { | ||||||
|  |           Logger.debug(`[Audiobook] Track ${at.filename} found audio file with matching ino ${at.path}/${af.path}`) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for (let i = 0; i < this.otherFiles.length; i++) { | ||||||
|  |       var file = this.otherFiles[i] | ||||||
|  |       if (!file.ino || file.ino === this.ino) { | ||||||
|  |         file.ino = await getIno(file.fullPath) | ||||||
|  |         if (!file.ino) { | ||||||
|  |           Logger.error('[Audiobook] checkUpdateInos: Failed to set ino for other file', file.fullPath) | ||||||
|  |         } else { | ||||||
|  |           Logger.debug(`[Audiobook] Set INO For other file ${file.path}`) | ||||||
|         } |         } | ||||||
|         hasUpdates = true |         hasUpdates = true | ||||||
|       } |       } | ||||||
| @ -329,6 +380,11 @@ class Audiobook { | |||||||
|     this.audioFiles = this.audioFiles.filter(f => f.ino !== audioFile.ino) |     this.audioFiles = this.audioFiles.filter(f => f.ino !== audioFile.ino) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   removeAudioTrack(track) { | ||||||
|  |     this.tracks = this.tracks.filter(t => t.ino !== track.ino) | ||||||
|  |     this.audioFiles = this.audioFiles.filter(f => f.ino !== track.ino) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   checkUpdateMissingParts() { |   checkUpdateMissingParts() { | ||||||
|     var currMissingParts = (this.missingParts || []).join(',') || '' |     var currMissingParts = (this.missingParts || []).join(',') || '' | ||||||
| 
 | 
 | ||||||
| @ -363,6 +419,7 @@ class Audiobook { | |||||||
|     var newOtherFilePaths = newOtherFiles.map(f => f.path) |     var newOtherFilePaths = newOtherFiles.map(f => f.path) | ||||||
|     this.otherFiles = this.otherFiles.filter(f => newOtherFilePaths.includes(f.path)) |     this.otherFiles = this.otherFiles.filter(f => newOtherFilePaths.includes(f.path)) | ||||||
| 
 | 
 | ||||||
|  |     // TODO: Should use inode
 | ||||||
|     newOtherFiles.forEach((file) => { |     newOtherFiles.forEach((file) => { | ||||||
|       var existingOtherFile = this.otherFiles.find(f => f.path === file.path) |       var existingOtherFile = this.otherFiles.find(f => f.path === file.path) | ||||||
|       if (!existingOtherFile) { |       if (!existingOtherFile) { | ||||||
|  | |||||||
| @ -85,7 +85,7 @@ function getTrackNumberFromFilename(title, author, series, publishYear, filename | |||||||
| 
 | 
 | ||||||
| async function scanAudioFiles(audiobook, newAudioFiles) { | async function scanAudioFiles(audiobook, newAudioFiles) { | ||||||
|   if (!newAudioFiles || !newAudioFiles.length) { |   if (!newAudioFiles || !newAudioFiles.length) { | ||||||
|     Logger.error('[AudioFileScanner] Scan Audio Files no files', audiobook.title) |     Logger.error('[AudioFileScanner] Scan Audio Files no new files', audiobook.title) | ||||||
|     return |     return | ||||||
|   } |   } | ||||||
|   var tracks = [] |   var tracks = [] | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| const Path = require('path') | const Path = require('path') | ||||||
| const dir = require('node-dir') | const dir = require('node-dir') | ||||||
| const Logger = require('../Logger') | const Logger = require('../Logger') | ||||||
|  | const { getIno } = require('./index') | ||||||
| 
 | 
 | ||||||
| const AUDIO_FORMATS = ['m4b', 'mp3', 'm4a'] | const AUDIO_FORMATS = ['m4b', 'mp3', 'm4a'] | ||||||
| const INFO_FORMATS = ['nfo'] | const INFO_FORMATS = ['nfo'] | ||||||
| @ -26,7 +27,7 @@ function isAudioFile(path) { | |||||||
|   return AUDIO_FORMATS.includes(ext.slice(1).toLowerCase()) |   return AUDIO_FORMATS.includes(ext.slice(1).toLowerCase()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function groupFilesIntoAudiobookPaths(paths) { | function groupFilesIntoAudiobookPaths(paths, useAllFileTypes = false) { | ||||||
|   // Step 1: Normalize path, Remove leading "/", Filter out files in root dir
 |   // Step 1: Normalize path, Remove leading "/", Filter out files in root dir
 | ||||||
|   var pathsFiltered = paths.map(path => Path.normalize(path.slice(1))).filter(path => Path.parse(path).dir) |   var pathsFiltered = paths.map(path => Path.normalize(path.slice(1))).filter(path => Path.parse(path).dir) | ||||||
| 
 | 
 | ||||||
| @ -37,11 +38,11 @@ function groupFilesIntoAudiobookPaths(paths) { | |||||||
|     return pathsA - pathsB |     return pathsA - pathsB | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   // Step 2.5: Seperate audio files and other files
 |   // Step 2.5: Seperate audio files and other files (optional)
 | ||||||
|   var audioFilePaths = [] |   var audioFilePaths = [] | ||||||
|   var otherFilePaths = [] |   var otherFilePaths = [] | ||||||
|   pathsFiltered.forEach(path => { |   pathsFiltered.forEach(path => { | ||||||
|     if (isAudioFile(path)) audioFilePaths.push(path) |     if (isAudioFile(path) || useAllFileTypes) audioFilePaths.push(path) | ||||||
|     else otherFilePaths.push(path) |     else otherFilePaths.push(path) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
| @ -134,7 +135,12 @@ async function scanRootDir(abRootPath, serverSettings = {}) { | |||||||
|     var audiobookData = getAudiobookDataFromDir(abRootPath, audiobookPath, parseSubtitle) |     var audiobookData = getAudiobookDataFromDir(abRootPath, audiobookPath, parseSubtitle) | ||||||
| 
 | 
 | ||||||
|     var fileObjs = cleanFileObjects(audiobookData.fullPath, audiobookPath, audiobookGrouping[audiobookPath]) |     var fileObjs = cleanFileObjects(audiobookData.fullPath, audiobookPath, audiobookGrouping[audiobookPath]) | ||||||
|  |     for (let i = 0; i < fileObjs.length; i++) { | ||||||
|  |       fileObjs[i].ino = await getIno(fileObjs[i].fullPath) | ||||||
|  |     } | ||||||
|  |     var audiobookIno = await getIno(audiobookData.fullPath) | ||||||
|     audiobooks.push({ |     audiobooks.push({ | ||||||
|  |       ino: audiobookIno, | ||||||
|       ...audiobookData, |       ...audiobookData, | ||||||
|       audioFiles: fileObjs.filter(f => f.filetype === 'audio'), |       audioFiles: fileObjs.filter(f => f.filetype === 'audio'), | ||||||
|       otherFiles: fileObjs.filter(f => f.filetype !== 'audio') |       otherFiles: fileObjs.filter(f => f.filetype !== 'audio') | ||||||
| @ -241,11 +247,15 @@ async function getAudiobookFileData(abRootPath, audiobookPath, serverSettings = | |||||||
|     otherFiles: [] |     otherFiles: [] | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   filepaths.forEach((filepath) => { |   for (let i = 0; i < filepaths.length; i++) { | ||||||
|  |     var filepath = filepaths[i] | ||||||
|  | 
 | ||||||
|     var relpath = Path.normalize(filepath).replace(abRootPath, '').slice(1) |     var relpath = Path.normalize(filepath).replace(abRootPath, '').slice(1) | ||||||
|     var extname = Path.extname(filepath) |     var extname = Path.extname(filepath) | ||||||
|     var basename = Path.basename(filepath) |     var basename = Path.basename(filepath) | ||||||
|  |     var ino = await getIno(filepath) | ||||||
|     var fileObj = { |     var fileObj = { | ||||||
|  |       ino, | ||||||
|       filetype: getFileType(extname), |       filetype: getFileType(extname), | ||||||
|       filename: basename, |       filename: basename, | ||||||
|       path: relpath, |       path: relpath, | ||||||
| @ -257,7 +267,7 @@ async function getAudiobookFileData(abRootPath, audiobookPath, serverSettings = | |||||||
|     } else { |     } else { | ||||||
|       audiobook.otherFiles.push(fileObj) |       audiobook.otherFiles.push(fileObj) | ||||||
|     } |     } | ||||||
|   }) |   } | ||||||
|   return audiobook |   return audiobook | ||||||
| } | } | ||||||
| module.exports.getAudiobookFileData = getAudiobookFileData | module.exports.getAudiobookFileData = getAudiobookFileData | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user