mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 03:10:07 +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,6 +2160,8 @@ module.ShiftAnimation = ImageGridFeatures.Feature({ | |||||||
| 	depends: ['ui'], | 	depends: ['ui'], | ||||||
| 
 | 
 | ||||||
| 	handlers: [ | 	handlers: [ | ||||||
|  | 		//['shiftImageUp.pre shiftImageDown.pre '
 | ||||||
|  | 		//		+'travelImageUp.pre travelImageDown.pre', 
 | ||||||
| 		['shiftImageUp.pre shiftImageDown.pre', | 		['shiftImageUp.pre shiftImageDown.pre', | ||||||
| 			function(target){ | 			function(target){ | ||||||
| 				// XXX do not do target lists...
 | 				// XXX do not do target lists...
 | ||||||
| @ -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