内容简介:使用 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 秋季《深度学习导论》中文字幕版今日上线!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTTP
David Gourley、Brian Totty、Marjorie Sayer、Anshu Aggarwal、Sailu Reddy / O'Reilly Media / 2002-10-7 / USD 54.99
Product Description Web technology has become the foundation for all sorts of critical networked applications and far-reaching methods of data exchange, and beneath it all is a fundamental protocol......一起来看看 《HTTP》 这本书的介绍吧!