// ==UserScript== // @name Bilibili上下弹幕变字幕 // @namespace https://space.bilibili.com/68391#!/ // @version 2.0 // @description 用于突出显示B站的顶部弹幕与底部弹幕,使其呈现Youtube字幕的效果。适用于一些有字幕弹幕的生肉视频。 // @author 剧情帝 // @match *://www.bilibili.com/video/av* // @match *://www.bilibili.com/watchlater* // @run-at document-end // @create 2017-11-16 // @lastmodified 2018-10-22 // @note 2017.11.24-V0.2 新增识别弹幕颜色,深色弹幕增加白色文字边框的功能 // @note 2017.11.27-V1.0 新增字幕样式设置,可更改字幕的大小、颜色,以及是否显示文字的黑色背景 // @note 2018.04.12-V1.1 修复插件 // @note 2018.10-22-V2.0 代码完全重构,同时支持新旧播放器,设置面板重新设计 // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @require http://code.jquery.com/jquery-1.7.2.min.js // @downloadURL https://update.greasyfork.icu/scripts/35205/Bilibili%E4%B8%8A%E4%B8%8B%E5%BC%B9%E5%B9%95%E5%8F%98%E5%AD%97%E5%B9%95.user.js // @updateURL https://update.greasyfork.icu/scripts/35205/Bilibili%E4%B8%8A%E4%B8%8B%E5%BC%B9%E5%B9%95%E5%8F%98%E5%AD%97%E5%B9%95.meta.js // ==/UserScript== (function() { 'use strict'; let style = GM_addStyle(''); let $configPanel; SetCss(); SetTextShadow(); CreateConfigPanel(); GM_registerMenuCommand('Bilibili字幕样式设置', ToggleConfigPanel); function SetCss() { if(style.sheet.cssRules.length > 0){ style.sheet.deleteRule(0); } let css = `#bofqi .bilibili-player-video-danmaku .bilibili-danmaku:not([style*="transition"]) { ${If_Html( GM_getValue('showBackground', true), ` background-color: rgba(0,0,0,0.75); padding: 4px 10px; border-radius: 3px;`)} ${If_Html( GM_getValue('fontsize', 25) !== 'original', ` font-size:${ GM_getValue('fontsize', 25)}px !important;`)} ${If_Html( GM_getValue('color', 'original') !== 'original', ` color: ${ GM_getValue('color', 'original')} !important;`)} opacity: 1 !important; }`; style.sheet.insertRule(css); } function If_Html(statement, html1, html2 = '') { return statement ? html1: html2; } function CreateConfigPanel() { $configPanel = $(`
字幕设置

(对所有顶端与底端弹幕生效)



`); if($(".has-stardust").length === 0){ //旧版播放器,加入新播放器调色盘的css $configPanel.append(``); } $("select[name=size]", $configPanel).val( GM_getValue('fontsize', 25)).change(e=>{ GM_setValue('fontsize', e.target.value); SetCss(); }); $("input[name=background", $configPanel).prop('checked', GM_getValue('showBackground', true)).change(e=>{ GM_setValue('showBackground', $(e.target).prop('checked')); SetCss(); }); SetColor( GM_getValue('color', 'original'), false); //初始化颜色选框与色盘 $("select[name=color]", $configPanel).change(e=>{ SetColor( e.target.value); }); $(".bui-color-picker-option", $configPanel).click(e=>{ SetColor( $(e.target).data('value')); }); let $buiInputInput = $(".bui-input-input", $configPanel); $buiInputInput.on('input', e=>{ if( /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test( $buiInputInput.val())){ $buiInputInput.css('background-color', 'unset'); SetColor( $buiInputInput.val()); } else{ $buiInputInput.css('background-color', 'hsla(0, 100%, 50%, 0.2)'); } }); $configPanel.click(e=>{ e.stopPropagation(); }); $(".close", $configPanel).click(()=>{ $configPanel.hide(); }); $('body').append( $configPanel).click(()=>{ $configPanel.hide(); }); } function SetColor( color, setCss = true) { let $selectColor = $("select[name=color]", $configPanel); let $buiColorPickerMask = $(".bui-color-picker-mask", $configPanel); let $buiInputInput = $(".bui-input-input", $configPanel); let $buiColorPickerDisplay = $(".bui-color-picker-display", $configPanel); if(color === 'original'){ $selectColor.val('original'); $buiColorPickerMask.show(); $buiInputInput.val( '#').css('background-color', 'unset'); $buiColorPickerDisplay.css('background', '#fff'); if(setCss){ GM_setValue('color', color); SetCss(); } } else if(color === 'selected'){ $selectColor.val('selected'); $buiColorPickerMask.hide(); } else{ $selectColor.val('selected'); $buiColorPickerMask.hide(); $buiInputInput.val( color); $buiColorPickerDisplay.css('background', color); if(setCss){ GM_setValue('color', color); SetCss(); } } } function ToggleConfigPanel() { if($configPanel.css('display') === 'none'){ $configPanel.show(); } else{ $configPanel.hide(); } } function CalLight (rgb) { rgb = rgb.replace('rgb(', ''); rgb = rgb.replace(')', ''); rgb = rgb.split(', '); return ((parseInt(rgb[0]) * 0.3 + parseInt(rgb[1]) * 0.6 + parseInt(rgb[2]) * 0.1) / 255); } function SetTextShadow() { //监测弹幕变化 let damnuObserver = new MutationObserver( records => { let $currentDanmu; records.map( record =>{ for (let i = record.addedNodes.length - 1; i >= 0; i--) { if(record.addedNodes[i].nodeName === '#text'){ $currentDanmu = $(record.addedNodes[i].parentNode); } else{ $currentDanmu = $(record.addedNodes[i]); } if($currentDanmu.css('transform') == 'none' && CalLight($currentDanmu.css('color')) <= 0.5){ //不移动的弹幕,也就是顶端和底端弹幕 $currentDanmu.css('text-shadow', '#fff 1px 0px 1px, #fff 0px 1px 1px, #fff 0px -1px 1px, #fff -1px 0px 1px'); } } }); }); //等待弹幕图层的加载 let damunContainerWaiter = new MutationObserver( records => { let $damunContainer = $('#bofqi .bilibili-player-video-danmaku'); if($damunContainer.length > 0){ //弹幕图层加载完毕 damunContainerWaiter.disconnect(); damnuObserver.observe($damunContainer[0], {'childList':true, 'subtree':true}); } }); if($("#bofqi").length > 0){ damunContainerWaiter.observe($("#bofqi")[0], {'childList':true, 'subtree':true}); } else{ //稍后再看页面一开始没有播放器,须等待 let bofqiWaiter = new MutationObserver( records => { if($("#bofqi").length > 0){ damunContainerWaiter.observe($("#bofqi")[0], {'childList':true, 'subtree':true}); bofqiWaiter.disconnect(); } }); bofqiWaiter.observe( $("#viewlater-app .app-wrap .view-later-module")[0], {'childList':true, 'subtree':true}); } } })();