@@ -25,6 +25,11 @@ export default {
},
computed: {},
methods: {
+ checkBlurExpressionInput() {
+ // returns true if advanced cron input is focused
+ if (!this.$refs.cronExpressionBuilder) return false
+ return this.$refs.cronExpressionBuilder.checkBlurExpressionInput()
+ },
toggleEnableAutoScan(v) {
if (!v) this.updatedCron(null)
else if (!this.cronExpression) {
diff --git a/client/components/ui/TextInput.vue b/client/components/ui/TextInput.vue
index 7943e288..5ae15663 100644
--- a/client/components/ui/TextInput.vue
+++ b/client/components/ui/TextInput.vue
@@ -36,7 +36,8 @@ export default {
data() {
return {
showPassword: false,
- isHovering: false
+ isHovering: false,
+ isFocused: false
}
},
computed: {
@@ -66,9 +67,11 @@ export default {
this.inputValue = ''
},
focused() {
+ this.isFocused = true
this.$emit('focus')
},
blurred() {
+ this.isFocused = false
this.$emit('blur')
},
change(e) {
diff --git a/client/components/widgets/CronExpressionBuilder.vue b/client/components/widgets/CronExpressionBuilder.vue
index 3e3f261b..31cb4761 100644
--- a/client/components/widgets/CronExpressionBuilder.vue
+++ b/client/components/widgets/CronExpressionBuilder.vue
@@ -24,7 +24,7 @@
Cron Expression
-
+
@@ -127,6 +127,14 @@ export default {
}
},
methods: {
+ checkBlurExpressionInput() {
+ if (!this.showAdvancedView || !this.$refs.customExpressionInput) return false
+ if (this.$refs.customExpressionInput.isFocused) {
+ this.$refs.customExpressionInput.blur()
+ return true
+ }
+ return false
+ },
updateCron() {
if (!this.minuteIsValid || !this.hourIsValid || !this.selectedWeekdays.length) {
this.cronExpression = null
@@ -168,11 +176,12 @@ export default {
this.customCronError = 'Invalid cron expression'
this.isValid = false
return
- } else if (this.customCronExpression.split(' ')[0] === '*') {
- this.customCronError = 'Cannot use * in minutes position'
- this.isValid = false
- return
}
+ // if (this.customCronExpression.split(' ')[0] === '*') {
+ // this.customCronError = 'Cannot use * in minutes position'
+ // this.isValid = false
+ // return
+ // }
if (this.customCronExpression !== this.cronExpression) {
this.selectedWeekdays = []
diff --git a/server/Server.js b/server/Server.js
index ac06ea26..ec11c30c 100644
--- a/server/Server.js
+++ b/server/Server.js
@@ -32,6 +32,7 @@ const PlaybackSessionManager = require('./managers/PlaybackSessionManager')
const PodcastManager = require('./managers/PodcastManager')
const AudioMetadataMangaer = require('./managers/AudioMetadataManager')
const RssFeedManager = require('./managers/RssFeedManager')
+const CronManager = require('./managers/CronManager')
class Server {
constructor(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH) {
@@ -74,9 +75,10 @@ class Server {
this.rssFeedManager = new RssFeedManager(this.db, this.emitter.bind(this))
this.scanner = new Scanner(this.db, this.coverManager, this.emitter.bind(this))
+ this.cronManager = new CronManager(this.db, this.scanner)
// Routers
- this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.abMergeManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.audioMetadataManager, this.rssFeedManager, this.emitter.bind(this), this.clientEmitter.bind(this))
+ this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.abMergeManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.audioMetadataManager, this.rssFeedManager, this.cronManager, this.emitter.bind(this), this.clientEmitter.bind(this))
this.hlsRouter = new HlsRouter(this.db, this.auth, this.playbackSessionManager, this.emitter.bind(this))
this.staticRouter = new StaticRouter(this.db)
@@ -151,6 +153,7 @@ class Server {
await this.logManager.init()
await this.rssFeedManager.init()
this.podcastManager.init()
+ this.cronManager.init()
if (this.db.serverSettings.scannerDisableWatcher) {
Logger.info(`[Server] Watcher is disabled`)
diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js
index 2e27dfa6..d9e30130 100644
--- a/server/controllers/LibraryController.js
+++ b/server/controllers/LibraryController.js
@@ -108,6 +108,9 @@ class LibraryController {
// Update watcher
this.watcher.updateLibrary(library)
+ // Update auto scan cron
+ this.cronManager.updateLibraryScanCron(library)
+
// Remove libraryItems no longer in library
var itemsToRemove = this.db.libraryItems.filter(li => li.libraryId === library.id && !library.checkFullPathInLibrary(li.path))
if (itemsToRemove.length) {
diff --git a/server/libs/nodeCron/scheduler.js b/server/libs/nodeCron/scheduler.js
index 72febb4f..171d3844 100644
--- a/server/libs/nodeCron/scheduler.js
+++ b/server/libs/nodeCron/scheduler.js
@@ -3,14 +3,14 @@
const EventEmitter = require('events');
const TimeMatcher = require('./time-matcher');
-class Scheduler extends EventEmitter{
- constructor(pattern, timezone, autorecover){
+class Scheduler extends EventEmitter {
+ constructor(pattern, timezone, autorecover) {
super();
this.timeMatcher = new TimeMatcher(pattern, timezone);
this.autorecover = autorecover;
}
- start(){
+ start() {
// clear timeout if exists
this.stop();
@@ -22,11 +22,11 @@ class Scheduler extends EventEmitter{
const elapsedTime = process.hrtime(lastCheck);
const elapsedMs = (elapsedTime[0] * 1e9 + elapsedTime[1]) / 1e6;
const missedExecutions = Math.floor(elapsedMs / 1000);
-
- for(let i = missedExecutions; i >= 0; i--){
+
+ for (let i = missedExecutions; i >= 0; i--) {
const date = new Date(new Date().getTime() - i * 1000);
let date_tmp = this.timeMatcher.apply(date);
- if(lastExecution.getTime() < date_tmp.getTime() && (i === 0 || this.autorecover) && this.timeMatcher.match(date)){
+ if (lastExecution.getTime() < date_tmp.getTime() && (i === 0 || this.autorecover) && this.timeMatcher.match(date)) {
this.emit('scheduled-time-matched', date_tmp);
date_tmp.setMilliseconds(0);
lastExecution = date_tmp;
@@ -38,8 +38,8 @@ class Scheduler extends EventEmitter{
matchTime();
}
- stop(){
- if(this.timeout){
+ stop() {
+ if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = null;
diff --git a/server/managers/BackupManager.js b/server/managers/BackupManager.js
index 1a6288ea..e56aa95c 100644
--- a/server/managers/BackupManager.js
+++ b/server/managers/BackupManager.js
@@ -56,14 +56,14 @@ class BackupManager {
updateCronSchedule() {
if (this.scheduleTask && !this.serverSettings.backupSchedule) {
Logger.info(`[BackupManager] Disabling backup schedule`)
- if (this.scheduleTask.destroy) this.scheduleTask.destroy()
+ if (this.scheduleTask.stop) this.scheduleTask.stop()
this.scheduleTask = null
} else if (!this.scheduleTask && this.serverSettings.backupSchedule) {
Logger.info(`[BackupManager] Starting backup schedule ${this.serverSettings.backupSchedule}`)
this.scheduleCron()
} else if (this.serverSettings.backupSchedule) {
Logger.info(`[BackupManager] Restarting backup schedule ${this.serverSettings.backupSchedule}`)
- if (this.scheduleTask.destroy) this.scheduleTask.destroy()
+ if (this.scheduleTask.stop) this.scheduleTask.stop()
this.scheduleCron()
}
}
diff --git a/server/managers/CronManager.js b/server/managers/CronManager.js
new file mode 100644
index 00000000..66166588
--- /dev/null
+++ b/server/managers/CronManager.js
@@ -0,0 +1,61 @@
+const cron = require('../libs/nodeCron')
+const Logger = require('../Logger')
+
+class CronManager {
+ constructor(db, scanner) {
+ this.db = db
+ this.scanner = scanner
+
+ this.libraryScanCrons = []
+ }
+
+ init() {
+ this.initLibraryScanCrons()
+ }
+
+ initLibraryScanCrons() {
+ for (const library of this.db.libraries) {
+ if (library.settings.autoScanCronExpression) {
+ this.startCronForLibrary(library)
+ }
+ }
+ }
+
+ startCronForLibrary(library) {
+ Logger.debug(`[CronManager] Init library scan cron for ${library.name} on schedule ${library.settings.autoScanCronExpression}`)
+ const libScanCron = cron.schedule(library.settings.autoScanCronExpression, () => {
+ Logger.debug(`[CronManager] Library scan cron executing for ${library.name}`)
+ this.scanner.scan(library)
+ })
+ this.libraryScanCrons.push({
+ libraryId: library.id,
+ expression: library.settings.autoScanCronExpression,
+ task: libScanCron
+ })
+ }
+
+ removeCronForLibrary(library) {
+ Logger.debug(`[CronManager] Removing library scan cron for ${library.name}`)
+ this.libraryScanCrons = this.libraryScanCrons.filter(lsc => lsc.libraryId !== library.id)
+ }
+
+ updateLibraryScanCron(library) {
+ const expression = library.settings.autoScanCronExpression
+ const existingCron = this.libraryScanCrons.find(lsc => lsc.libraryId === library.id)
+
+ if (!expression && existingCron) {
+ if (existingCron.task.stop) existingCron.task.stop()
+
+ this.removeCronForLibrary(library)
+ } else if (!existingCron && expression) {
+ this.startCronForLibrary(library)
+ } else if (existingCron && existingCron.expression !== expression) {
+ if (existingCron.task.stop) existingCron.task.stop()
+
+ this.removeCronForLibrary(library)
+ this.startCronForLibrary(library)
+ }
+ }
+
+}
+module.exports = CronManager
\ No newline at end of file
diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js
index e4139fb8..2ac09cef 100644
--- a/server/routers/ApiRouter.js
+++ b/server/routers/ApiRouter.js
@@ -25,7 +25,7 @@ const Series = require('../objects/entities/Series')
const FileSystemController = require('../controllers/FileSystemController')
class ApiRouter {
- constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, rssFeedManager, emitter, clientEmitter) {
+ constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, rssFeedManager, cronManager, emitter, clientEmitter) {
this.db = db
this.auth = auth
this.scanner = scanner
@@ -38,6 +38,7 @@ class ApiRouter {
this.podcastManager = podcastManager
this.audioMetadataManager = audioMetadataManager
this.rssFeedManager = rssFeedManager
+ this.cronManager = cronManager
this.emitter = emitter
this.clientEmitter = clientEmitter