...
 
Commits (3)
# CHANGELOG
## 1.0.8
- Detect CRLF on txt data and turns it into LF.
- Added ability to take just a txt as parameter containing frm+lyr files
## 1.0.7
- Do not add \k100 on first line if song begins at 00:00:00
......
......@@ -52,6 +52,8 @@ toyunda2ass myfile.frm myfile.lyr 23.98
It produces an ASS file on stdout.
You can also provide a txt file instead of frm+lyr. In this case splitTime() is called. Of course the FPS number becomes the second parameter.
FPS is optional. If not provided it'll strip the `.frm` on the first file and try to find a matching `.avi` file.
You need to have `ffmpeg` installed in your PATH so Toyunda2ASS can read fps info from a video file
......
{
"name": "toyunda2ass",
"version": "1.0.7",
"version": "1.0.8",
"description": "Convert Epitanime Toyunda karaoke files to ASS files",
"main": "dist/index.js",
"bin": {
......
#!/usr/bin/env node
import { asyncExists, asyncReadFile, msToAss, clone } from './utils';
import { asyncExists, asyncReadFile, msToAss, clone, getLineBreakChar } from './utils';
import { ToyundaData } from './types';
import stringify from 'ass-stringify';
import execa from 'execa';
......@@ -10,6 +10,7 @@ export function splitTime(txt: string): ToyundaData {
const lyr = [];
const frm = [];
let position = '';
if (getLineBreakChar(txt) === 'CRLF') txt = txt.replace(/\r\n/g, '\n');
for (const line of txt.split('\n')) {
if (line === '# --- LYRICS - GENERATE AGAIN AFTER YOU EDIT ---') {
position = 'lyr';
......@@ -127,18 +128,34 @@ async function mainCLI() {
Output goes to stdout
`;
}
const frmFile = process.argv[2];
const lyrFile = process.argv[3];
let fps = +process.argv[4];
let fps: number;
let lyr: string;
let frm: string;
let aviFile: string;
if (process.argv[2].endsWith('.txt')) {
const txtFile = process.argv[2];
fps = +process.argv[3];
if (!await asyncExists(txtFile)) throw `File ${txtFile} does not exist`;
aviFile = txtFile.replace('.txt', '.avi');
const txt = await asyncReadFile(txtFile, 'utf8');
const data = splitTime(txt);
lyr = data.lyrics.join('\n');
frm = data.frames.join('\n');
} else {
// We're in frm+lyr
fps = +process.argv[4];
const frmFile = process.argv[2];
const lyrFile = process.argv[3];
if (!await asyncExists(frmFile)) throw `File ${frmFile} does not exist`;
if (!await asyncExists(lyrFile)) throw `File ${lyrFile} does not exist`;
lyr = await asyncReadFile(lyrFile, 'utf8');
frm = await asyncReadFile(frmFile, 'utf8');
aviFile = frmFile.replace('.frm', '.avi');
}
if (!fps || isNaN(fps)) {
// Trying to guess FPS from video file
fps = await findFPS(frmFile.replace('.frm', '.avi'));
}
if (!await asyncExists(frmFile)) throw `File ${frmFile} does not exist`;
if (!await asyncExists(lyrFile)) throw `File ${lyrFile} does not exist`;
const lyr = await asyncReadFile(lyrFile, 'utf8');
const frm = await asyncReadFile(frmFile, 'utf8');
fps = await findFPS(aviFile);
}
return convertToASS({lyrics: lyr.split('\n'), frames: frm.split('\n')}, fps);
}
......
......@@ -28,3 +28,17 @@ export function msToAss(ms: number): string {
export function clone(a: any) {
return JSON.parse(JSON.stringify(a));
}
export function getLineBreakChar(string: string): 'CR' | 'LF' | 'CRLF' {
const indexOfLF = string.indexOf('\n', 1); // No need to check first-character
if (indexOfLF === -1) {
if (string.indexOf('\r') !== -1) return 'CR';
return 'LF';
}
if (string[indexOfLF - 1] === '\r') return 'CRLF';
return 'LF';
}
\ No newline at end of file