Created
June 17, 2021 20:42
-
-
Save brennancheung/620f66136e70a814b05f7d2ae95125f1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const chokidar = require('chokidar') | |
const fs = require('fs') | |
const winPicsPath = '/c/Users/brenn/Pictures/exports' | |
const picsPath = '/mnt/c/Users/brenn/Pictures/exports' | |
const watchPaths = { | |
exports: `${picsPath}`, | |
} | |
const MB = 1024 * 1024 | |
const getFileSize = path => fs.statSync(path).size | |
const fileExists = path => fs.existsSync(path) | |
const generateWinPath = fullPath => winPicsPath + '/' + fullPath | |
const hasEditingPath = path => /.*?\/editing\/.+/.test(path) | |
const hasStyledPath = path => /.*?\/styled\/.+/.test(path) | |
const hasOriginal = path => /.*\.psd_original/.test(path) | |
const hasTmpPath = path => /.*\.tmp/.test(path) | |
const isEditing = path => hasEditingPath(path) && !hasTmpPath(path) | |
const isStyled = path => hasStyledPath(path) && !hasTmpPath(path) && !hasOriginal(path) | |
const extractModelPathInfo = path => { | |
const [p, date, model, filename] = path.match(/(\d+-\d+-\d+)\/(.*?)\/.*?\/(.*)/) | |
const [_, baseFilename] = path.match(/.*\/(.*)\..{3}/) | |
return { date, model, filename, baseFilename, path: p } | |
} | |
let editQueue = [] | |
let styledQueue = [] | |
let isProcessing = false | |
let modelPath = '' | |
const mkdir = dir => { | |
if (fs.existsSync(dir)) return | |
console.log(`Creating directory ${dir}`) | |
fs.mkdirSync(dir) | |
} | |
const prepOtherFoldersSync = info => { | |
modelPath = `${picsPath}/${info.date}/${info.model}` | |
mkdir(`${modelPath}/final`) | |
mkdir(`${modelPath}/styled`) | |
} | |
// We don't want Photoshop trying to open the file before it is fully written. | |
const SECONDS = 1000 | |
const ENQUEUE_DELAY = 10*SECONDS | |
const enqueueStyled = info => { | |
const enqueue = () => styledQueue.push(info) | |
console.log(`Queueing styled ${info.baseFilename}, delayed ${ENQUEUE_DELAY}`) | |
setTimeout(enqueue, ENQUEUE_DELAY) | |
} | |
const enqueueEditing = info => { | |
const enqueue = () => editQueue.push(info.path) | |
console.log(`Queueing editing ${info.baseFilename}, delayed ${ENQUEUE_DELAY}`) | |
setTimeout(enqueue, ENQUEUE_DELAY) | |
} | |
const start = async g => { | |
const getOrientation = ({ bounds }) => bounds.bottom >= bounds.right ? 'portrait' : 'landscape' | |
const isPortrait = doc => getOrientation(doc) === 'portrait' | |
const isLandscape = doc => getOrientation(doc) === 'portrait' | |
const playAction = (action, actionSet) => { | |
const str = `app.doAction("${action}", "${actionSet}")` | |
return g.evaluateJSXString(str) | |
} | |
const playBatchAction = () => playAction('Batch full', 'brennan') | |
const playToJpgAction = () => playAction('to jpg', 'brennan') | |
const closeCurrentDoc = (save=false) => { | |
const saveOption = 'SaveOptions.' + (save ? 'SAVECHANGES' : 'DONOTSAVECHANGES') | |
return g.evaluateJSXString(`app.activeDocument.close(${saveOption})`) | |
} | |
const shrinkPortrait = () => playAction('2000x3000', 'brennan') | |
const shrinkLandscape = () => playAction('3000x2000', 'brennan') | |
const processEditingDoc = async docId => { | |
const docInfo = await g.getDocumentInfo(docId) | |
const orientation = getOrientation(docInfo) | |
const { bounds } = docInfo | |
const isBig = Math.max(bounds.bottom, bounds.right) > 3000 | |
console.log(`Editing: #${docId} ${docInfo.file} ${orientation}`) | |
if (!isBig) { | |
await closeCurrentDoc() | |
return console.log(`Skipping ${docInfo.file} because it is too small`) | |
} | |
const resizeFn = isPortrait(docInfo) ? shrinkPortrait : shrinkLandscape | |
await resizeFn() | |
await playBatchAction() | |
} | |
const processStyledDoc = async info => { | |
console.log(`To jpeg: ${info.path}`) | |
await playToJpgAction() | |
const srcPath = `${picsPath}/to-jpg/${info.baseFilename}.jpg` | |
const destPath = `${modelPath}/final/${info.baseFilename}.jpg` | |
console.log(`Moving ${srcPath} to ${destPath}`) | |
fs.renameSync(srcPath, destPath) | |
} | |
const openDoc = async docInfo => { | |
const winPath = generateWinPath(docInfo) | |
const str = `app.open(File("${winPath}"))` | |
return g.evaluateJSXString(str) | |
} | |
const runQueue = async () => { | |
if (isProcessing) return | |
if (editQueue.length > 0) { | |
isProcessing = true | |
const path = editQueue.shift() | |
await openDoc(path) | |
const ids = await g.getOpenDocumentIDs() | |
await processEditingDoc(ids[0]) | |
isProcessing = false | |
return | |
} | |
if (styledQueue.length > 0) { | |
isProcessing = true | |
const info = styledQueue.shift() | |
await openDoc(info.path) | |
await processStyledDoc(info) | |
isProcessing = false | |
return | |
} | |
} | |
setInterval(runQueue, 200) | |
const handleFileAdd = async path => { | |
console.log(`\nNew file added: ${path}`) | |
if (isEditing(path)) { | |
if (getFileSize(path) < 20*MB) return console.log(`Skipping edit because file too small ${path}`) | |
const info = extractModelPathInfo(path) | |
prepOtherFoldersSync(info) | |
enqueueEditing(info) | |
} | |
if (isStyled(path)) { | |
const info = extractModelPathInfo(path) | |
modelPath = `${picsPath}/${info.date}/${info.model}` | |
const finalPath = `${modelPath}/final/${info.baseFilename}.jpg` | |
if (fileExists(finalPath)) return console.log(`Skipping styled because jpg already exists ${path}`) | |
enqueueStyled(info) | |
} | |
} | |
const watcher = chokidar.watch(watchPaths.exports, { | |
usePolling: true, | |
interval: 1000, | |
}) | |
watcher.on('add', handleFileAdd) | |
} | |
(function () { | |
const init = async g => { | |
console.log('edit-workflow (init)') | |
start(g) | |
} | |
exports.init = init | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment