You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
thumbsup/src/steps/step-process.js

99 lines
3.0 KiB
JavaScript

const path = require('node:path')
const fs = require('node:fs')
const debug = require('debug')('thumbsup:debug')
const error = require('debug')('thumbsup:error')
const info = require('debug')('thumbsup:info')
const ListrWorkQueue = require('../components/listr-work-queue/index')
const actions = require('./actions')
exports.run = function (files, problems, opts, parentTask) {
const jobs = exports.create(files, opts, problems)
// wrap each job in a Listr task that returns a Promise
const tasks = jobs.map(job => listrTaskFromJob(job, opts.output))
const listr = new ListrWorkQueue(tasks, {
concurrent: opts.concurrency,
update: (done, total) => {
const progress = done === total ? '' : `(${done}/${total})`
parentTask.title = `Processing media ${progress}`
}
})
return listr
}
/*
Return a list of task to build all required outputs (new or updated)
*/
exports.create = function (files, opts, problems) {
const tasks = {}
const sourceFiles = new Set()
const actionMap = actions.createMap(opts)
// accumulate all tasks into an object
// to remove duplicate destinations
files.forEach(f => {
Object.keys(f.output).forEach(out => {
const src = path.join(opts.input, f.path)
const dest = path.join(opts.output, f.output[out].path)
const destDate = modifiedDate(dest)
const action = actionMap[f.output[out].rel]
// ignore output files that don't have an action (e.g. existing links)
if (action) {
debug(`Comparing ${f.path} (${f.date}) and ${f.output[out].path} (${destDate})`)
}
if (action && f.date > destDate) {
sourceFiles.add(f.path)
tasks[dest] = {
file: f,
dest,
rel: f.output[out].rel,
action: (done) => {
fs.mkdirSync(path.dirname(dest), { recursive: true })
debug(`${f.output[out].rel} from ${src} to ${dest}`)
return action({ src, dest }, err => {
if (err) {
error(`Error processing ${f.path} -> ${f.output[out].path}\n${err}`)
problems.addFile(f.path)
}
done()
})
}
}
}
})
})
// back into an array
const list = Object.keys(tasks).map(dest => tasks[dest])
info('Calculated required tasks', {
sourceFiles: sourceFiles.size,
tasks: list.length
})
return list
}
function listrTaskFromJob (job, outputRoot) {
const relative = path.relative(outputRoot, job.dest)
return {
title: relative,
task: (ctx, task) => {
return new Promise((resolve, reject) => {
const progressEmitter = job.action(err => {
err ? reject(err) : resolve()
})
// render progress percentage for videos
if (progressEmitter) {
progressEmitter.on('progress', (percent) => {
task.title = `${relative} (${percent}%)`
})
}
})
}
}
}
function modifiedDate (filepath) {
try {
return fs.statSync(filepath).mtime.getTime()
} catch (ex) {
return 0
}
}