From e4ad465eb0b9d56cf94a662c021a184906533cf7 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sun, 6 Dec 2020 19:09:06 +0300 Subject: [PATCH] migrated .makePreviews(..) to queue + minor tweaks and fixes... Signed-off-by: Alex A. Naanou --- Viewer/features/core.js | 1 - Viewer/features/sharp.js | 194 +++++++++++++-------------------- Viewer/features/ui-progress.js | 39 +++++-- 3 files changed, 104 insertions(+), 130 deletions(-) diff --git a/Viewer/features/core.js b/Viewer/features/core.js index a5d306b5..a1f8bcfc 100755 --- a/Viewer/features/core.js +++ b/Viewer/features/core.js @@ -2867,7 +2867,6 @@ var TaskActions = actions.Actions({ this.logger && this.logger.emit('skipped'+suffix, t, err) }) .on('stop', function(){ this.logger - && suffix != '' && this.logger.emit('reset') this.clear() }) // cleanup... diff --git a/Viewer/features/sharp.js b/Viewer/features/sharp.js index 949a9e79..75bc2c76 100755 --- a/Viewer/features/sharp.js +++ b/Viewer/features/sharp.js @@ -185,6 +185,8 @@ var SharpActions = actions.Actions({ // from filesystem.IndexFormat... }, + // XXX either make this a session task or make this survive loading + // a new index... // XXX revise return values... // XXX make backup name pattern configurable... // XXX CROP ready for crop support... @@ -251,7 +253,7 @@ var SharpActions = actions.Actions({ throw new Error('.makeResizedImage(..): ' +'need at least: images, size and path.') } return [ - (!images || images == 'all') ? + (images == null || images == 'all') ? this.data.getImages('all') : images == 'current' ? [this.current] @@ -319,7 +321,10 @@ var SharpActions = actions.Actions({ this.location.path, pathlib.join( path, - this.formatImageName(name, image, data || {}))) + // if name is not a pattern do not re-format it... + name.includes('%') ? + this.formatImageName(name, image, data || {}) + : name)) var img = sharp(source) return (skipSmaller ? @@ -385,7 +390,8 @@ var SharpActions = actions.Actions({ // XXX what should we return??? return to }) }) }) })], - // XXX move to core.queue... + // XXX either make this a session task or make this survive loading + // a new index... // XXX should this use .makeResizedImage(..) in sync mode??? // ...would be interesting to try a nested queue... // XXX this does not update image.base_path -- is this correct??? @@ -417,129 +423,79 @@ var SharpActions = actions.Actions({ NOTE: if base_path is given .images will not be updated with new preview paths... `, - core.taskAction('makePreviews', function(ticket, images, sizes, base_path, logger){ - var that = this + core.queueHandler('Make image previews', + function(queue, images, ...args){ + // get/normalize images... + return [ + (images == null || images == 'all') ? + this.data.getImages('all') + : images == 'current' ? + [this.current] + : images instanceof Array ? + images + : [images], + ...args, + ] }, + function(gid, sizes, base_path, logger){ + var that = this - // setup runtime interactions... - // - // NOTE: we will resolve the ticket when we are fully done - // and not on stop... - var STOP = false - ticket - .onmessage('stop', function(){ - STOP = true }) - .then(function(){ - // close progress bar... - // NOTE: if we have multiple tasks let the last one - // close the progress bar... - if(that.tasks.titled(ticket.title).length == 0){ - gid_logger - && gid_logger.emit('close') - logger - && logger.emit('close') } - // cleanup... - delete that.__cache_metadata_reading }) - var abort = function(){ - that.tasks.stop(ticket.title) } + var logger_mode = this.config['preview-progress-mode'] || 'gids' - var CHUNK_SIZE = 4 + // get/normalize sizes.... + var cfg_sizes = this.config['preview-sizes'].slice() || [] + cfg_sizes + .sort() + .reverse() + // XXX revise... + if(sizes){ + sizes = sizes instanceof Array ? sizes : [sizes] + // normalize to preview size... + sizes = (this.config['preview-normalized'] ? + sizes + .map(function(s){ + return cfg_sizes.filter(function(c){ return c >= s }).pop() || s }) + : sizes) + .unique() + } else { + sizes = cfg_sizes } - var logger_mode = this.config['preview-progress-mode'] || 'gids' - logger = logger !== false ? - (logger || this.logger) - : false - var gid_logger = logger - && logger.push('Images', - {onclose: abort}) - logger = logger - && logger.push('Previews', - {onclose: abort}) + var path_tpl = that.config['preview-path-template'] + .replace(/\$INDEX|\$\{INDEX\}/g, this.config['index-dir'] || '.ImageGrid') - // get/normalize images... - images = images - || 'all' - // keywords... - images = images == 'all' ? - this.data.getImages('all') - : images == 'current' ? - this.current - : images - images = images instanceof Array ? - images - : [images] - // get/normalize sizes.... - var cfg_sizes = this.config['preview-sizes'].slice() || [] - cfg_sizes - .sort() - .reverse() - // XXX revise... - if(sizes){ - sizes = sizes instanceof Array ? sizes : [sizes] - // normalize to preview size... - sizes = (this.config['preview-normalized'] ? - sizes - .map(function(s){ - return cfg_sizes.filter(function(c){ return c >= s }).pop() || s }) - : sizes) - .unique() - } else { - sizes = cfg_sizes } + var img = this.images[gid] + var base = base_path + || img.base_path + || this.location.path - var path_tpl = that.config['preview-path-template'] - .replace(/\$INDEX|\$\{INDEX\}/g, that.config['index-dir'] || '.ImageGrid') + return sizes + .map(function(size, i){ + var name = path = path_tpl + .replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, parseInt(size)) + .replace(/\$GID|\$\{GID\}/g, gid) + .replace(/\$NAME|\$\{NAME\}/g, img.name) + // XXX do we need this to be sync??? + return that.makeResizedImage('sync', gid, size, base, { + name, + skipSmaller: true, + transform: false, + logger: logger_mode == 'gids' ? + false + : logger, + }) + // XXX handle errors -- rejected because image exists... + .then(function(res){ + // did not create a preview... + if(!res){ + return false } - gid_logger && gid_logger.emit('queued', images) + // update metadata... + if(!base_path){ + var preview = img.preview = img.preview || {} + preview[parseInt(size) + 'px'] = name + that.markChanged + && that.markChanged('images', [gid]) } - return images - .mapChunks(CHUNK_SIZE, function(gid){ - if(STOP){ - throw Array.STOP('aborted') } - - var img = that.images[gid] - var base = base_path - || img.base_path - || that.location.path - - return sizes - .map(function(size, i){ - if(STOP){ - throw Array.STOP('aborted') } - - var name = path = path_tpl - .replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, parseInt(size)) - .replace(/\$GID|\$\{GID\}/g, gid) - .replace(/\$NAME|\$\{NAME\}/g, img.name) - // XXX do we need this to be sync??? - return that.makeResizedImage('sync', gid, size, base, { - name, - skipSmaller: true, - transform: false, - logger: logger_mode == 'gids' ? - false - : logger, - }) - // XXX handle errors -- rejected because image exists... - .then(function(res){ - i == sizes.length-1 - && gid_logger && gid_logger.emit('done', gid) - - // did not create a preview... - if(!res){ - return false } - - // update metadata... - if(!base_path){ - var preview = img.preview = img.preview || {} - preview[parseInt(size) + 'px'] = name - that.markChanged - && that.markChanged('images', [gid]) } - - return [gid, size, name] }) }) }) - .then(function(res){ - ticket.resolve(res) - return res == 'aborted' ? - Promise.reject('aborted') - : res.flat() }) })], + return [gid, size, name] }) }) })], // XXX add support for offloading the processing to a thread/worker... // XXX revise logging and logger passing... diff --git a/Viewer/features/ui-progress.js b/Viewer/features/ui-progress.js index 76f5a891..dfc7c8b1 100755 --- a/Viewer/features/ui-progress.js +++ b/Viewer/features/ui-progress.js @@ -123,6 +123,9 @@ var ProgressActions = actions.Actions({ - max is greater than 1, or - it did not close before .config['progress-pre-delay'] ms of start This is done to avoid spamming the user with single point progress bars. + + + NOTE: to force show the progress bar set attrs.forceShow to true. `, function(text, value, max, attrs){ var that = this @@ -130,14 +133,23 @@ var ProgressActions = actions.Actions({ // get attrs... var args = [...arguments] - attrs = args.slice(1).last() instanceof Object ? + attrs = args.last() instanceof Object ? args.pop() : null + var forceShow = !!(attrs || {}).forceShow ;[text, value, max] = args var msg = text instanceof Array ? text.slice(1).join(': ') : null text = text instanceof Array ? text[0] : text + // reset -- clear cache and set everything to 0... + // NOTE: we will later draw the progress bar full... + var reset = value == 'reset' + if(reset){ + delete (this.__progress_cache || {})[text] + value = 0 + max = 0 } + // cache -- make sure we do not update too often... if(value != 'close'){ var cache = (this.__progress_cache = this.__progress_cache || {}) @@ -249,21 +261,28 @@ var ProgressActions = actions.Actions({ // format the message... msg = msg ? ': '+msg : '' msg = ' '+ msg - + (value && value >= (max || 0) ? ' (done)' - : max && value != max ? ' ('+ (value || 0) +' of '+ max +')' + + (value && value >= (max || 0) ? + ' (done)' + : max && value != max ? + ' ('+ (value || 0) +' of '+ max +')' : '...') // update widget... - widget.find('progress') - .attr({ - value: value || '', - max: max || '', - }) + reset ? + // NOTE: on reset we show the progress bar full... + widget.find('progress') + .attr({ value: 1, max: 1 }) + : widget.find('progress') + .attr({ + value: (value || ''), + max: (max || ''), + }) widget.find('.progress-details') .text(msg) // auto-show... - if(max > 1 + if(forceShow + || max > 1 || !this.config['progress-pre-delay']){ widget.css({display: ''}) } else { @@ -316,7 +335,7 @@ var ProgressActions = actions.Actions({ this.showProgress(path, 'close', attrs) // reset... } else if(status == 'reset' || reset.has(status)){ - this.showProgress(path, 0, 0, attrs) + this.showProgress(path, 'reset', attrs) // added new item -- increase max... // XXX show msg in the progress bar??? } else if(status == 'add' || add.has(status)){