0%

日常开发中,遇到一个需求是视频文件上传之前,判断用户选择的 mp4 文件编码格式,若不是期望的编码,则不予上传。分析一下,这是一个比较 basic 的需求,我们只需要获取到视频文件的 MINE 信息,就可以判断视频编码。由于网上没有比较完整的文章,所以著文分享。

我们会使用到mp4box这个工具库。首先安装它:

1
yarn add mp4box

如果你使用Typescript,请参考Typescript Support添加声明。

接着引入库和声明一个 FileReader 用于协助读取文件

1
2
import MP4Box from 'mp4box'
var reader: FileReader = new FileReader()

创建 Input 和处理 onChange,这里我们使用HTML5的accept属性限制只能选择mp4格式的文件。

1
<Input type="file" onChange={onFileSelected} accept="video/mp4"></Input>
1
2
3
const onFileSelected = (e: any) => {
reader.readAsArrayBuffer(e.target.files[0]);
}

接着通过 FileReader 的 loadend 事件进行后续处理,这里记得要回收reader变量。

1
2
3
4
5
6
7
8
9
10
11
12
useEffect(() => {
reader.addEventListene ('loadend', function () {
let result: any = reader.result;
result.fileStart = 0;
let mp4boxfile = MP4Box.createFile()
mp4boxfile.onReady = mp4Parsed
mp4boxfile.appendBuffer(result);
});
return () => {
(reader as any) = null
}
}, [])

获取到文件后,解析文件MINE类型,后续可以自行添加提示信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const mp4Parsed = (info: any) => {
var codecs = [];
for (var t = 0; t < info.tracks.length; ++t) {
codecs.push(info.tracks[t].codec);
}
let fileCode = analysisCode(codecs[0])
console.log(fileCode)
};

const analysisCode = (code: string) => {
if (code.startsWith('avc')) {
// h264
return 'h264'
} else if (code.startsWith('hvc')) {
// h265
return 'h265'
} else {
throw new Error('unknown video code')
}
}

基于Create React App写了一个demo,详见github

生活

2020年我的生活发生了翻天覆地的变化,在COVID-19的影响下,被迫降薪了三个月,从计划换工作开始,到最后签offer,经过了整整四个月。那段时间饱受煎熬,不少公司锁了HC,投了没反应,甚至很长一段时间在考虑是否进外包公司,最后戏剧化地在做了外包公司入职体检之后,接受了现公司的offer。新公司很有意思,入职之后需要做半个月的服务员,这种纯体力活对我来说毫无意义,也算是丰富了人生的体验吧。接近年底的时候搬出了住了三年的城中村,到了一个单程通勤一小时的地方,生活作息提前进入了老年状态,由于时间太长,我甚至开始养成在地铁上读书的习惯。

新工作

事实证明,在待遇差不多的情况下,我会选择更具有挑战性的工作。在著文的时候,恰巧是我半年以来工作成果的验收————项目上线。过去的半年里,我在electron方面有很多实践,许多同事反应在进行两到三年的前端工作之后开始出现厌倦的感觉,日复一日的编写业务逻辑确实会降低编码的欲望,我也不例外,所以我更乐意去探索新的领域,从几年前的小程序转为桌面端开发,踩坑其实也是一种乐趣。不出意外,今年你们会在我司许多门店里见到我的作品:)

Best buy

斐讯n1

同事推荐的型号,为主路由降低了大量负载,现在可以无压力地看油管了:),低廉的价格真是便宜又大碗。

2021.05.27 update

因为发新文章的缘故看到这篇半成品,更新一下近况:换了新工作,老东家的作品还在发挥余热,在全国「太二」门店都已经上线,恰逢这个时间点,「太二前传」也即将开业,里面有我iPad端的作品,迫不及待去尝试啦~

因业务需要开了新坑,选型为Electron-Vue,发展到现在比较成熟了,但是没想到项目初始化都启动不了,把一些小坑记录下来。

Get Started

安装vue-cli

1
npm install -g vue-cli

通过vue-cli初始化项目模版

1
vue init simulatedgreg/electron-vue my-project

安装依赖并运行开发模式

1
2
3
cd my-project
yarn # or npm install
yarn run dev # or npm run dev

ReferenceError: process is not defined

进行到这里,跑不起来就对了,会报ReferenceError: process is not defined,原因是webpack配置有问题,我们修改项目目录下的 ./electron-vue 下的webpack.renderer.config.js和webpack.web.config.jsHtmlWebpackPlugin配置为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../src/index.ejs'),
templateParameters(compilation, assets, options) {
return {
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: options
},
process,
};
},
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true
},
nodeModules: false
}),

axios is not defined

改毕再yarn dev一下就可以解锁第二关axios is not defined,这里很容易联想到依赖安装不完整的问题,如果你尝试安装依赖的话会发现错误没有变化,后经过搜索发现插件白名单没有配置。

接着修改webpack.renderer.config.js

1
let whiteListedModules = ['vue','axios','vue-electron','vue-router','element-ui','vuex-electron','vuex']

把所需要的依赖加上即可,进行到这里项目终于可以跑起来了,文章写到这里不忍结束,接着我们迎来第三关:eslint

eslint vscode代码格式化

在使用vue-cli进行项目初始化的时候,我选择了Javascript Standard Style作为代码风格校验,很多人会不堪其扰选择关闭,但其实一个合适的代码风格在团队协作中是很有必要的,至于烦人的红波浪提醒,我们大可交给code formatter去帮我们格式化代码。
首先安装vscode拓展 Prettier-Standard - JavaScript formatter,并于vscode首选项中打开editor.formatOnSave即可愉快地匹配项目代码风格。

后记

以上是我花了一天时间踩的坑,后续伴随项目发展,本系列文章将会同步更新,感谢观看~

因为macbook空间不足卸载了没怎么用的Xcode,导致下班前提交代码时发现git报以下错误:

1
xcrun: error: invalid active developer path (/Applications/Xcode.app/Contents/Developer), missing xcrun at: /Applications/Xcode.app/Contents/Developer/usr/bin/xcrun

经过一番尝试,发现git依赖的CommandLineTools命令行工具路径指向的是Xcode。我们可以通过xcode-select -p查看。那么此时我们先把它装回来,执行:
1
xcode-select --install

看下安装成功了没:
1
2
xcode-select --version
-> xcode-select version 2354.

然后把系统命令行路径重新指向到刚安装的xcode-select目录:
1
sudo /usr/bin/xcode-select  --switch /Library/Developer/CommandLineTools

好了,试试git回来了没:
1
2
git --version
-> git version 2.20.1 (Apple Git-117)

Done.

定义

贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。

用途

以上介绍摘自百度百科,看起来有点晦涩难懂,一年多以前我第一次接触到这个名词便心生抗拒之意。然而在前端开发中,我们在实现抛物线动画时,贝塞尔曲线绝对是个好帮手。今天我们通过在微信小程序实现一个常见的加入购物车动画,来进一步理解它。

Read more »

最近的一个改版需求设计师在设计稿中使用了苹方字体,在网上找了一下解决方案,无外乎两种方式:

第一种方式,base64 encode

如果字体比较小,如各种英文字体,可以把字体上传到 https://transfonter.org/ 转换成base64格式,然后直接在样式中使用。具体使用可参考 【微信小程序】如何引入外部字体样式一文。

第二种方式,官方API

如果字体比较大,如各种中文字体动辄超过10mb,用base64显然是不合适的,小程序超过2m还要分包处理,为了一个字体实在不值当,那么可以用官方的API wx.loadFontFace加载外部字体,像这样:

1
2
3
4
5
wx.loadFontFace({
family: 'PingFangSC-Medium',
source: 'url("https://www.your-server.com/PingFangSC-Medium.ttf")',
success: function(){console.log('load font success')}
})

这里需要注意的一点是,family处的名称就是使用时font-family的名称,举个例子,上方加载的字体这样使用:

1
2
3
.foo{
font-family:PingFangSC-Medium;
}

建议

由于字体可能会比较大,所以不建议在一个小程序中使用多种字体,这样会影响用户体验。为了保证界面效果,可以在onLoad周期加载字体,在success回调中执行后续操作,必要时加上Loading,让程序更加友好。

2018.12.28日更新:

结合实践,决定写得更详细一点,希望可以帮助到更多道友。

遇到的问题是下载字体时界面已经渲染完毕,导致字体显示不正确。解决方法的总体思路是在使用到该字体的容器中增加一个loading属性,当字体加载完毕后再显示布局,这样可以确保字体渲染正确。

注:下方代码使用了 wxPromise 以支援小程序API Promise化

1
2
3
<!-- mall.wxml -->
<view wx:if="{{loading}}" class="mall-root">
</view>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- mall.js -->
Page({
data:{
loading:false
},
onLoad(){
this.loadFonts().then(()=>{
this.setData({
loading: true
})
})
},
methods:{
loadFonts(){
let PingFangMedium = wx.pro.loadFontFace({
family: 'PingFangSC-medium',
source: 'url("https://img2.misssixty.com.cn/rs/lib/fonts/PingFangSC-medium.ttf")'
})

let PingFangRegular = wx.pro.loadFontFace({
family: 'PingFangSC-regular',
source: 'url("https://img2.misssixty.com.cn/rs/lib/fonts/PingFangSC-regular.ttf")'
})
return Promise.all([PingFangMedium, PingFangRegular]).then((res) => {
console.log(res)
}
}
})

今年的首发新车数量比往年多了不少,由于精力问题只去了部分展馆,大众、奥迪全系都换完了代,给人焕然一新的感觉。A6、新A class、新X5、新卡罗拉、ES是本届的超人气车型。连续五年去看车展,不容易啊~

Read more »

在最近的项目开发中,用Webpack做了一套脚手架,用jQuery作为主要工具库,一顿操作猛如虎,一看代码2w5。😅今天在这里记一下无法给Dom绑定监听的小问题。

谈起jQuery绑定事件,这里以最常用的点击事件为例,常见的两种写法有:

1
2
3
4
5
6
7
8
9
10
11
method one:

$('.selector').on('click',()=>{
//do something here
})

method two:
$('.selector').click(()=>{
//do something here
})

这两种写法大多数旁友都非常熟悉,平时用起来一点问题也没有,但在我的项目中,却愣是绑定不起来,经过一番查找,原因出在我要绑定事件的Dom是循环后append的,所以,点击事件就失效了,查了下jQuery的API:

1
on(eve,[sel],[data],fn)

发现on存在可选的第二个selector参数,官方说明:「一个选择器字符串用于过滤器的触发事件的选择器元素的后代。如果选择的< null或省略,当它到达选定的元素,事件总是触发。」OK,那么要解决这个问题,必须在append html element之后,去on要绑定事件元素的父元素。写成表达式即为:

1
$('.parentSelector').on('click','.childSelector',()=>{})

好了,事情解决了,可以开启开心星期四了。🤪

界面

写在开始

今天在这里介绍下如何使用koa框架,结合js,实现k歌作品的『批量/单曲/试听』功能。

需求分析

当用户输入uid时,获取到全部的作品列表,并在页面上展示,包含歌曲名称、歌曲试听、单曲保存的功能, 并以弹窗的形式,给予用户明确的提示:是否下载全部歌曲。当用户点击『下载全部』按钮时,开始下载,并在控制台显示相关进度。当用户点击『取消』时,不影响作品列表的相关操作,点击『分析并下载』时,仍然可以下载全部作品。

相关数据获取

第一步的目的是获取到所有作品的列表,自然而然地从个人页开始分析,首先观察url,为以下形式:

个人中心

https://node.kg.qq.com/personal?uid=18位uid

接着发现页面默认加载八首歌,点击『查看更多』按钮会多加载八首歌,在Chrome-Nerwork中查看请求,多请求几页发现规律,用postman模拟请求,发现接口的每页返回数量做了限制,num最大值为15,start为页数,share_uid可从个人中心url获得。至此,我们可以循环请求,获取所有歌曲列表。

获取作品列表

https://node.kg.qq.com/cgi/fcgi-bin/kg_ugc_get_homepage?type=get_ugc&start=页数&num=8&share_uid=18位uid

最后是获取歌曲播放(下载)的url,在歌曲的播放页的script标签里,我们可以直接获取到一串加密的地址,如果使用这个地址,显然无法与我们之前所做的努力结合,所以我找到了其他网友分享的url,通过share_uid,我们可以获取下载url。

获取歌曲url

http://node.kg.qq.com/cgi/fcgi-bin/fcg_get_play_url?shareid=shareid

技术选型

本次项目选择了koa2框架,使用koa-generator生成带ejs模板项目,方便后续功能拓展。加上axios、jquery、sweetalert2等辅助库。
sweetalert2

整体流程

程序运行
整体流程如上图,具体的实现还需要考虑uid校验、node的fs文件流操作,测试过程中发现某用户有相同作品名,还需要加上相同文件名的判断,如果有相同文件名,加上随机数字串,不然创建文件时会覆盖之前的文件。



程序运行
程序运行

TODO

  • [X] 单曲试听
  • [X] 单曲下载
  • [X] 作品批量下载
  • 在前端显示下载进度

项目地址

github

写在开始

进入现在的公司快满一年了,记得入职第一天是让我看文档,第二天就正式投入开发了,期间一直想要写点学习心得,但是因为工作量较大,连域名未认证被封了几个月都不知道,趁这次修复blog,大致写一写这一年来积累的东西。

学习方式

学习一门语言最好的方法就是实战,我进入公司的时候恰好碰上技术栈转型,逐渐把老项目过渡到Angular4,所以大家都是边做边摸索,Angular在国内远没有Vue那么火,不少问题的解决都要靠老外,国内的开发者也有几个知名的实践,把我们常用的插件集成在一个demo中,这里贴上几个比较经典的学习资源,有需要可以参考:

官方中文文档

大漠老师的美人鱼

CodeBe插件集成demo

Angular2随便问

理论上实际开发都是专注于业务,所以一般都会使用框架以提高开发速度,这里推荐阿里的NG-ZORRO和PrimeNG,经过多个版本迭代已经比较成熟,可以放心使用:)

强烈推荐的框架:NG-ZORRO

PrimeNG

实用技巧


这里就不再讲什么数据绑定、http请求等基础用法了,说几个在实际项目中比较实用的技巧,官方文档或许有提及但不够详细。

全局变量

或许你在某些教程中已经学习了Angular的组件通讯,知道常用的组件关系是父子关系,用的是@Input和@Output去传参,但是在实际项目中,经常会遇到兄弟关系的组件,这时候我们可以定义一个全局共用的Service进行传值,需要避免的坑是使用EventEmitter发送的值在订阅之前要先new EventEmiiter()一下,不然会造成重复触发。具体的使用方法可以参考 https://segmentfault.com/q/1010000011080965

动态组件

当模版内容较多时,例如一个页面包含了多个弹窗,弹窗的内容、逻辑也非常多的时候,按照默认模式Angular会一次全部渲染,影响性能。这时候我们可以使用动态组件,只有初始化事件触发时,才去生成这个弹窗组件,并且这样做有个好处:抽出来的组件可以进行复用。
具体的使用方法可以参考 https://www.jianshu.com/p/10feab2c3102