Merge branch 'master' of github.com:flynx/ImageGrid

This commit is contained in:
Alex A. Naanou 2019-10-02 02:55:55 +03:00
commit c09b055ee5
8 changed files with 441 additions and 93 deletions

View File

@ -1,5 +1,18 @@
sync-flash.sh
Syncs a camera flash card to an archive folder.
Dependencies:
- process-archive.sh
- compress-archive.sh (optional)
- bash
For more info see:
sync-flash.sh --help
process-archive.sh
Processes and prepares the archive folder for viewing.
Processes and prepares the archive folder for viewing via
ImageGrid.Viewer.
Dependencies:
- exiftool
@ -9,17 +22,19 @@ process-archive.sh
XXX add self dependency check...
process-archive.bat -- windows version of process-archive.sh (partial)
For more info see:
process-archive.sh --help
sync-flash.sh
Syncs a camera flash card to an archive folder.
compress-archive.sh
compresses raw files.
By default this will NTFS compress sony ARW files, but other
compression methods and raw formats are supported...
For more info see:
compress-archive.sh --help
Dependencies:
- process-archive.sh
- bash
update-exif.sh
Updates processed preview metadata from appropriate .PSD files.
@ -27,6 +42,12 @@ update-exif.sh
Dependencies:
- exiv2 (to be deprecated)
For more info see:
update-exif.sh --help
---
flatten.sh
Flatten flickr/instagram favorite folder structure created by
@ -34,11 +55,13 @@ flatten.sh
./<author>/<filename> -> ./ALL/<author> - <filename>
vips-tn.sh
cleannwcache.bat
extract-metadata.sh
process-archive.bat -- windows version of process-archive.sh (partial)

View File

@ -29,11 +29,11 @@ printhelp(){
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
echo " -bz -bzip2 - use bzip2 to compress (default)."
echo " -gz -gzip - use gzip to compress."
echo " -c -compact - use ntfs compression."
echo " -bz -bzip2 - use bzip2 to compress`[[ $ARCH == $ARCH_BZIP2 ]] && echo " (default)" || echo ""`."
echo " -gz -gzip - use gzip to compress`[[ $ARCH == $ARCH_GZIP ]] && echo " (default)" || echo ""`."
echo " -c -compact - use ntfs compression`[[ $ARCH == $ARCH_NTFS ]] && echo " (default)" || echo ""`."
echo
echo " -ext EXT - set file extension to compress (default: ARW)"
echo " -ext EXT - set file extension to compress (default: ${EXT})"
echo " NOTE: only one -ext is supported now".
echo
}

View File

@ -5,7 +5,8 @@ COUNT=1
TITLE=""
RSYNC=rsync
RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable"
#RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable"
RSYNCFLAGS="-arpt --info=progress2,flist --human-readable"
CP=cp
CPFLAGS=-Rpfv
@ -14,6 +15,10 @@ CPFLAGS=-Rpfv
COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS
COMPRESSOR=./compress-archive.sh
COMPRESS=1
# base mount dir...
# systems with /mnt
if [ -d /mnt ] ; then
@ -40,10 +45,20 @@ while true ; do
echo " single shoot."
echo " -l|-last last flash card in set, run"
echo " process-archive.sh after copying."
echo " -b|-base the base dir to look for drives in"
echo " -b|-base BASE the base dir to look for drives in"
echo " default: $BASE"
echo " --rsync use rsync (default)"
echo " --cp use cp"
if ! [ -z $COMPRESSOR ] ; then
echo " --compress toggle archive compression"
echo " default: `[[ $COMPRESS ]] && echo "on" || echo "off"`"
fi
# notes...
echo
if ! [ -z $COMPRESSOR ] ; then
echo "NOTE: the index is fully usable during the compression stage"
fi
echo "NOTE: cp under Cygwin may messup permissions, use rsync."
echo
exit
;;
@ -61,17 +76,24 @@ while true ; do
shift
;;
-b|-base|--base)
BASE=1
shift
BASE=$2
shift 2
;;
-cp|--cp)
COPY=cp
COPYFLAGS=-Rpfv
shift
break
;;
-rsync|--rsync)
COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS
shift
break
;;
-compress|--compress)
COMPRESS=`[[ $COMPRESS ]] && echo "" || echo 1`
shift
break
;;
*)
@ -99,7 +121,12 @@ while true ; do
echo "Enter) copy drive ${DRIVE}"
fi
echo "2) build."
echo "3) quit."
if ! [ -z $COMPRESSOR ] ; then
echo "3) compresion is `[[ $COMPRESS ]] && echo "on" || echo "off"`"
echo "4) quit."
else
echo "3) quit."
fi
read -p ": " RES
case $RES in
@ -126,8 +153,15 @@ while true ; do
LAST=1
break
;;
3)
if ! [ -z $COMPRESSOR ] ; then
COMPRESS=`[[ ! $COMPRESS ]] && echo 1 || echo ""`
else
exit
fi
continue
;;
4)
exit
;;
@ -138,6 +172,17 @@ while true ; do
esac
fi
# sanity check...
if ! [ -e "${BASE}/${DRIVE}" ] ; then
echo
echo "ERR: ${BASE}/${DRIVE}: does not exist, nothing to copy."
echo
if [[ $INTERACTIVE || ! $DRIVE ]] ; then
continue
fi
exit
fi
# XXX do a real three digit count...
# single flash card...
SCOUNT=`printf "%03d" $COUNT`
@ -166,7 +211,7 @@ while true ; do
mkdir -vp "$DIR"
echo "Copying files from ${BASE}/${DRIVE}..."
echo "Copying files from ${BASE}/${DRIVE} (`du -hs "${BASE}/${DRIVE}" | cut -f 1`)..."
$COPY $COPYFLAGS ${BASE}/${DRIVE}/* "$DIR"
echo "Copying files: done."
@ -187,4 +232,13 @@ if [[ ! $MULTI || $LAST ]] ; then
echo "Building archive: done."
fi
if [[ $COMPRESS ]] ; then
echo "Compressing archive..."
${COMPRESSOR} "$BASE_DIR"
echo "Compressing archive: done."
fi
echo "`basename "$0"`: done."
# vim:set nowrap :

View File

@ -1,7 +1,32 @@
#!/bin/bash
DIR=`pwd`
printhelp(){
echo "Usage: `basename $0` [ARGUMENTS] [PATH]"
echo
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
}
while true ; do
case $1 in
-h|--help)
printhelp
exit
;;
*)
break
;;
esac
done
exifup(){
PREVIEW_DIR=$1

View File

@ -0,0 +1,92 @@
#!/bin/bash
# TODO make this runnable from anywhere...
# - prepend paths with './' only if local/relative
BASE_PATH=.
ARCH_BZIP2='bzip2 -v {}'
ARCH_GZIP='gzip -v {}'
# XXX should we cygpath -w all the inputs???
ARCH_NTFS='compact /c /exe:lzx {}'
# default...
ARCH=$ARCH_NTFS
EXT=ARW
# HACK: this is here to avoid using windows find...
PATH=/bin:$PATH
printhelp(){
echo "Usage: `basename $0` [ARGUMENTS] [PATH]"
echo
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
echo " -bz -bzip2 - use bzip2 to compress`[[ $ARCH == $ARCH_BZIP2 ]] && echo " (default)" || echo ""`."
echo " -gz -gzip - use gzip to compress`[[ $ARCH == $ARCH_GZIP ]] && echo " (default)" || echo ""`."
echo " -c -compact - use ntfs compression`[[ $ARCH == $ARCH_NTFS ]] && echo " (default)" || echo ""`."
echo
echo " -ext EXT - set file extension to compress (default: ${EXT})"
echo " NOTE: only one -ext is supported now".
echo
}
# process args...
while true ; do
case $1 in
-h|--help)
printhelp
exit
;;
# archivers...
-bz|--bzip2)
ARCH=$ARCH_BZIP2
shift
;;
-gz|--gzip)
ARCH=$ARCH_GZIP
shift
;;
-c|--compact)
ARCH=$ARCH_NTFS
shift
;;
# extension to compress...
--ext)
EXT=$2
shift
shift
;;
*)
break
;;
esac
done
# get path...
if [ "$1" ] ; then
BASE_PATH=$1
fi
# do the work...
find "$BASE_PATH" -name \*.${EXT} -exec ${ARCH} \;
echo done.
# vim:set nowrap nospell :

View File

@ -5,7 +5,8 @@ COUNT=1
TITLE=""
RSYNC=rsync
RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable"
#RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable"
RSYNCFLAGS="-arpt --info=progress2,flist --human-readable"
CP=cp
CPFLAGS=-Rpfv
@ -14,6 +15,10 @@ CPFLAGS=-Rpfv
COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS
COMPRESSOR=./compress-archive.sh
COMPRESS=1
# base mount dir...
# systems with /mnt
if [ -d /mnt ] ; then
@ -40,10 +45,20 @@ while true ; do
echo " single shoot."
echo " -l|-last last flash card in set, run"
echo " process-archive.sh after copying."
echo " -b|-base the base dir to look for drives in"
echo " -b|-base BASE the base dir to look for drives in"
echo " default: $BASE"
echo " --rsync use rsync (default)"
echo " --cp use cp"
if ! [ -z $COMPRESSOR ] ; then
echo " --compress toggle archive compression"
echo " default: `[[ $COMPRESS ]] && echo "on" || echo "off"`"
fi
# notes...
echo
if ! [ -z $COMPRESSOR ] ; then
echo "NOTE: the index is fully usable during the compression stage"
fi
echo "NOTE: cp under Cygwin may messup permissions, use rsync."
echo
exit
;;
@ -61,17 +76,24 @@ while true ; do
shift
;;
-b|-base|--base)
BASE=1
shift
BASE=$2
shift 2
;;
-cp|--cp)
COPY=cp
COPYFLAGS=-Rpfv
shift
break
;;
-rsync|--rsync)
COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS
shift
break
;;
-compress|--compress)
COMPRESS=`[[ $COMPRESS ]] && echo "" || echo 1`
shift
break
;;
*)
@ -99,7 +121,12 @@ while true ; do
echo "Enter) copy drive ${DRIVE}"
fi
echo "2) build."
echo "3) quit."
if ! [ -z $COMPRESSOR ] ; then
echo "3) compresion is `[[ $COMPRESS ]] && echo "on" || echo "off"`"
echo "4) quit."
else
echo "3) quit."
fi
read -p ": " RES
case $RES in
@ -126,8 +153,15 @@ while true ; do
LAST=1
break
;;
3)
if ! [ -z $COMPRESSOR ] ; then
COMPRESS=`[[ ! $COMPRESS ]] && echo 1 || echo ""`
else
exit
fi
continue
;;
4)
exit
;;
@ -138,6 +172,17 @@ while true ; do
esac
fi
# sanity check...
if ! [ -e "${BASE}/${DRIVE}" ] ; then
echo
echo "ERR: ${BASE}/${DRIVE}: does not exist, nothing to copy."
echo
if [[ $INTERACTIVE || ! $DRIVE ]] ; then
continue
fi
exit
fi
# XXX do a real three digit count...
# single flash card...
SCOUNT=`printf "%03d" $COUNT`
@ -166,7 +211,7 @@ while true ; do
mkdir -vp "$DIR"
echo "Copying files from ${BASE}/${DRIVE}..."
echo "Copying files from ${BASE}/${DRIVE} (`du -hs "${BASE}/${DRIVE}" | cut -f 1`)..."
$COPY $COPYFLAGS ${BASE}/${DRIVE}/* "$DIR"
echo "Copying files: done."
@ -187,4 +232,13 @@ if [[ ! $MULTI || $LAST ]] ; then
echo "Building archive: done."
fi
if [[ $COMPRESS ]] ; then
echo "Compressing archive..."
${COMPRESSOR} "$BASE_DIR"
echo "Compressing archive: done."
fi
echo "`basename "$0"`: done."
# vim:set nowrap :

View File

@ -1,7 +1,32 @@
#!/bin/bash
DIR=`pwd`
printhelp(){
echo "Usage: `basename $0` [ARGUMENTS] [PATH]"
echo
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
}
while true ; do
case $1 in
-h|--help)
printhelp
exit
;;
*)
break
;;
esac
done
exifup(){
PREVIEW_DIR=$1

View File

@ -524,17 +524,52 @@ var BaseItemPrototype = {
: undefined },
// XXX BUG: this does not work for nested header elements...
// NOTE: these should not clash with user-supplied handlers ('update' does not)...
//
// XXX BUG: calling this on a nested/inlined browser will mess things up...
// ...the issue seems to be with root options not being available
// for partial render in a nested context...
// ...one way to fix this would be to make the options inheritance
// protocol more strict:
// - if no options given use defaults (i.e. this.options)
// - if options given use as-is
// - defaults are taken from this.options if not present
//
// to reproduce:
// dialog
// .get({children: true})
// .update()
// ...for some reason the affected element is removed from dom...
// dialog.disable('2')
// or:
// dialog.disable('B/C/D/a')
//
// ...in both cases the whole nested browser disappears...
//
// but this works OK:
// dialog.disable('nested/2')
//
// This might also be a side effect of the .dom / .elem set of
// issues...
//
// This issue seems to go away after expanding/collapsing the
// nested item several times, the buttons are gone but the
// subtrees stop vanishing on update -- could this be related
// to .dom/.elem again???
update: function(options){
this.parent
&& this.parent.render(this, options)
return this
},
return this },
/* XXX this is disabled to avoid user confusion when a user item
// event handler would not call/replicate the top-level (this)
// functionality and this break code relying on it...
// ...for this to work well need to either:
// - separate item options form the item object,
// - force the user to follow strict protocols,
// - use a proxy when accessing items (reverse of #1)
// XXX this also applies to .update(..) above...
focus: function(){
arguments.length == 0
&& this.parent
&& this.parent.focus(this)
return this },
//*/
__init__(...state){
@ -785,6 +820,9 @@ object.Constructor('BaseRenderer', {
// placeholders...
root: null,
isRendered: function(){
throw new Error('.isRendered(..): Not implemented.') },
// component renderers...
elem: function(item, index, path, options){
throw new Error('.elem(..): Not implemented.') },
@ -810,6 +848,9 @@ module.TextRenderer =
object.Constructor('TextRenderer', {
__proto__: BaseRenderer.prototype,
// always render...
isRendered: function(){ return false },
elem: function(item, index, path, options){
return path
.slice(0, -1)
@ -840,6 +881,9 @@ module.PathRenderer =
object.Constructor('PathRenderer', {
__proto__: TextRenderer.prototype,
// always render...
isRendered: function(){ return false },
elem: function(item, index, path, options){
return path.join('/') },
inline: function(item, lst, index, path, options){
@ -2654,10 +2698,14 @@ var BaseBrowserPrototype = {
return r && typeof(e) != typeof({}) }, true))){
// reverse index...
index = this
.reduce(function(res, e, i, p){
res.set(e, [i, p])
return res
}, new Map(), {iterateAll: true})
.reduce(
function(res, e, i, p){
res.set(e, [i, p])
return res },
new Map(),
Object.assign(
Object.flatCopy(options || {}),
{iterateAll: true}))
var res
var Stop = new Error('Stop iteration')
try {
@ -2676,7 +2724,10 @@ var BaseBrowserPrototype = {
throw Stop })
: pattern ]
// search...
: that.search(pattern, ...args.slice(1)) })
: !(pattern instanceof BaseItem) ?
that.search(pattern, ...args.slice(1))
// not found...
: [] })
.flat()
.unique()
} catch(e){
@ -2946,6 +2997,13 @@ var BaseBrowserPrototype = {
__renderer__: TextRenderer,
isRendered: function(renderer){
var render = renderer || this.__renderer__
render = render.root == null ?
new render(this, this.options)
: render
return render.isRendered() },
//
// Render browser...
// .render([options])
@ -3594,19 +3652,39 @@ var BaseBrowserPrototype = {
// XXX should we force calling update if options are given???
// ...and should full get passed if at least one call in sequence
// got a full=true???
__update_full: undefined,
// XXX supported mdoes:
// 'full' | true - make - render - post-render
// 'normal' - render - post-render
// 'partial' - post-render
__update_mode: undefined,
__update_args: undefined,
__update_timeout: undefined,
__update_max_timeout: undefined,
update: makeEventMethod('update',
function(evt, full, options){
options =
(full && full !== true && full !== false) ?
full
: options
full = full === options ?
false
: full
function(evt, mode, options){
var modes = [
'full',
'normal',
'partial',
]
options = mode instanceof Object ?
mode
: options
mode = mode === options ?
'normal'
: mode === true ?
'full'
: mode
// sanity check...
if(!modes.includes(mode)){
throw new Error(`.update(..): unsupported mode: ${mode}`) }
var m = this.__update_mode
// if the queued mode is deeper than the requested, ignore the requested...
if(m != null && modes.indexOf(mode) > modes.indexOf(m)){
return this }
// queue update...
// NOTE: we can't simply use _update(..) closure for this as
// it can be called out of two contexts (timeout and
// max_timeout), one (timeout) is renewed on each call
@ -3616,14 +3694,14 @@ var BaseBrowserPrototype = {
// its setTimeout(..)...
// storing the arguments in .__update_args would remove
// this inconsistency...
this.__update_mode = mode
var args = this.__update_args = [
[evt, full,
[evt, mode,
...(options ?
[options]
: [])],
options]
this.__update_full = (full && args)
|| this.__update_full
var timeout = (options || {}).updateTimeout
|| this.options.updateTimeout
var max_timeout = (options || {}).updateMaxDelay
@ -3637,20 +3715,22 @@ var BaseBrowserPrototype = {
delete this.__update_timeout }.bind(this)
var _update = function(){
_clear_timers()
var full = !!this.__update_full
var [args, opts] = this.__update_full
|| this.__update_args
var mode = this.__update_mode
var [args, opts] = this.__update_args
delete this.__update_full
delete this.__update_mode
delete this.__update_args
full
// make...
modes.indexOf(mode) <= modes.indexOf('full')
&& this.make(opts)
var context = {}
this
// XXX this needs access to render context....
.preRender(opts, (opts || {}).renderer, context)
.render(opts, (opts || {}).renderer, context)
// render...
;(!this.isRendered((opts || {}).renderer)
|| modes.indexOf(mode) <= modes.indexOf('normal'))
&& this
.preRender(opts, (opts || {}).renderer)
.render(opts, (opts || {}).renderer)
// update...
this.trigger(...args) }.bind(this)
var _update_n_delay = function(){
// call...
@ -3771,6 +3851,7 @@ object.Constructor('BaseBrowser',
//---------------------------------------------------------------------
// HTML-specific UI...
var KEYBOARD_CONFIG =
module.KEYBOARD_CONFIG = {
@ -4034,17 +4115,17 @@ var updateElemClass = function(action, cls, handler){
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Renderer...
// HTML Renderer...
// XXX needs testing...
// - partial rendering...
// - local re-rendering...
// XXX HACK: see .nest(..)
var HTMLRenderer =
module.HTMLRenderer =
object.Constructor('HTMLRenderer', {
__proto__: BaseRenderer.prototype,
isRendered: function(){
return !!this.root.dom },
// secondary renderers...
//
// base dialog...
@ -4654,7 +4735,6 @@ var HTMLBrowserPrototype = {
__item__: HTMLItem,
__renderer__: HTMLRenderer,
options: {
__proto__: BaseBrowser.prototype.options,
@ -5045,29 +5125,28 @@ var HTMLBrowserPrototype = {
__copy: function(text){
navigator.clipboard.writeText(text || this.path) },
// XXX need a better name...
_updateDOMItems: function(){
// Events extensions...
//
// XXX should tweaking DOM be done here or in the renderer???
__update__: function(){
var c = 0
this.forEach(function(e){
// shortcut number hint...
if(c < 10 && !e.disabled && !e.hidden){
var a = e.attrs = e.attrs || {}
c = a['shortcut-number'] = (++c) % 10
e.elem
&& e.elem.setAttribute('shortcut-number', c)
&& e.elem.setAttribute('shortcut-number',
a['shortcut-number'] = (c+1) % 10)
// cleanup...
} else {
delete (e.attrs || {})['shortcut-number']
e.elem
&& e.elem.removeAttribute('shortcut-number')
}
c++
}) },
// Events extensions...
//
// NOTE: this will also kill any user-set keys for disabled/hidden items...
//
// XXX also handle global button keys...
__preRender__: function(evt, options, renderer, context){
var that = this
@ -5079,18 +5158,6 @@ var HTMLBrowserPrototype = {
var i = 0
this.map(function(e){
// shortcut number hint...
// NOTE: these are just hints, the actual keys are handled
// in .keybindings...
// XXX move this to the renderer...
if(i < 10 && !e.disabled && !e.hidden){
var attrs = e.attrs = e.attrs || {}
attrs['shortcut-number'] = (++i) % 10
// cleanup...
} else {
delete (e.attrs || {})['shortcut-number']
}
// handle item keys...
if(!e.disabled && !e.hidden){
;((e.value instanceof Array ?
@ -5140,7 +5207,7 @@ var HTMLBrowserPrototype = {
block: 'nearest',
})
})
// set focus...
// XXX do we need this???
.focus() },
__blur__: function(evt, elem){
var that = this
@ -5157,14 +5224,22 @@ var HTMLBrowserPrototype = {
// element up to reveal the expanded subtree...
// ...would also be logical to "show" the expanded tree but
// keeping the focused elem in view...
__expand__: function(evt, elem){ elem.update() },
__collapse__: function(evt, elem){ elem.update() },
__expand__: function(evt, elem){
elem.update()
this.update('partial') },
__collapse__: function(evt, elem){
elem.update()
this.update('partial') },
__select__: updateElemClass('add', 'selected'),
__deselect__: updateElemClass('remove', 'selected'),
__disable__: updateElemClass('add', 'disabled',
function(evt, elem){ elem.update() }),
function(evt, elem){
elem.update()
this.update('partial') }),
__enable__: updateElemClass('remove', 'disabled',
function(evt, elem){ elem.update() }),
function(evt, elem){
elem.update()
this.update('partial') }),
__hide__: updateElemClass('add', 'hidden'),
__show__: updateElemClass('remove', 'hidden'),