博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
爱奇艺弹幕解码 JS+ArrayBuffer+ungzip+utf8ArrayToStr
阅读量:6430 次
发布时间:2019-06-23

本文共 3029 字,大约阅读时间需要 10 分钟。

hot3.png

前文

解码爱奇艺弹幕为明文字符串,涉及ArrayBuffer、gzip、字符数组转换,主要是前端部分范畴,很多东西不太了解,做此记录。

某剧弹幕资源地址

http://cmts.iqiyi.com/bullet/77/00/874217700_300_3.z?business=danmu&is_iqiyi=true&is_video_page=true&tvid=874217700&albumid=205025001&categoryid=2

尝试请求这个地址,发现资源结果是这样儿的,而非常规的xml/Json。

180407_oiNu_2366984.png

 

最后抓包,在JS中xhr请求完毕后处理的逻辑进行调试。

http://static.iqiyi.com/js/player_v1/skin.default.af360b73f3e281095e89.js

180738_fDvO_2366984.png

可悲的是测试了许久却始终走不进这段代码。

最后发现同解码逻辑一致还有其他几处逻辑,经测试,拖一拖进度条开关弹幕等待即可进入这段调试断点。

180912_mGrs_2366984.png

这里首先异步请求后端拿到弹幕编码资源,将其转换成为了Unit8Array的资源类型,之后将其ungzip,再之将其转换成string即可获得弹幕XML。

 

即分三步得到弹幕明文:

1.获得Unit8Array资源类型

爱奇艺原代码是

var r = new Uint8Array(i)

令我没有想到的是这个函数是javascript内置的,也白白在这上面耗费了很多时间。

182132_t6dZ_2366984.png

这里 变量 i 被赋值的是异步的请求结果

i = t.response

i的类型是ArrayBuffer,也就意味着返回结果同样这样,而Jquery的ajax资源类型不包含ArrayBuffer,返回的Text对应不上,转换貌似也有些问题,所以也就没有采用,最后采用原生XHR请求访问。

182424_jswq_2366984.png

// 字符串转为ArrayBuffer对象,参数为字符串function str2ab(str) {    var buf = new ArrayBuffer(str.length*2); // 每个字符占用2个字节    var bufView = new Uint16Array(buf);    for (var i=0, strLen=str.length; i

该代码将text转换为ArrayBuffer,摘自。

实现简单的XHR请求,设定返回资源为 ArrayBuffer。避免跨域,资源将由gzip.php代理请求。

var xhr = new XMLHttpRequest();xhr.open('GET', '/gzip.php', true);xhr.responseType = 'arraybuffer'; xhr.onload = function(e) {  console.log(this.response)}; xhr.send()

183435_0EUR_2366984.png

测试返回资源类型是OK的,只需要再将其转换为Uint8Array就好。

var xhr = new XMLHttpRequest();xhr.open('GET', '/gzip.php', true);xhr.responseType = 'arraybuffer'; xhr.onload = function(e) {  // response is unsigned 8 bit integer  var responseArray = new Uint8Array(this.response);  console.log(responseArray);}; xhr.send()

 

2.ungzip解压数据

这里实现拿到的数组进行ungzip解压。

这里没法直接用爱奇艺的代码了,webpack打包的不成样子,没法剥离。直接引用现成的库。

https://raw.githubusercontent.com/nodeca/pako/master/dist/pako.js

将其下载到项目目录里再使用,否则出现跨域无法执行。

var xhr = new XMLHttpRequest();xhr.open('GET', '/gzip.php', true);xhr.responseType = 'arraybuffer'; xhr.onload = function(e) {  // response is unsigned 8 bit integer  var responseArray = new Uint8Array(this.response);   console.log(pako.ungzip(responseArray));}; xhr.send()

解压之后数据量会变的很大。

184757_kZ5M_2366984.png

3.Unit8ArrayToStr

最后我们再将其转换为肉眼可识别的XML文本。

var xhr = new XMLHttpRequest();xhr.open('GET', '/gzip.php', true);xhr.responseType = 'arraybuffer'; xhr.onload = function(e) {  // response is unsigned 8 bit integer  var responseArray  = new Uint8Array(this.response);   var responseString = new TextDecoder().decode(pako.ungzip(responseArray));  responseString = responseString.replace(/&#\d{2};/g, "");  console.log(responseString);}; xhr.send()

 

这里TextDecoder也是JavaScript内置的功能类。

185008_kOUR_2366984.png

最终返回结果

185310_OdYj_2366984.png

至此,弹幕解码完毕。

爱奇艺utf8ArrayToStr 转换剥离代码

function utf8ArrayToStr(e) {	var t, a, i, r, n, o;	for (t = "",	i = e.length,	a = 0; a < i; )		switch ((r = e[a++]) >> 4) {		case 0:		case 1:		case 2:		case 3:		case 4:		case 5:		case 6:		case 7:			t += String.fromCharCode(r);			break;		case 12:		case 13:			n = e[a++],			t += String.fromCharCode((31 & r) << 6 | 63 & n);			break;		case 14:			n = e[a++],			o = e[a++],			t += String.fromCharCode((15 & r) << 12 | (63 & n) << 6 | (63 & o) << 0)		}	return t}

 

后文

这个解码即如此,反向来看这个编码并且压缩之后体积会小很多,很适合一些大数据量场景向后端提交时使用。

 

扩展文章

转载于:https://my.oschina.net/u/2366984/blog/1620852

你可能感兴趣的文章
R-基础测试(1)
查看>>
技术人生:每天进步一点点
查看>>
今天讲座的感悟--java
查看>>
o(1)复杂度之双边滤波算法的原理、流程、实现及效果。
查看>>
Logcat多tag过滤
查看>>
corner2
查看>>
我见过的几种类型的员工(转)
查看>>
web前端的十种jquery特效及源码下载
查看>>
poj 3414 Pots (bfs+线索)
查看>>
Binary search
查看>>
http://jingyan.baidu.com/article/08b6a591f0fafc14a9092275.html
查看>>
MySQL查询数据表的Auto_Increment(自增id)
查看>>
java多线程系类:JUC集合:01之框架
查看>>
【Linux】 源码安装make命令详解,避免踩坑
查看>>
数据库中间表插入乱序
查看>>
[Python爬虫] 之四:Selenium 抓取微博数据
查看>>
使用OPENROWSET爆破SQL Server密码
查看>>
Mac_安装Homebrew以及Maven
查看>>
eclipse web开发Server配置
查看>>
曹政--互联网搜索老师傅
查看>>