标签: 笔记

  • LeanCloud 笔记

    慢慢记。

    慎用 await Promise.all(items.map(item => ....))

    很容易造成 409 too many requests 问题。

    最好用

    const newItems = [];
    for (const item of items) {
      item = await doSomeAsyncJob();
      newItems.push(item);
    }

    Pointer 时尽量用 query

    取单一对象的时候,方法有很多,比如 createWithoutData + fetch。不过如果如果对象内部属性有 Pointer,且我们希望一次性把 Pointer 取回来的话,最好用 query,因为只有它支持 .include(),可以一次性拉取全部需要的数据,减少请求次数,减少发生 too many requests 的可能。

  • Chrome Devtool Protocol 开发笔记

    Chrome Devtool Protocol 开发笔记

    周末动笔写教程,越写越长暂时收不了笔;周日发现上一台 iMac 回收被坑了,显示器从烧屏变闪屏了,心情大坏,简直写不动了,哎……

    Chrome Devtool Protocol(下面简称 CDP)是一个非常强大工具,简单来说,它可以揭开束缚 Chrome 的各种封印,从浏览器角度深入页面(及其它领域,包括 worker),完成一些平日里难以完成的操作。

    我目前研究它主要是想优化我厂官网的首屏 CSS,顺便为将来 QA 插件的深入开发做准备。

    不过 CDP 的文档、资料各种不全,Google 也没什么结果,所以我会把日常踩到的坑记到这里,以备回顾。

    (更多…)
  • 正则笔记

    正则笔记

    常看常新的正则教程

    正则表达式30分钟入门教程

    匹配中文及中文标点

    如今建议用 /\p{sc=Han}/gu,参见:JavaScript 中使用正则 `u` 标记匹配多语言。

    const reg = /[\u4E00-\u9FCC\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]+/g

    ES2018~ES2019 中的正则

    转大写/小写

    转大写 \U\u,转小写 \L\l。比如 camel case 转 kebab case,可以查找 [A-Z],替换为 \L$0

    IDE 里可以,JS 不行。

    判断行开头或xx

    比如 css 规则中的值,我们可能会用 /[\s:](值表达式)/ 这样的表达式,但它没法匹配行的开头,^ 不能放到 [] 里。此时只需要 (^|[\s:]) 即可。

  • wget 笔记

    wget 笔记

    抓取整站

    wget -r https://target.site/
  • FFMPEG 笔记

    FFMPEG 笔记

    截取视频

    ffmpeg -i abc.mp4 -ss 3:13 -to 2:41:13 -c copy output.mp4
    • -i 输入文件
    • -ss 开始时间
    • -to 结束时间
    • -c copy 直接截取

    这样的截取方式,如果源视频的关键帧间隙很大,可能出现因缺失第一个关键帧导致的黑屏。此时,可以考虑用 -c:v libx264 之类的参数重新编码。

    合并

    ffmpeg -f concat -safe 0 -i files.txt -c copy -y output.wav

    其中,files.txt 是所有待合并的文件,以以下的形式记录:

    file /path/to/wav/1.wav
    file /path/to/wav/2.wav
    ....

    转换格式

    转换格式很简单,有输入有输出,ffmpeg 会根据它们的扩展名自动选择合适的编码器,生成通用性最好的目标文件。比如 wav 2 mp3:

    ffmpeg -i a.wav a.mp3

    如果需要截取或者使用特定的编码器,那么就按照一般的用法添加参数即可,比如 flv 2 mp4:

    ffmpeg -i 1.flv -c:v libx264 -crf 19 -strict experimental 1.mp4

    其中,-c:v 是“视频编码器”的意思,音频编码器就是 -c:acrf 是质量,最小越好,取值范围是 18 -28。类似的,rm 2 MP4:

    ffmpeg -i ss.rm -c:v libx264 -c:a aac -b:a 32k -strict experimental ss.avi

    在 Ubuntu 下不能使用 libfaac,只能使用 aac。还要调整级别,-strict -2 不行,必须是 -strict experimental

    转换 iPad 支持的视频

    ffmpeg -i input.mkv -c:v libx264 -profile:v main -level 3.1 -preset medium -crf 23 -x264-params ref=4 -c:a copy -movflags +faststart output.mp4

    不知道为啥,直接 .mp4 或者 -c:v libx264 都不行,必须用上面这个。

    缩放

    ffmpeg -i input.mp4 -vf scale=320:-1 -strict -2 output.mp4

    好吧,这次 -strict -2 好使了。如果报错,可以试着把 -1 改成 -2

    裁剪画面

    ffmpeg -i input.mp4 -filter:v "crop=500:1080:1420:0" output.mp4

    crop 的参数为:宽、高、x、y。

    调整声音

    有些视频声音太小,需要调整一下:

    ffmpeg -i input.mp4 -filter:a "volume=N" output.mp4

    其中,N 可以是百分比,比如 1.0(一倍,不变),2.0(两倍);或者是加减的分贝,比如 10dB(增加10分贝),-20dB(减少20分贝)。不过根据我实地测试,调整后的视频的平均音量并不完全是调整的分贝。

    获取平均音量:

    ffmpeg -i input.mp4 -filter:a volumedetect -f null /dev/null 

    提取声音

    # 不转码,只提取声音,很快
    ffmpeg -i input-video.avi -vn -acodec copy output-audio.aac
    # 转码,便于四处播放
    ffmpeg -i sample.avi -q:a 0 -map a sample.mp3
  • Vue 代码校验工具

    Vue 代码校验工具

    写 Vue 的时候,时不时会发生一些笔误,出的错并不会被编译器和运行时发现,但确实会影响工作,所以想写一个工具把它跑出来。我目前遇到的问题有:

    1. :v-model
    2. attr="false"
  • Puppeteer 笔记

    Puppeteer 笔记

    记录使用 Puppeteer 的一些经验。

    安装使用

    puppeteer 是一个“库”,没有自带的命令行功能。所以要使用的话必须写一个文件,然后实现对应的功能。

    npm i puppeteer
    

    在墙内安装

    puppeteer 里面包含完成的浏览器程序,少说也是 100MB,所以需要下载比较长的时间,在墙内则经常会失败。所以建议国内开发者用淘宝的源:

    npm config set puppeteer_download_host=https://npm.taobao.org/mirrors

    Could not find browser revision xxxxx

    如果安装依赖时,默认的浏览器下载不成功,使用时可能会报这个错误。里面的 xxxxx 是某个版本号。此时可以使用 npm i puppeteer --force 重新安装。如果是墙内用户,那么按照上一小节设置源之后再安装,多半就可以解决问题了。

    在 WSL 下使用

    关于 WSL 使用,请参考这篇博文:在 Windows 10 WSL 中使用 Puppeteer

    我的测试仓库和工具

    参见 GitHub puppeteer-tool

  • Laravel 开发笔记

    Laravel 开发笔记

    记录 Laravel 开发中的一些心得体会,踩过的坑。

    (更多…)
  • MediaElement 笔记

    MediaElement 笔记

    贵司官网需要放视频,于是需要用播放器。然后就产生如下需求:

    1. 协议好,支持免费商用,最好 MIT
    2. 支持 SRT 字幕
    3. 支持尽可能多的平台

    经过筛选,最后选定 MediaElement,一看 WordPress 在用基本就放心了。然后就开始踩坑之旅。当然,有些是我的问题,不过也有不少是文档没说清楚。这里记录一下。


    全屏和弹性宽度

    当前版本 4.2.5 有个 Bug,如果设置宽度为 100%,那么从全屏恢复到内嵌状态时,会留着全屏的宽度,撑开页面。如果设定一个特定的宽度就不会。但我们的页面是响应式的,需要允许它随页面变化而变化。

    这个时候只好手工来做,我的选择是让它 100%,然后侦听从全屏返回的事件,发生后就把宽度恢复。另外,因为 fullscreenchange 事件还没有统一标准,所以不同浏览器里的事件名称也不一样,更不爽的是,IE 下是驼峰,其它浏览器是全小写,我也懒得再写函数转化了,反正就3种情况,全写一遍好了。

    // fix MediaElement's issue
      let fitVideo = function() {
        setTimeout(() => {
        $('.mejs__container').width('100%')
          .find('video').width('100%')
          .end().find('.mejs__layers')
          .children().width('100%');
      }, 50);
    };
    if ('onwebkitfullscreenchange' in document) {
      document.onwebkitfullscreenchange = function() {
        if (!document.webkitFullscreenElement) {
           fitVideo();
        }
      };
    } else if ('onmozfullscreenchange' in document) {
      document.onmozfullscreenchange = function() {
        if (!document.mozFullScreenElement) {
          fitVideo();
        }
      };
    } else if ('MSFullscreenChange' in document) {
      document.MSFullscreenChange = function() {
        if (!document.msFullscreenElement) {
          fitVideo();
        }
      };
    }
    

    默认字幕

    Web 标准是有默认字幕的,<track defualt> 即可。但是 MediaElement 没有,最后在 StackOverflow 上找到答案,原来有个未记录在文档里的初始化属性可以控制:

    let player = new MediaElementPlayer('intro-video', {
      startLanguage: 'cn', // 这里的名字应该和 <track> 种的 srclang 属性一致
    });
    

    插件与生态

    MediaElement 把一些有用但不太常用的功能抽出来做成了插件,放在 MediaElement Plugins。不过看起来这个项目有些属于维护,使用的时候很多问题。比如,直接在 features 里开启特定功能,即使对应的插件没有加载,也不会报错,就是没反应,很令人迷茫。

    避免发起又取消请求

    网站上线后,老板发现一个问题:从 Chrome 的 Network 面板可以看到,网页打开后,对视频文件发起了一到多个不等的请求,并且都取消了。

    经过研究,我认为这个请求是 <video> 发起的,因为 preload 的默认值是 auto(参见:MDN),也即打开页面就预加载。而此时 MediaElement 被初始化,为了正确显示 UI,它会把 <video> 标签挪到自己创建的 <div> 里,这个过程就会导致“预加载 -> 取消”。因为视频默认不播放,所以我给 <video> 加上了 preload="none",问题解决。


    其它大体上文档都能找到,就不多说了。

  • Vue 笔记:事件

    Vue 笔记:事件

    onload

    需要侦听 load

    <template>
      <img src="/path/to/img" @load="onLoad">
    </template>
    
    <script>
    export default {
      methods: {
        onLoad(event) {
          // do something
        }
      }
    }
    </script>
    

    drop

    需要阻止 dragover 的默认行为,不然不触发。

    <template>
      <div class="drop-area" @dragover.prevent="onDragOver" @drop="onDrop">
    </template>
    
    <script>
    export default {
      methods: {
        onDragOver(event) {
          // 此时仍然可以处理
        },
        onDrop(event) {
          console.log(event.dataTransfer);
        }
      }
    }
    </script>