分类
技术

欢迎欢迎

欢迎来到我的博客,我是 Meathill,想了解我可以点 关于我

我工作日晚上 9:00~10:00 会在 B 站直播,https://live.bilibili.com/5126601,大部分都是全栈开发相关,感兴趣的同学可以关注下。

10-18 ~ 10-22 直播计划。

日期上半场下半场
10-18重构插件
10-19重构插件
10-20重构插件
10-21重构插件Streamee
10-22重构插件Streamee
直播计划

欢迎留言点播各种内容。


近期作品

分类
chrome

Chrome Extension Manifest V3 升级笔记

关于 MV3 的知识,可以看这篇前文:

《Chrome 扩展大升级 Manifest V3:变化》

近期尝试把一个浏览器扩展升级到 MV3,然后发现了很多问题,写篇博客记录一下。

与文档不符

  • 很多号称返回 Promise 实例的方法实际上不会返回结果,或者在没有 callback 的时候会报错

文档未说明

  • service worker 里无法使用 chrome.i18n.getMessage 或者 chrome.i18n.getUILanguage。于是目前右键菜单都无法 i18n 了。

未实现 Promise 或者有 bug

  • chrome.storage.get(keys) 未 Promise 化,固定返回 undefined,需用回 callback
  • chrome.permissions.request 未 Promise 化
  • chrome.permissions.contains 必须传入 callback,不然报错

文档写了,但我没看见(>_<!)

  • 在 service worker 里使用 chrome.contextMenus.create 时,必须传入 id,且不能使用 onclick 函数,比如侦听 chrome.contextMenus.onClicked.addListener
分类
招聘

代友招聘:广州番禺广告公司招 PHP 工程师

做 ocpx 和 rta 方面的。dsp 平台 adx 方便的接口对接。

(上面这一行我完全看不懂……)

岗位职责:

  1. 负责公司产品后端系统维护,新功能开发,广告投放API对接;
  2. 参与需求讨论,对产品原型、功能逻辑设计等提出可靠建议;
  3. 使用yii2框架实现产品的标准化。

岗位要求:

  1. 计算机相关专业大专或本科学历,有2年以上PHP开发经验,有大型网站或者数据系统开发经验者优先;
  2. 熟悉前端语言:HTML5/CSS3,JavaScript,Ajax,jQuery等;
  3. 熟悉 MVC 框架,熟悉主流 PHP 框架 yii2,有独立开发项目经验者优先;
  4. 精通 MySQL,熟悉 Linux、Apache/nginx、Redis 的管理和维护。
  5. 有开发小程序后端、广告 Marketing API 项目经验者优先;
  6. 熟悉版本控制器 git/svn 的使用;
  7. 有优秀的沟通与表达能力,突出的学习能力,较强的动手能力与逻辑分析能力;
  8. 具备良好的团队合作精神,高度的责任感,善于沟通,为人踏实,抗压能力强,拥有严谨的工作态度,能虚心学习。
  9. 具备良好的代码编程习惯,熟悉面向对象编程,及较强的文档编写能力。

工作地点在番禺,朋友的公司,很靠谱。感兴趣的同学直接联系我吧。

分类
招聘

OpenResty Inc. 诚聘中高级前端工程师

OpenResty Inc. 是一家根植于开源 DNA 的技术型公司,我们致力于机器编程。我们有世界一流的技术实力,研发全新的技术,解决工业级别的挑战,服务全球众多企业级客户。

目前我们有四大产品,本次招聘的对象主要负责其中的 OpenResty Showman。所用到的技术栈包括 Vue 全家桶,现代化前端工具链,CodeMirror,浏览器扩展等。

岗位要求

  1. 精通 HTML/CSS/JavaScript
  2. 熟练掌握 Vue,了解其生态、发展状态,具备很好的开发和调试能力
  3. 熟悉 Web 规范,具备较强的工程能力,能够妥善规划和实施前端项目开发
  4. 熟悉 Node.js,了解前端工具链的发展,具备工具链开发能力
  5. 对设计模式等软件工程知识有较深理解
  6. 理解浏览器工作原理,具备较强的分析和调优能力
  7. 具备良好的代码习惯,能够坚持最佳实践
  8. 具备良好的自我管理能力,能独立完成工作

加分项

  1. 有实现过自己的小语言,写过语言编译器,或 CodeMirror Mode
  2. 熟悉浏览器插件机制和 API,写过自己的浏览器插件
  3. 有较强的主动学习能力
  4. 英语能力佳

工作地点不限,国家不限。我们不纠结于学历和专业,只看能力和经验。远程工作模式,自由度高。我们在深圳也有办公室。

分类
nodejs

捕获 promisify `child_process.exec` 的错误

这个东西文档里没写清楚,所以写篇博客记一下。

在 Node.js 里,我们可以使用 child_process 下的命令分裂出一个进程,执行其他的命令。这些命令包括 execexecFilespawn

我比较常使用 execspawn。前者用起来比较方便,只要传入完整的命令和参数,很接近日常命令行体验;后者传参要麻烦一些,不过可以实时获取输出,包括 stdoutstderr,比较方便给用户及时反馈。

下面贴一下文档里的例子,spawn 的使用将来有机会再说。

const { exec } = require('child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
});

Node.js 8 之后,我们可以用 util.promisify() 命令将 exec 转换为 Promise 风格的方法,即不再需要 callback 函数,而是返回 Promise 实例,方便我们链式调用或者使用 Async function。

此时,它的样子是这样的:

const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample();

官方文档没解释清楚错误处理,经过我的尝试,是这样的:

  1. 命令发生错误,或者被意外中断都会引发错误
  2. 如果不出错,就会正确返回 stdoutstderr
  3. 否则,错误实例里会包含 stdoutstderrcode
  4. 1~127 是各种错误编码,128+ 则是 signal + 127 的结果,通常来说是受控于我们的操作。比如使用 FFmpeg 录屏的时候,结束录制就要 Ctrl+C,此时就会得到值为 128 的 code。所以此时很可能不是真的失败。
const util = require('util');
const exec = util.promisify(require('child_process').exec);

(async () => {
  let code, stdout, stderr;
  try {
    ({stdout, stderr} = await exec('ls'));
  } catch (e) {
    ({code, stdout, stderr} = e);
  }

  if (code && code > 127) {
    // 确实失败了
  }
  console.log('stdout:', stdout);
  console.log('stderr:', stderr);
})();
分类
应用

应用创意:家用媒体中心

(这个灵感部分来源于群里的同学)

前阵子群里有同学问,能否用 electron 搭建服务器,提供局域网内的文件共享。

我突然想到,可以做一个这样的简单家用媒体中心:

  1. 封装成 Electron 应用,分发部署会容易很多
  2. 集成 Ghost,作为 CMS,提供 API 和网页服务
  3. 启动后,选择本地视频文件,就自动提取关键信息,然后从豆瓣上抓取影片内容,并生成影片详情页
  4. 然后局域网内电脑就可以访问这个服务,然后点播视频
  5. 也可以集成一些下载工具,直接下载磁力、BT等开放格式

产品功用

从功能来说,虽然弱于同类产品,比如 NAS 服务器。但是对于我这样的用户来说,平时下片和看片不多,偶尔可能需要在家里不同设备上看片,如果有个低成本的贡献工具,会比来回拷简单很多。

教程价值

从教程价值来考虑,这个项目倒是可圈可点。

  1. Electron 跨平台、易部署,其实一直都很受人关注
  2. Ghost 可以提供完整的 RESTful API,甚至好用的界面
  3. 于是我们可以很容易的把注意力集中在:
    1. 使用 RESTful API 的 SPA 开发,Vue3 全家桶可用
    2. 从豆瓣等网站抓取内容,简单的爬虫开发
    3. 集成第三方库,开发下载工具

简单来说,就是技术选型潜力大,开发量可控,开发难度不大,覆盖面广,且最终产品有一定市场价值。似乎是个很好的教程题材。

分类
招聘

OpenResty 再次开启招聘!

以下内容来源于老板春哥,关键词:一流的技术实力研发全新的技术远程工作模式

OpenResty Inc. 公司诚邀有追求的工程师加入我们的研发团队。

我们的技术栈是 Nginx, OpenResty, Lua, C/C++, Perl, Python 等等。从高性能网关系统和 CDN 系统,小语言编译器的开发,再到内核开发和动态追踪,以及数据库分析和调优,还有视频生成和处理,可按能力和兴趣选择。我们有世界一流的技术实力,研发全新的技术,解决工业级别的挑战,服务全球众多企业级客户。

工作地点不限,国家不限。我们不纠结于学历和专业,只看能力和经验。远程工作模式,自由度高。我们在深圳也有办公室。

有兴趣的朋友欢迎发送简历至 talents@openresty.com

详情请戳:网页链接


另外老板说,前端也可以聊,欢迎投简历。

分类
应用

应用创意:视频剪辑工具 Not-Final-Cut

0. 目标视频类型

我日常要处理的视频类型和工作流程是:

  1. 教学视频、分享视频、讲解视频
  2. 我会录制一个长视频,说清楚前因后果,然后以此视频为主,进行剪辑,大部分时候往下剪,很少往上加
  3. 我也很少分镜、混入多素材等
  4. 我希望通过 STT,得到人声对应的文本。然后以文本为基础进行剪辑,自动删掉不要的内容。也以文本为基础,添加图层、剪辑、音乐等

1. 产品需求

做视频 Up 主一段时间之后,越发感觉缺少一个趁手的视频剪辑工具。结合我的日常录制流程,我需要的剪辑工具应该具备以下功能:

  1. 自动剪掉没有人声的部分。我不说话的片段基本都不需要保留
  2. STT,输出语音对应的文本
  3. 可以根据文本进行剪辑,比如我不想要保留“嗯啊哦这个那个”这种无意义的虚词,都可以剪掉。
  4. 可以使用新文本替代现有文本,作为字幕,自动对齐时间。
  5. 可以方便地插入 slide,用来显示需要强调的内容。时间用文字来标记。
  6. 可以方便地切分视频,类似插入分页符
  7. 可以方便地插入章节标题
  8. 可以方便地插入暂停、插入图片、插入其它视频等,都用文字作为标记。
  9. 可以加片头、片尾、背景音乐等。

2. 产品形态

至于产品形态,我觉得可以分三种:

2.1 命令行工具

  1. 安装:npm i @meathill/nfc
  2. 启动:nfc a.mp4
  3. 打开浏览器,编辑并保存、导出

需要用户能够自行配置 node.js 环境、自行配置 ffmpeg、自行配置云服务 key。可以开放给其它录制教学视频的开发者使用,以便收集需求、bug,说不定还有人给我发 PR。

2.2 Electron 打包

像普通软件一样使用。可以卖给普通用户,不过考虑到大家的付费意愿,不一定能收回云服务的成本。也会有大量盗版问题。

还有个办法是要求用户注册,付少量的费用,只 cover 阿里云的费用。因为转码过程在本地,不消耗我的资源。

2.3 网站

用户上传视频到网站,在线编辑,导出。成本控制会容易一些,不过运营网站挺麻烦,而且视频剪辑需要的资源不是一星半点。

3. 项目启动

项目早就启动了,不过搁置很久了,以后继续吧。

感兴趣的同学可以关注:https://github.com/meathill/not-final-cut

4. 项目进展

  1. 选定视频开始编辑
  2. 剪辑文字
  3. 剪掉没有人声的片段
  4. 导出视频
  5. 修改字幕
  6. 添加章节封面
  7. 打包发布
  8. electron 版本
  9. 网站版本
分类
职业

再谈谈远程工作,主要供老板们参考

近期有几个朋友找我咨询远程工作的问题,都是老板,因为种种原因,考虑给团队开远程的口子。我也很长时间没分享远程工作的感受了,所以再写一篇。

0. TL; DR

  • 不是所有人都适合远程工作;
  • 远程工作对团队的要求很高,对老板的管理能力要求也很高。

老板开设远程岗位、推行远程工作时务必要慎重。

1. to 老板

通用能力,集中办公也需要的能力,此处不再赘述。

1.1 加强前置沟通

首先是流程。远程工作,尤其是全员远程的情况下,充分的前置沟通非常重要。

因为彼此距离很远,沟通成本高了很多,随口一问一答不太可能,所以必须在动手前就把需求、设计、实施方案、验收标准、模块划分都沟通清楚,不然后面效率一定会收到影响。

老板要建立这样的流程并监督执行,直到大家养成习惯。

1.2 工作中沟通要积极,多留档

我厂默认异步沟通,回复时间半天内即可。所以有问题就要积极沟通;甚至不是遇到问题,自己规划了功能/界面设计,选择了技术方案,也要及时沟通。

这里的沟通可能只是发个消息给协作者,“我要 XXX 了”,“我打算 OOOO”。对方可能不回复,也没关系,因为主要目的就是加强沟通和留档。于是将来就可以回溯,其他人也能通过这里的记录了解到前因后果,做出自己的判断。

老板应该不断强调这一点,直到大家养成习惯。

1.3 要有验收工具

对技术研发来说,验收至关重要。对远程开发岗来说,自动化测试更显得重要。一方面,自动化测试可以节省大量时间,让开发人员知道自己产品的质量,并及时修改;另一方面,自动化测试可以避免 QA 和开发人员之间的矛盾,提升大家的工作效率。

测试工具推荐我厂的 Navlang 工具链。自动化工具选项比较多。

1.4 加强工具建设和流程建设

很多人不适合远程工作,很多人没有接受过远程工作的训练。招聘远程岗位,招聘成本很高,淘汰率也很高。所以与其寄望于招到合适的人才,不如加强工具建设和流程建设,提升团队管理能力,让更多人适配远程工作。

1.5 99% 想找远程工作的人,都不适合远程工作

很多人都想找远程工作,多半是因为他们对远程工作抱有不切实际的幻想。这点我深有体会。我当年也以为,远程工作,拿着现在的高工资,想在哪儿工作就在哪儿工作,只要按自己的想法完成工作,其它时间自由支配,潜水滑雪,多安逸。

实际上,远程工作会面临很多问题,比如电脑设备、网络情况,甚至办公桌椅都会成为问题。在人均颈肩腰腿痛的今天,随处工作基本上是一种奢望。

再加上工资降低,结果考核带来的工作压力,很多人可能会发现,远程工作并不如想象中美好。那么他能否应对接下来的工作,就要画一个问号。

更别提还有很多人远程之后根本无法保证工作效率。

2. to 员工

2.1 要有主动性

远程不同于集中办公,每个人都要有主动性,主动管理自己,也主动管理别人。

比如一个功能,前后端分离,我是前端,我把自己的做完了,就要去催着后端做,直到最终验收。他也一样,遇到前端 bug,他也要催着我改。绝不能被动等待对方完成。

集中办公的时候,可能有项目经理、可能有需求人、可能有领导盯着,上厕所吃午饭时随口一句就足够大家紧张起来。远程工作,必须大家互相督促才行。

2.2 远程工作并不美好

正如水往低处流,因为有引力有势能。工作也一样,如果一个工作非常爽,就会涌入一大堆竞争者,通过内卷把它的爽度抹平,直到这份工作与其它工作相比乏善可陈。

所以这世上没有很爽的工作。如果有,要么工作有问题,要么你有问题。

分类
前端

使用 SVG 制作扇形

有时候我们需要制作扇形,比如图形化数据生成饼图的时候。使用 HTML + CSS 做不到,必须借助 SVG 帮助。经过一些摸索,大概方式如下:

0. 创建 SVG

我们需要一个 SVG,然后在里面画一个园:

<svg xmlns="http://www.w3.org/2000/svg" height="600" width="600" viewBox="0 0 20 20">
  <circle r="5" cx="10" cy="10" />
</svg>

这里,我创建了一个 SVG,并且以 10,10 位圆心,画了一个半径为 5 的圆。SVG 的视窗只需要显示这个圆,所以是 0 0 20 20 的正方形。widthheight 用来定义网页中 SVG 的尺寸,SVG 是矢量图形,可以实现内容的无损缩放,所以即使显示尺寸比图形尺寸大很多,也不用担心出现锯齿。

1. 用边框画圆形

接下来,我们用给圆加边框的方式来做圆形。

<circle
  r="5"
  cx="10"
  cy="10"
  fill="transparent"
  stroke="tomato"
  stroke-linecap="butt"
  stroke-width="10"
></circle>

首先,我们用 fill="transparent" 清理掉圆形内部的颜色,然后用 stroke="tomato" 给边框加上橙色。接下来,我们通过 stroke-width="10" 设置边框宽度为 10,这也是矩形半径。

此时,屏幕上会出现一个橙色的正圆。

2. 画扇形

画扇形的方式有很多,比如画两条半径然后画弧形再填充颜色。但是利用边框画扇形最简单。

用边框画扇形说白了,其实是结合圆环和虚线,需要有扇形的地方,就填充颜色;不需要扇形的地方,就用虚线的空白。这里要用到 stroke-dasharray 属性,它的规则很简单,奇数为实偶数为虚,所以我们只要计算扇形所需的弧形长度,然后剩下的填充周长即可。

在我们这里,就是 stroke-dasharray=”calc(10 * 3.1415926 * 1/6) 31.415926",即取绘制一个 1/6 大小的扇形。

3. 修改位置

修改位置需要使用 stroke-dashoffset 属性,它会把图形从原来的位置移动若干距离,正的就往起点移动,负的就往终点移动。

在我们这里,就是 stroke-dashoffset="calc(-10 * 3.1415926 * 1/6)",将第二个扇形移到第一个扇形的旁边。

4. 其它+已知问题+扩展阅读

最终效果:https://codepen.io/meathill/pen/yLMQqBQ?editors=1000

这些属性,也可以使用 CSS 样式替换,效果一样。

Safari 问题比较多,首先半圆就不是半圆,其次偏移也不对,不知道是否只支持 CSS。

分类
nodejs

node.js 里使用 fifo

0. 需求

前两天 Showman 遇到一个需求:

  1. 我们需要在服务器端录制视频
  2. 录制视频的过程主要由 node.js 控制,借助 puppeteer 操作浏览器
  3. 但是也会需要执行一些 shell 命令,此时为安全考虑,我们会启动一个封闭的临时环境给用户执行
  4. 这些封闭环境是用户进程间共用的,不会随时启动随时销毁
  5. 所以 node.js 就需要在其它环境里执行一些操作,返回内容,等待执行完毕后再继续下面的

于是我的同事就让我用 fifo。

1. 什么是 fifo

我以前没有用过 fifo,所以搜索了一下。

FIFO 特殊文件(同具名管道)与管道类似,只是可以用访问文件系统的方式来访问它。它可以被多个进程同时打开和读写。当进程通过 FIFO 交换数据时,内核将直接在内部交换数据,而不会写入到文件系统中。因此,FIFO 特殊文件在文件系统中没有内容;文件系统的入口(即文件)只是作为引用方式,让各进程能够使用文件名来访问管道。

原文:https://man7.org/linux/man-pages/man7/fifo.7.html

管道大家应该都知道,把 A 进程的输出直接输入到 B 进程里,加快处理速度。fifo 与管道的差别就是 fifo 可以通过文件路径直接访问,用起来更简单。

2. 在命令行里使用 fifo

创建 fifo,使用 mkfifo 命令:

mkfifo xxx.fifo

写入内容到 fifo:

echo "something" > xxx.fifo

读取 fifo:

cat xxx.fifo

因为 fifo 是管道,内容直接走内核,所以实际上硬盘上不会存储任何内容。如果我们在写入之后再 cat fifo,就不会得到任何内容。

3. 在 node.js 里使用 fifo

在 node.js 里使用 fifo 需要用 fs.opennet.Socket。因为我需要在执行完毕后继续下一步,所以进行了 Promise 封装:

try {
  // 为避免执行时间过长导致进程超时,不断输出些内容
  const interval = setInterval(() => {
    log('termlang is processing...');
  }, 3E4);
  await new Promise((resolve, reject) => {
    // 打开名为 $basename-$lineno.sp.fifo 的管道
    open('./$basename-$lineno.sp.fifo', constants.O_RDONLY | constants.O_NONBLOCK, (err, fd) => {
      if (err) {
        clearInterval(interval);
        reject(err);
      }
      const pipe = new Socket({fd});
      pipe.on('data', data => {
        data = data.toString();
        // 以输出内容包括 finished 或 errored 为结束标记
        if (/(finished|errored)/.test(data)) {
          resolve(data);
        }
      });
    });
  });
  clearInterval(interval);
} catch (err) {
  log(err);
}

4. 总结

作为半路出家的前端,我对系统、对 Linux 一直缺乏了解。所以类似管道这种东西,我一直也不太熟悉,这次算学会了一个新技能,记录分享一下。