mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 11:20: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 events = require('events') | ||||
| 
 | ||||
| var fse = require('fs.extra') | ||||
| var fse = require('fs-extra') | ||||
| var glob = require('glob') | ||||
| 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') | ||||
| 
 | ||||
| 
 | ||||
| define(function(require){ var module = {} | ||||
| console.log('>>> file') | ||||
| 
 | ||||
| 
 | ||||
| //var DEBUG = DEBUG != null ? DEBUG : true
 | ||||
| 
 | ||||
| var data = require('data') | ||||
| @ -73,8 +78,8 @@ module.gGlob = function(){ | ||||
| 
 | ||||
| var listIndexes = | ||||
| module.listIndexes =  | ||||
| function(base){ | ||||
| 	return gGlob(base +'/**/'+ INDEX_DIR) | ||||
| function(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 writeFile = Promise.denodeify(fse.writeFile) | ||||
| var ensureDir = Promise.denodeify(fse.ensureDir) | ||||
| 
 | ||||
| 
 | ||||
| // XXX handle errors...
 | ||||
| @ -174,7 +181,8 @@ function loadJSON(path){ | ||||
| // 			...(a) seems more logical...
 | ||||
| var 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 
 | ||||
| 	// 		return the whole thing as a block (Promise)...
 | ||||
| 	// 		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){ | ||||
| 		// we've got an index...
 | ||||
| 		// 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) | ||||
| 
 | ||||
| @ -355,7 +363,7 @@ function(path, logger){ | ||||
| 			var loaders = [] | ||||
| 
 | ||||
| 			// XXX handle 'error' event...
 | ||||
| 			listIndexes(path) | ||||
| 			listIndexes(path, index_dir) | ||||
| 				// XXX handle errors...
 | ||||
| 				.on('error', function(err){ | ||||
| 					logger && logger.emit('error', err) | ||||
| @ -369,7 +377,7 @@ function(path, logger){ | ||||
| 							// 		dir (the parent dir to the index root)
 | ||||
| 							// 		we do not need to include the index 
 | ||||
| 							// 		itself in the base path...
 | ||||
| 							var p = path.split(INDEX_DIR)[0] | ||||
| 							var p = path.split(index_dir)[0] | ||||
| 							res[p] = obj[path]  | ||||
| 						})) | ||||
| 				}) | ||||
| @ -401,8 +409,9 @@ function(path, logger){ | ||||
| // XXX handle errors....
 | ||||
| var loadPreviews = | ||||
| module.loadPreviews = | ||||
| function(base, previews, absolute_path){ | ||||
| function(base, previews, index_dir, absolute_path){ | ||||
| 	previews = previews || {} | ||||
| 	index_dir = index_dir || INDEX_DIR | ||||
| 
 | ||||
| 	return new Promise(function(resolve, reject){ | ||||
| 		listIndexes(base) | ||||
| @ -438,7 +447,7 @@ function(base, previews, absolute_path){ | ||||
| 						// add a preview...
 | ||||
| 						// NOTE: this will overwrite a previews if they are found in
 | ||||
| 						// 		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(){ | ||||
| @ -518,8 +527,130 @@ module.buildIndex = function(index, base_path){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*********************************************************************/ | ||||
| // Builder...
 | ||||
| // 	- read list
 | ||||
| // 	- generate previews (use config)
 | ||||
| // 	- build images/data
 | ||||
| // 		.loadURLs(..)
 | ||||
| // 	- write (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": { | ||||
|     "flickrapi": "^0.3.28", | ||||
|     "fs-walk": "0.0.1", | ||||
|     "fs.extra": "^1.2.1", | ||||
|     "fs-extra": "*", | ||||
|     "glob": "^4.0.6", | ||||
|     "guarantee-events": "^1.0.0", | ||||
|     "promise": "^6.0.1", | ||||
|     "requirejs": "*" | ||||
|     "requirejs": "*", | ||||
|     "sharp": "^0.12.0" | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,6 @@ | ||||
| * | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| 
 | ||||
| window.nodejs = (typeof(process) === 'object' && process.features.uv)  | ||||
| 	? { | ||||
| 		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 
 | ||||
| // 		as it is now???
 | ||||
| var AlignRibbonsToImageOrder =  | ||||
| @ -2157,6 +2150,7 @@ module.ManualAlignRibbons = ImageGridFeatures.Feature({ | ||||
| //---------------------------------------------------------------------
 | ||||
| 
 | ||||
| // XXX at this point this does not support target lists...
 | ||||
| // XXX shift up/down to new ribbon is not too correct...
 | ||||
| var ShiftAnimation = | ||||
| module.ShiftAnimation = ImageGridFeatures.Feature({ | ||||
| 	title: '', | ||||
| @ -2166,6 +2160,8 @@ module.ShiftAnimation = ImageGridFeatures.Feature({ | ||||
| 	depends: ['ui'], | ||||
| 
 | ||||
| 	handlers: [ | ||||
| 		//['shiftImageUp.pre shiftImageDown.pre '
 | ||||
| 		//		+'travelImageUp.pre travelImageDown.pre', 
 | ||||
| 		['shiftImageUp.pre shiftImageDown.pre', | ||||
| 			function(target){ | ||||
| 				// XXX do not do target lists...
 | ||||
| @ -3329,10 +3325,16 @@ if(window.nodejs != null){ | ||||
| 
 | ||||
| 
 | ||||
| var FileSystemLoaderActions = actions.Actions({ | ||||
| 	config: { | ||||
| 		'index-dir': '.ImageGrid', | ||||
| 	}, | ||||
| 	 | ||||
| 	// NOTE: when passed no path this will not do anything...
 | ||||
| 	// XXX should this set something like .path???
 | ||||
| 	// 		...and how should this be handled when merging indexes or
 | ||||
| 	//		viewing multiple/clustered indexes???
 | ||||
| 	// XXX add a symmetric equivalent to .prepareIndexForWrite(..) so as 
 | ||||
| 	// 		to enable features to load their data...
 | ||||
| 	// XXX look inside...
 | ||||
| 	loadIndex: ['File/Load index', | ||||
| 		function(path, logger){ | ||||
| @ -3345,7 +3347,7 @@ var FileSystemLoaderActions = actions.Actions({ | ||||
| 			// XXX get a logger...
 | ||||
| 			logger = logger || this.logger | ||||
| 
 | ||||
| 			file.loadIndex(path, logger) | ||||
| 			file.loadIndex(path, this.config['index-dir'], logger) | ||||
| 				.then(function(res){ | ||||
| 					// XXX if res is empty load raw...
 | ||||
| 
 | ||||
| @ -3593,6 +3595,67 @@ module.FileSystemLoaderUI = ImageGridFeatures.Feature({ | ||||
| //---------------------------------------------------------------------
 | ||||
| // 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-ui', | ||||
| 	'fs-writer', | ||||
| 
 | ||||
| 	'app-control', | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user