refactor(node-syncsub): take in a list of langs to sync
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
551691f061
commit
aeddb3eb92
3 changed files with 265 additions and 50 deletions
|
@ -28,7 +28,6 @@
|
||||||
"default-param-last": ["error"],
|
"default-param-last": ["error"],
|
||||||
"eqeqeq": ["error", "smart"],
|
"eqeqeq": ["error", "smart"],
|
||||||
"func-names": ["warn", "never"],
|
"func-names": ["warn", "never"],
|
||||||
"func-style": ["warn", "expression"],
|
|
||||||
"logical-assignment-operators": ["warn", "always"],
|
"logical-assignment-operators": ["warn", "always"],
|
||||||
"no-array-constructor": ["error"],
|
"no-array-constructor": ["error"],
|
||||||
"no-empty-function": ["warn"],
|
"no-empty-function": ["warn"],
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export const iso6391To3 = new Map([
|
export const ISO6391To3 = new Map([
|
||||||
['aa', 'aar'],
|
['aa', 'aar'],
|
||||||
['ab', 'abk'],
|
['ab', 'abk'],
|
||||||
['af', 'afr'],
|
['af', 'afr'],
|
||||||
|
@ -184,3 +184,190 @@ export const iso6391To3 = new Map([
|
||||||
['zh', 'zho'],
|
['zh', 'zho'],
|
||||||
['zu', 'zul'],
|
['zu', 'zul'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const ISO6393To1 = new Map([
|
||||||
|
['aar', 'aa'],
|
||||||
|
['abk', 'ab'],
|
||||||
|
['afr', 'af'],
|
||||||
|
['aka', 'ak'],
|
||||||
|
['amh', 'am'],
|
||||||
|
['ara', 'ar'],
|
||||||
|
['arg', 'an'],
|
||||||
|
['asm', 'as'],
|
||||||
|
['ava', 'av'],
|
||||||
|
['ave', 'ae'],
|
||||||
|
['aym', 'ay'],
|
||||||
|
['aze', 'az'],
|
||||||
|
['bak', 'ba'],
|
||||||
|
['bam', 'bm'],
|
||||||
|
['bel', 'be'],
|
||||||
|
['ben', 'bn'],
|
||||||
|
['bis', 'bi'],
|
||||||
|
['bod', 'bo'],
|
||||||
|
['bos', 'bs'],
|
||||||
|
['bre', 'br'],
|
||||||
|
['bul', 'bg'],
|
||||||
|
['cat', 'ca'],
|
||||||
|
['ces', 'cs'],
|
||||||
|
['cha', 'ch'],
|
||||||
|
['che', 'ce'],
|
||||||
|
['chu', 'cu'],
|
||||||
|
['chv', 'cv'],
|
||||||
|
['cor', 'kw'],
|
||||||
|
['cos', 'co'],
|
||||||
|
['cre', 'cr'],
|
||||||
|
['cym', 'cy'],
|
||||||
|
['dan', 'da'],
|
||||||
|
['deu', 'de'],
|
||||||
|
['div', 'dv'],
|
||||||
|
['dzo', 'dz'],
|
||||||
|
['ell', 'el'],
|
||||||
|
['eng', 'en'],
|
||||||
|
['epo', 'eo'],
|
||||||
|
['est', 'et'],
|
||||||
|
['eus', 'eu'],
|
||||||
|
['ewe', 'ee'],
|
||||||
|
['fao', 'fo'],
|
||||||
|
['fas', 'fa'],
|
||||||
|
['fij', 'fj'],
|
||||||
|
['fin', 'fi'],
|
||||||
|
['fra', 'fr'],
|
||||||
|
['fry', 'fy'],
|
||||||
|
['ful', 'ff'],
|
||||||
|
['gla', 'gd'],
|
||||||
|
['gle', 'ga'],
|
||||||
|
['glg', 'gl'],
|
||||||
|
['glv', 'gv'],
|
||||||
|
['grn', 'gn'],
|
||||||
|
['guj', 'gu'],
|
||||||
|
['hat', 'ht'],
|
||||||
|
['hau', 'ha'],
|
||||||
|
['hbs', 'sh'],
|
||||||
|
['heb', 'he'],
|
||||||
|
['her', 'hz'],
|
||||||
|
['hin', 'hi'],
|
||||||
|
['hmo', 'ho'],
|
||||||
|
['hrv', 'hr'],
|
||||||
|
['hun', 'hu'],
|
||||||
|
['hye', 'hy'],
|
||||||
|
['ibo', 'ig'],
|
||||||
|
['ido', 'io'],
|
||||||
|
['iii', 'ii'],
|
||||||
|
['iku', 'iu'],
|
||||||
|
['ile', 'ie'],
|
||||||
|
['ina', 'ia'],
|
||||||
|
['ind', 'id'],
|
||||||
|
['ipk', 'ik'],
|
||||||
|
['isl', 'is'],
|
||||||
|
['ita', 'it'],
|
||||||
|
['jav', 'jv'],
|
||||||
|
['jpn', 'ja'],
|
||||||
|
['kal', 'kl'],
|
||||||
|
['kan', 'kn'],
|
||||||
|
['kas', 'ks'],
|
||||||
|
['kat', 'ka'],
|
||||||
|
['kau', 'kr'],
|
||||||
|
['kaz', 'kk'],
|
||||||
|
['khm', 'km'],
|
||||||
|
['kik', 'ki'],
|
||||||
|
['kin', 'rw'],
|
||||||
|
['kir', 'ky'],
|
||||||
|
['kom', 'kv'],
|
||||||
|
['kon', 'kg'],
|
||||||
|
['kor', 'ko'],
|
||||||
|
['kua', 'kj'],
|
||||||
|
['kur', 'ku'],
|
||||||
|
['lao', 'lo'],
|
||||||
|
['lat', 'la'],
|
||||||
|
['lav', 'lv'],
|
||||||
|
['lim', 'li'],
|
||||||
|
['lin', 'ln'],
|
||||||
|
['lit', 'lt'],
|
||||||
|
['ltz', 'lb'],
|
||||||
|
['lub', 'lu'],
|
||||||
|
['lug', 'lg'],
|
||||||
|
['mah', 'mh'],
|
||||||
|
['mal', 'ml'],
|
||||||
|
['mar', 'mr'],
|
||||||
|
['mkd', 'mk'],
|
||||||
|
['mlg', 'mg'],
|
||||||
|
['mlt', 'mt'],
|
||||||
|
['mon', 'mn'],
|
||||||
|
['mri', 'mi'],
|
||||||
|
['msa', 'ms'],
|
||||||
|
['mya', 'my'],
|
||||||
|
['nau', 'na'],
|
||||||
|
['nav', 'nv'],
|
||||||
|
['nbl', 'nr'],
|
||||||
|
['nde', 'nd'],
|
||||||
|
['ndo', 'ng'],
|
||||||
|
['nep', 'ne'],
|
||||||
|
['nld', 'nl'],
|
||||||
|
['nno', 'nn'],
|
||||||
|
['nob', 'nb'],
|
||||||
|
['nor', 'no'],
|
||||||
|
['nya', 'ny'],
|
||||||
|
['oci', 'oc'],
|
||||||
|
['oji', 'oj'],
|
||||||
|
['ori', 'or'],
|
||||||
|
['orm', 'om'],
|
||||||
|
['oss', 'os'],
|
||||||
|
['pan', 'pa'],
|
||||||
|
['pli', 'pi'],
|
||||||
|
['pol', 'pl'],
|
||||||
|
['por', 'pt'],
|
||||||
|
['pus', 'ps'],
|
||||||
|
['que', 'qu'],
|
||||||
|
['roh', 'rm'],
|
||||||
|
['ron', 'ro'],
|
||||||
|
['run', 'rn'],
|
||||||
|
['rus', 'ru'],
|
||||||
|
['sag', 'sg'],
|
||||||
|
['san', 'sa'],
|
||||||
|
['sin', 'si'],
|
||||||
|
['slk', 'sk'],
|
||||||
|
['slv', 'sl'],
|
||||||
|
['sme', 'se'],
|
||||||
|
['smo', 'sm'],
|
||||||
|
['sna', 'sn'],
|
||||||
|
['snd', 'sd'],
|
||||||
|
['som', 'so'],
|
||||||
|
['sot', 'st'],
|
||||||
|
['spa', 'es'],
|
||||||
|
['sqi', 'sq'],
|
||||||
|
['srd', 'sc'],
|
||||||
|
['srp', 'sr'],
|
||||||
|
['ssw', 'ss'],
|
||||||
|
['sun', 'su'],
|
||||||
|
['swa', 'sw'],
|
||||||
|
['swe', 'sv'],
|
||||||
|
['tah', 'ty'],
|
||||||
|
['tam', 'ta'],
|
||||||
|
['tat', 'tt'],
|
||||||
|
['tel', 'te'],
|
||||||
|
['tgk', 'tg'],
|
||||||
|
['tgl', 'tl'],
|
||||||
|
['tha', 'th'],
|
||||||
|
['tir', 'ti'],
|
||||||
|
['ton', 'to'],
|
||||||
|
['tsn', 'tn'],
|
||||||
|
['tso', 'ts'],
|
||||||
|
['tuk', 'tk'],
|
||||||
|
['tur', 'tr'],
|
||||||
|
['twi', 'tw'],
|
||||||
|
['uig', 'ug'],
|
||||||
|
['ukr', 'uk'],
|
||||||
|
['urd', 'ur'],
|
||||||
|
['uzb', 'uz'],
|
||||||
|
['ven', 've'],
|
||||||
|
['vie', 'vi'],
|
||||||
|
['vol', 'vo'],
|
||||||
|
['wln', 'wa'],
|
||||||
|
['wol', 'wo'],
|
||||||
|
['xho', 'xh'],
|
||||||
|
['yid', 'yi'],
|
||||||
|
['yor', 'yo'],
|
||||||
|
['zha', 'za'],
|
||||||
|
['zho', 'zh'],
|
||||||
|
['zul', 'zu'],
|
||||||
|
]);
|
||||||
|
|
|
@ -1,55 +1,98 @@
|
||||||
import { readdir } from 'fs';
|
import {
|
||||||
import { ffprobe } from 'fluent-ffmpeg';
|
mkdir,
|
||||||
|
readdir as readDir,
|
||||||
|
rename as mv,
|
||||||
|
} from 'fs/promises';
|
||||||
|
|
||||||
|
import { ffprobe as ffProbe } from 'fluent-ffmpeg';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { iso6391To3 } from './lang-codes';
|
|
||||||
|
|
||||||
const SUB_EXT_LENGTH = 7;
|
import { ISO6391To3, ISO6393To1 } from './lang-codes';
|
||||||
|
|
||||||
|
|
||||||
const FILE = process.argv[2];
|
/**
|
||||||
|
* These are the cli arguments
|
||||||
|
*
|
||||||
|
* @param directory the directory in which we want to sync the subtitles
|
||||||
|
* @param languages a comma-separated list of languages (3 letters) to sync the subtitles
|
||||||
|
*/
|
||||||
|
const DIR = process.argv[2];
|
||||||
|
let langs = process.argv[3].split(',');
|
||||||
|
|
||||||
const main = () => {
|
|
||||||
const BASE_NAME = FILE.substring(
|
|
||||||
FILE.lastIndexOf('/') + 1,
|
|
||||||
FILE.length - SUB_EXT_LENGTH,
|
|
||||||
);
|
|
||||||
|
|
||||||
const DIR = FILE.substring(0, FILE.lastIndexOf('/'));
|
// Check if there are 2 params
|
||||||
|
if (DIR && langs) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error('Error: no argument passed');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
readdir(DIR, (_, files) => {
|
function getVideoPath(files: string[]) {
|
||||||
const VIDEO = `${DIR}/${files.filter((f) =>
|
const fileName = DIR.split('/').at(-1) ?? '';
|
||||||
f.includes(BASE_NAME) &&
|
|
||||||
|
return `${DIR}/${files.filter((f) =>
|
||||||
|
f.includes(fileName) &&
|
||||||
!f.endsWith('.nfo') &&
|
!f.endsWith('.nfo') &&
|
||||||
!f.endsWith('.srt'))[0]}`;
|
!f.endsWith('.srt'))[0]}`;
|
||||||
|
}
|
||||||
|
|
||||||
ffprobe(VIDEO, (_e, data) => {
|
async function main() {
|
||||||
const LANG = iso6391To3.get(FILE.split('.').at(-2) ?? 'en') ?? 'eng';
|
const files = await readDir(DIR);
|
||||||
|
|
||||||
const OUT_FILE = `${BASE_NAME}.synced.${LANG.substring(0, 2)}.srt`;
|
const VIDEO = getVideoPath(files);
|
||||||
const OUT_PATH = `${DIR}/${OUT_FILE}`;
|
const BASE_NAME = VIDEO.split('/').at(-1)?.replace(/\.[^.]*$/, '');
|
||||||
|
|
||||||
if (files.includes(OUT_FILE)) {
|
// Check if backup folder already exists and create it if not
|
||||||
console.warn('Synced subtitles already exist, not doing anything');
|
if (!files.some((f) => f.endsWith('.srt.bak'))) {
|
||||||
|
await mkdir(`${DIR}/.srt.bak`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const backups = await readDir(`${DIR}/.srt.bak`);
|
||||||
|
|
||||||
|
// Remove synced subtitles from the list to sync
|
||||||
|
// langs - backups
|
||||||
|
langs = langs.filter((n) => !backups
|
||||||
|
.some((s) => n === ISO6391To3.get(s.split('.').at(-2) ?? '')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (langs.length === 0) {
|
||||||
|
console.warn('Subtitles have already been synced');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const availLangs = data.streams
|
// ffprobe the video file to see available audio tracks
|
||||||
|
ffProbe(VIDEO, (_e, data) => {
|
||||||
|
const AVAIL_LANGS = data.streams
|
||||||
.filter((s) => s.codec_type === 'audio')
|
.filter((s) => s.codec_type === 'audio')
|
||||||
.map((s) => s['tags']['language']);
|
.map((s) => s['tags']['language']);
|
||||||
|
|
||||||
|
// Sync subtitles one by one
|
||||||
|
langs.forEach(async(lang) => {
|
||||||
|
const FILE_NAME = `${BASE_NAME}.${ISO6393To1.get(lang)}.srt`;
|
||||||
|
const IN_FILE = `${DIR}/.srt.bak/${FILE_NAME}`;
|
||||||
|
const OUT_FILE = `${DIR}/${FILE_NAME}`;
|
||||||
|
|
||||||
|
if (files.includes(FILE_NAME)) {
|
||||||
|
await mv(OUT_FILE, IN_FILE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO: check data and extract sub
|
||||||
|
}
|
||||||
|
|
||||||
const cmd = [
|
const cmd = [
|
||||||
'--cli sync',
|
'--cli sync',
|
||||||
`--sub-lang ${LANG}`,
|
`--sub-lang ${lang}`,
|
||||||
|
|
||||||
`--ref-stream-by-lang ${availLangs.includes(LANG) ? LANG : availLangs[0]}`,
|
`--ref-stream-by-lang ${AVAIL_LANGS.includes(lang) ?
|
||||||
|
lang :
|
||||||
|
AVAIL_LANGS[0]}`,
|
||||||
'--ref-stream-by-type "audio"',
|
'--ref-stream-by-type "audio"',
|
||||||
|
|
||||||
`--sub '${FILE}'`,
|
`--sub '${IN_FILE}'`,
|
||||||
`--out '${OUT_PATH}'`,
|
`--out '${OUT_FILE}'`,
|
||||||
// `--out '${OUT_PATH}'`,
|
|
||||||
`--ref '${VIDEO}'`,
|
`--ref '${VIDEO}'`,
|
||||||
|
|
||||||
// '--overwrite',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
spawn('subsync', cmd, {
|
spawn('subsync', cmd, {
|
||||||
|
@ -58,18 +101,4 @@ const main = () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
if (FILE) {
|
|
||||||
if (FILE.includes('synced.srt')) {
|
|
||||||
console.warn('Won\'t sync already synced subtitles, not doing anything');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
main();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.error('Error: no argument passed');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue