// ==UserScript==
// @name Bilibili上下弹幕变字幕
// @namespace https://space.bilibili.com/68391#!/
// @version 1.1
// @description 用于突出显示B站的顶部弹幕与底部弹幕,使其呈现Youtube字幕的效果。适用于一些有字幕弹幕的生肉视频。
// @author 剧情帝
// @match https://www.bilibili.com/video/av*
// @match http://www.bilibili.com/video/av*
// @match https://www.bilibili.com/watchlater*
// @match http://www.bilibili.com/watchlater*
// @run-at document-end
// @create 2017-11-16
// @lastmodified 2017-04-12
// @note 2017.11.24-V0.2 新增识别弹幕颜色,深色弹幕增加白色文字边框的功能
// @note 2017.11.27-V1.0 新增字幕样式设置,可更改字幕的大小、颜色,以及是否显示文字的黑色背景
// @note 2-18.-4.12-V1.1 修复插件
// ==/UserScript==
(function() {
'use strict';
var $style = $('<style id="subtitleStyle" type="text/css"></style>');
$('head').append($style);
var sheet = $style[0].sheet;
var $style2 = $('<style id="colorPickerStyle" type="text/css"></style>');
$('head').append($style2);
$style2[0].sheet.insertRule('.bilibili-player-color-picker-container .bilibili-player-color-picker-panel .color-span:hover {z-index:10; border-color:#fff}'); //色盘格子的hover样式
function rgb2hex(rgb) {
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
function hex(x) {
return ("0" + parseInt(x).toString(16)).slice(-2);
}
return "" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); //#号不要了
}
function setCookie (name, value) {
var newCookie = name + '=' + value + '; path=/; domain=.bilibili.com; expires=';
var date = new Date();
if(value != null)
date.setTime( date.getTime() + 90 * 24 * 3600 * 1000);
else
date.setTime( date.getTime() - 1 * 24 * 3600 * 1000);
newCookie += date.toGMTString();
document.cookie = newCookie;
}
function getCookie (cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0)
return c.substring(name.length,c.length);
}
return null;
}
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);
}
var $damunContainer, $currentDanmu;
//监测弹幕变化
var observer = new MutationObserver(function(records){
records.map(function(record){
if(record.addedNodes.length > 0){
for (var i = record.addedNodes.length - 1; i >= 0; i--) {
$currentDanmu = $(record.addedNodes[i]);
if($currentDanmu.css('transform') == 'none'){ //不移动的弹幕,也就是顶端和底端弹幕
if(calLight($currentDanmu.css('color')) < 0.5)
$currentDanmu.css('text-shadow', 'rgb(255, 255, 255) 1px 0px 1px, rgb(255, 255, 255) 0px 1px 1px, rgb(255, 255, 255) 0px -1px 1px, rgb(255, 255, 255) -1px 0px 1px');
}
}
}
});
});
//等待弹幕图层的加载
var damunContainerWaiter = new MutationObserver(function(records){
$damunContainer = $('#bofqi .bilibili-player-video-danmaku');
if($damunContainer.length > 0){ //弹幕图层加载完毕
damunContainerWaiter.disconnect();
observer.observe($damunContainer[0], {'childList':true});
createSettings();
}
});
damunContainerWaiter.observe($("#bofqi")[0], {'childList':true, 'subtree':true});
function createSettings(){
var $player = $("#bofqi #bilibiliPlayer");
var $playerSetting = $(".bilibili-player-setting-btn", $player);
var $playerRight = $(".bilibili-player-auxiliary-area", $player);
var $settingBtn = $('<div class="bilibili-player-setting-btn" name="subtitle_setting" style="right: 72px;"><svg class="icon" style="height: 28px;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1289"><path d="M188.7 604.6c-12.6-29.7-18.9-61.5-18.9-95.5 0-37.1 7.1-69.5 21.3-97.1 14.1-27.6 34.3-48.6 60.5-62.9 26.2-14.4 55-21.5 86.4-21.5 35.6 0 65.6 9.1 89.9 27.2 24.3 18.1 41.2 43.7 50.8 76.6l-46.4 10.9c-8.3-25.9-20.3-44.8-36-56.6-15.7-11.8-35.5-17.7-59.3-17.7-27.4 0-50.3 6.6-68.6 19.7-18.4 13.1-31.4 30.7-38.8 52.9-7.4 22.1-11.2 44.9-11.2 68.4 0 30.3 4.4 56.7 13.2 79.4 8.8 22.6 22.6 39.5 41.2 50.7 18.6 11.2 38.8 16.8 60.5 16.8 26.4 0 48.8-7.6 67.1-22.9 18.3-15.2 30.7-37.8 37.2-67.8l47.2 11.9c-9.9 38.7-27.7 68.3-53.4 88.6-25.7 20.3-57.1 30.5-94.2 30.5-38.4 0-69.7-7.8-93.7-23.5-23.9-15.8-42.2-38.4-54.8-68.1z m414.5 67.9c24 15.7 55.3 23.5 93.7 23.5 37.1 0 68.5-10.2 94.2-30.5 25.7-20.4 43.5-49.9 53.4-88.6L797.3 565c-6.5 30-18.9 52.6-37.2 67.8-18.3 15.2-40.7 22.9-67.1 22.9-21.7 0-41.9-5.6-60.5-16.8-18.6-11.2-32.4-28.1-41.2-50.7-8.8-22.7-13.2-49.1-13.2-79.4 0-23.5 3.7-46.3 11.2-68.4 7.4-22.2 20.4-39.8 38.8-52.9 18.4-13.1 41.3-19.7 68.6-19.7 23.8 0 43.6 5.9 59.3 17.7 15.7 11.8 27.7 30.7 36 56.6l46.4-10.9c-9.6-32.9-26.5-58.4-50.8-76.6-24.3-18.1-54.3-27.2-89.9-27.2-31.5 0-60.2 7.1-86.4 21.5-26.2 14.3-46.3 35.3-60.5 62.9-14.2 27.7-21.3 60-21.3 97.1 0 34 6.3 65.9 18.9 95.5 12.4 29.9 30.7 52.5 54.8 68.1z m357.2-462.3v597.4H64.2V210.2h896.2z m-49.8 49.7H114v497.9h796.6V259.9z" p-id="1290"></path></svg></div>');
var settingPanelHtml = '';
settingPanelHtml += '<div id="settingPanel" class="bilibili-player-setting mCustomScrollbar _mCS_9 mCS-autoHide mCS_no_scrollbar _mCS_6">\n';
settingPanelHtml += '<div class="mCustomScrollBox mCS-light mCSB_vertical mCSB_inside" style="max-height: none;" tabindex="0">\n';
settingPanelHtml += '<div class="mCSB_container mCS_y_hidden mCS_no_scrollbar_y" style="position: relative; top: 0px; left: 0px;" dir="ltr">\n';
settingPanelHtml += '<div class="mCustomScrollBox mCS-light mCSB_vertical mCSB_inside" style="max-height: 556px;" tabindex="0">\n';
settingPanelHtml += '<div class="mCSB_container mCS_y_hidden mCS_no_scrollbar_y" style="position: relative; top: 0px; left: 0px;" dir="ltr">\n';
settingPanelHtml += '<div class="bilibili-player-panel-title">字幕设置\n';
settingPanelHtml += '<small style="font-size:13px">(对所有顶端与底端弹幕生效)</small>\n';
settingPanelHtml += '<i class="bilibili-player-iconfont bilibili-player-panel-back icon-close"></i>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '<div class="bilibili-player-panel-area" style="padding:23px">\n';
settingPanelHtml += '<div class="size-setting">\n';
settingPanelHtml += '<label>字体大小:</label>\n';
settingPanelHtml += '<select name="size">\n';
settingPanelHtml += '<option value="original">原大小</option>\n';
settingPanelHtml += '<option value="big">大</option>\n';
settingPanelHtml += '<option value="medium">中</option>\n';
settingPanelHtml += '<option value="small">小</option>\n';
settingPanelHtml += '</select>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '<br>\n';
settingPanelHtml += '<div class="back-setting">\n';
settingPanelHtml += '<label style="vertical-align: bottom;">底板: </label>\n';
settingPanelHtml += '<input name="back" type="checkbox">\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '<br>\n';
settingPanelHtml += '<div class="color-setting">\n';
settingPanelHtml += '<label>文字颜色:</label>\n';
settingPanelHtml += '<select name="color">\n';
settingPanelHtml += '<option value="original">原颜色</option>\n';
settingPanelHtml += '<option value="selected">自定义</option>\n';
settingPanelHtml += '</select>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '</div>\n';
settingPanelHtml += '</div>\n';
var $settingPanel = $(settingPanelHtml);
var $colorPicker = $('.bilibili-player-area .bilibili-player-color-picker-container', $player).clone();
$('.bilibili-player-color-picker-mask', $colorPicker).remove();
$colorPicker.css({
'position': 'unset',
'margin-top': '25px',
'border-left': '1px solid #e2e2e2',
'width': '263px'
});
$('.bilibili-player-color-picker-panel .color-spans .color-span.active', $colorPicker).removeClass('active').prop('data-active', null);
$('.bilibili-player-panel-area .color-setting', $settingPanel).append( $colorPicker);
$settingBtn.click(function(){
$settingPanel.show();
});
$(".icon-close", $settingPanel).click(function(){
$settingPanel.hide();
});
//设置字体大小选择框的功能
var size = getCookie('subtitle-size');
if(size == null){
setCookie('subtitle-size', 'big');
size = 'big';
}
$(".size-setting select", $settingPanel).val( size).change(function(){
setCookie('subtitle-size', $(this).val());
setCss();
});
//设置底板选项框的功能
var bg = getCookie('subtitle-bg');
if(bg == null){
setCookie('subtitle-bg', true);
bg = true;
}
else if(bg == 'true')
bg = true;
else if(bg == 'false')
bg = false;
$(".back-setting input", $settingPanel).prop('checked', bg).change(function(){
setCookie('subtitle-bg', $(this).prop('checked'));
setCss();
});
//设置颜色选项功能
var color = getCookie('subtitle-color');
if(color == null){
setCookie('subtitle-color', 'original');
color = 'original';
}
if(color != 'original'){
$colorPicker.addClass('active');
$(".bilibili-player-color-picker-color-current", $colorPicker).css('background-color', '#'+color);
$(".bilibili-player-color-picker-color-code", $colorPicker).val( color);
}
$(".color-setting select", $settingPanel).val( (color == 'original') ? 'original' : 'selected').change(function(){
if($(this).val() == 'original'){
setCookie('subtitle-color', 'original');
$colorPicker.removeClass('active');
}
else if($(this).val() == 'selected'){
setCookie('subtitle-color', 'ffffff');
$(".bilibili-player-color-picker-color-current", $colorPicker).css('background-color', '#ffffff');
$(".bilibili-player-color-picker-color-code", $colorPicker).val( 'ffffff');
$colorPicker.addClass('active');
}
setCss();
});
//设置色盘功能
$(".bilibili-player-color-picker-panel", $colorPicker).click(function(e){
color = rgb2hex( $(e.target).css('background-color'));
$(".bilibili-player-color-picker-color-current", $colorPicker).css('background-color', '#'+color);
$(".bilibili-player-color-picker-color-code", $colorPicker).val( color);
setCookie('subtitle-color', color);
setCss();
});
$settingBtn.insertBefore( $playerSetting);
$settingPanel.appendTo($playerRight);
setCss();
}
//读取Cookie,设置字幕的样式
function setCss(){
if(sheet.cssRules.length > 0)
sheet.deleteRule(0);
var cssRule = '#bofqi .bilibili-player-video-danmaku .bilibili-danmaku:not([style*="transition"]) {';
if(getCookie('subtitle-bg') == 'true'){
cssRule += 'background-color:rgba(0,0,0,0.75);';
cssRule += ' padding:4px 10px;';
cssRule += ' border-radius:3px;';
cssRule += ' line-height:1 !important;';
}
switch( getCookie('subtitle-size')){
case 'big':
cssRule += ' font-size:36px !important;';
break;
case 'medium':
cssRule += ' font-size:25px !important;';
break;
case 'small':
cssRule += ' font-size:18px !important;';
}
if(getCookie('subtitle-color') != 'original')
cssRule += ' color:#' + getCookie('subtitle-color') + ' !important;';
cssRule += ' opacity:1 !important; }';
sheet.insertRule( cssRule);
}
})();