Bilibili - Whose Bullets

为您探寻到那些弹幕后的作者

  1. // ==UserScript==
  2. // @name Bilibili - Whose Bullets
  3. // @namespace http://www.xljbear.com/
  4. // @version 1.4.5
  5. // @description 为您探寻到那些弹幕后的作者
  6. // @author XljBearSoft
  7. // @match https://www.bilibili.com/video/av*
  8. // @match https://www.bilibili.com/bangumi/play/*
  9. // @icon https://www.bilibili.com/favicon.ico
  10. // @supportURL https://greasyfork.org/zh-CN/scripts/40341
  11. // @grant none
  12. // ==/UserScript==
  13. (function() {
  14. setTimeout(WhoseBulletsInit,1000);
  15. })();
  16. var BiliBili_midcrc = function(){
  17. const CRCPOLYNOMIAL = 0xEDB88320;
  18. var startTime=performance.now(),
  19. crctable=new Array(256),
  20. create_table=function(){
  21. var crcreg,
  22. i,j;
  23. for (i = 0; i < 256; ++i)
  24. {
  25. crcreg = i;
  26. for (j = 0; j < 8; ++j)
  27. {
  28. if ((crcreg & 1) !== 0)
  29. {
  30. crcreg = CRCPOLYNOMIAL ^ (crcreg >>> 1);
  31. }
  32. else
  33. {
  34. crcreg >>>= 1;
  35. }
  36. }
  37. crctable[i] = crcreg;
  38. }
  39. },
  40. crc32=function(input){
  41. if(typeof(input)!='string')
  42. input=input.toString();
  43. var crcstart = 0xFFFFFFFF, len = input.length, index;
  44. for(var i=0;i<len;++i){
  45. index = (crcstart ^ input.charCodeAt(i)) & 0xff;
  46. crcstart = (crcstart >>> 8) ^ crctable[index];
  47. }
  48. return crcstart;
  49. },
  50. crc32lastindex=function(input){
  51. if(typeof(input)!='string')
  52. input=input.toString();
  53. var crcstart = 0xFFFFFFFF, len = input.length, index;
  54. for(var i=0; i<len;++i){
  55. index = (crcstart ^ input.charCodeAt(i)) & 0xff;
  56. crcstart = (crcstart >>> 8) ^ crctable[index];
  57. }
  58. return index;
  59. },
  60. getcrcindex=function(t){
  61. for(var i=0;i<256;i++){
  62. if(crctable[i] >>> 24 == t)
  63. return i;
  64. }
  65. return -1;
  66. },
  67. deepCheck=function(i, index){
  68. var tc=0x00,str='',
  69. hash=crc32(i);
  70. tc = hash & 0xff ^ index[2];
  71. if (!(tc <= 57 && tc >= 48))
  72. return [0];
  73. str+=tc-48;
  74. hash = crctable[index[2]] ^ (hash >>> 8);
  75. tc = hash & 0xff ^ index[1];
  76. if (!(tc <= 57 && tc >= 48))
  77. return [0];
  78. str+=tc-48;
  79. hash = crctable[index[1]] ^ (hash >>> 8);
  80. tc = hash & 0xff ^ index[0];
  81. if (!(tc <= 57 && tc >= 48))
  82. return [0];
  83. str+=tc-48;
  84. hash = crctable[index[0]] ^ (hash >>> 8);
  85. return [1,str];
  86. };
  87. create_table();
  88. var index=new Array(4);
  89. return function(input){
  90. var ht=parseInt('0x'+input)^0xffffffff,
  91. snum,i,lastindex,deepCheckData;
  92. for(i=3;i>=0;i--){
  93. index[3-i]=getcrcindex( ht >>> (i*8) );
  94. snum=crctable[index[3-i]];
  95. ht^=snum>>>((3-i)*8);
  96. }
  97. for(i=0;i<10000000; i++){
  98. lastindex = crc32lastindex(i);
  99. if(lastindex == index[3]){
  100. deepCheckData=deepCheck(i,index);
  101. if(deepCheckData[0])
  102. break;
  103. }
  104. }
  105. if(i==10000000)
  106. return -1;
  107. return i+''+deepCheckData[1];
  108. };
  109. };
  110. var page_url = "";
  111. var b_crc = null;
  112. var ToastTime = null;
  113. var danmuList = [];
  114. var danmu_count = 0;
  115. var menu = '<li class="context-line context-menu-function gotoSpace" data-append="1"><a class="context-menu-a js-action gotoSpace" title="" href="javascript:void(0);" data-disabled="0"><span>正在获取...</span></a></li>';
  116. var menu_fail = '<li class="context-line context-menu-function" data-append="1"><a class="context-menu-a js-action" title="" href="javascript:void(0);" data-disabled="0">- (゜ロ゜;)抱歉!居然失败了... -</a></li>';
  117. var toast = '<div id="x_toast" style="box-shadow: white 0px 0px 3px;" class="player-tooltips info center-center animation active"><div class="tooltip" style="padding:15px 20px 15px 20px;"></div></div>';
  118. function CreateMessageBox(){
  119. var html = '<div id="x_message_box" style="background-color: black;font-size: 13px;color: white;text-align: center;padding: 10px;"></div>';
  120. $(".bilibili-player-area").prepend(html);
  121. $("#x_message_box").hide();
  122. }
  123. function ShowMessage(message){
  124. if(!$("#x_message_box")[0])CreateMessageBox();
  125. $("#x_message_box").slideDown(500);
  126. $("#x_message_box").html("Whose Bullets : " + message);
  127. setTimeout(HideMessage,3000);
  128. }
  129. function HideMessage(){
  130. $("#x_message_box").slideUp(500);
  131. }
  132. function GetAuthorProfile(mid){
  133. $.post("https://space.bilibili.com/ajax/member/GetInfo",{mid:mid},function(result){
  134. switch(result.data.sex){
  135. case "男":
  136. sex = '<span style="color:#00a1d6">汉子</span>';
  137. break;
  138. case "女":
  139. sex = '<span style="color:#fb7299">妹纸?</span>';
  140. break;
  141. default:
  142. sex = '<span style="color:#ff6c00">秀吉</span>';
  143. }
  144. vip = result.data.vip.vipStatus==1?" vip-red-name":"";
  145. place = result.data.place==""||result.data.place==undefined?"无地区信息":result.data.place;
  146. profile = '<div style="min-height:0px;z-index:-5;" class="bb-comment"><div style="padding-top:10px;" class="comment-list"><div class="list-item"><div class="reply-box"><div style="padding:0px" class="reply-item reply-wrap"><div style="margin:15px;" class="reply-face"><img src="'+ result.data.face +'" alt=""></div><div class="reply-con"><div class="user"><a style="display:initial;padding: 0px;" data-usercard-mid="'+ mid +'" href="//space.bilibili.com/'+ mid +'" target="_blank" class="name'+ vip +'">'+ result.data.name +'</a> '+ sex +'<a style="display:initial;padding: 0px;" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l'+ result.data.level_info.current_level +'"></i></a></div><div class="info"><span class="time">'+ place +'</span></span></span></div></div></div></div></div></div></div>';
  147. $(".context-menu-function.gotoSpace").html(profile);
  148. if($(".bilibili-player-context-menu-container.white.active>ul>li:eq(1)>a").html().substr(0,2)=="取消"){
  149. $(".bilibili-player-context-menu-container.white.active>ul>li:eq(1)>a").html("取消对" + result.data.name + "的弹幕屏蔽");
  150. }else{
  151. $(".bilibili-player-context-menu-container.white.active>ul>li:eq(1)>a").html("屏蔽" + result.data.name);
  152. }
  153. $(".bilibili-player-context-menu-container.white.active>ul>li:eq(4)>a").html("查看"+ result.data.name +"的所有弹幕");
  154. });
  155. }
  156. function ProcessDanmu(showToast){
  157. crcidList = [];
  158. $.ajax({
  159. url:"https://comment.bilibili.com/" + window.cid + ".xml",
  160. dataType:"XML",
  161. success: function(danmu_xml){
  162. $(danmu_xml).find("d").each(function(index,item){
  163. danmuList[index] = $(item).attr("p").split(",");
  164. danmuList[index].push($(item).html());
  165. });
  166. danmu_count = danmuList.length;
  167. if(!showToast)return;
  168. if(danmuList.length>0){
  169. ShowToast(danmuList.length + "条弹幕处理成功!");
  170. }else{
  171. ShowToast("弹幕库为空!");
  172. }
  173. }
  174. });
  175. }
  176. function PageReload(){
  177. if(page_url == window.location.href){
  178. return;
  179. }
  180. page_url = window.location.href;
  181. ShowToast("重载视频信息中...");
  182. danmuList = [];
  183. ProcessDanmu(true);
  184. }
  185. function ShowToast(message){
  186. if(!$("#x_toast")[0]){
  187. $("body").append(toast);
  188. }
  189. $("#x_toast>div").html("Whose Bullets : " + message);
  190. $("#x_toast").css("top",document.documentElement.clientHeight/2 - $("#x_toast")[0].offsetHeight/2 + "px");
  191. $("#x_toast").css("left",document.documentElement.clientWidth/2 - $("#x_toast")[0].offsetWidth/2 + "px");
  192. $("#x_toast").hide();
  193. $("#x_toast").fadeIn(500);
  194. clearTimeout(ToastTime);
  195. ToastTime = setTimeout(function(){$("#x_toast").fadeOut(1000);},3000);
  196. }
  197. function TimeCompareUp(danmu1,danmu2){
  198. return danmu1[0]-danmu2[0];
  199. }
  200. function TimeCompareDown(danmu1,danmu2){
  201. return danmu2[0]-danmu1[0];
  202. }
  203. function DanmuCompareUp(danmu1,danmu2){
  204. if(danmu1[8]<danmu2[8]){
  205. return -1;
  206. }else if(danmu1[8]>danmu2[8]){
  207. return 1;
  208. }
  209. return 0;
  210. }
  211. function DanmuCompareDown(danmu1,danmu2){
  212. if(danmu1[8]<danmu2[8]){
  213. return 1;
  214. }else if(danmu1[8]>danmu2[8]){
  215. return -1;
  216. }
  217. return 0;
  218. }
  219. function SendTimeCompareUp(danmu1,danmu2){
  220. return danmu1[4]-danmu2[4];
  221. }
  222. function SendTimeCompareDown(danmu1,danmu2){
  223. return danmu2[4]-danmu1[4];
  224. }
  225. function WhoseBulletsInit(){
  226. ShowToast("初始化弹幕库...");
  227. b_crc = new BiliBili_midcrc();
  228. $.ajax({
  229. url:"https://comment.bilibili.com/" + window.cid + ".xml",
  230. dataType:"XML",
  231. success: function(danmu_xml){
  232. $(danmu_xml).find("d").each(function(index,item){
  233. danmuList[index] = $(item).attr("p").split(",");
  234. danmuList[index].push($(item).html());
  235. });
  236. danmu_count = danmuList.length;
  237. if(danmuList.length>0){
  238. $(document).on("contextmenu",".danmaku-info-row.bpui-selected",function(){
  239. if($(".bilibili-player-danmaku-wrap-child").css("display")!="none")
  240. return;
  241. cid = $(this).attr("dmno");
  242. mid = b_crc(danmuList[cid][6]);
  243. if(mid == -1){
  244. ShowToast("嗷~用户信息获取失败了...");
  245. $(".bilibili-player-context-menu-container.white.active>ul").prepend(menu_fail);
  246. return;
  247. }
  248. $(".bilibili-player-context-menu-container.white.active>ul").prepend(menu).attr("mid",mid);
  249. $(".bilibili-player-context-menu-container.white.active").css("z-index","999");
  250. GetAuthorProfile(mid);
  251. });
  252. $(document).on("click","a.gotoSpace",function(){
  253. mid = $(this).parent().parent().attr("mid");
  254. window.open("https://space.bilibili.com/"+ mid +"/#/");
  255. });
  256. $(document).on("click",".bilibili-player-danmaku-btn-time",function(){
  257. if($(".bilibili-player-danmaku-wrap-child").css("display")!="none")
  258. return;
  259. if($(this).find(".bilibili-player-icon-arrow-up")[0]||$(this).find(".bp-icon.icon-general-pullup-s")[0]){
  260. danmuList.sort(TimeCompareUp);
  261. }else{
  262. danmuList.sort(TimeCompareDown);
  263. }
  264. });
  265. $(document).on("click",".bilibili-player-danmaku-btn-danmaku",function(){
  266. if($(".bilibili-player-danmaku-wrap-child").css("display")!="none")
  267. return;
  268. if($(this).find(".bilibili-player-icon-arrow-up")[0]||$(this).find(".bp-icon.icon-general-pullup-s")[0]){
  269. danmuList.sort(DanmuCompareUp);
  270. }else{
  271. danmuList.sort(DanmuCompareDown);
  272. }
  273. });
  274. $(document).on("click",".bilibili-player-danmaku-btn-date",function(){
  275. if($(".bilibili-player-danmaku-wrap-child").css("display")!="none")
  276. return;
  277. if($(this).find(".bilibili-player-icon-arrow-up")[0]||$(this).find(".bp-icon.icon-general-pullup-s")[0]){
  278. danmuList.sort(SendTimeCompareUp);
  279. }else{
  280. danmuList.sort(SendTimeCompareDown);
  281. }
  282. });
  283. $(document).on("contextmenu",".bilibili-player-video",function(){
  284. //Todo
  285. });
  286. page_url = window.location.href;
  287. setInterval(PageReload,1000);
  288. ShowToast(danmuList.length + "条弹幕处理成功!");
  289. }else{
  290. ShowToast("弹幕库为空!");
  291. }
  292. }
  293. });
  294. }