Add LibrarySettings and update edit library modal to include settings tab

This commit is contained in:
advplyr 2022-04-14 17:15:52 -05:00
parent cbde451120
commit 5a26b01ffb
12 changed files with 356 additions and 162 deletions

View File

@ -5,7 +5,7 @@
<p class="font-book text-3xl text-white truncate pointer-events-none">{{ title }}</p> <p class="font-book text-3xl text-white truncate pointer-events-none">{{ title }}</p>
</div> </div>
</template> </template>
<div class="absolute -top-10 left-0 w-full flex"> <div class="absolute -top-10 left-0 z-10 w-full flex">
<template v-for="tab in availableTabs"> <template v-for="tab in availableTabs">
<div :key="tab.id" class="w-28 rounded-t-lg flex items-center justify-center mr-1 cursor-pointer hover:bg-bg font-book border-t border-l border-r border-black-300 tab text-xs sm:text-base" :class="selectedTab === tab.id ? 'tab-selected bg-bg pb-px' : 'bg-primary text-gray-400'" @click="selectTab(tab.id)">{{ tab.title }}</div> <div :key="tab.id" class="w-28 rounded-t-lg flex items-center justify-center mr-1 cursor-pointer hover:bg-bg font-book border-t border-l border-r border-black-300 tab text-xs sm:text-base" :class="selectedTab === tab.id ? 'tab-selected bg-bg pb-px' : 'bg-primary text-gray-400'" @click="selectTab(tab.id)">{{ tab.title }}</div>
</template> </template>
@ -252,7 +252,7 @@ export default {
} }
</script> </script>
<style> <style scoped>
.tab { .tab {
height: 40px; height: 40px;
} }

View File

@ -1,22 +1,18 @@
<template> <template>
<div class="w-full h-full px-4 py-2 mb-4"> <div class="w-full h-full px-4 py-2 mb-4">
<div v-show="showDirectoryPicker" class="flex items-center py-1 mb-2">
<span class="material-icons text-3xl cursor-pointer hover:text-gray-300" @click="backArrowPress">arrow_back</span>
<p class="px-4 text-xl">{{ title }}</p>
</div>
<div v-if="!showDirectoryPicker" class="w-full h-full py-4"> <div v-if="!showDirectoryPicker" class="w-full h-full py-4">
<div class="flex flex-wrap md:flex-nowrap -mx-1"> <div class="flex flex-wrap md:flex-nowrap -mx-1">
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0"> <div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
<ui-dropdown v-model="mediaType" :items="mediaTypes" label="Media Type" :disabled="!!library" small @input="changedMediaType" /> <ui-dropdown v-model="mediaType" :items="mediaTypes" label="Media Type" :disabled="!isNew" small @input="changedMediaType" />
</div> </div>
<div class="w-full md:flex-grow px-1 py-1 md:py-0"> <div class="w-full md:flex-grow px-1 py-1 md:py-0">
<ui-text-input-with-label v-model="name" label="Library Name" /> <ui-text-input-with-label v-model="name" label="Library Name" @blur="nameBlurred" />
</div> </div>
<div class="w-1/5 md:w-18 px-1 py-1 md:py-0"> <div class="w-1/5 md:w-18 px-1 py-1 md:py-0">
<ui-media-icon-picker v-model="icon" /> <ui-media-icon-picker v-model="icon" @input="iconChanged" />
</div> </div>
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0"> <div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
<ui-dropdown v-model="provider" :items="providers" label="Metadata Provider" small /> <ui-dropdown v-model="provider" :items="providers" label="Metadata Provider" small @input="formUpdated" />
</div> </div>
</div> </div>
@ -27,39 +23,23 @@
<ui-editable-text v-model="folder.fullPath" readonly type="text" class="w-full" /> <ui-editable-text v-model="folder.fullPath" readonly type="text" class="w-full" />
<span v-show="folders.length > 1" class="material-icons ml-2 cursor-pointer hover:text-error" @click="removeFolder(folder)">close</span> <span v-show="folders.length > 1" class="material-icons ml-2 cursor-pointer hover:text-error" @click="removeFolder(folder)">close</span>
</div> </div>
<!-- <p v-if="!folders.length" class="text-sm text-gray-300 px-1 py-2">No folders</p> -->
<div class="flex py-1 px-2 items-center w-full"> <div class="flex py-1 px-2 items-center w-full">
<span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span> <span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span>
<ui-editable-text v-model="newFolderPath" placeholder="New folder path" type="text" class="w-full" /> <ui-editable-text v-model="newFolderPath" placeholder="New folder path" type="text" class="w-full" @blur="newFolderInputBlurred" />
</div> </div>
<ui-btn class="w-full mt-2" color="primary" @click="showDirectoryPicker = true">Browse for Folder</ui-btn> <ui-btn class="w-full mt-2" color="primary" @click="showDirectoryPicker = true">Browse for Folder</ui-btn>
</div> </div>
<div class="absolute bottom-0 left-0 w-full py-4 px-4">
<div class="flex items-center">
<div class="flex-grow" />
<ui-btn v-show="!disableSubmit" color="success" :disabled="disableSubmit" @click="submit">{{ library ? 'Update Library' : 'Create Library' }}</ui-btn>
</div>
</div>
</div> </div>
<modals-libraries-folder-chooser v-else :paths="folderPaths" @select="selectFolder" /> <modals-libraries-folder-chooser v-else :paths="folderPaths" @back="showDirectoryPicker = false" @select="selectFolder" />
<div v-if="!showDirectoryPicker">
<div class="flex items-center pt-2">
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="disableWatcher" />
<ui-toggle-switch v-else disabled :value="false" />
<p class="pl-4 text-lg">Disable folder watcher for library</p>
</div>
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*Watcher is disabled globally in server settings</p>
</div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
isNew: Boolean,
library: { library: {
type: Object, type: Object,
default: () => null default: () => null
@ -73,7 +53,6 @@ export default {
icon: '', icon: '',
folders: [], folders: [],
showDirectoryPicker: false, showDirectoryPicker: false,
disableWatcher: false,
newFolderPath: '', newFolderPath: '',
mediaType: null, mediaType: null,
mediaTypes: [ mediaTypes: [
@ -89,36 +68,54 @@ export default {
} }
}, },
computed: { computed: {
title() {
if (this.showDirectoryPicker) return 'Choose a Folder'
return ''
},
folderPaths() { folderPaths() {
return this.folders.map((f) => f.fullPath) return this.folders.map((f) => f.fullPath)
}, },
disableSubmit() {
if (!this.library) {
return false
}
var newfolderpaths = this.folderPaths.join(',')
var origfolderpaths = this.library.folders.map((f) => f.fullPath).join(',')
return newfolderpaths === origfolderpaths && this.name === this.library.name && this.provider === this.library.provider && this.disableWatcher === this.library.disableWatcher && this.icon === this.library.icon && !this.newFolderPath
},
providers() { providers() {
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
return this.$store.state.scanners.providers return this.$store.state.scanners.providers
},
globalWatcherDisabled() {
return this.$store.getters['getServerSetting']('scannerDisableWatcher')
} }
}, },
methods: { methods: {
getLibraryData() {
return {
name: this.name,
provider: this.provider,
folders: this.folders,
icon: this.icon,
mediaType: this.mediaType
}
},
formUpdated() {
this.$emit('update', this.getLibraryData())
},
newFolderInputBlurred() {
if (this.newFolderPath) {
this.folders.push({ fullPath: this.newFolderPath })
this.newFolderPath = ''
this.formUpdated()
}
},
iconChanged() {
this.formUpdated()
},
nameBlurred() {
if (this.name !== this.library.name) {
this.formUpdated()
}
},
changedMediaType() { changedMediaType() {
this.provider = this.providers[0].value this.provider = this.providers[0].value
this.formUpdated()
},
selectFolder(fullPath) {
this.folders.push({ fullPath })
this.showDirectoryPicker = false
this.formUpdated()
}, },
removeFolder(folder) { removeFolder(folder) {
this.folders = this.folders.filter((f) => f.fullPath !== folder.fullPath) this.folders = this.folders.filter((f) => f.fullPath !== folder.fullPath)
this.formUpdated()
}, },
backArrowPress() { backArrowPress() {
if (this.showDirectoryPicker) { if (this.showDirectoryPicker) {
@ -129,95 +126,9 @@ export default {
this.name = this.library ? this.library.name : '' this.name = this.library ? this.library.name : ''
this.provider = this.library ? this.library.provider : 'google' this.provider = this.library ? this.library.provider : 'google'
this.folders = this.library ? this.library.folders.map((p) => ({ ...p })) : [] this.folders = this.library ? this.library.folders.map((p) => ({ ...p })) : []
this.disableWatcher = this.library ? !!this.library.disableWatcher : false
this.icon = this.library ? this.library.icon : 'default' this.icon = this.library ? this.library.icon : 'default'
this.mediaType = this.library ? this.library.mediaType : 'book' this.mediaType = this.library ? this.library.mediaType : 'book'
this.showDirectoryPicker = false this.showDirectoryPicker = false
},
selectFolder(fullPath) {
this.folders.push({ fullPath })
this.showDirectoryPicker = false
},
submit() {
if (this.newFolderPath) {
this.folders.push({ fullPath: this.newFolderPath })
}
if (this.library) {
this.updateLibrary()
} else {
this.createLibrary()
}
},
updateLibrary() {
if (!this.name) {
this.$toast.error('Library must have a name')
return
}
if (!this.folders.length) {
this.$toast.error('Library must have at least 1 path')
return
}
var newLibraryPayload = {
name: this.name,
provider: this.provider,
folders: this.folders,
icon: this.icon,
disableWatcher: this.disableWatcher
}
this.$emit('update:processing', true)
this.$axios
.$patch(`/api/libraries/${this.library.id}`, newLibraryPayload)
.then((res) => {
this.$emit('update:processing', false)
this.$emit('close')
this.$toast.success(`Library "${res.name}" updated successfully`)
})
.catch((error) => {
console.error(error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
} else {
this.$toast.error('Failed to update library')
}
this.$emit('update:processing', false)
})
},
createLibrary() {
if (!this.name) {
this.$toast.error('Library must have a name')
return
}
if (!this.folders.length) {
this.$toast.error('Library must have at least 1 path')
return
}
var newLibraryPayload = {
name: this.name,
provider: this.provider,
folders: this.folders,
icon: this.icon,
mediaType: this.mediaType,
disableWatcher: this.disableWatcher
}
this.$emit('update:processing', true)
this.$axios
.$post('/api/libraries', newLibraryPayload)
.then((res) => {
this.$emit('update:processing', false)
this.$emit('close')
this.$toast.success(`Library "${res.name}" created successfully`)
})
.catch((error) => {
console.error(error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
} else {
this.$toast.error('Failed to create library')
}
this.$emit('update:processing', false)
})
} }
}, },
mounted() { mounted() {

View File

@ -5,8 +5,20 @@
<p class="font-book text-3xl text-white truncate">{{ title }}</p> <p class="font-book text-3xl text-white truncate">{{ title }}</p>
</div> </div>
</template> </template>
<div class="p-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh"> <div class="absolute -top-10 left-0 z-10 w-full flex">
<modals-libraries-edit-library v-if="show" :library="library" :processing.sync="processing" @close="show = false" /> <template v-for="tab in tabs">
<div :key="tab.id" class="w-28 rounded-t-lg flex items-center justify-center mr-1 cursor-pointer hover:bg-bg font-book border-t border-l border-r border-black-300 tab text-xs sm:text-base" :class="selectedTab === tab.id ? 'tab-selected bg-bg pb-px' : 'bg-primary text-gray-400'" @click="selectTab(tab.id)">{{ tab.title }}</div>
</template>
</div>
<div class="px-4 w-full text-sm pt-6 pb-20 rounded-b-lg rounded-tr-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh">
<component v-if="libraryCopy && show" :is="tabName" :is-new="!library" :library="libraryCopy" :processing.sync="processing" @update="updateLibrary" @close="show = false" />
<div class="absolute bottom-0 left-0 w-full px-4 py-4 border-t border-opacity-10">
<div class="flex justify-end">
<ui-btn @click="submit">{{ buttonText }}</ui-btn>
</div>
</div>
</div> </div>
</modals-modal> </modals-modal>
</template> </template>
@ -22,7 +34,21 @@ export default {
}, },
data() { data() {
return { return {
processing: false processing: false,
selectedTab: 'details',
tabs: [
{
id: 'details',
title: 'Details',
component: 'modals-libraries-edit-library'
},
{
id: 'settings',
title: 'Settings',
component: 'modals-libraries-library-settings'
}
],
libraryCopy: null
} }
}, },
computed: { computed: {
@ -36,10 +62,157 @@ export default {
}, },
title() { title() {
return this.library ? 'Update Library' : 'New Library' return this.library ? 'Update Library' : 'New Library'
},
buttonText() {
return this.library ? 'Update Library' : 'Create New Library'
},
tabName() {
var _tab = this.tabs.find((t) => t.id === this.selectedTab)
return _tab ? _tab.component : ''
}
},
watch: {
show: {
handler(newVal) {
if (newVal) this.init()
}
}
},
methods: {
selectTab(tab) {
this.selectedTab = tab
},
updateLibrary(library) {
this.mapLibraryToCopy(library)
},
getNewLibraryData() {
return {
name: '',
provider: 'google',
folders: [],
icon: 'database',
mediaType: 'book',
settings: {
disableWatcher: false
}
}
},
init() {
this.selectedTab = 'details'
this.libraryCopy = this.getNewLibraryData()
if (this.library) {
this.mapLibraryToCopy(this.library)
}
},
mapLibraryToCopy(library) {
for (const key in this.libraryCopy) {
if (library[key] !== undefined) {
if (key === 'folders') {
this.libraryCopy.folders = library.folders.map((f) => ({ ...f }))
} else if (key === 'settings') {
this.libraryCopy.settings = { ...library.settings }
} else {
this.libraryCopy[key] = library[key]
}
}
}
},
validate() {
if (!this.libraryCopy.name) {
this.$toast.error('Library must have a name')
return false
}
if (!this.libraryCopy.folders.length) {
this.$toast.error('Library must have at least 1 path')
return false
}
return true
},
submit() {
if (!this.validate()) return
if (this.library) {
this.submitUpdateLibrary()
} else {
this.submitCreateLibrary()
}
},
getLibraryUpdatePayload() {
var updatePayload = {}
for (const key in this.libraryCopy) {
if (key === 'folders') {
if (this.libraryCopy.folders.join(',') !== this.library.folders.join(',')) {
updatePayload.folders = [...this.libraryCopy.folders]
}
} else if (key === 'settings') {
for (const settingsKey in this.libraryCopy.settings) {
if (this.libraryCopy.settings[settingsKey] !== this.library.settings[settingsKey]) {
if (!updatePayload.settings) updatePayload.settings = {}
updatePayload.settings[settingsKey] = this.libraryCopy.settings[settingsKey]
}
}
} else if (key !== 'mediaType' && this.libraryCopy[key] !== this.library[key]) {
updatePayload[key] = this.libraryCopy[key]
}
}
return updatePayload
},
submitUpdateLibrary() {
var newLibraryPayload = this.getLibraryUpdatePayload()
if (!Object.keys(newLibraryPayload).length) {
this.$toast.info('No updates are necessary')
return
}
this.processing = true
this.$axios
.$patch(`/api/libraries/${this.library.id}`, newLibraryPayload)
.then((res) => {
this.processing = false
this.show = false
this.$toast.success(`Library "${res.name}" updated successfully`)
})
.catch((error) => {
console.error(error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
} else {
this.$toast.error('Failed to update library')
}
this.processing = false
})
},
submitCreateLibrary() {
this.processing = true
this.$axios
.$post('/api/libraries', this.libraryCopy)
.then((res) => {
this.processing = false
this.show = false
this.$toast.success(`Library "${res.name}" created successfully`)
})
.catch((error) => {
console.error(error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
} else {
this.$toast.error('Failed to create library')
}
this.processing = false
})
} }
}, },
methods: {},
mounted() {}, mounted() {},
beforeDestroy() {} beforeDestroy() {}
} }
</script> </script>
<style scoped>
.tab {
height: 40px;
}
.tab.tab-selected {
height: 41px;
}
</style>

View File

@ -1,10 +1,14 @@
<template> <template>
<div class="w-full h-full"> <div class="w-full h-full bg-bg absolute top-0 left-0 px-4 py-4 z-10">
<div class="flex items-center py-1 mb-2">
<span class="material-icons text-3xl cursor-pointer hover:text-gray-300" @click="$emit('back')">arrow_back</span>
<p class="px-4 text-xl">Choose a Folder</p>
</div>
<div v-if="allFolders.length" class="w-full bg-primary bg-opacity-70 py-1 px-4 mb-2"> <div v-if="allFolders.length" class="w-full bg-primary bg-opacity-70 py-1 px-4 mb-2">
<p class="font-mono truncate">{{ selectedPath || '\\' }}</p> <p class="font-mono truncate">{{ selectedPath || '\\' }}</p>
</div> </div>
<div v-if="allFolders.length" class="flex bg-primary bg-opacity-50 p-4"> <div v-if="allFolders.length" class="flex bg-primary bg-opacity-50 p-4 folder-container">
<div class="w-1/2 border-r border-bg"> <div class="w-1/2 border-r border-bg h-full overflow-y-auto">
<div v-if="level > 0" class="w-full p-1 cursor-pointer flex items-center" @click="goBack"> <div v-if="level > 0" class="w-full p-1 cursor-pointer flex items-center" @click="goBack">
<span class="material-icons bg-opacity-50 text-yellow-200" style="font-size: 1.2rem">folder</span> <span class="material-icons bg-opacity-50 text-yellow-200" style="font-size: 1.2rem">folder</span>
<p class="text-base font-mono px-2">..</p> <p class="text-base font-mono px-2">..</p>
@ -15,7 +19,7 @@
<span v-if="dir.dirs && dir.dirs.length && dir.path === selectedPath" class="material-icons" style="font-size: 1.1rem">arrow_right</span> <span v-if="dir.dirs && dir.dirs.length && dir.path === selectedPath" class="material-icons" style="font-size: 1.1rem">arrow_right</span>
</div> </div>
</div> </div>
<div class="w-1/2"> <div class="w-1/2 h-full overflow-y-auto">
<div v-for="dir in _subdirs" :key="dir.path" :class="dir.className" class="dir-item w-full p-1 cursor-pointer flex items-center hover:text-white text-gray-200" @click="selectSubDir(dir)"> <div v-for="dir in _subdirs" :key="dir.path" :class="dir.className" class="dir-item w-full p-1 cursor-pointer flex items-center hover:text-white text-gray-200" @click="selectSubDir(dir)">
<span class="material-icons bg-opacity-50 text-yellow-200" style="font-size: 1.2rem">folder</span> <span class="material-icons bg-opacity-50 text-yellow-200" style="font-size: 1.2rem">folder</span>
<p class="text-base font-mono px-2 truncate">{{ dir.dirname }}</p> <p class="text-base font-mono px-2 truncate">{{ dir.dirname }}</p>
@ -30,12 +34,8 @@
<p class="text-gray-300">Note: folders already mapped will not be shown</p> <p class="text-gray-300">Note: folders already mapped will not be shown</p>
</div> </div>
<div class="absolute bottom-0 left-0 w-full py-4 px-8"> <div class="w-full py-2">
<ui-btn :disabled="!selectedPath" color="primary" class="w-full mt-2" @click="selectFolder">Select Folder Path</ui-btn> <ui-btn :disabled="!selectedPath" color="primary" class="w-full mt-2" @click="selectFolder">Select Folder Path</ui-btn>
<!-- <div class="flex items-center">
<div class="flex-grow" />
<ui-btn color="success" @click="selectFolder">Select</ui-btn>
</div> -->
</div> </div>
</div> </div>
</template> </template>
@ -161,4 +161,9 @@ export default {
.dir-item.dir-used { .dir-item.dir-used {
background-color: rgba(255, 25, 0, 0.1); background-color: rgba(255, 25, 0, 0.1);
} }
.folder-container {
max-height: calc(100% - 130px);
height: calc(100% - 130px);
min-height: calc(100% - 130px);
}
</style> </style>

View File

@ -0,0 +1,63 @@
<template>
<div class="w-full h-full px-4 py-1 mb-4">
<div class="py-3">
<div class="flex items-center">
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="disableWatcher" @input="formUpdated" />
<ui-toggle-switch v-else disabled :value="false" />
<p class="pl-4 text-lg">Disable folder watcher for library</p>
</div>
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*Watcher is disabled globally in server settings</p>
</div>
</div>
</template>
<script>
export default {
props: {
library: {
type: Object,
default: () => null
},
processing: Boolean
},
data() {
return {
provider: null,
disableWatcher: false
}
},
computed: {
librarySettings() {
return this.library.settings || {}
},
globalWatcherDisabled() {
return this.$store.getters['getServerSetting']('scannerDisableWatcher')
},
mediaType() {
return this.library.mediaType
},
providers() {
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
return this.$store.state.scanners.providers
}
},
methods: {
getLibraryData() {
return {
settings: {
disableWatcher: !!this.disableWatcher
}
}
},
formUpdated() {
this.$emit('update', this.getLibraryData())
},
init() {
this.disableWatcher = !!this.librarySettings.disableWatcher
}
},
mounted() {
this.init()
}
}
</script>

View File

@ -40,8 +40,8 @@ export default {
showMenu: false, showMenu: false,
types: [ types: [
{ {
id: 'default', id: 'database',
name: 'Default' name: 'Database'
}, },
{ {
id: 'audiobook', id: 'audiobook',
@ -65,7 +65,7 @@ export default {
computed: { computed: {
selected: { selected: {
get() { get() {
return this.value || 'default' return this.value || 'database'
}, },
set(val) { set(val) {
this.$emit('input', val) this.$emit('input', val)
@ -75,7 +75,7 @@ export default {
return this.types.find((t) => t.id === this.selected) return this.types.find((t) => t.id === this.selected)
}, },
selectedName() { selectedName() {
return this.selectedItem ? this.selectedItem.name : 'Default' return this.selectedItem ? this.selectedItem.name : 'Database'
} }
}, },
methods: { methods: {

View File

@ -3,7 +3,7 @@
<p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''"> <p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">
{{ label }}<em v-if="note" class="font-normal text-xs pl-2">{{ note }}</em> {{ label }}<em v-if="note" class="font-normal text-xs pl-2">{{ note }}</em>
</p> </p>
<ui-text-input ref="input" v-model="inputValue" :disabled="disabled" :readonly="readonly" :type="type" class="w-full" /> <ui-text-input ref="input" v-model="inputValue" :disabled="disabled" :readonly="readonly" :type="type" class="w-full" @blur="inputBlurred" />
</div> </div>
</template> </template>
@ -38,6 +38,9 @@ export default {
if (this.$refs.input && this.$refs.input.blur) { if (this.$refs.input && this.$refs.input.blur) {
this.$refs.input.blur() this.$refs.input.blur()
} }
},
inputBlurred() {
this.$emit('blur')
} }
}, },
mounted() {} mounted() {}

View File

@ -9,7 +9,7 @@ const UserCollection = require('./objects/UserCollection')
const Library = require('./objects/Library') const Library = require('./objects/Library')
const Author = require('./objects/entities/Author') const Author = require('./objects/entities/Author')
const Series = require('./objects/entities/Series') const Series = require('./objects/entities/Series')
const ServerSettings = require('./objects/ServerSettings') const ServerSettings = require('./objects/settings/ServerSettings')
const PlaybackSession = require('./objects/PlaybackSession') const PlaybackSession = require('./objects/PlaybackSession')
class Db { class Db {

View File

@ -69,19 +69,19 @@ class FolderWatcher extends EventEmitter {
initWatcher(libraries) { initWatcher(libraries) {
libraries.forEach((lib) => { libraries.forEach((lib) => {
if (!lib.disableWatcher) { if (!lib.settings.disableWatcher) {
this.buildLibraryWatcher(lib) this.buildLibraryWatcher(lib)
} }
}) })
} }
addLibrary(library) { addLibrary(library) {
if (this.disabled || library.disableWatcher) return if (this.disabled || library.settings.disableWatcher) return
this.buildLibraryWatcher(library) this.buildLibraryWatcher(library)
} }
updateLibrary(library) { updateLibrary(library) {
if (this.disabled || library.disableWatcher) return if (this.disabled || library.settings.disableWatcher) return
var libwatcher = this.libraryWatchers.find(lib => lib.id === library.id) var libwatcher = this.libraryWatchers.find(lib => lib.id === library.id)
if (libwatcher) { if (libwatcher) {
libwatcher.name = library.name libwatcher.name = library.name

View File

@ -1,4 +1,5 @@
const Folder = require('./Folder') const Folder = require('./Folder')
const LibrarySettings = require('./settings/LibrarySettings')
const { getId } = require('../utils/index') const { getId } = require('../utils/index')
class Library { class Library {
@ -10,9 +11,9 @@ class Library {
this.icon = 'database' // database, podcast, book, audiobook, comic this.icon = 'database' // database, podcast, book, audiobook, comic
this.mediaType = 'book' // book, podcast this.mediaType = 'book' // book, podcast
this.provider = 'google' this.provider = 'google'
this.disableWatcher = false
this.lastScan = 0 this.lastScan = 0
this.settings = null
this.createdAt = null this.createdAt = null
this.lastUpdate = null this.lastUpdate = null
@ -34,7 +35,11 @@ class Library {
this.icon = library.icon || 'database' this.icon = library.icon || 'database'
this.mediaType = library.mediaType this.mediaType = library.mediaType
this.provider = library.provider || 'google' this.provider = library.provider || 'google'
this.disableWatcher = !!library.disableWatcher
this.settings = new LibrarySettings(library.settings)
if (library.settings === undefined) { // LibrarySettings added in v2, migrate settings
this.settings.disableWatcher = !!library.disableWatcher
}
this.createdAt = library.createdAt this.createdAt = library.createdAt
this.lastUpdate = library.lastUpdate this.lastUpdate = library.lastUpdate
@ -62,7 +67,7 @@ class Library {
icon: this.icon, icon: this.icon,
mediaType: this.mediaType, mediaType: this.mediaType,
provider: this.provider, provider: this.provider,
disableWatcher: this.disableWatcher, settings: this.settings.toJSON(),
createdAt: this.createdAt, createdAt: this.createdAt,
lastUpdate: this.lastUpdate lastUpdate: this.lastUpdate
} }
@ -89,7 +94,7 @@ class Library {
this.icon = data.icon || 'database' this.icon = data.icon || 'database'
this.mediaType = data.mediaType || 'book' this.mediaType = data.mediaType || 'book'
this.provider = data.provider || 'google' this.provider = data.provider || 'google'
this.disableWatcher = !!data.disableWatcher this.settings = new LibrarySettings(data.settings)
this.createdAt = Date.now() this.createdAt = Date.now()
this.lastUpdate = Date.now() this.lastUpdate = Date.now()
} }
@ -105,10 +110,10 @@ class Library {
} }
}) })
if (payload.disableWatcher !== this.disableWatcher) { if (payload.settings && this.settings.update(payload.settings)) {
this.disableWatcher = !!payload.disableWatcher
hasUpdates = true hasUpdates = true
} }
if (!isNaN(payload.displayOrder) && payload.displayOrder !== this.displayOrder) { if (!isNaN(payload.displayOrder) && payload.displayOrder !== this.displayOrder) {
this.displayOrder = Number(payload.displayOrder) this.displayOrder = Number(payload.displayOrder)
hasUpdates = true hasUpdates = true

View File

@ -0,0 +1,34 @@
const { BookCoverAspectRatio } = require('../../utils/constants')
const Logger = require('../../Logger')
class LibrarySettings {
constructor(settings) {
this.disableWatcher = false
if (settings) {
this.construct(settings)
}
}
construct(settings) {
this.disableWatcher = !!settings.disableWatcher
}
toJSON() {
return {
disableWatcher: this.disableWatcher
}
}
update(payload) {
var hasUpdates = false
for (const key in payload) {
if (this[key] !== payload[key]) {
this[key] = payload[key]
hasUpdates = true
}
}
return hasUpdates
}
}
module.exports = LibrarySettings

View File

@ -1,5 +1,5 @@
const { BookCoverAspectRatio, BookshelfView } = require('../utils/constants') const { BookCoverAspectRatio, BookshelfView } = require('../../utils/constants')
const Logger = require('../Logger') const Logger = require('../../Logger')
class ServerSettings { class ServerSettings {
constructor(settings) { constructor(settings) {