如何把含内嵌字幕的mkv转换为mp4

我走的哪些弯路就不详细说了,直奔主题。曾经 mkv 如此流行,以至于好多老资源都是 mkv 格式的,在 PC 上播放没问题,但如果想直接在电视或者投屏,问题就很多了,可能编码不支持,可能字幕不显示。但对于 mp4 格式的视频,手机和电视等设备都显得友好很多。如果直接用转换工具把 mkv 转换成 mp4 的话,得到的结果是不包含字幕的,对于不擅长看生肉的人来说是很痛苦的。而对于已经包含内嵌字幕的 mkv,解决的思路是先把字幕提取出来,然后在转换的时候带上。

在此之前先说明一下,这个方案是在win上的工具来完成的。而且源视频是包含内嵌字幕的。对于没有内嵌字幕的,只能从网上找好,然后直接压制。

1,准备工具

需要小丸工具箱。建议从官方网站下载。

如何安装请参考官方指南。打开界面如下图。

继续阅读“如何把含内嵌字幕的mkv转换为mp4”

匆匆过客

不知道每个人各自的目的地会是在哪里。

或许,我们不必知道。

因为在人生的大道上,总会有一些人会一路同行,互为同伴。

有过疑惑,也有过争执;有过沉默,也有过并肩作战。

彼此信念不同,种族不同,但不成障碍,也不成牵绊。

你我都只是匆匆过客。

好好的道一声,别了。

Phantomjs截图里的中文乱码问题

使用 Phantomjs 对网页进行截图,在本地运行都是好好的,但是一到服务器,首先遇到部署问题,然后是中文乱码问题,遇到中文字符就渲染成下划线 “_”。(其实不仅仅是中文,韩文什么的也是渲染不出来)。

这个问题应该不难,应该是因为服务器没有安装中文字体导致的。但难题是 alpine linux 的中文字体不太好找。网上搜了一圈,在这个 How can I use Chinese in Alpine headless chrome? 问答里找到点线索。

主要有以下两种写法(使用 Docker 进行部署的):

RUN echo @edge http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && apk add wqy-zenhei@edge

还有这种:

RUN apk add wqy-zenhei --update-cache --repository http://nl.alpinelinux.org/alpine/edge/testing --allow-untrusted

上面两种写法我都试过了,都不行,第一种写法说找不到 @edge 的版本,第二种写法说抛了个错 BAD signature 就退出了。

反正都不行。

无奈只能继续搜索,在 alpine linux package 网站里是可以搜到这个 wqy-zenhei 的,理论上第二种写法应该是对的,但是为何始终提示 BAD signature 这个错误?重新又试了几次之后,感觉肯定有哪里出错了,难道这个 repo 里的文件是不对的?于是搜索 alpine linux 的其它 repository,还找到了,赶紧试试。

RUN apk add fontconfig mkfontscale wqy-zenhei --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing --allow-untrusted

运气真好,这个 repository 里的文件是没有问题的。然后修改了一下配置,加上 fontconfig 和 mkfontscale 两个依赖。这样,就可以在服务器愉快地渲染中文内容了,神奇的是加上这一行之后,连韩文都搞定了。一箭双雕笑。

Phantomjs部署到docker服务器

基础环境是 alpine-node:6,要把 Phantomjs 部署到该服务器上,发现直接在 package.json 里加上 phantomjs-prebuilt 的依赖是不能运行的。

网络搜了一轮,发现是 Phantomjs 在 alpine linux 上是有问题的,找到这个 issue,尝试把下面这段加到 Dockerfile 里:

RUN apk update && apk add --no-cache fontconfig curl curl-dev && \
    mkdir -p /usr/share && \
    cd /usr/share \
    && curl -L https://github.com/Overbryd/docker-phantomjs-alpine/releases/download/2.11/phantomjs-alpine-x86_64.tar.bz2 | tar xj \
    && ln -s /usr/share/phantomjs/phantomjs /usr/bin/phantomjs \
    && phantomjs --version

的确在加入这段之后,它能找到 phantomjs 了,但是执行 createPage 的操作时并不返回,不清楚是不是哪个 package 里的 bug,打开 debug 之后,发现 send 事件之后是没有 receive 事件的,NOOP command 也仅仅发送一次,也就是说 phantomjs 没有收到命令,或者收到了没有反应。由于缺乏上下文,不清楚网上其它人是怎么能跑起来的,没办法,只好另寻它路。

然后搜到这个代码片段,它里面是使用了 phantomized,试了一下这段代码:

# 2: Download+Install PhantomJS, as the npm package 'phantomjs-prebuilt' won't work on alpine!
# See https://github.com/dustinblackman/phantomized
RUN set -ex \
  && apk add --no-cache --virtual .build-deps ca-certificates openssl \
  && wget -qO- "https://github.com/dustinblackman/phantomized/releases/download/2.1.1/dockerized-phantomjs.tar.gz" | tar xz -C / \
  && npm install -g phantomjs \
  && apk del .build-deps

这次终于能运行了。

很好的 C语言入门教程(中文)

豆瓣上备受好评的 《Linux C 编程一站式学习》 网上几大书店都无货了,淘宝有,但是贵,然后竟然在 Github 上找到它的在线版本 http://akaedu.github.io/book/,真心要点赞啊。

linux-c-on-github

这个书还有个新版本,叫《一站式学习 C 编程》,也是无货的。具体内容我没有比较过,但是基础知识应该是差不多的。新版书名中把 Linux 去掉了,也是可以理解的,毕竟 C 不局限于 Linux,特别是现在多种平台,还有逐步升温的各式嵌入式设备,在可以 预见的未来 C 语言还将继续扛大旗

program-language-trends

这样看趋势还不明显,不过相信很快大家都会感受到的了。

Javascript hashCode 函数

网上找了好一轮,找到个比较像样而且足够短的 hashCode 实现,是从 Java 的 hashCode 中借鉴而得的。原理见 Java hashCode() ,也可以跟这里的 Java String 的源码 参照对比一下。

为了使用的方便,稍稍再改良了一下

function hashcode(str) {
  var hash = 0, i, chr, len;
  if (str.length === 0) return hash;
  for (i = 0, len = str.length; i < len; i++) {
    chr   = str.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
}

hashcode("this is a string")
//-1853110172

这里接受的参数是一个 String,其它类型怎么办?可以先做一个统一的处理,比如

hashcode(JSON.stringify(obj))

序列化之后再使用 hashCode 函数,基本所有类型数据都通吃,除了含有循环嵌套的对象。

PS:
函数实现中有一行使用了 “|” 运算符,只是利用 Bitwise 运算符转换参数为 32bit,用来确保结果是个 32位整数。

如何生成唯一且不可预测的 ID

通常数据库可以生成唯一的 ID,最多的就是数字序列,也有像 MongoDB 这样产生组合序列的,不过这种形式的 ID 由于是序列,是可以预测的。如果想得到不可预测且唯一的 ID,方法还是有的。

下面主要以 Node.js 的环境为例。

Node-uuid

Github 上有个 node-uuid 项目,它可以快速地生成符合 RFC4122 规范 version 1 或者 version 4 的 UUID。

安装,既可以通过 npm install node-uuid ,也可以在 package.json 中定义。使用方式:

var uuid = require('node-uuid');

// 产生一个 v1 (基于时间的) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// 产生一个 v4 (随机) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1’

听起来很有保证,只是……有点太长了。

坊间也有一些在 UUID 基础上随机截取几位的办法来组成一个新的短一点的字符串,只不过唯一性就又重新成为一个问号了。

Hashids

另外一个方法,来自 hashids,它的原理就是从数字经过一个加盐(salted)算法产生一个哈希(hash)字符串。这样算法就是通过混淆使结果具有不可预测性,而唯一性依然由数字本身来达成,从而得到(类似 youtube 里的)足够短,不可预测且唯一的 ID。

安装方式类似,只是 hashids 建议使用一个固定的版本。比如在 package.json 中

"dependencies": {
  "hashids": "0.3.3"
}

使用方法也很简单。先设定一个字符串作为 salt。

var Hashids = require("hashids"),
    hashids = new Hashids("this is my salt”);

然后对数字(准确来说是数字数组)进行编码

var hash = hashids.encrypt(12345);
// Nkk9

var hash = hashids.encrypt(683, 94108, 123, 5);
// aBMswoO2UB3Sj

对数组编码可以有很有趣的用法,比如需要在一个分布式的环境里使用,可以使用机器编号 + 序列数字组合数组然后再编码。

有编码就有解码

var numbers = hashids.decrypt("NkK9”);
// [12345]

编码的输出会随着数字的增大而变长,为了达到足够混淆,它可以指定最少长度。

hashids = new Hashids("this is my salt", 8);

var hash = hashids.encrypt(1);
// gB0NV05e

还有其它选项,比如控制输出所使用的字符,编码 MongoDB 的 ObjectId 等等。

上面介绍的两个项目,各有各优缺点,不过目的是一致的,可以根据实际情况选用。两个项目在其它语言上也有类似的实现。

如何在命令行中使用 proxy

国内的网络形势你懂的,要翻墙,无法是 VPN 或者 proxy。我个人还是用 proxy 比较多,浏览器里装个插件就能自动适应。但是那只是针对浏览器,命令行也很常用,遇墙就会卡着不动了。

有一个软件可以帮助你在 Command Line 里使用 proxy,叫 ProxyChains-NG (new generation)

在 Mac 上安装超简单(只要你机器上装好了 brew

brew install proxychains-ng

==> Downloading https://downloads.sourceforge.net/project/proxychains-ng/proxychains-4.7.tar.bz2
 ######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/proxychains-ng/4.7 --sysconfdir=/usr/local/Cellar/proxychains-ng/4.7/etc
==> make
==> make install
==> make install-config
==> /usr/local/Cellar/proxychains-ng/4.7: 9 files, 92K, built in 10 seconds

其它平台的安装大同小异,先找找有没有一个命令能搞掂的,没有的话参考一下其文档的 Installation 部分。

然后,做一个简单配置,打开配置文件

vi /usr/local/etc/proxychains.conf

视乎你的安装方式不同,配置文件的地方略有不同,但会遵从平台的一般规范,例如在 Linux 上安装,配置文件的位置可能在 /etc/proxychains.conf

打开配置文件之后,略过前面所有,直奔最后一行,默认配置是使用 tor 的,根据你机器上 proxy 的种类配置好就可以了。常见的配置

http    127.0.0.1  8080
socks5  127.0.0.1  1080

其实上面几行就有 example ,找到合适的照抄就是了。

最后,使用也非常简单,只要在命令前面加个 proxychains4,比如

proxychains4 telnet targethost.com

PS. 还有个名字接近但更加老牌的同类软件, ProxyChains ,使用方法几乎一样。

Javascript void(0)

JavaScript-logo常有人疑惑一个看上去很简单的问题,<a href=”javascript:void(0)”>some button</a> 里面的 void(0) 是什么意思?又或者不明白为什么好像很多人要这么写而不是其它更加简洁的写法,比如 <a href=”#”>some button</a>

href=”javascript:void(0)” 实际上是为了在 link 被点击的时候,返回一个空值,告诉浏览器什么都不用做。因为浏览器会把当前页面里的内容替换为返回的结果。(这个效果反而让我感到奇怪,因为真的很少这么用)

而 href=”#” 看上去简洁,但是它其实有个默认的行为,会把页面重新定位到页面顶部,这就是为什么页面会跳一下的一个原因。因为更多的情况,点击后页面保持在原位才是我们想要的结果。使用 # 甚至可能出现一些更加奇葩的问题

除了这个,还有没有其它更加简洁的写法呢?会不会是 <a href=””>some button</a> 呢?这个点击后会刷新当前页面,显然不符合要求。应该是 <a href=”javascript:;”>some button</a> ,什么都不执行。但有时过分简洁也容易造成“不清晰”的印象从而引起不必要争拗。如果从代码可读性考虑,也为了团队内沟通少点分歧,我会建议使用 href=”javascript:void(0)”。

void 操作符最原始就是用来“制造” undefined ,特别是某段代码只需要其副作用(side effect)又不希望有返回值产生。void 本身没有副作用,也没有正作用(返回值是空),但却能包含一切,犹如黑洞一般神秘。

== 参考 ==
Void Operator in MDN