forked from LeenkxTeam/LNXSDK
286 lines
14 KiB
JavaScript
286 lines
14 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.AssetConverter = void 0;
|
|
const ProjectFile_1 = require("./ProjectFile");
|
|
const fs = require("fs-extra");
|
|
const path = require("path");
|
|
const log = require("./log");
|
|
const chokidar = require("chokidar");
|
|
const crypto = require("crypto");
|
|
const Throttle = require("promise-parallel-throttle");
|
|
class AssetConverter {
|
|
constructor(exporter, options, assetMatchers) {
|
|
this.exporter = exporter;
|
|
this.options = options;
|
|
this.platform = options.target;
|
|
this.assetMatchers = assetMatchers;
|
|
}
|
|
close() {
|
|
if (this.watcher)
|
|
this.watcher.close();
|
|
}
|
|
static replacePattern(pattern, name, fileinfo, options, from) {
|
|
let basePath = options.nameBaseDir ? path.join(from, options.nameBaseDir) : from;
|
|
let dirValue = path.relative(basePath, fileinfo.dir);
|
|
if (basePath.length > 0 && basePath[basePath.length - 1] === path.sep
|
|
&& dirValue.length > 0 && dirValue[dirValue.length - 1] !== path.sep) {
|
|
dirValue += path.sep;
|
|
}
|
|
if (options.namePathSeparator) {
|
|
dirValue = dirValue.split(path.sep).join(options.namePathSeparator);
|
|
}
|
|
const dirRegex = dirValue === ''
|
|
? /{dir}\//g
|
|
: /{dir}/g;
|
|
return pattern.replace(/{name}/g, name).replace(/{ext}/g, fileinfo.ext).replace(dirRegex, dirValue);
|
|
}
|
|
static createExportInfo(fileinfo, keepextension, options, from) {
|
|
let nameValue = fileinfo.name;
|
|
let destination = fileinfo.name;
|
|
if (options.md5sum) {
|
|
let data = fs.readFileSync(path.join(fileinfo.dir, fileinfo.base));
|
|
let md5sum = crypto.createHash('md5').update(data).digest('hex'); // TODO yield generateMd5Sum(file);
|
|
destination += '_' + md5sum;
|
|
}
|
|
if ((keepextension || options.noprocessing) && (!options.destination || options.destination.indexOf('{ext}') < 0)) {
|
|
destination += fileinfo.ext;
|
|
}
|
|
if (options.destination) {
|
|
destination = AssetConverter.replacePattern(options.destination, destination, fileinfo, options, from);
|
|
}
|
|
if (options.destinationCallback) {
|
|
destination = options.destinationCallback(destination);
|
|
}
|
|
if (keepextension && (!options.name || options.name.indexOf('{ext}') < 0)) {
|
|
nameValue += fileinfo.ext;
|
|
}
|
|
if (options.name) {
|
|
nameValue = AssetConverter.replacePattern(options.name, nameValue, fileinfo, options, from);
|
|
}
|
|
return { name: nameValue, destination: destination };
|
|
}
|
|
canDecodeFormat(ext) {
|
|
var _a, _b, _c, _d, _e, _f;
|
|
// without ffmpeg we need to encode mp3 and ogg files
|
|
const hasFFmpeg = !!this.options.ffmpeg;
|
|
const hasFFmpegOgg = (_b = (_a = this.options.ogg) === null || _a === void 0 ? void 0 : _a.includes('ffmpeg')) !== null && _b !== void 0 ? _b : false;
|
|
const hasFFmpegMp3 = (_d = (_c = this.options.mp3) === null || _c === void 0 ? void 0 : _c.includes('ffmpeg')) !== null && _d !== void 0 ? _d : false;
|
|
const hasFFmpegAac = (_f = (_e = this.options.aac) === null || _e === void 0 ? void 0 : _e.includes('ffmpeg')) !== null && _f !== void 0 ? _f : false;
|
|
switch (ext) {
|
|
case '.wav':
|
|
return true;
|
|
case '.ogg':
|
|
return hasFFmpeg || (hasFFmpegOgg && (hasFFmpegMp3 || hasFFmpegAac));
|
|
case '.mp3':
|
|
// lame can decode mp3, so we only need ogg ffmpeg encoder
|
|
return hasFFmpeg || (hasFFmpegOgg && !!this.options.mp3);
|
|
case '.flac':
|
|
return hasFFmpeg;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
watch(watch, match, temp, options) {
|
|
return new Promise((resolve, reject) => {
|
|
let ready = false;
|
|
let files = [];
|
|
this.watcher = chokidar.watch(match, { ignored: /[\/\\]\.(svn|git|DS_Store)/, persistent: watch, followSymlinks: false });
|
|
const onFileChange = async (file) => {
|
|
const fileinfo = path.parse(file);
|
|
let outPath = fileinfo.name;
|
|
// with subfolders
|
|
if (options.destination) {
|
|
// remove trailing slash
|
|
const nameBaseDir = options.nameBaseDir.replace(/\/$/, '');
|
|
const lastIndex = options.baseDir.lastIndexOf(nameBaseDir);
|
|
const from = path.resolve(options.baseDir.substring(0, lastIndex));
|
|
outPath = AssetConverter.replacePattern(options.destination, fileinfo.name, fileinfo, options, from);
|
|
}
|
|
const ext = fileinfo.ext.toLowerCase();
|
|
log.info('Reexporting ' + outPath + ext);
|
|
switch (ext) {
|
|
case '.png':
|
|
case '.jpg':
|
|
case '.jpeg':
|
|
case '.hdr':
|
|
{ }
|
|
await this.exporter.copyImage(this.platform, file, outPath, {}, {});
|
|
break;
|
|
case '.ogg':
|
|
case '.mp3':
|
|
case '.flac':
|
|
case '.wav': {
|
|
if (!this.canDecodeFormat(ext)) {
|
|
log.error(`Error: ${fileinfo.base} should be in wav format, or use \`--ffmpeg path/to/ffmpeg\` option to convert ogg/mp3/flac files`);
|
|
}
|
|
await this.exporter.copySound(this.platform, file, outPath, {});
|
|
break;
|
|
}
|
|
case '.mp4':
|
|
case '.webm':
|
|
case '.mov':
|
|
case '.wmv':
|
|
case '.avi': {
|
|
await this.exporter.copyVideo(this.platform, file, outPath, {});
|
|
break;
|
|
}
|
|
case '.ttf':
|
|
await this.exporter.copyFont(this.platform, file, outPath, {});
|
|
break;
|
|
default:
|
|
await this.exporter.copyBlob(this.platform, file, outPath + ext, {});
|
|
}
|
|
for (let callback of ProjectFile_1.Callbacks.postAssetReexporting) {
|
|
callback(outPath + ext);
|
|
}
|
|
};
|
|
this.watcher.on('add', (file) => {
|
|
if (ready) {
|
|
onFileChange(file);
|
|
}
|
|
else {
|
|
files.push(file);
|
|
}
|
|
});
|
|
if (watch) {
|
|
this.watcher.on('change', (file) => {
|
|
if (ready) {
|
|
onFileChange(file);
|
|
}
|
|
});
|
|
}
|
|
this.watcher.on('ready', async () => {
|
|
ready = true;
|
|
let parsedFiles = [];
|
|
let cache = {};
|
|
let cachePath = path.join(temp, 'cache.json');
|
|
if (fs.existsSync(cachePath)) {
|
|
cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
|
|
}
|
|
const convertAsset = async (file, index) => {
|
|
let fileinfo = path.parse(file);
|
|
log.info('Exporting asset ' + (index + 1) + ' of ' + files.length + ' (' + fileinfo.base + ').');
|
|
const ext = fileinfo.ext.toLowerCase();
|
|
switch (ext) {
|
|
case '.png':
|
|
case '.jpg':
|
|
case '.jpeg':
|
|
case '.hdr': {
|
|
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
|
|
let images;
|
|
if (options.noprocessing) {
|
|
images = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
else {
|
|
images = await this.exporter.copyImage(this.platform, file, exportInfo.destination, options, cache);
|
|
}
|
|
if (!options.notinlist) {
|
|
parsedFiles.push({ name: exportInfo.name, from: file, type: 'image', files: images.files, file_sizes: images.sizes, original_width: options.original_width, original_height: options.original_height, readable: options.readable });
|
|
}
|
|
break;
|
|
}
|
|
case '.ogg':
|
|
case '.mp3':
|
|
case '.flac':
|
|
case '.wav': {
|
|
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
|
|
let sounds;
|
|
if (options.noprocessing) {
|
|
sounds = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
else {
|
|
if (!this.canDecodeFormat(ext)) {
|
|
log.error(`Error: ${fileinfo.base} should be in wav format, or use \`--ffmpeg\` option to convert ogg/mp3/flac files`);
|
|
process.exit(1);
|
|
}
|
|
sounds = await this.exporter.copySound(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
if (sounds.files.length === 0) {
|
|
throw 'Audio file ' + file + ' could not be exported, you have to specify a path to ffmpeg.';
|
|
}
|
|
if (!options.notinlist) {
|
|
parsedFiles.push({ name: exportInfo.name, from: file, type: 'sound', files: sounds.files, file_sizes: sounds.sizes, original_width: undefined, original_height: undefined, readable: undefined });
|
|
}
|
|
break;
|
|
}
|
|
case '.ttf': {
|
|
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
|
|
let fonts;
|
|
if (options.noprocessing) {
|
|
fonts = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
else {
|
|
fonts = await this.exporter.copyFont(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
if (!options.notinlist) {
|
|
parsedFiles.push({ name: exportInfo.name, from: file, type: 'font', files: fonts.files, file_sizes: fonts.sizes, original_width: undefined, original_height: undefined, readable: undefined });
|
|
}
|
|
break;
|
|
}
|
|
case '.mp4':
|
|
case '.webm':
|
|
case '.mov':
|
|
case '.wmv':
|
|
case '.avi': {
|
|
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
|
|
let videos;
|
|
if (options.noprocessing) {
|
|
videos = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
else {
|
|
videos = await this.exporter.copyVideo(this.platform, file, exportInfo.destination, options);
|
|
}
|
|
if (videos.files.length === 0) {
|
|
log.error('Video file ' + file + ' could not be exported, you have to specify a path to ffmpeg.');
|
|
}
|
|
if (!options.notinlist) {
|
|
parsedFiles.push({ name: exportInfo.name, from: file, type: 'video', files: videos.files, file_sizes: videos.sizes, original_width: undefined, original_height: undefined, readable: undefined });
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
let exportInfo = AssetConverter.createExportInfo(fileinfo, true, options, this.exporter.options.from);
|
|
let blobs = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
|
|
if (!options.notinlist) {
|
|
parsedFiles.push({ name: exportInfo.name, from: file, type: 'blob', files: blobs.files, file_sizes: blobs.sizes, original_width: undefined, original_height: undefined, readable: undefined });
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
if (this.options.parallelAssetConversion !== 0) {
|
|
let todo = files.map((file, index) => {
|
|
return async () => {
|
|
await convertAsset(file, index);
|
|
};
|
|
});
|
|
let processes = this.options.parallelAssetConversion === -1
|
|
? require('os').cpus().length - 1
|
|
: this.options.parallelAssetConversion;
|
|
await Throttle.all(todo, {
|
|
maxInProgress: processes,
|
|
});
|
|
}
|
|
else {
|
|
let index = 0;
|
|
for (let file of files) {
|
|
await convertAsset(file, index);
|
|
index += 1;
|
|
}
|
|
}
|
|
fs.ensureDirSync(temp);
|
|
fs.writeFileSync(cachePath, JSON.stringify(cache), { encoding: 'utf8' });
|
|
resolve(parsedFiles);
|
|
});
|
|
});
|
|
}
|
|
async run(watch, temp) {
|
|
let files = [];
|
|
for (let matcher of this.assetMatchers) {
|
|
files = files.concat(await this.watch(watch, matcher.match, temp, matcher.options));
|
|
}
|
|
return files;
|
|
}
|
|
}
|
|
exports.AssetConverter = AssetConverter;
|
|
//# sourceMappingURL=AssetConverter.js.map
|