以下是一些写脚ben时获得的数据记录,最后面是脚ben代码。

抓包加上查资料拿到的弹幕数据接口:

  • "https://api.bilibili.com/x/v1/dm/list.so?oid=" + cid 返回数据类型为XML(旧接口)。
  • https://api.bilibili.com/x/v2/dm/web/seg.so?oid=" + cid + "&type=1&segment_index=1 返回二进制数据(新接口)

二进制数据处理比较麻烦,我就用了XML的接口。

cid是视频的id,也叫oid,不是AV号,获取方式有两种:

  • 在控制台输入cid获取当前视频的cid
  • 通过方法:window.__INITIAL_STATE__.videoData.pages

接口测试时获取的数据如下:

弹幕的返回数据含义如下:

<d p="1611.18000,1,25,16777215,1631635549,0,ab0d3321,54811347826209280,10">来看八爷</d>

有9个参数,经过查询并且测试获得了部分参数的含义:

  • 参数1: 1611.18000 弹幕出现的时间,以秒数为单位
  • 参数2: 1 弹幕的模式,1-3 滚动弹幕,4 底端弹幕,5顶端弹幕,6 逆向弹幕,7 精准定位,8 高级弹幕
  • 参数3: 25 字号 (12非常小,16特小,18小,25中,36大,45很大,64特别大)
  • 参数4: 16777215 字体的颜色,这串数字是十进制表示
  • 参数5: 1631635549 unix时间戳
  • 参数6: 0 弹幕池类型,0普通池,1字幕池,2特殊池 【目前特殊池为高级弹幕专用】
  • 参数7: ab0d3321 发送者的Hash,用于“屏蔽此弹幕的发送者”功能
  • 参数8: 54811347826209280 弹幕在弹幕数据库中rowID 用于“历史弹幕”功能。
  • 参数9: 10 未知,貌似是新增的,查阅的资料里都没有这个参数

这里只有第一个参数用得到,剩下的参数会在我的另一个修改视频弹幕的脚ben里用到。

最终效果如下:

代码如下:

// 允许跨域请求,防止浏览器拦截
var meta = document.createElement("meta");
meta.httpEquiv = "Access-Control-Allow-Origin";
meta.content = "*";
$("head")[0].appendChild(meta);// 初始化若干变量
var page_loc = location.href;
var page_start = page_loc.indexOf("?p=");
var page_p;// 获取视频cid
if (page_start == -1 || page_start == 1) page_p = 0;
else page_p = page_loc.slice(page_start + 3) - 1;
var page_cid = window.__INITIAL_STATE__.videoData.pages[page_p].cid;// 发起请求,拿到弹幕数据
$.ajax({url: "https://api.bilibili.com/x/v1/dm/list.so?oid=" + page_cid,type: "GET",dataType: "XML",success: function (xml) {// 处理返回数据data_deal(xml.all);},error: function (err) {console.log(err);alert("弹幕列表滚动脚本失效,可尝试更新最新版本脚本解决问题!\n如果有一定编程基础可以打开控制台查看报错信息。");}
});// 存储数据
function data_deal(data) {var data_list = new Array(); // 存信息var data_arr = new Array(); // 存内容var data_length = data.length;for (var i = 8; i < data_length; i++) {var data_array = data[i].attributes.p.value.split(",");$.each(data_array, function (i) {data_array[i] = parseFloat(data_array[i]); // 转换类型,便于排序})data_list.push(data_array);data_arr.push(data[i].innerHTML);}// 执行排序data_sort(data_list, 0, data_list.length - 1, data_arr);// 修改弹幕列表$(".bui-collapse-header").bind("click", function () {var clearInter = setInterval(function () {if ($(".player-auxiliary-danmaku-load-status").css("display") == "none") {list_change(data_list, data_arr);clearInterval(clearInter);}}, 100);});
}// 数据排序(快排算法)
function data_sort(data_list, l, r, data_arr) {if (l < r) {var i = l,j = r,temp = data_list[l],t1, t2, t3;while (i < j) {while (i < j && data_list[j][0] >= temp[0]) j--;while (i < j && data_list[i][0] <= temp[0]) i++;if (i < j) {t1 = data_list[i];data_list[i] = data_list[j];data_list[j] = t1;t2 = data_arr[i];data_arr[i] = data_arr[j];data_arr[j] = t2;}}data_list[l] = data_list[i];data_list[i] = temp;t3 = data_arr[l];data_arr[l] = data_arr[i];data_arr[i] = t3;data_sort(data_list, l, i - 1, data_arr);data_sort(data_list, i + 1, r, data_arr);}
}// 时间格式转换(分转秒)
function time_m_s(a) {if (a.length == 2) return a[0] * 60 + a[1];else return a[0] * 3600 + a[1] * 60 + a[2];
}// 时间格式转换(秒转分)
function time_s_m(a) {a = Math.floor(a);var m = Math.floor(a / 60);var s = (a - Math.floor(a / 60) * 60);if (m < 0) m = "00";else if (m < 10) m = "0" + String(m);if (s < 10) s = "0" + String(s);return m + ":" + s;
}// 发送日期格式转换
function data_s_d(a) {var date = new Date(a * 1000);var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';var D = date.getDate();if (D < 10) D = "0" + String(D) + ' ';else D = D + ' ';var h = date.getHours();if (h < 10) h = "0" + String(h) + ":";else if (h == 0) h = "00" + ":";else h = h + ":";var m = date.getMinutes();if (m < 10) m = "0" + String(m);else if (m == 0) m = "00";return M + D + h + m;
}// 获取当前视频播放秒数
function get_now_s() {var time_now = $('.bilibili-player-video-time-now')[0].innerHTML.split(":");$.each(time_now, function (i) {time_now[i] = parseInt(time_now[i]);})return time_m_s(time_now);
}function list_change(data_list, data_arr) {// 修改页面控制$(".player-auxiliary-danmaku-btn-time").removeAttr("orderby");$(".player-auxiliary-danmaku-btn-danmaku").removeAttr("orderby");$(".player-auxiliary-danmaku-btn-date").removeAttr("orderby");$(".player-auxiliary-danmaku-function > .player-auxiliary-danmaku-btn-danmaku")[0].innerHTML = "滚动弹幕(共" + data_arr.length + "条)";// 弹幕排序list_sort(data_list, data_arr);
}function list_sort(data_list, data_arr) {// 破坏初始列表结构$(".player-auxiliary-danmaku-wrap > div > ul").empty();$(".player-auxiliary-danmaku-wrap > .player-auxiliary-danmaku-contaner").removeClass("player-auxiliary-danmaku-contaner player-auxiliary-bscrollbar");$(".player-auxiliary-danmaku-wrap").off();$(".player-auxiliary-danmaku-wrap > div > ul").off();// 清除BFCvar div = document.createElement("div");var nothing = document.createTextNode(".");div.appendChild(nothing);$(".player-auxiliary-danmaku-wrap > div > ul")[0].appendChild(div);$(div).addClass("BFC-nothing");$(".BFC-nothing").css("opacity", "0");// 构造有序列表$(data_arr).each(function (i, v) {var li = document.createElement("li");var span1 = document.createElement("span");var span2 = document.createElement("span");var span3 = document.createElement("span");var span4 = document.createElement("span");var text1 = document.createTextNode(time_s_m(data_list[i][0]));var text2 = document.createTextNode(v);var text3 = document.createTextNode(data_s_d(data_list[i][4]));var text4 = document.createTextNode(">");span1.appendChild(text1);span2.appendChild(text2);span3.appendChild(text3);span4.appendChild(text4);$(li).attr("dmno", i);$(span2).attr("title", v);$(li).addClass("danmaku-info-row");$(span1).addClass("danmaku-info-time");$(span2).addClass("danmaku-info-danmaku");$(span3).addClass("danmaku-info-date");$(span4).addClass("danmaku-info-animate");li.appendChild(span1);li.appendChild(span2);li.appendChild(span3);li.appendChild(span4);$(".player-auxiliary-danmaku-wrap > div > ul")[0].appendChild(li);$('.danmaku-info-animate').css({'position': 'absolute','width': '15px','height': '100%','padding': '0','left': '0px','font-size': '15px','color': 'rgb(1,185,245)','transition': '1s ease-in-out'});});// 播放动画(监听视频播放进度)var isChange = $(".bilibili-player-video-time-now")[0].innerHTML;player_animate(data_list, get_now_s());setInterval(function () {if (isChange != $(".bilibili-player-video-time-now")[0].innerHTML) {player_animate(data_list);  // 动画播放isChange = $(".bilibili-player-video-time-now")[0].innerHTML;}}, 1000);
}// 播放动画
function player_animate(data_list) {var time_now_s = get_now_s();var length = data_list.length;var begin = -1, end = -1;for (var i = 0; i < length; i++) {if (Math.floor(data_list[i][0]) < time_now_s) continue;if (Math.floor(data_list[i][0]) > time_now_s) break;if (begin != -1) end++;if (begin == -1) begin = end = i;}if (end == -1) return;var li_height = parseFloat($(".player-auxiliary-danmaku-wrap > div > ul > li").css("height").replace("px", ""));var li_width = parseFloat($(".player-auxiliary-danmaku-wrap > div > ul > li").css("width").replace("px", ""));for (var i = begin; i <= end; i++) {if (length > 15 && i > 11) $(".player-auxiliary-danmaku-wrap > div > ul > li:first").css("margin-top", "-" + (i - 11) * li_height + "px");  // 列表滚动$($('.player-auxiliary-danmaku-wrap > div > ul > li')[i]).find(".danmaku-info-animate").css("left", li_width);  // 播放动画}
}

如果有兴趣了解更多相关内容,欢迎来访我的个人网站:eyes++的个人空间

如果对该类脚本感兴趣的话,欢迎来到我的github看看,我开源了一个script仓库,里面有很多我写的和正在写的脚本,大佬们有兴趣可以一起贡献代码,仓库地址

------------------分割线(2021/10/7)-------------------
之前那个脚本效率太低了,所以没有投入使用,我给它优化了一下逻辑,现在可以投入使用了,但是我实在是不会用js注入动画,所以这次的我取消了动画。。。。。。有知道的大佬可以教教我,下载地址:bilibili弹幕列表实时滚动播放

代码如下:

// ==UserScript==
// @name         bilibili弹幕列表实时滚动播放
// @namespace    https://eyesblog.gitee.io
// @version      1.0
// @description  在B站看视频时弹幕一多就会遮住内容,可我又想看视频又想看弹幕,就写了这个脚本,安装后右侧的弹幕列表会随视频播放而滚动,并且会有弹幕出现提示
// @author       eyes++
// @match        https://www.bilibili.com/video/*
// @require      https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js
// @grant        none
// ==/UserScript==(function () {'use strict';// 允许跨域请求,防止浏览器拦截let meta = document.createElement("meta");meta.httpEquiv = "Access-Control-Allow-Origin";meta.content = "*";$("head")[0].appendChild(meta);// 初始化若干变量let page_loc = location.href;let page_start = page_loc.indexOf("?p=");let page_p;// 获取视频cidif (page_start == -1 || page_start == 1) page_p = 0;else page_p = page_loc.slice(page_start + 3) - 1;let page_cid = window.__INITIAL_STATE__.videoData.pages[page_p].cid;// 发起请求,拿到弹幕数据$.ajax({url: "https://api.bilibili.com/x/v1/dm/list.so?oid=" + page_cid,type: "GET",dataType: "XML",success: function (xml) {// 处理返回数据data_deal(xml.all);},error: function (err) {console.log("弹幕列表滚动脚本报错:", err);alert("弹幕列表滚动脚本失效,可尝试更新最新版本脚本解决问题!\n如果有一定编程基础可以打开控制台查看报错信息。");}});// 存储数据let data_deal = data => {let data_list = new Array(); // 存时间信息let data_arr = new Array(); // 存内容let data_length = data.length;for (var i = 8; i < data_length; i++) {let data_array = data[i].attributes.p.value.split(",");data_array.splice(5, 4);data_array.splice(1, 3);$.each(data_array, function (i) {data_array[i] = parseFloat(data_array[i]); // 转换类型,便于排序})data_list.push(data_array);data_arr.push(data[i].innerHTML);}// 执行排序data_sort(data_list, 0, data_length - 9, data_arr);// 修改弹幕列表let clear = setInterval(() => {if ($(".bui-collapse-header")[0]) { // 等待弹幕列表加载出来clearInterval(clear);$(".bui-collapse-header").click(() => {let clearInter = setInterval(function () {if ($(".player-auxiliary-danmaku-load-status").css("display") == "none") { // 等待弹幕数据加载出来clearInterval(clearInter);list_change(data_list, data_arr); // 然后开始修改列表}}, 100);})}}, 100)}// 数据排序(快排算法)let data_sort = (data_list, l, r, data_arr) => {if (l < r) {let i = l,j = r,temp = data_list[l],t1, t2, t3;while (i < j) {while (i < j && data_list[j][0] >= temp[0]) j--;while (i < j && data_list[i][0] <= temp[0]) i++;if (i < j) {t1 = data_list[i];data_list[i] = data_list[j];data_list[j] = t1;t2 = data_arr[i];data_arr[i] = data_arr[j];data_arr[j] = t2;}}data_list[l] = data_list[i];data_list[i] = temp;t3 = data_arr[l];data_arr[l] = data_arr[i];data_arr[i] = t3;data_sort(data_list, l, i - 1, data_arr);data_sort(data_list, i + 1, r, data_arr);}}// 查找let danmaku_search = (arr, time) => {try {arr.forEach((v, i) => {if (v[0] - time >= 0 && v[0] - time < 1) throw new Error(String(i));if (v[0] - time > 1) throw new Error(i);});} catch (e) {return e.message;}return -1;}// 时间格式转换(分转秒)let time_m_s = a => {if (a.length == 2) return a[0] * 60 + a[1];else return a[0] * 3600 + a[1] * 60 + a[2];}// 时间格式转换(秒转分)let time_s_m = a => {a = Math.floor(a);let m = Math.floor(a / 60);let s = (a - Math.floor(a / 60) * 60);if (m < 0) m = "00";else if (m < 10) m = "0" + String(m);if (s < 10) s = "0" + String(s);return m + ":" + s;}// 发送日期格式转换let data_s_d = a => {let date = new Date(a * 1000);let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';let D = date.getDate();if (D < 10) D = "0" + String(D) + ' ';else D = D + ' ';let h = date.getHours();if (h < 10) h = "0" + String(h) + ":";else if (h == 0) h = "00" + ":";else h = h + ":";let m = date.getMinutes();if (m < 10) m = "0" + String(m);else if (m == 0) m = "00";return M + D + h + m;}// 获取当前视频播放秒数let get_now_s = () => {let time_now = $('.bilibili-player-video-time-now')[0].innerHTML.split(":");$.each(time_now, function (i) {time_now[i] = parseInt(time_now[i]);})return time_m_s(time_now);}let list_change = (data_list, data_arr) => {// 修改页面控制$(".player-auxiliary-danmaku-btn-time").removeAttr("orderby");$(".player-auxiliary-danmaku-btn-danmaku").removeAttr("orderby");$(".player-auxiliary-danmaku-btn-date").removeAttr("orderby");$(".player-auxiliary-danmaku-function > .player-auxiliary-danmaku-btn-danmaku")[0].innerHTML = "滚动弹幕(共" + data_arr.length + "条)";// 破坏初始列表结构$(".player-auxiliary-danmaku-wrap > .player-auxiliary-danmaku-contaner").removeClass("player-auxiliary-danmaku-contaner player-auxiliary-bscrollbar");$(".player-auxiliary-danmaku-wrap").off();$(".player-auxiliary-danmaku-wrap > div > ul").off();// 监听视频播放let danmaku_length = $(".player-auxiliary-danmaku-wrap > div > ul > li").length; // 获取当前展示的弹幕数量let li_width = $(".player-auxiliary-danmaku-wrap > div > ul > li").css("width"); // 列表宽度let isChange = $(".bilibili-player-video-time-now")[0].innerHTML;let data_length = data_list.length;// 开场进行一次排序if (parseFloat($(".player-auxiliary-danmaku-wrap").css("height").replace("px", "")) >= parseFloat($(".player-auxiliary-danmaku-wrap > div > ul").css("height").replace("px", ""))) {setInterval(() => {if (isChange != $(".bilibili-player-video-time-now")[0].innerHTML) {let now_i = danmaku_search(data_list, get_now_s()); // 获取即将播放的弹幕if (now_i != -1) list_structure(data_list, data_arr, 0, danmaku_length - 1, now_i, li_width);isChange = $(".bilibili-player-video-time-now")[0].innerHTML;}}, 1000);} else {setInterval(() => {if (isChange != $(".bilibili-player-video-time-now")[0].innerHTML) {// 获取列表首尾let now_i = danmaku_search(data_list, get_now_s());// 判断是否需要更新if (now_i != -1 && parseInt(now_i) + danmaku_length - 15 >= data_length) list_structure(data_list, data_arr, data_length - danmaku_length, data_length - 1);else if (now_i != -1) list_structure(data_list, data_arr, parseInt(now_i) - 7, parseInt(now_i) + danmaku_length - 8);isChange = $(".bilibili-player-video-time-now")[0].innerHTML;}}, 1000);}// 开启与停止滚动控制}// 构建弹幕列表let list_structure = (data_list, data_arr, start, end) => {$(".player-auxiliary-danmaku-wrap > div > ul").empty(); // 清除先前的弹幕,重新构建for (let i = start; i <= end; i++) {let li = document.createElement("li");let span1 = document.createElement("span");let span2 = document.createElement("span");let span3 = document.createElement("span");let text1 = document.createTextNode(time_s_m(data_list[i][0]));let text2 = document.createTextNode(data_arr[i]);let text3 = document.createTextNode(data_s_d(data_list[i][1]));span1.appendChild(text1);span2.appendChild(text2);span3.appendChild(text3);$(span1).addClass("danmaku-info-time");$(span2).addClass("danmaku-info-danmaku");$(span3).addClass("danmaku-info-date");li.appendChild(span1);li.appendChild(span2);li.appendChild(span3);$(li).addClass("danmaku-info-row");$(".player-auxiliary-danmaku-wrap > div > ul")[0].appendChild(li);}}
})();

安装脚本后只要打开右边的弹幕列表,弹幕就会随视频播放而滚动了。

js实现bilibili弹幕列表随视频播放滚动相关推荐

  1. php+js实现弹幕,基于HTML5的有弹幕功能的视频播放器

    如何使用 Danmmu Player需要依赖jQuery,因此首先需要加入相关css和js文件. 接下来,在body中需要放置播放器的位置加入如下代码: 最后,关键的部分,配置参数,调用插件. $(& ...

  2. 基于JS实现新闻列表无缝向上滚动实例代码

    当新闻较多,并且空前有限的时候,使用滚动是一个不错的选择,本章节就通过代码实例介绍一下如何实现此效果. 代码实例如下: <!DOCTYPE html> <html> <h ...

  3. html5实现视频播放器 弹幕效果,基于HTML5的有弹幕功能的视频播放器

    如何使用 Danmmu Player需要依赖jQuery,因此首先需要加入相关css和js文件. 接下来,在body中需要放置播放器的位置加入如下代码: 最后,关键的部分,配置参数,调用插件. $(& ...

  4. python爬取bilibili弹幕_Python抓取BiliBili拦河坝并生成单词云,爬取,bilibili,弹幕

    木秀于林,风亦惧之:虽为萤火,亦绽光芒. Python爬取bilibili弹幕并生成词云 目标网站: 哔哩哔哩: https://www.bilibili.com/ 我这里以 TES vs SN 第四 ...

  5. 菜鸟弟弟从零开始的爬取Bilibili弹幕的Python爬虫教程-哔哩哔哩 - ( ゜- ゜)つロ 干杯~

    从零开始的爬取Bilibili弹幕的Python爬虫教程 或许可以作为一个爬虫小白的练手的demo? 还是先看看什么是爬虫吧!(还有Bilibili! ) 网络爬虫: 网络爬虫(又称为网页蜘蛛,网络机 ...

  6. 怎么用python发弹幕_[python]bilibili弹幕发送者查询器软件

    简介: 一款用于查询bilibili弹幕发送者的软件,输入视频号(需要保证视频有效且有弹幕)后对弹幕池中的弹幕按照发送时间(从新到旧的顺序)进行查询.操作简单,需要联网使用. 查询结果以uid格式展示 ...

  7. vue.js循环for(列表渲染)详解

    vue.js循环for(列表渲染)详解 一.总结 一句话总结: v-for <ul id="example-1"> <li v-for="item in ...

  8. draft.js_如何使用快捷方式在Draft.js中创建有序列表和无序列表

    draft.js by Andrey Semin 通过安德烈·塞米(Andrey Semin) 如何使用快捷方式在Draft.js中创建有序列表和无序列表 (How to create ordered ...

  9. html仿qq最小化怎么实现,JS仿QQ好友列表展开、收缩功能(第一篇)

    JS仿QQ好友列表展开.收缩功能(第一篇) 发布时间:2020-10-17 14:20:03 来源:脚本之家 阅读:96 作者:erdouzhang 效果图如下所示: html: 我的好友 张三 李四 ...

  10. 一款JS+CSS实现的无缝平滑图片滚动代码

    代码简介: 非常平滑的JS图片滚动特效代码,无缝循环,速度可自定义,鼠标悬停时停止.它的特点是JS和图片地址分离,这样做你就经易的从数据库动态调用每张图片的地址,方便控制,因此它非常的应用. 代码内容 ...

最新文章

  1. 我要一颗原子弹 -- 开发者思维
  2. python字符串写入excel-Python向excel中写入数据的方法
  3. Oracle Exception
  4. 两个多精度十进制数加法程序设计_翁恺老师的程序设计入门——C语言 第四周习题...
  5. String All Methods
  6. 《JSON笔记之三》---postman中传入json串
  7. sed的模式匹配用法探讨
  8. creo工程图模板_Creo工程图的优越性总结(仅供参考),来自网友与君共享
  9. C/C++[codeup 1962]单词替换
  10. 机器学习之-BoostedTree
  11. Fresco 5.0以上内存持续增长问题优化
  12. 用户画像中常用的用户模型
  13. linux系统bcast,Linux系统下取IP地址的几种方法
  14. Mac: 椰菜花叶和FileVault2
  15. 谷俊丽分享之基于深度学习的大数据挖掘
  16. 知识图谱方向顶会小记
  17. 高德地图 地理编码报result参数报 USERKEY_PLAT_NOMATCH INVALID_USER_SCODE
  18. 天猫重复购买用户预测数据集
  19. 用计算机亩换算成平方,平米与亩换算(平方米换算亩计算器)
  20. 163企业邮箱价格费用标准是多少?

热门文章

  1. html拼凑成一张图片,(代码片段)利用canvas,把多张图合并成一张图片
  2. vue3.0+vite+ts使用swiper如何掉用autoplay
  3. mysql 删除数据 分页_使用limit分页查询时,做delete操作,会导致丢失数据
  4. 卸载office2010安装包时提示语言不受系统支持
  5. 解决魅族手机不输出Log日志 或者输出部分日志问题
  6. linux locale 编译,Linux locale 缺失和安装
  7. ROS 入门基础(四)自定义话题, publisher和Subscriber
  8. IOI2022 D2T1 数字电路(计数概率/组合数学+线段树区间翻转)
  9. 1330: PIPI的乐高积木
  10. 小白学语句:省市区选择(带全国省市区数据)