UNPKG

kar-to-ass

Version:

Converts midi/kar karaoke files to ass format

146 lines 5.98 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertKarToAss = exports.convertKarStringToAss = exports.parseKar = void 0; const utils_1 = require("./utils"); const ass_stringify_1 = __importDefault(require("ass-stringify")); const uuid_1 = require("uuid"); const commander_1 = __importDefault(require("commander")); const kar_1 = require("./kar"); const ass = require('./assTemplate'); const pjson = require('../package.json'); function generateASSLine(line, sectionId, options) { const offset = options.offset || 0; const syncType = options.progressive ? 'kf' : 'k'; const dialogue = utils_1.clone(ass.dialogue); const comment = utils_1.clone(ass.dialogue); const lineStart = line[0].timeUs + 1e4 * (offset - ass.previewTime); const lineStartComment = line[0].timeUs + 1e4 * offset; const lineEnd = line[line.length - 1].timeUs + 1e4 * (offset + ass.postviewTime); const correction = lineStart < 0 ? lineStart : 0; dialogue.value.Style = sectionId; dialogue.value.Start = utils_1.usToAss(lineStart - correction); dialogue.value.End = utils_1.usToAss(lineEnd - correction); dialogue.value.Text = writeLineAsAss(line, syncType); dialogue.value.Effect = 'fx'; comment.value.Style = sectionId; comment.value.Start = utils_1.usToAss(lineStartComment - correction); comment.value.End = utils_1.usToAss(lineEnd - correction); comment.value.Text = writeLineAsAss(line, syncType, true); comment.value.Effect = 'karaoke'; comment.key = 'Comment'; return { dialogue, comment }; } function parseKar(fileContent) { return kar_1.parseKar(fileContent); } exports.parseKar = parseKar; function convertKarStringToAss(fileContent, options) { return convertKarToAss(parseKar(fileContent), options); } exports.convertKarStringToAss = convertKarStringToAss; function convertKarToAss(kar, options) { const defaultStyle = ass.styles.body.filter(style => style.key == 'Style')[0]; const dialogues = []; const comments = []; const styles = utils_1.clone(ass.styles); const script = utils_1.clone(ass.dialogue); script.value.Effect = ass.scriptFX; script.value.Text = ass.script; script.key = 'Comment'; comments.push(script); for (const track of kar.tracks) { const sectionId = uuid_1.v4().replace(/-/g, '').substring(0, 16); const sectionStyle = utils_1.clone(defaultStyle); sectionStyle.value.Name = sectionId; styles.body.push(sectionStyle); for (const line of splitLines(track)) { const ASSLines = generateASSLine(line, sectionId, options); comments.push(utils_1.clone(ASSLines.comment)); dialogues.push(utils_1.clone(ASSLines.dialogue)); } } const scriptInfo = utils_1.clone(ass.scriptInfo); scriptInfo.body[0].value = scriptInfo.body[0].value.replace('%version', pjson.version); scriptInfo.body[1].value = scriptInfo.body[1].value.replace('%options', JSON.stringify(options)); const events = utils_1.clone(ass.events); events.body = events.body.concat(comments, dialogues); return ass_stringify_1.default([scriptInfo, styles, events]); } exports.convertKarToAss = convertKarToAss; function splitLines(track) { const lines = []; let tempLine = []; for (const event of track) { if (event.type === 'EndOfLine' && tempLine.length > 0) { tempLine.push(event); lines.push(tempLine); tempLine = []; } else if (event.type === 'Lyrics') { tempLine.push(event); } } return lines; } function writeLineAsAss(line, syncType, comment) { if (line.length == 0) return ''; const realPreview = Math.max(Math.min(ass.previewTime, line[0].timeUs * 1e-4), 0); const resArray = []; if (!comment) resArray.push(`{\\k${realPreview}\\fad(300,200)}`); for (let i = 0; i < line.length - 1; i++) { resArray.push(`${line[i].text.startsWith(' ') ? ' ' : ''}{\\${syncType}${Math.round(1e-4 * (line[i + 1].timeUs - line[i].timeUs))}}${line[i].text.trim()}${(line[i].text.endsWith(' ') ? ' ' : '')}`); } return resArray.join(''); } async function mainCLI() { const argv = parseArgs(); if (!argv.in) throw '--in argument is required'; const karFile = argv.in; const correctionString = argv.correction; const outFile = argv.out; const correction = (correctionString && !isNaN(+correctionString)) ? +correctionString : 0; const options = { offset: correction, progressive: argv.progressive || false, }; if (!await utils_1.asyncExists(karFile)) throw `File ${karFile} does not exist`; const fileContent = await utils_1.asyncReadFile(karFile); const kar = parseKar(fileContent); const assString = convertKarToAss(kar, options); if (!outFile) { return assString; } else { await utils_1.asyncWriteFile(outFile, assString); return ''; } } function parseArgs() { const argv = process.argv.filter(e => e !== '--'); return commander_1.default .command('kar-to-ass') .description('Converts midi/kar files to ass format') .version(pjson.version) .option('-i, --in <karFile> (required)', 'the file to read data from') .option('-o, --out <assFile>', 'if set, saves the converted data there instead of printing it on stdout') .option('-c, --correction <cs>', 'offsets said amount of cs on each line', 0) .option('-p, --progressive', 'use kf instead of k ') .parse(argv); } if (require.main === module) mainCLI() .then(data => console.log(data)) .catch(err => console.error(err)); //# sourceMappingURL=index.js.map