您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
匹配直播中同传man的弹幕以字幕形式显示
// ==UserScript== // @name bilibili同传man弹幕字幕显示 // @namespace https://space.bilibili.com/13525042 // @version 0.4 // @description 匹配直播中同传man的弹幕以字幕形式显示 // @author wetor (www.wetor.top) // @match *://live.bilibili.com/* // @run-at document-end // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @require http://code.jquery.com/jquery-1.7.2.min.js // ==/UserScript== /* 此脚本根据 “Bilibili上下弹幕变字幕” 改写,原作者信息如下 @name Bilibili上下弹幕变字幕 @namespace https://space.bilibili.com/68391#!/ @version 2.0 @description 用于突出显示B站的顶部弹幕与底部弹幕,使其呈现Youtube字幕的效果。适用于一些有字幕弹幕的生肉视频。 @author 剧情帝 */ /* 字幕样式来自bilibili CC字幕 */ (function() { 'use strict'; let style = GM_addStyle(''); let $configPanel; let historySub = []; initCss(); SetCss(); SetTextShadow(); CreateConfigPanel(); GM_registerMenuCommand('Bilibili字幕样式设置', ToggleConfigPanel); function initCss(){ var new_element = document.createElement("style"); new_element.innerHTML =( `.bilibili-player-video-subtitle { position: absolute; width: 100%; height: 100%; overflow: visible; cursor: pointer; -webkit-box-sizing: border-box; box-sizing: border-box; color: #fff; z-index: 12; pointer-events: none; text-shadow: rgb(0, 0, 0) 1px 0px 1px, rgb(0, 0, 0) 0px 1px 1px, rgb(0, 0, 0) 0px -1px 1px, rgb(0, 0, 0) -1px 0px 1px; } .subtitle-position { position: absolute; left: 5%; width: 90%; max-height: 83%; text-align: center; } .subtitle-position .subtitle-wrap { display: inline-block; } .subtitle-item-text { position: relative; white-space: normal; cursor: move; pointer-events: auto; padding: 0 8px; -webkit-box-decoration-break: clone; box-decoration-break: clone; border-radius: 2px; line-height: normal; font-family: none; word-wrap: break-word; }`); document.body.appendChild(new_element); } function SetCss() { for(var i=0;i<2;i++){ if(style.sheet.cssRules.length > 0){ style.sheet.deleteRule(0); } } let css1=` .subtitle-position-custom { ${If_Html(GM_getValue('position', 'top') == 'down', `bottom: 20px;`)} ${If_Html(GM_getValue('position', 'top') == 'top', `top: 20px;`)} font-size: ${ GM_getValue('fontsize', 0)}px; ${If_Html(GM_getValue('fontsize', 0) == 0, 'font-size:unset;')} ${If_Html( GM_getValue('color', 'original') !== 'original', `color: ${ GM_getValue('color', 'original')};`)} opacity: ${ GM_getValue('textAlpha', 0.8)} ; }`; let css2=` .subtitle-item-text-custom{ ${If_Html( GM_getValue('showBackground', false), `background-color: rgba(0,0,0,0);`)} ${If_Html( GM_getValue('showBackground', true), `background-color: rgba(0,0,0,${ GM_getValue('backgroundAlpha', 0.75)});`)} } `; //console.log($('#js-player-decorator .bilibili-live-player-video-area').height() - (Number(GM_getValue('fontsize', 25))+8 ) * 3); //style.sheet.insertRule(css); style.sheet.insertRule(css1,0); style.sheet.insertRule(css2,1); } function If_Html(statement, html1, html2 = '') { return statement ? html1: html2; } function CreateConfigPanel() { $configPanel = $(`<div style="display: none; position: fixed;top: 10px;right: 10px;z-index: 10000;background: #fff;padding: 20px 10px;border: 3px solid #00a1d6;font-size: 18px;"> <div style="text-align: center;"> <b>同传字幕设置</b><br> <label style="vertical-align: middle;">启用:</label> <input name="sub-enable" type="checkbox" style="width: 20px; height: 20px; vertical-align: middle;"> </div> <div style="padding: 20px; padding-bottom:0"> <div> <label>匹配规则(正则表达式):</label> <br> <input name="match" id="match-id" type="text" value="(.*?)【(.*?)(】|$)" style="width: 170px; height: 20px; vertical-align: middle;"> <br> <button id='btn-default' style="font-size:16px; height: 21px; vertical-align: middle;" >恢复默认</button> <button id='btn-save' style="font-size:16px;height: 21px; vertical-align: middle;" >保存</button> </div> <br> <div> <label>字幕行数:</label> <select name="sub-lines" style="height: 30px;" > <option value="1">1行</option> <option value="2">2行</option> <option value="3">3行</option> <option value="4">4行</option> <option value="5">5行</option> </select> </div> <br> <div> <label>历史字幕:</label> <select name="sub-order" style="height: 30px;" > <option value="backward">向上堆叠</option> <option value="forward">向下堆叠</option> </select> </div> <br> <div> <label>位置: </label> <select name="sub-position" style="height: 30px;" > <option value="top">顶部</option> <option value="down">底部</option> </select> </div> <br> <div> <label>字体大小:</label> <select name="size" style="height: 30px;" > <option value="16">16</option> <option value="20">20</option> <option value="24">24</option> <option value="28">28</option> <option value="32">32</option> <option value="36">36</option> <option value="40">40</option> </select> </div> <br> <div> <label style="vertical-align: middle;">底板显示:</label> <input name="background" type="checkbox" style="width: 20px; height: 20px; vertical-align: middle;"> <br> <label style="vertical-align: middle;">底板透明:</label> <input name="background-alpha" type="number" placeholder="1.0" step="0.05" min="0" max="1" value="0.75" style="width: 60px; height: 20px; vertical-align: middle;"> </div> <br> <div> <label>文字颜色:</label> <select name="color" style="height: 30px;"> <option value="original">默认(白)</option> <option value="selected">自定义</option> </select> <div style="margin-top: 10px;display: flex;vertical-align: middle;-webkit-box-align: center;-ms-flex-align: center;align-items: center;-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;" class="row-selection danmaku-color bui bui-color-picker bui-dark"> <div class="bui-color-picker-wrap" style="width: 176px; position:relative"> <div class="bui-color-picker-result"> <span class="bui-color-picker-input bui bui-input" style="width: auto; flex: 1;"> <div class="bui-input-wrap "> <input class="bui-input-input" type="text" value="" style="color: #000;border: 1px solid hsla(0, 0%, 0%, 0.2);"> </div> </span> <span class="bui-color-picker-display" style="background: #FFFFFF; border: 1px solid hsla(0, 0%, 0%, 0.2);"></span> </div> <ul class="bui-color-picker-options" style=" margin-right: -10.666666666666666px;"> <li class="bui-color-picker-option" style="background: #FE0302; margin-right: 10.666666666666666px;" data-value="#FE0302"></li> <li class="bui-color-picker-option" style="background: #FF7204; margin-right: 10.666666666666666px;" data-value="#FF7204"></li> <li class="bui-color-picker-option" style="background: #FFAA02; margin-right: 10.666666666666666px;" data-value="#FFAA02"></li> <li class="bui-color-picker-option" style="background: #FFD302; margin-right: 10.666666666666666px;" data-value="#FFD302"></li> <li class="bui-color-picker-option" style="background: #FFFF00; margin-right: 10.666666666666666px;" data-value="#FFFF00"></li> <li class="bui-color-picker-option" style="background: #A0EE00; margin-right: 10.666666666666666px;" data-value="#A0EE00"></li> <li class="bui-color-picker-option" style="background: #00CD00; margin-right: 10.666666666666666px;" data-value="#00CD00"></li> <li class="bui-color-picker-option" style="background: #019899; margin-right: 10.666666666666666px;" data-value="#019899"></li> <li class="bui-color-picker-option" style="background: #4266BE; margin-right: 10.666666666666666px;" data-value="#4266BE"></li> <li class="bui-color-picker-option" style="background: #89D5FF; margin-right: 10.666666666666666px;" data-value="#89D5FF"></li> <li class="bui-color-picker-option" style="background: #CC0273; margin-right: 10.666666666666666px;" data-value="#CC0273"></li> <li class="bui-color-picker-option" style="background: #222222; margin-right: 10.666666666666666px;" data-value="#222222"></li> <li class="bui-color-picker-option" style="background: #9B9B9B; margin-right: 10.666666666666666px;" data-value="#9B9B9B"></li> <li class="bui-color-picker-option bui-color-picker-option-active" style="background: #FFFFFF; margin-right: 10.666666666666666px;" data-value="#FFFFFF"></li> </ul> <div class="bui-color-picker-mask" style="display:none; position: absolute; width: 100%; height: 100%; top: 0; background-color: #0003; cursor:not-allowed"></div> </div> </div> <br> <label style="vertical-align: middle;">文字透明:</label> <input name="text-alpha" type="number" placeholder="1.0" step="0.05" min="0" max="1" value="0.80" style="width: 60px; height: 20px; vertical-align: middle;"> </div> </div> <p class="close" style="position:absolute;top: 2px;right: 2px;color: #aaa;width: 20px;height: 20px;text-align: center;font-size: 15px;cursor: pointer;">✖</p> </div>`); if($(".has-stardust").length === 0){ //旧版播放器,加入新播放器调色盘的css $configPanel.append(`<style type="text/css"> .bui-input { display: -webkit-inline-box; display: -ms-inline-flexbox; display: inline-flex; position: relative; -webkit-box-pack: start; -ms-flex-pack: start; justify-content: flex-start; font-size: 0; height: 22px } .bui-input .bui-input-wrap { width: 100%; height: 100%; -webkit-box-sizing: border-box; box-sizing: border-box; position: relative } .bui-input .bui-input-input { border: 1px solid silver; border-radius: 2px; outline: none; -webkit-transition: all .3s; transition: all .3s; -webkit-transform: translateZ(0); transform: translateZ(0); padding: 4px 7px; resize: none; width: 100%; height: 100%; -webkit-box-sizing: border-box; box-sizing: border-box; font-size: 12px; -moz-appearance: textfield } .bui-input .bui-input-input::-webkit-inner-spin-button,.bui-input .bui-input-input::-webkit-outer-spin-button { -webkit-appearance: none } .bui-color-picker { -webkit-box-pack: start; -ms-flex-pack: start; justify-content: flex-start } .bui-color-picker.bui-dark .bui-input .bui-input-input { background-color: transparent; color: #fff; border: 1px solid hsla(0,0%,100%,.2) } .bui-color-picker.bui-dark .bui-color-picker-display { border: 1px solid hsla(0,0%,100%,.2) } .bui-color-picker.bui-dark .bui-color-picker-option[data-value="#222222"] { border-color: hsla(0,0%,100%,.1) } .bui-color-picker.bui-dark .bui-color-picker-option.bui-color-picker-option-active { border-color: #000 } .bui-color-picker .bui-color-picker-result { margin-bottom: 6px; display: -webkit-box; display: -ms-flexbox; display: flex; vertical-align: middle } .bui-color-picker .bui-color-picker-input { margin-right: 6px; width: 98px } .bui-color-picker .bui-color-picker-display { display: inline-block; width: 50px; height: 22px; border: 1px solid rgba(0,0,0,.3); border-radius: 2px; vertical-align: middle; -webkit-box-sizing: border-box; box-sizing: border-box; -webkit-transition: background .2s; transition: background .2s; -webkit-transform: translateZ(0); transform: translateZ(0) } .bui-color-picker .bui-color-picker-options { padding: 0; margin: 0 -6px 0 0; list-style-type: none; white-space: normal; font-size: 0; line-height: 0 } .bui-color-picker .bui-color-picker-option { width: 16px; height: 16px; border: 1px solid rgba(0,0,0,.3); -webkit-box-sizing: border-box; box-sizing: border-box; border-radius: 2px; margin-right: 6px; margin-bottom: 4px; cursor: pointer; display: inline-block } .bui-color-picker .bui-color-picker-option.bui-color-picker-option-active { -webkit-box-shadow: 0 0 1px 1px #fff; box-shadow: 0 0 1px 1px #fff } </style>`); } //sub-enable $("input[name=sub-enable]", $configPanel).prop('checked', GM_getValue('enable', true)).change(e=>{ GM_setValue('enable', $(e.target).prop('checked')); if($(e.target).prop('checked')) $('.bilibili-player-video-subtitle').css('display',''); else $('.bilibili-player-video-subtitle').css('display','none'); }); $("#btn-default", $configPanel).click(()=>{ $('#match-id').val('(.*?)【(.*?)(】|$)'); //console.log($('#match-id').val()) GM_setValue('match', $('#match-id').val()); }); $("#btn-save", $configPanel).click(()=>{ GM_setValue('match', $('#match-id').val()); }); $("input[name=match]", $configPanel).val( GM_getValue('match', '(.*?)【(.*?)(】|$)')).change(e=>{ GM_setValue('match', e.target.value); }); $("select[name=sub-lines]", $configPanel).val( GM_getValue('lines', 3)).change(e=>{ GM_setValue('lines', e.target.value); }); $("select[name=sub-order]", $configPanel).val( GM_getValue('order', 'forward')).change(e=>{ GM_setValue('order', e.target.value); }); $("select[name=sub-position]", $configPanel).val( GM_getValue('position', 'top')).change(e=>{ GM_setValue('position', e.target.value); SetCss(); }); $("select[name=size]", $configPanel).val( GM_getValue('fontsize', 0)).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(); }); $("input[name=background-alpha]", $configPanel).val( GM_getValue('backgroundAlpha', 0.75)).change(e=>{ GM_setValue('backgroundAlpha', e.target.value); SetCss(); }); SetColor( GM_getValue('color', 'original'), false); //初始化颜色选框与色盘 $("select[name=color]", $configPanel).change(e=>{ SetColor( e.target.value); }); $("input[name=text-alpha]", $configPanel).val( GM_getValue('textAlpha', 0.80)).change(e=>{ GM_setValue('textAlpha', e.target.value); SetCss(); }); $(".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 $videoDanmaku; //监测弹幕变化 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]); } var danmaku = $currentDanmu.attr('data-danmaku'); var showSub = ''; if(danmaku){ var tran = danmaku.match(GM_getValue('match',"(.*?)【(.*?)(】|$)")); if(tran){ if(tran[1]) showSub = tran[1]+':'+tran[2]; else showSub = tran[2]; } } if(showSub){ historySub.push(showSub); while(historySub.length>GM_getValue('lines',3)){ historySub.shift(); } showSub=''; var j; if(GM_getValue('order', 'forward') == 'backward'){ for(j=0;j<historySub.length;j++){ if(j==historySub.length-1) showSub=showSub+"<span class='subtitle-item-text subtitle-item-text-custom' style='font-weight:blod'>"+historySub[j]+"</span><br>"; else showSub=showSub+`<span class='subtitle-item-text subtitle-item-text-custom' style='font-size:${ Number(GM_getValue('fontsize', 24)) * 0.8}px'>`+historySub[j]+"</span><br>"; } }else if(GM_getValue('order', 'forward') == 'forward'){ //上方 for(j=historySub.length-1;j>=0;j--){ if(j==historySub.length-1) showSub=showSub+"<span class='subtitle-item-text subtitle-item-text-custom' style='font-weight:blod'>"+historySub[j]+"</span><br>"; else showSub=showSub+`<span class='subtitle-item-text subtitle-item-text-custom' style='font-size:${ Number(GM_getValue('fontsize', 24)) * 0.8}px'>`+historySub[j]+"</span><br>"; } } $(".subtitle-group").html(showSub); } } }); }); //等待弹幕图层的加载 let damunContainerWaiter = new MutationObserver( records => { let $damunContainer = $('#chat-history-list'); if($damunContainer.length > 0){ //弹幕图层加载完毕 damunContainerWaiter.disconnect(); damnuObserver.observe($damunContainer[0], {'childList':true, 'subtree':true}); //var html="<div id='video-danmaku-sub'></div>"; var html=` <div class="bilibili-player-video-subtitle"> <div class="subtitle-position subtitle-position-custom"> <div class="subtitle-wrap"> <div class="subtitle-group"> </div> </div> </div> </div> `; $("#js-player-decorator .bilibili-live-player-video-danmaku").html(html+$("#js-player-decorator .bilibili-live-player-video-danmaku").html()); } }); if($("#chat-history-list").length > 0){ damunContainerWaiter.observe($("#chat-history-list")[0], {'childList':true, 'subtree':true}); } } // Your code here... })();