使用 nodejs 开发命令行小工具 - 谷歌翻译字幕

栏目: Node.js · 发布时间: 6年前

内容简介:使用 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 可以用来打印信息到屏幕

使用 nodejs 开发命令行小工具 - 谷歌翻译字幕

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
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Sexy Web Design

Sexy Web Design

Elliot Stocks / SitePoint / 2009-03-28 / $39.95

Description A guide to building usable, aesthetically pleasing interfaces for web sites and web applications by applying timeless principles of user-centered design. This book focuses on practical ......一起来看看 《Sexy Web Design》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具