内容简介:使用 nodejs 可以非常方便的开发命令行工具,来解决我们遇到的一些问题。现在就让我们看看如何使用 nodejs 开发一个把 .srt 格式的字幕文件翻译成中文和外语的双语字幕,然后在把它发布到 npm 仓库中。在安装好 nodejs 环境后,进入到项目目录后使用
使用 nodejs 可以非常方便的开发命令行工具,来解决我们遇到的一些问题。
现在就让我们看看如何使用 nodejs 开发一个把 .srt 格式的字幕文件翻译成中文和外语的双语字幕,然后在把它发布到 npm 仓库中。
准备
在安装好 nodejs 环境后,进入到项目目录后使用
npm init -y 复制代码
来,创建 package.json 文件,然后我选择把主文件放入 src 下。
├── package.json
└── src
└── fysrt.js
复制代码
然后我们需要安装如下依赖
commander.js
commander.js 可以帮助我们解析命令行参数和注册子命令,显示帮助信息,版本号。。。
var program = require('commander');
program
.version('0.1.0')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
program.on('--help', function(){
console.log('')
console.log('Examples:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
});
program.parse(process.argv);
复制代码
Usage: custom-help [options] Options: -h, --help output usage information -V, --version output the version number -f, --foo enable some foo -b, --bar enable some bar -B, --baz enable some baz Examples: $ custom-help --help $ custom-help -h 复制代码
Inquirer.js
Inquirer.js 可以让命令行与用户进行交互。
signale
signale 可以用来打印信息到屏幕
fs-extra 和 klaw
fs-extra 是对 fs 的包装,它提供了 promise 支持,还有一些有用的功能。
klaw 原本属于 fs-extra 的一个功能,但是现在它被抽离出来,它可以用来遍历目录。
translate-google-cn
translate-google-cn 是我把 google-translate-api 稍微改了一下。
- 把
google.com变成google.cn - 修改了获取
token的正则(原来的不起作用了)。 - 添加了 cookie ,这样更不容易被 google 封 ip
更多
执行脚本
现在我们可以使用 $ node src/fysrt.js 来执行这个文件,但是这很麻烦,我们想使用 $ fysrt 来直接执行这个文件。
首先我们在文件开头加入
#!/usr/bin/env node 复制代码
不加的话我们的脚本文件,就不会使用 node 执行它。
bin
然后我们在 package.json 中加入 bin 字段
使用 bin 字段可以将命令名和文件名映射,在安装时 npm 会将我们的可执行文件符号链接到 {prefix}/bin (全局安装)或 ./node_modules/.bin/ 本地安装,这样我们就不用输入路径来执行文件了。
{
"name": "fysrt",
"main": "src/fysrt.js",
"bin": "src/fysrt.js"
}
复制代码
当 bin 是一个字符串时,代表命令名与包名同名。
它还可以安装多个命令。
{
"bin": {
"c1": "bin/c1.js",
"c2": "bin/c2.js"
}
}
复制代码
这样安装就有 c1 与 c2 两个命令。
npm link
我们想让上面设置的 bin 起作用,可以发布和安装包,npm 才会帮我们做符号链接,但是这样太麻烦,我们还可以使用 npm link 命令。
它可以简写为 npm ln ,我们直接去项目目录执行 npm link 就可以了。
它会根据 package.json 的配置,在 {prefix}/lib/node_modules/<package> 中创建一个符号链接,它还会将包中的任何 bin 文件链接到 {prefix}/bin/{name} 。
如果我们想把它当作一个普通的包使用,我们可以去要用到它的项目文件夹,执行 npm link fysrt ,它会在该项目文件夹下的 node_modules 中链接到全局的 fysrt 。我们对 fysrt 的修改都可以直接映射到该项目的 fysrt。
当我们想取消链接时可以执行 npm unlink fysrt 。
srt 字幕文件
srt 字幕文件中的一句字幕,分为三部分。
650 00:45:07,650 --> 00:45:09,110 Fifteen minutes. 651 00:45:10,650 --> 00:45:20,110 Fifteen minutes.Fifteen minutes.Fifteen minutes. 复制代码
索引编号,时间,和字幕。字幕前面可能会有一些特效代码,如 {\an6} 等等命令,或者还有 html 形式的。
每句字幕使用两个换行符分隔。
代码编写
我们使用 commander.js 来处理命令行参数。
commander
.version(version)
.option('-d, --delete', '删除原文件')
.option('-s, --single', '单语字幕,而不是双语字幕')
.option('-f, --from <lang>', '原始语言,默认 auto')
.option('-t, --to <lang>', '翻译成什么语言,默认 zh-cn')
.option(
'-T, --time <time>',
'每个字幕文件的翻译时间间隔 毫秒,默认 3000 毫秒'
)
.option(
'-S, --size <size>',
'一次给 google api 翻译的文本量,默认一次 50 行字幕'
)
.on('--help', () => {
console.log();
console.log('Examples:');
console.log(' $ fysrt ./subtitles');
console.log(' $ fysrt -d a.srt');
console.log(' $ fysrt -f en a.srt');
})
.parse(process.argv);
复制代码
然后我们可以使用 commander.args[0] 获取到输入的 目录或者字幕文件。
当没有目录或文件时,我们可以提示是否翻译当前目录下的所有字幕文件。
const ans = await inquirer.prompt([
{
type: 'confirm',
name: 'dir',
message: '翻译当前文件夹下的所有字幕文件?',
default: false
}
]);
if (!ans.dir) return;
复制代码
如果是文件夹的话,我们使用 klaw 遍历目录,找到所有 srt 文件。
const files = [];
walk(target)
.on('data', ({ path: p }) => p && p.endsWith('.srt') && files.push(p))
.on('end', async () => {
const len = files.length;
if (len === 0) {
signale.error(`目录下没有 .srt 文件 -> ${target}`);
process.exit(1)
}
// ...
});
复制代码
然后我们读取字幕文件然后解析它,由于有些 srt 字幕文件不严格符合规范, 所以需要一行一行的判断这一行是时间还是字幕。
const lines = rawData.trim().split(/(?:\r\n|\n|\r)/); // 获取所有行
const data = [];
for (let i = 0, len = lines.length; i < len; i++) {
let l = lines[i].trim();
// eslint-disable-next-line eqeqeq
if (!l || ~~l !== 0 || l == 0) continue; // 如果是空行或者是编号行则跳过
if (/^(?:\d+:){2}\d+,\d+\s-->\s(?:\d+:){2}\d+[,.]\d+$/.test(l)) {
data.push([l]); // 处理时间行
} else if (/^\d+:\d+\.\d+\s-->\s\d+:\d+\.\d+$/.test(l)) {
data.push([ // 处理 vtt 文件格式的时间行
l
.replace(/\./g, ',')
.split(' --> ')
.map(s => '00:' + s)
.join(' --> ')
]);
} else { // 处理字幕行
l = l.replace(/^(?:\{\\\w.*\})+/, ''); // 去除特效代码
let last = data[data.length - 1];
if (last.length === 1) {
last.push(l);
} else {
last[1] = last[1] + '\n' + l;
}
}
}
复制代码
然后我们就使用谷歌翻译
const requests = [];
for (let i = 0, len = textArr.length; i <= len; i += size) {
// textArr 就是上面 data 的 data.map(d => d[1]),size 是上面命令行传入的参数,默认 50 行
// 因为翻译是 get 请求,一次性太多文字,谷歌服务器会报 413 错
requests.push(
translate(textArr.slice(i, i + size).join('\n\n'), {
from,
to
})
);
}
const res = await Promise.all(requests); // 并发的去翻译
复制代码
最后把得到的翻译组合起来,然后写入到文件中就可以了。
const translate = res
.map(r => r.text.split('\n\n'))
.reduce((acc, val) => {
acc.push(...val);
return acc;
}, []);
data
.map(
(d, i) =>
`${i + 1}\n${d[0]}\n${translate[i]}${keep ? '\n' + d[1] : ''}`
)
.join('\n\n') + '\n\n'
复制代码
源码
上面的代码只是这个小工具的核心部分,
完整的代码可以参考 github 仓库 。
发布 npm 包
npm 包分为 unscoped 和 scoped,unscoped 就是我们常见的 npm 包,scoped 就是包前面有一个 @ 符号的包比如 @vue/cli 。
scoped 包可以分为团体和个人。
scoped 的包默认是私有的,但需要付费。可修改 package.json 文件让它是公开的。
要发布包到 npm 我们首先要注册一个 npm 帐号。
然后登入账户
npm login 复制代码
再发布包
npm publish 复制代码
这样就可以了。但是有可能报错,比如仓库中已经有这个包名了,这时只有换一个名字,或者发布 scoped 包。
我们可以修改 package.json
{
"name": "@npm账户名称/包名"
}
复制代码
账户名可以通过
npm whoami 复制代码
查询。
然后我们在发布公共包
npm publish --access public 复制代码
迭代包
我们可以使用 npm version 命令递增版本号。
npm 版本号是 major.minor.patch 主版本.次版本.补丁版本。
npm version patch 复制代码
我们去查看 package.json 就会发现 version 字段改变了。
然后再发布包
npm publish 复制代码
废弃 删除 包
我们可以废弃一个包的版本或者整个包。
npm deprecate <pkg>[@<version>] <message> 复制代码
npm 不建议删除包,因为包可能被别人引用。所以 npm 做了限制
- 删除的版本 24 小时后方可重发
- 包发布 72 小时之内才可删除
npm unpublish pkg --force 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Subtitle Edit 3.5.15 发布,字幕编辑工具
- Subtitle Edit 3.5.17 发布,字幕编辑工具
- 重磅 | CS 294 2018 今日开课!双语字幕独家上线!
- Subtitle Edit 3.5.10 发布,字幕编辑工具
- 【FreeBuf字幕组】Hacker101白帽进阶之路-密码存储问题
- 独家 | CMU 2018 秋季《深度学习导论》中文字幕版今日上线!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hit Refresh
Satya Nadella、Greg Shaw / HarperBusiness / 2017-9-26 / USD 20.37
Hit Refresh is about individual change, about the transformation happening inside of Microsoft and the technology that will soon impact all of our lives—the arrival of the most exciting and disruptive......一起来看看 《Hit Refresh》 这本书的介绍吧!