标签归档:bilibili

b站弹幕重构相关 – 新api+新格式

两周前了吧,b站半废弃了旧版 comment 域名。除了直接访问的xml外都403了,然后接口换到了api下。获取内容是 /x/v1/dm/list.so ,历史弹幕则是 /x/v2/dm/history 底下并且要登录。

昨晚想确认客户端的情况,看到客户端访问的是 /x/v2/dm/list.so ,点开一个一看是个二进制?

因为b ios app的框架魔性加载,clutch没法导出,重新找一个 frida-ios-dump 才成功导出框架。名字很直接,弹幕相关在 BFCDanmaku 里面。用ida打开研究了俩小时,处理函数是 -[BFCDanmakuRemoteParser parseBinaryData: (NSData)data] 。文件格式也是真的暴力。开头一个length,然后读length取一个json,好像是屏蔽用的?这个json可能gz压缩,需要判断开头字节是否1f8b 。然后就是gz压缩的xml。是的还是xml,我还以为用其他格式了,上次那个protobuf本来也挺好,不是很懂。

再观察了一阵,这个和上次pb类似,分段,6min一段。想了想类名大概在线时候用这个动态加载,离线保存还是xml。

在lcz大佬的博客说几句about biliplus……

大家好,我是爬丝,对,那个傻逼爬丝~
在加拿大的最后一天,此时是下午,闲的没事,就想把之前想说的话都说出来,想了半天,还是在lcz大佬的博客写吧~

其实吧,我是15年知道的biliplus,之前知道的都是jj啊还有一些现在的新人都不知道的解析网站。

曾经硕鼠都用过几年(现在基本都属于半死不活的状态),所以在16年中,因为乐视黑科技的问题,lcz大佬在b吧发了乐视云的解析相关信息,我们当时已经在后乐视时期成立了新的 B站胡乱瞎搞黑名单开发小组,简称B站黑名单小组。一共算我是四位成员。

后来看到lcz大佬的帖子后,我感觉这不是个好事情,然后私信留言,加QQ聊个半天,居然发现这个人很有趣啊,技术也可以,人也很正直,于是在进行讨论后,我把lcz大佬拉入了表群,视频研究协会,然后几天后拉入了里群。

至此,5人组正式成立了。

很开心,在我没想到的时间点有这样的志同道合的瞎几把搞的同好(大雾)一起玩确实开心。

然后在聊天中得知,lcz大佬是xian人,来沈阳上学,居然是学他妈的最特么屌炸天的物理。

贼巧,我当时毕业后在沈阳上班,正好是我上了半年班的时候,于是顺理成章的面基了。

大佬坐地铁到铁西,我把他领到了我的家里,然后一起玩了一些游♂戏。

非常开心,非常愉♂悦,时常屋子里传出了开心的呻吟声……(←巨雾)

第一次面基研究了无数的技术,在lcz大佬的帮助下,我的xbr192音频压制器被完善了,神他妈没有ffmpeg哈哈哈哈哈哈哈……

于是走的越来越近后,biliplus我也逐渐的开始研究测试。

lcz大佬技术确实没问题,这方面我是很有自信的,没有lcz大佬办不到的事,如果有,请看这行第一句……

但是毕竟是学生,有些方面,我身为一个长者,给他传授些人生的经验,很惭愧,我只做了一点微小的工作,毕竟苟利国家生死以,岂因祸福避趋之……

于是顺理成章,bp的一些额外的事情我也逐渐开始给lcz大佬提建议与我的想法。

只是,没想到,bp居然到17年的今天,出现了这样的事情。

B站在经历了两次商业化的举动后,现在彻底已经成为了一家正经的商业公司,倒不是说商业化不好,毕竟是需要赚钱,这道理没有任何问题,别谈什么爱,现实就是金钱,想的太多反而给自己弄得那么累。

只是B站最近几年做的是越来越差,总体感觉就是三次元充斥这整个网站,已经无法找到曾经的那个感觉了,老用户流失度越来越高,新用户脑残度越来越高,老员工离职率一直居高不下。

这些问题说明了,B站已经变质了,已经完全不是曾经的B站了。

从视频整体质量和直播活动与一些(所谓的逸国趣事)等都能看出来很多细节。

所以,逐渐打击曾经是巴不得你创建的网站。
也就是,曾经幕后支持bp、jj此类网站,而且也是放任不管。
现在是正式开始打击,因为,【此类网站已经开始损害了B站的利益!】

什么叫损害?你让B站赚不到钱,你让B站本来赚6位数,你的网站让他损失了5位数,那就得律师函了对吧。

同类网站,某知名网站站长发微博,在前几天收到了律师函,并正式停止了网站,可怜可惜可叹。

而bp目前还没有大面积损失B站的利益,所以,也可以勉强苟活一段时间。

从lcz大佬的关于网站的一些事情(附后文)】的文中能看到他对bp的爱,以及对这个网站的不舍,以及暗讽B站的举动。

不难看出,现在的bp已经到了一个关键点,关于这方面的事情我前一段时间跟lcz大佬彻夜长谈,相信他心里已经有B数了。

正如lcz大佬所说,bp迟早会关闭,但不是现在,起码,低成本的维护bp还是可以的。

【你们有没有想过,bp,是lcz大佬一个人从头到尾整整2年半的维护。】

期间B站更新一次,lcz大佬就得重新后台维护一次,还为了保证网站不进入维护状态,自己花了多少心血,付出了多少汗水,这些东西没人知道,你们只在乎你们自己爽不爽,从来没有关心过这些幕后的staff。

我对bp的爱全部都是因为lcz大佬,我是一心想帮助lcz大佬做好bp。

每一次lcz大佬有新功能,都会在我们内部群让我们帮忙测试。

写一个新功能需要付出多少精力和时间,做这个的人你们自己明白。也得亏lcz大佬没有产品经理管他,他自己说的算……

总之,说这么多到现在有1800字了,我还是难以接受bp的现状。

如果你用过biliplus,如果你真的觉得这个网站不错,如果你真的想让bp再苟活几天,如果,如果你不想以后再也看不到这些网站的幕后维护人,不想看到他们逐渐丧失动力,丧失理想。

仅你自己一份力,在bp困难的时候伸出援手。

B站已经没有爱了,但是,我们这群老人还是在努力的做我们自己,我们还在努力的坚持着,我们,还在,让大家开心。

谢谢那些曾经帮助过bp的人,谢谢那些曾经为了bp做出贡献的人。

谢谢你们,谢谢,我的谢谢微不足道,但是,我的心所想,我希望让你们明白。

没有你们,也就没有biliplus的今天。

【附】:

↓ lcz大佬的个人支付宝赞助二维码 ↓

lcz大佬的paypal赞助地址:esterTion的Paypal赞助地址】

以及,曾经为了这份爱的大家:biliplus赞助名单】

就这样,再一次,感谢你们。

(Ps.大佬啥时候回沈阳,你还欠我一顿饭呢,是吧,上次海底捞吃得多爽,这次我想吃潮汕嫩牛火锅,大佬咱是不是,嗯?~\(≧▽≦)/~)

[NyaPass7 于 (加拿大东部时间)2017年8月16日 15:42:29 有感而发]

关于b站新弹幕格式.pb

格式为google protocol buffer (protobuf)

地址格式为{cid}-{part}.pb,每part包含3分钟的弹幕内容,即边播放边加载模式,如-3.pb包含第6-9分弹幕

在bilibiliPlayer.min.js中有大部分field id的定义,但文件中出现了id12-14

pb格式弹幕 Field常量
1  row (Row)
2  chat_server (string)
3  chat_id (varint32)
4  mission (varint32)
5  max_limit (varint32)
6  source (string)
7  ds (varint32)
8  de (varint32)
9  max_count (varint32)
10 realname (varint32)
11 sectionlen (varint32)(一般为180)
//猜测id
12 duration (float)
13 total_count (varint32)
14 pb_version (varint32)(目前常量1)

pb格式弹幕row Field常量
1  playtime (float)
2  mode (varint32)
3  fontsize (varint32)
4  color (varint32)
5  times (varint32)
6  poolid (varint32)
7  hash (string)
8  dmid (varint32)
9  msg (string)
10 uid (varint32)(暂未出现)
11 uname (string)(暂未出现)

其中varint32为变长度int32格式,具体为每字节只有后7位存储数据,第1位为指示位,为1时继续读取下一字节

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}

文件读取代码样本

<?php
/*
 BiliBili pb danmaku reader
 @author esterTion(esterTionCN@gmail.com)
*/
$pb=fopen('http://comment.bilibili.com/14328539-1.pb','r');

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}
function readString($fp){
	$strLength=readVarInt32($fp);
	return fread($fp,$strLength);
}
$types=array(
	'VARINT'=>0,
	'FIXED64'=>1,
	'DELIMITED'=>2,
	'START_GROUP'=>3,
	'END_GROUP'=>4,
	'FIXED32'=>5
);
$rowCount=0;
while(true){
	$id=fread($pb,1);
	if($id==='')
		break;
	$id=unpack('C',$id)[1];
	$type = $id & 7;
	$id = $id >> 3;
	switch($id){
		case 1:
			$rowLength=readVarInt32($pb);
			echo 'row length:'.$rowLength.' ';
			$end=ftell($pb)+$rowLength;
			$row=array();
			while(ftell($pb) < $end){
				$id=unpack('C',fread($pb,1))[1];
				$id = $id >> 3;
				switch($id){
					case 1:
						$row['playtime']=unpack('f',fread($pb,4))[1];
					break;
					case 2:
						$row['mode']=readVarInt32($pb);
					break;
					case 3:
						$row['fontsize']=readVarInt32($pb);
					break;
					case 4:
						$row['color']=substr(pack('N', readVarInt32($pb) ),2);
					break;
					case 5:
						$row['timestamp']=readVarInt32($pb);
					break;
					case 6:
						$row['poolid']=readVarInt32($pb);
					break;
					case 7:
						$row['hash']=readString($pb);
					break;
					case 8:
						$row['dmid']=readVarInt32($pb);
					break;
					case 9:
						$row['msg']=readString($pb);
					break;
					case 10:
						$row['uid']=readVarInt32($pb);
					break;
					case 11:
						$row['uname']=readString($pb);
					break;
				}
			}
			print_r($row);
			$rowCount++;
		break;
		case 2:
			echo '[chat_server] => '.readString($pb)."\n";
		break;
		case 3:
			echo '[chat_id] => '.readVarInt32($pb)."\n";
		break;
		case 4:
			echo '[mission] => '.readVarInt32($pb)."\n";
		break;
		case 5:
			echo '[max_limit] => '.readVarInt32($pb)."\n";
		break;
		case 6:
			echo '[source] => '.readString($pb)."\n";
		break;
		case 7:
			echo '[ds] => '.readVarInt32($pb)."\n";
		break;
		case 8:
			echo '[de] => '.readVarInt32($pb)."\n";
		break;
		case 9:
			echo '[max_count] => '.readVarInt32($pb)."\n";
		break;
		case 10:
			echo '[realname] => '.readVarInt32($pb)."\n";
		break;
		case 11:
			echo '[sectionlen] => '.readVarInt32($pb)."\n";
		break;
		default:
			switch($type){
				case 0:
					echo '--Unknown ID '.$id.' with varint32 value '.readVarInt32($pb)."\n";
				break;
				case 1:
					echo '--Unknown ID '.$id.' with fixed 64bit data hex '.bin2hex(fread($pb,8))."\n";
				break;
				case 5:
					echo '--Unknown ID '.$id.' with fixed 32bit data hex '.bin2hex(fread($pb,4))."\n";
				break;
				default:
					echo '--Unknown ID '.$id.' with type '.$type."\n";
			}
	}
}
echo $rowCount.' rows in file'."\n";

 

番剧数据

写了三天的小东西

https://www.biliplus.com/data/

先写的后端挂到服务器上cron

初弄时感觉好无聊啊,表格难看啊什么的

不过多起来后似乎好看一些QQ截图20160701123342

不过目前看到了几次奇怪的故障,导致数据出问题


本来吧,我一开始的代码是,每次更新一次性读取所有已存数据,按个添加当次数据,再分别保存

结果不到一天已经700K数据了

吓得我赶紧重构了一下

按sid打开、追加、保存


7/1晚 更新log:

  • 完善菜单体验
  • 横轴显示变更
  • 按屏幕高比例缩放

7/2 更新log:

  • 侧栏收缩
  • 标题当前数据类型

7/4 更新log


7/5 更新log

  • 换用Highcharts
  • -效率更高
  • -支持缩放
  • 移动端适配完成
  • ——写iOS网页时,设置line-height能解决几乎所有辣鸡苹方带来的问题

7/6 更新log

  • 早起看HxH数据发现会员专属,添加备用获取
  • (火星异种拉了一周0播放……)

某直播基引发的一些深♂入

某姬闹的好大啊

嘛,关我卵事

听说有一键登录接口,就去看了看

总结一下发现

image

一个新的appkey:1327d048d3ab5f78,暂没有获取到appSecret

几个新的api

其中所说的直接登录的就是getRoomUrl

此api跳转至 https://account.bilibili.com/api/login/sso 并且该api接受自己生成的有效参数组合

接受参数 access_key用于登陆,附带gourl可指定登录后跳转地址


 

6/16

在某dalao的挖掘下,翻到了appSecret

关于知乎上什么“安全隐患”,持怀疑态度,这客户端不就是个rsa登录,全程accesskey的东西么,里面能有什么重要东西

或许最珍贵的就是这个secret了吧

关于b站的广告

一开始我还不知道逼开始贴片了

看番一向都是bdown下载后bililocal+svp看,没有受到任何影响

就算是网页,也是替换修改播放器,基本没用过原版

晚上的时候看到有C的微博才知道今天的re0上了贴片,这才去看了看情况

http://api.bilibili.com/x/ad/video?aid=4738388

{"code":0,"data":[{"name":"沪江4738388","aid":4738388,"cid":4709603,"url":"http://class.hujiang.com/?ch_campaign=cls10988\u0026ch_source=opp_bz_0_spag","skipable":0,"strategy":0}]}

奇怪的加载逻辑,嵌套miniplaylite.swf,用一种类似站外播放的方式播放广告

据说可以用flashvar设置不显示广告

pre_ad=0

出于部分考虑吧,bp原始播放器还是不整这个参数了

aid搜索告一段落

一直把ac双库放在别人那里

一夜消失

用一些特殊方法搞到的比较高级的服务器,被管理员发现了,就没了

加上扫描的时间,差不多用了两个月

当初放的时候就知道会有这一天,只不过一直无事感觉像是永远没有问题一样

考虑看看腾讯,看起来还算比较便宜

毕竟a+c总共3G+大小的数据库,可不是普通的地方能撑得住的

 

5/13 下午

试用腾讯“按量收费”,抛弃

辣鸡玩意儿,实际上是按照开通时长计费的,即“开通时间=使用时间”,还以为会是按照CPU时间计费

 

5/14凌晨

暂时利用阿里云9.9学生机挂上,腾讯学生认证略慢,之后准备换到那边的1元机上。极限压缩成本中

登录系统更新的后话

昨天因为一些事情,又关注到了b的登录系统

从各种意义上来说,现在的登录管理算是很安全了

去年的时候看到的那些帖子,比如借给别人号,没法注销,改密码也能用。

现在这些问题已经没了

改密码后,所有与该账号对应的accesskey全部删除

至于cookie,改后只有passport底下失效,member倒是可以正常打开,应该是验证系统没有改进吧

B站上传Shell

写起来也不算很复杂就是了~

-user <用户名> 登录
-getnew 获取地址
-file <filename> 指定文件上传
按步骤进行,登陆过可直接获取,cookie可能会过期

#!/bin/sh

while [[ $1 != "" ]]; do
  case $1 in
    -user)
      user=$2
      shift 2
    ;;
    -file)
      file=$2
      shift 2
    ;;
    -silent)
      silent=" -s"
      shift 1
    ;;
    -getnew)
      getnew="true"
      shift 1
    ;;
    -h|--help)
      echo "BiliBili Uploader in shell
  by lcz970

-h --help
  输出本帮助信息

-user <userid> 
  登录模式,指定用户名,密码将在执行时询问,用于获取cookie

-getnew
  获取地址,获取后写入文件方可开始上传,需要cookie正常获取

-file <path/to/file>
  上传模式,读取给定的文件并上传,需要存在可用的上传地址
-silent
  静默上传,不输出curl信息,只显示切片字节"
      exit
    ;;
    *)
      echo "未知参数 $1"
      exit
    ;;
  esac
done

if [[ $user != "" ]]; then
  echo "登陆用户 $user"
  read -s -p "输入密码 " pwd
  if [[ $pwd == "" ]]; then echo "密码为空"; exit; fi
  echo -e "\n登陆中..."
  return=$(curl -s --data "userid=$user&pwd=$pwd" "https://passport.bilibili.com/ajax/miniLogin/login" -c /tmp/bili_cookie)
  if [[ $return != ${return#*status\"\:true} ]]; then echo "登陆成功"; else echo "登陆失败"; echo $return; fi
  exit
fi

if [[ $getnew == "true" ]]; then
  echo "获取新上传地址"
  return=$(curl -s "http://member.bilibili.com/get_vupload_url" -b /tmp/bili_cookie)
  if [[ $return == ${return#*url\"\:} ]]; then echo "获取失败"; echo $return; else
    url=${return#*url\"\:\"}
    until [[ "$url" == "${url%\"*}" ]]; do url="${url%\"*}"; done
    filename=${return#*file_name\"\:\"}
    until [[ "$filename" == "${filename%\"*}" ]]; do filename="${filename%\"*}"; done
    echo -e "上传服务器:${url:7:5}\n上传文件名 $filename\n地址已保存"
    echo -n $url >/tmp/bili_upload_url
  fi
  exit
fi

if [[ $file == "" ]]; then
  echo "上传必需参数不足,-h查看帮助"
  exit
fi

if [[ ! -f $file ]]; then
  echo "文件不存在"
  exit
fi

if [[ ! -f /tmp/bili_upload_url ]]; then
  echo "上传地址不存在,请使用-getnew获取"
  exit
fi

url=$(</tmp/bili_upload_url)
filename=${url#*filename=}; until [[ "$filename" == "${filename%&*}" ]]; do filename="${filename%&*}"; done
hash=${url#*hash=}; until [[ "$hash" == "${hash%&*}" ]]; do hash="${hash%&*}"; done
uploadFile=$file; until [[ "$uploadFile" == "${uploadFile#*/}" ]]; do uploadFile="${uploadFile#*/}"; done

echo "上传服务器:${url:7:5}
上传vid: $filename
上传文件:$uploadFile"

size=$(ls -l "$file")
size=${size#* * * * }
until [[ "$size" == "${size% *}" ]]; do size="${size% *}"; done
let start=0 sizeR=size-1
let M=size/1024/1024 "K=(size-M*1024*1024)/1024*100/1024"; if (( $K < 10 )); then K=0$K; fi; sizeh=$M.$K

while (( $start < $size )); do
  let block=512*1024 end=start+block-1
  if (( $end >= $sizeR )); then
    let end=sizeR block=end-start+1
  fi
  let M=start/1024/1024 "K=(start-M*1024*1024)/1024*100/1024"; if (( $K < 10 )); then K=0$K; fi; starth=$M.$K
  let M=end/1024/1024 "K=(end-M*1024*1024)/1024*100/1024"; if (( $K < 10 )); then K=0$K; fi; endh=$M.$K
  let "percent=start/(size/10000)" percentI=percent/100 "percentD=percent-(percentI*100)"
  if (( $percentI < 10 )); then percentI=0$percentI; fi
  if (( $percentD < 10 )); then percentD=0$percentD; fi
  echo "上传分片 ${starth}M-${endh}M/${sizeh}M($start-$end/$size) $percentI.$percentD%"
  dd "if=$file" of=/tmp/part.flv skip=$start bs=$block count=1 iflag=skip_bytes status=none
  return=
  return=$(curl "$url" -A "Mozilla/5.0 (Windows NT 6.1; rv:35.0) Gecko/20100101 Firefox/43.0.4" -H "Content-Range: bytes $start-$end/$size" -H "Content-Disposition: attachment" -F "files[]=@/tmp/part.flv;type=video/x-flv;filename=\"$uploadFile\""$silent)
  if [[ $silent == "" ]]; then echo; fi
  if [[ $return == "-1" ]]; then echo "无效地址"; exit; fi
  if [[ "$return" == "${return#*size\"\:}" ]]; then
    echo "上传出错,重新尝试"
  else
    current=${return#*size\"\:}
    until [[ "$current" == "${current%,*}" ]]; do current="${current%,*}"; done
    start=$current
  fi
  rm -rf /tmp/part.flv
done

echo "完成
投稿代码:
[vupload]$filename;$uploadFile;2;[/vupload]#p#这里填分P标题#e#"
echo -e "[vupload]$filename;$uploadFile;2;[/vupload]#p#这里填分P标题#e#\r" >>~/bili_upload_history.txt

扫描收藏夹那些事~

本来想在微博发的,想想算了,给自己惹事

和群里几个人密谋了一个计划,进行了两周,结束了
整理整理自己的作死经历

excited

很久以前就注意到B的收藏夹了,大概是上次换API的时候。收藏夹这个东西,首先是视个人隐私设定如无物,只要有mid随便看别人的收藏夹。其次就是,除了投稿的list信息,收藏夹有剩下的所有信息。
于是来灵感了,全扫一遍怎么样
于是谋划了这个计划

20160326182703

其中一开头就遇到了问题

20160326182203

这里得出了B站收藏夹的一个奇怪的特性
收 藏夹号称无上限,实际上是有上限的,上限30000个。但是这个上限和平时的上限不太一样,在加满30000个的状态下,添加第30001个视频的时候,收藏夹里是找不到这个视频的,但是它并不是没有添加上,而是处于一个“溢出”的状态。如果删除前30000个里的一个,则第30001个进入收藏列表,收藏夹总数依旧显示30000。

 

历时两周,扫下了4100000前的数据

20160326183428

顺便就放几个大数据吧

投稿状态数

2016032618250220160326182616

劳模榜

20160326182444