最近闲的无聊开始看番,然后B站的番要大会员,网上看视频又没有弹幕,于是就想着把B站弹幕加载到别的视频上,于是研究就开始了。。。

获取cid

查了很多资料,有很多可以获取cid的方法,但是都没办法用php写出来,我一度裂开了啊。然后不小心点到查看源代码,发现所有的cid都写在了里面。。。

算了,不多做解释了,贴个代码吧。

获取方法:?url=番剧分享地址(不能是b.tv开头的)

 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
29
30
31
32
33
34
35
36
37
<? php
header("Content-type:application/json");

function get($url) {
    $ua = "Mozilla/5.0 (Windows NT 6.3; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36 Edg/81.0.416.62";
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_USERAGENT, $ua);
    curl_setopt($curl, CURLOPT_ENCODING, "gzip"); //这里是关键,曾一度乱码,一直以为是编码的问题,让我又裂了好久
    $result = curl_exec($curl);
    curl_close($curl);
    return $result;
}
$url = str_replace('m.bilibili.com', 'www.bilibili.com', $_GET['url']);
$result = get($url);
preg_match("/window\.__INITIAL_STATE__=\{(.*?)\};/", $result, $matches);
$preJson = str_replace("window.__INITIAL_STATE__=", "", $matches[0]);
$preJson = str_replace(";", "", $preJson);
$dataArray = json_decode($preJson, true);
$epList = $dataArray['epList'];
for ($i = 0; $i < count($epList); $i++) {
    $return[] = [
        'cid' => $epList[$i]['cid'],
        'name' => $epList[$i]['titleFormat'].$epList[$i]['longTitle'].$epList[$i]['badge'],
        'cover' => "https:".$epList[$i]['cover'],
        'comment' => "https://comment.bilibili.com/".$epList[$i]['cid'].
        ".xml"
    ];
    //cover和comment完全是闲了么事加的
}

echo json_encode($return, JSON_UNESCAPED_UNICODE);

?>

转换弹幕格式

总体内容

梅开二度,我又裂了啊,Dplayer不支持xml的格式,还必须自己转换。在网上查到一个,没有用,又不知道他在写什么玩意,只好自己动手了。

参考了一下Dplayer 的示例视频的弹幕,我开始了研究

获取方法: ?cid={cid}

 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<? php
header("Content-type:application/json");

function get($url) {
    $ua = "Mozilla/5.0 (Windows NT 6.3; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36 Edg/81.0.416.62";
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_USERAGENT, $ua);
    curl_setopt($curl, CURLOPT_ENCODING, "gzip");
    $result = curl_exec($curl);
    curl_close($curl);
    return $result;
}

function xmlToJson($xmlContent) {
    //通过正则获取弹幕参数
    $query = "/<d.*?p=\"(.*?)\".*?>(.*?)<\/d>/";
    preg_match_all($query, $xmlContent, $matches);
    $result['code'] = 0;
    for ($i = 0; $i < count($matches[1]); $i++) {
        $p = explode(",", $matches[1][$i]);
        if ($p[1] == "4") {
            $p[1] = "2";
        }
        elseif($p[1] == '5') {
            $p[1] = '1';
        }
        elseif($p[1] == '1') {
            $p[1] = '0';
        }
        $result['data'][] = [
            round($p[0], 3),
            intval($p[1]),
            intval($p[3]),
            $p[6],
            $matches[2][$i]
        ];
    }

    return $result;
}
$xmlContent = get("https://comment.bilibili.com/".$_GET['cid'].
    ".xml");
$result = xmlToJson($xmlContent);
echo json_encode($result, JSON_UNESCAPED_UNICODE); 
?>

写完这一段,发现参数完全对上了,却加载不了,我又裂了啊,最后猜是JS对数据类型要求比较严格,于是做出了尝试,最终解决了。。。

弹幕位置的转化

写完之后,发现弹幕位置对不上。。。

参考资料:https://www.bilibili.com/read/mobile/6189156

经过尝试发现Dplayer的弹幕位置参数如下

顶部弹幕 底部弹幕 滚动弹幕
1 2 0

Dplayer的使用

基本使用

使用前需要引入js文件

1
<script src="https://jsd.imbai.cn/pics/npm/dplayer/dist/DPlayer.min.js">
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const dp = new DPlayer({
				container: document.getElementById('player'),//通过id获取位置
				preload: 'none',
				video: {
					url: url
				},
				danmaku: {
					addition: [comment]
				}
			});

出现的一些问题和解决办法

问题一: 部分格式文件播放不了

建议一次性引用下面这些JS文件

1
2
3
4
5
6
7
8
	<script src="https://jsd.imbai.cn/pics/npm/flv.js/dist/flv.min.js">
	</script>
	<script src="https://jsd.imbai.cn/pics/npm/hls.js/dist/hls.min.js">
	</script>
	<script src="https://jsd.imbai.cn/pics/npm/dashjs/dist/dash.all.min.js">
	</script>
	<script src="https://jsd.imbai.cn/pics/webtorrent/latest/webtorrent.min.js">
	</script>

这里我也裂开了,当时大晚上能用第二天早上就不能用了,当场蒙了,然后dp的api也用不了,就很懵,于是改成了下面这样。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function reload() {
			var num = Math.random() * 100;
			var player = "<div id=\"player" + num + "\"></div>";
			$("#play").empty();
			$("#play").append(player);
			var url = $("#videourl").val();
			var danmu = $("#danmuurl").val();
			load(url, danmu, num);
		}

function load(url, comment, num) {
			const dp = new DPlayer({
				container: document.getElementById('player' + num),
				preload: 'none',
				video: {
					url: url
				},
				danmaku: {
					addition: [comment]
				}
			});
		}

就是加了一个随机div,每次构建不同的dplayer 问题三:弹幕字体修改

这里。。。。发现手机不能用font-family的我蒙了

还好在Github上找到了解决办法:fonts.css

引用css

1
<link rel="stylesheet" href="https://jsd.imbai.cn/pics/npm/fonts.css@2.0.0/dist/fonts.css">

Github地址:https://github.com/zenozeng/fonts.css

效果

最后的最后放上结果的Github地址,随手弄了一个UI

45a49e90627e007066959410a909737a.webp

https://github.com/3401797899/bilibili-danmu

好累啊,去休息了。。。