mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-30 19:00:09 +00:00
started work on fs writer...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
4e31790f95
commit
0d47a559ba
@ -7,16 +7,21 @@
|
|||||||
var pathlib = require('path')
|
var pathlib = require('path')
|
||||||
var events = require('events')
|
var events = require('events')
|
||||||
|
|
||||||
var fse = require('fs.extra')
|
var fse = require('fs-extra')
|
||||||
var glob = require('glob')
|
var glob = require('glob')
|
||||||
var Promise = require('promise')
|
var Promise = require('promise')
|
||||||
|
|
||||||
|
// XXX seems that we need different buids of this for use with node and nw...
|
||||||
|
// XXX BUG: nw-gyp does not support msvs2015...
|
||||||
|
//var sharp = require('sharp')
|
||||||
|
|
||||||
var guaranteeEvents = require('guarantee-events')
|
var guaranteeEvents = require('guarantee-events')
|
||||||
|
|
||||||
|
|
||||||
define(function(require){ var module = {}
|
define(function(require){ var module = {}
|
||||||
console.log('>>> file')
|
console.log('>>> file')
|
||||||
|
|
||||||
|
|
||||||
//var DEBUG = DEBUG != null ? DEBUG : true
|
//var DEBUG = DEBUG != null ? DEBUG : true
|
||||||
|
|
||||||
var data = require('data')
|
var data = require('data')
|
||||||
@ -73,8 +78,8 @@ module.gGlob = function(){
|
|||||||
|
|
||||||
var listIndexes =
|
var listIndexes =
|
||||||
module.listIndexes =
|
module.listIndexes =
|
||||||
function(base){
|
function(base, index_dir){
|
||||||
return gGlob(base +'/**/'+ INDEX_DIR)
|
return gGlob(base +'/**/'+ index_dir || INDEX_DIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -93,6 +98,8 @@ function listJSON(path, pattern){
|
|||||||
|
|
||||||
|
|
||||||
var loadFile = Promise.denodeify(fse.readFile)
|
var loadFile = Promise.denodeify(fse.readFile)
|
||||||
|
var writeFile = Promise.denodeify(fse.writeFile)
|
||||||
|
var ensureDir = Promise.denodeify(fse.ensureDir)
|
||||||
|
|
||||||
|
|
||||||
// XXX handle errors...
|
// XXX handle errors...
|
||||||
@ -174,7 +181,8 @@ function loadJSON(path){
|
|||||||
// ...(a) seems more logical...
|
// ...(a) seems more logical...
|
||||||
var loadIndex =
|
var loadIndex =
|
||||||
module.loadIndex =
|
module.loadIndex =
|
||||||
function(path, logger){
|
function(path, index_dir, logger){
|
||||||
|
index_dir = index_dir || INDEX_DIR
|
||||||
// XXX should this be interactive (a-la EventEmitter) or as it is now
|
// XXX should this be interactive (a-la EventEmitter) or as it is now
|
||||||
// return the whole thing as a block (Promise)...
|
// return the whole thing as a block (Promise)...
|
||||||
// NOTE: one way to do this is use the logger, it will get
|
// NOTE: one way to do this is use the logger, it will get
|
||||||
@ -182,7 +190,7 @@ function(path, logger){
|
|||||||
return new Promise(function(resolve, reject){
|
return new Promise(function(resolve, reject){
|
||||||
// we've got an index...
|
// we've got an index...
|
||||||
// XXX do we need to check if if it's a dir???
|
// XXX do we need to check if if it's a dir???
|
||||||
if(pathlib.basename(path) == INDEX_DIR){
|
if(pathlib.basename(path) == index_dir){
|
||||||
|
|
||||||
logger && logger.emit('path', path)
|
logger && logger.emit('path', path)
|
||||||
|
|
||||||
@ -355,7 +363,7 @@ function(path, logger){
|
|||||||
var loaders = []
|
var loaders = []
|
||||||
|
|
||||||
// XXX handle 'error' event...
|
// XXX handle 'error' event...
|
||||||
listIndexes(path)
|
listIndexes(path, index_dir)
|
||||||
// XXX handle errors...
|
// XXX handle errors...
|
||||||
.on('error', function(err){
|
.on('error', function(err){
|
||||||
logger && logger.emit('error', err)
|
logger && logger.emit('error', err)
|
||||||
@ -369,7 +377,7 @@ function(path, logger){
|
|||||||
// dir (the parent dir to the index root)
|
// dir (the parent dir to the index root)
|
||||||
// we do not need to include the index
|
// we do not need to include the index
|
||||||
// itself in the base path...
|
// itself in the base path...
|
||||||
var p = path.split(INDEX_DIR)[0]
|
var p = path.split(index_dir)[0]
|
||||||
res[p] = obj[path]
|
res[p] = obj[path]
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
@ -401,8 +409,9 @@ function(path, logger){
|
|||||||
// XXX handle errors....
|
// XXX handle errors....
|
||||||
var loadPreviews =
|
var loadPreviews =
|
||||||
module.loadPreviews =
|
module.loadPreviews =
|
||||||
function(base, previews, absolute_path){
|
function(base, previews, index_dir, absolute_path){
|
||||||
previews = previews || {}
|
previews = previews || {}
|
||||||
|
index_dir = index_dir || INDEX_DIR
|
||||||
|
|
||||||
return new Promise(function(resolve, reject){
|
return new Promise(function(resolve, reject){
|
||||||
listIndexes(base)
|
listIndexes(base)
|
||||||
@ -438,7 +447,7 @@ function(base, previews, absolute_path){
|
|||||||
// add a preview...
|
// add a preview...
|
||||||
// NOTE: this will overwrite a previews if they are found in
|
// NOTE: this will overwrite a previews if they are found in
|
||||||
// several locations...
|
// several locations...
|
||||||
images[gid].preview[res] = INDEX_DIR +'/'+ path.split(INDEX_DIR)[1]
|
images[gid].preview[res] = index_dir +'/'+ path.split(index_dir)[1]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('end', function(){
|
.on('end', function(){
|
||||||
@ -518,8 +527,130 @@ module.buildIndex = function(index, base_path){
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
// Builder...
|
||||||
|
// - read list
|
||||||
|
// - generate previews (use config)
|
||||||
|
// - build images/data
|
||||||
|
// .loadURLs(..)
|
||||||
|
// - write (writer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
// Writer...
|
// Writer...
|
||||||
|
//
|
||||||
|
// This is just like the loader, done in two stages:
|
||||||
|
// - format dependent de-construction (symetric to buildIndex(..))
|
||||||
|
// - generic writer...
|
||||||
|
//
|
||||||
|
// NOTE: for now we'll stick to the current format...
|
||||||
|
|
||||||
|
// this will take the output of .json()
|
||||||
|
//
|
||||||
|
// .data
|
||||||
|
// .images
|
||||||
|
// .bookmarked
|
||||||
|
// .marked
|
||||||
|
// .tags
|
||||||
|
// .current
|
||||||
|
//
|
||||||
|
// NOTE: this will prepare for version 2.0 file structure...
|
||||||
|
//
|
||||||
|
// XXX write tags, marks and bookmarks only if changed...
|
||||||
|
var prepareIndex =
|
||||||
|
module.prepareIndex =
|
||||||
|
function(json, changes){
|
||||||
|
changes = changes || {}
|
||||||
|
|
||||||
|
var res = {
|
||||||
|
data: json.data,
|
||||||
|
current: json.data.current,
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we write the whole set ONLY if an item is true or undefined
|
||||||
|
// i.e. not false...
|
||||||
|
if(changes.bookmarked !== false){
|
||||||
|
res.bookmarked = json.data.tags.bookmark
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changes.selected !== false){
|
||||||
|
res.marked = json.data.tags.selected
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changes.tags !== false){
|
||||||
|
res.tags = json.data.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean out some stuff from data...
|
||||||
|
delete res.data.tags.bookmark
|
||||||
|
delete res.data.tags.selected
|
||||||
|
delete res.data.tags
|
||||||
|
|
||||||
|
if(changes.images){
|
||||||
|
var diff = res['images-diff'] = {}
|
||||||
|
changes.images.forEach(function(gid){
|
||||||
|
diff[gid] = json.images[gid]
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res.images = json.images
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var FILENAME = '${DATE}-${KEYWORD}.${EXT}'
|
||||||
|
|
||||||
|
var writeIndex =
|
||||||
|
module.writeIndex =
|
||||||
|
function(json, path, filename_tpl, logger){
|
||||||
|
filename_tpl = filename_tpl || FILENAME
|
||||||
|
// XXX for some reason this gets the unpatched node.js Date, so we
|
||||||
|
// get the patched date explicitly...
|
||||||
|
var date = window.Date.timeStamp()
|
||||||
|
var files = []
|
||||||
|
|
||||||
|
// build the path if it does not exist...
|
||||||
|
return ensureDir(path)
|
||||||
|
.catch(function(err){
|
||||||
|
logger && logger.emit('error', err)
|
||||||
|
})
|
||||||
|
.then(function(){
|
||||||
|
logger && logger.emit('path', path)
|
||||||
|
|
||||||
|
// write files...
|
||||||
|
// NOTE: we are not doing this sequencilly as there will not
|
||||||
|
// be too many files...
|
||||||
|
return Promise
|
||||||
|
.all(Object.keys(json).map(function(keyword){
|
||||||
|
var file = path +'/'+ (filename_tpl
|
||||||
|
.replace('${DATE}', date)
|
||||||
|
.replace('${KEYWORD}', keyword)
|
||||||
|
.replace('${EXT}', 'json'))
|
||||||
|
|
||||||
|
return ensureDir(pathlib.dirname(file))
|
||||||
|
.then(function(){
|
||||||
|
files.push(file)
|
||||||
|
var data = JSON.stringify(json[keyword])
|
||||||
|
|
||||||
|
logger && logger.emit('queued', file)
|
||||||
|
|
||||||
|
return writeFile(file, data, 'utf8')
|
||||||
|
.catch(function(err){
|
||||||
|
logger && logger.emit('error', err)
|
||||||
|
})
|
||||||
|
.then(function(){
|
||||||
|
logger && logger.emit('written', file)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.then(function(){
|
||||||
|
logger && logger.emit('done', files)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,10 +18,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flickrapi": "^0.3.28",
|
"flickrapi": "^0.3.28",
|
||||||
"fs-walk": "0.0.1",
|
"fs-walk": "0.0.1",
|
||||||
"fs.extra": "^1.2.1",
|
"fs-extra": "*",
|
||||||
"glob": "^4.0.6",
|
"glob": "^4.0.6",
|
||||||
"guarantee-events": "^1.0.0",
|
"guarantee-events": "^1.0.0",
|
||||||
"promise": "^6.0.1",
|
"promise": "^6.0.1",
|
||||||
"requirejs": "*"
|
"requirejs": "*",
|
||||||
|
"sharp": "^0.12.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
window.nodejs = (typeof(process) === 'object' && process.features.uv)
|
window.nodejs = (typeof(process) === 'object' && process.features.uv)
|
||||||
? {
|
? {
|
||||||
require: window.require,
|
require: window.require,
|
||||||
|
|||||||
@ -2079,13 +2079,6 @@ module.AutoAlignRibbons = ImageGridFeatures.Feature({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// XXX add a feature not to align the ribbons and focus the central
|
|
||||||
// image on next prev ribbon...
|
|
||||||
// XXX in general need a way to control .nextRibbon(..)/.prevRibbon(..)
|
|
||||||
// image selection...
|
|
||||||
|
|
||||||
// XXX this should also define up/down navigation behavior e.g. what to
|
|
||||||
// focus on next/prev ribbon...
|
|
||||||
// XXX should .alignByOrder(..) be a feature-specific action or global
|
// XXX should .alignByOrder(..) be a feature-specific action or global
|
||||||
// as it is now???
|
// as it is now???
|
||||||
var AlignRibbonsToImageOrder =
|
var AlignRibbonsToImageOrder =
|
||||||
@ -2157,6 +2150,7 @@ module.ManualAlignRibbons = ImageGridFeatures.Feature({
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
// XXX at this point this does not support target lists...
|
// XXX at this point this does not support target lists...
|
||||||
|
// XXX shift up/down to new ribbon is not too correct...
|
||||||
var ShiftAnimation =
|
var ShiftAnimation =
|
||||||
module.ShiftAnimation = ImageGridFeatures.Feature({
|
module.ShiftAnimation = ImageGridFeatures.Feature({
|
||||||
title: '',
|
title: '',
|
||||||
@ -2166,7 +2160,9 @@ module.ShiftAnimation = ImageGridFeatures.Feature({
|
|||||||
depends: ['ui'],
|
depends: ['ui'],
|
||||||
|
|
||||||
handlers: [
|
handlers: [
|
||||||
['shiftImageUp.pre shiftImageDown.pre',
|
//['shiftImageUp.pre shiftImageDown.pre '
|
||||||
|
// +'travelImageUp.pre travelImageDown.pre',
|
||||||
|
['shiftImageUp.pre shiftImageDown.pre',
|
||||||
function(target){
|
function(target){
|
||||||
// XXX do not do target lists...
|
// XXX do not do target lists...
|
||||||
if(target != null && target.constructor === Array
|
if(target != null && target.constructor === Array
|
||||||
@ -3329,10 +3325,16 @@ if(window.nodejs != null){
|
|||||||
|
|
||||||
|
|
||||||
var FileSystemLoaderActions = actions.Actions({
|
var FileSystemLoaderActions = actions.Actions({
|
||||||
|
config: {
|
||||||
|
'index-dir': '.ImageGrid',
|
||||||
|
},
|
||||||
|
|
||||||
// NOTE: when passed no path this will not do anything...
|
// NOTE: when passed no path this will not do anything...
|
||||||
// XXX should this set something like .path???
|
// XXX should this set something like .path???
|
||||||
// ...and how should this be handled when merging indexes or
|
// ...and how should this be handled when merging indexes or
|
||||||
// viewing multiple/clustered indexes???
|
// viewing multiple/clustered indexes???
|
||||||
|
// XXX add a symmetric equivalent to .prepareIndexForWrite(..) so as
|
||||||
|
// to enable features to load their data...
|
||||||
// XXX look inside...
|
// XXX look inside...
|
||||||
loadIndex: ['File/Load index',
|
loadIndex: ['File/Load index',
|
||||||
function(path, logger){
|
function(path, logger){
|
||||||
@ -3345,7 +3347,7 @@ var FileSystemLoaderActions = actions.Actions({
|
|||||||
// XXX get a logger...
|
// XXX get a logger...
|
||||||
logger = logger || this.logger
|
logger = logger || this.logger
|
||||||
|
|
||||||
file.loadIndex(path, logger)
|
file.loadIndex(path, this.config['index-dir'], logger)
|
||||||
.then(function(res){
|
.then(function(res){
|
||||||
// XXX if res is empty load raw...
|
// XXX if res is empty load raw...
|
||||||
|
|
||||||
@ -3593,6 +3595,67 @@ module.FileSystemLoaderUI = ImageGridFeatures.Feature({
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// fs writer...
|
// fs writer...
|
||||||
|
|
||||||
|
var FileSystemWriterActions = actions.Actions({
|
||||||
|
config: {
|
||||||
|
// XXX should this include the '.ImageGrid/' section???
|
||||||
|
'index-filename-template': '${DATE}-${KEYWORD}.${EXT}',
|
||||||
|
},
|
||||||
|
|
||||||
|
// This is here so as other features can participate in index
|
||||||
|
// preparation...
|
||||||
|
// There are several stages features can control the output format:
|
||||||
|
// 1) .json() action
|
||||||
|
// - use this for global high level serialization format
|
||||||
|
// - the output of this is .load(..) compatible
|
||||||
|
// 2) .prepareIndex(..) action
|
||||||
|
// - use this for file system write preparation
|
||||||
|
// - this directly affects the index structure
|
||||||
|
prepareIndexForWrite: ['File/Prepare index for writing',
|
||||||
|
function(json){
|
||||||
|
return file.prepareIndex(json || this.json())
|
||||||
|
}],
|
||||||
|
// XXX should this get the base uncropped state or the current state???
|
||||||
|
// XXX get real base path...
|
||||||
|
saveIndex: ['File/save index',
|
||||||
|
function(path, logger){
|
||||||
|
// XXX get real base path...
|
||||||
|
path = path || this.base_path +'/'+ this.config['index-dir']
|
||||||
|
|
||||||
|
file.writeIndex(
|
||||||
|
this.prepareIndexForWrite(),
|
||||||
|
path,
|
||||||
|
this.config['index-filename-template'],
|
||||||
|
logger || this.logger)
|
||||||
|
}],
|
||||||
|
|
||||||
|
// XXX same as ctrl-shif-s in gen3
|
||||||
|
exportView: ['File/Export current view',
|
||||||
|
function(){
|
||||||
|
}],
|
||||||
|
// XXX export current state as a full loadable index
|
||||||
|
// XXX might be interresting to unify this and .exportView(..)
|
||||||
|
exportCollection: ['File/Export as collection',
|
||||||
|
function(){
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
var FileSystemWriter =
|
||||||
|
module.FileSystemWriter = ImageGridFeatures.Feature({
|
||||||
|
title: '',
|
||||||
|
doc: '',
|
||||||
|
|
||||||
|
tag: 'fs-writer',
|
||||||
|
// NOTE: this is mostly because of the base path handling...
|
||||||
|
depends: ['fs-loader'],
|
||||||
|
|
||||||
|
actions: FileSystemWriterActions,
|
||||||
|
|
||||||
|
isApplicable: function(){
|
||||||
|
return window.nodejs != null
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
@ -3623,6 +3686,7 @@ ImageGridFeatures.Feature('viewer-testing', [
|
|||||||
|
|
||||||
'fs-loader',
|
'fs-loader',
|
||||||
'fs-loader-ui',
|
'fs-loader-ui',
|
||||||
|
'fs-writer',
|
||||||
|
|
||||||
'app-control',
|
'app-control',
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user