mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-17 11:29:12 +01:00
Fixing scanner inodes, select all fix, starting ebook reader
This commit is contained in:
parent
29ba62357d
commit
26b37def46
@ -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