// ==UserScript==
// @name bilibili直播自定义皮肤背景
// @namespace bilibili- ( ゜- ゜)つロ 乾杯~
// @version 1.1.4
// @description 自定义bilibili直播的皮肤和背景,仅自己可见!
// @author HCLonely
// @include /^https?:\/\/live.bilibili.com\/(blanc\/)?[\d]+/
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_openInTab
// @grant GM_log
// @grant GM_registerMenuCommand
// @require https://greasyfork.org/scripts/388035-jquery/code/$jQuery.js?version=736625
// @homepage https://blog.hclonely.com/posts/578f9be7/
// @supportURL https://blog.hclonely.com/posts/578f9be7/
// @run-at document-end
// @connect *
// @compatible chrome 没有测试其他浏览器的兼容性
// @downloadURL none
// ==/UserScript==
/* global $jQuery */
/* esline-disable camel-case */
(function ($jq) {
window.onload = function () {
'use strict'
if ($jq('main.app-content').length < 1) return
const backgroundImage = ['background', { id: 1, title: '纯色背景' }, { id: 2, title: '自定义背景' }, { id: 3, title: '默认背景①', url: 'http://static.hdslb.com/live-static/images/bg/1.jpg' }, { id: 4, title: '默认背景②', url: 'http://static.hdslb.com/live-static/images/bg/2.jpg' }, { id: 5, title: '默认背景③', url: 'http://static.hdslb.com/live-static/images/bg/3.jpg' }, { id: 6, title: '默认背景④', url: 'http://static.hdslb.com/live-static/images/bg/4.jpg' }, { id: 7, title: '默认背景⑤', url: 'http://static.hdslb.com/live-static/images/bg/5.jpg' }, { id: 8, title: '默认背景⑥', url: 'http://static.hdslb.com/live-static/images/bg/6.jpg' }]
const skinArr = ['skin', { id: 'default', name: '默认' }, { id: 'transparent', name: '透明' }, { id: 'customize', name: '自定义' }]
GM_setValue('skin', null)
const skin = GM_getValue('skinCache') || skinArr
start()
function start () {
$jq('body').append(`
`)
if (GM_getValue('skinCache')) {
GM_xmlhttpRequest({
method: 'GET',
url: `https://api.live.bilibili.com/room/v1/Skin/info?skin_platform=web&skin_version=1&id=${GM_getValue('skinCache').length - 3}`,
responseType: 'json',
onload: data => {
if (data.status === 200 && data.response.code === 0) {
if (Object.prototype.toString.call(data.response.data) === '[object Object]' && data.response.data.id + 4 > skin.length) {
$jq('span.update').css('display', 'inline-block')
$jq('span.update').parent().attr('title', '有新皮肤啦')
}
}
}
})
} else {
$jq('span.update').css('display', 'inline-block')
$jq('span.update').parent().attr('title', '首次使用请先更新缓存')
}
const sideBarLeft = $jq('[name="sideBarLeft"]')
const settingDiv = $jq('[name="settingDiv"]')
const settingH2 = $jq('[name="settingH2"]')
const settingInfoDiv = $jq('[name="settingInfoDiv"]')
const closeBtn = $jq('[name="closeBtn"]')
const backgroundDiv = $jq('[name="backgroundDiv"]')
const hideDiv = $jq('[name="hideDiv"]')
const skinDiv = $jq('[name="skinDiv"]')
const updateDiv = $jq('[name="updateDiv"]')
const saveBtn = $jq('.save-button')
const preBtn = $jq('.pre-button')
const skinInfo = $jq('.skin-info')
const biInfo = set_info(backgroundImage)
const skInfo = set_info(skin)
closeBtn.click(() => {
settingDiv.hide()
})
backgroundDiv.click(() => {
if (settingInfoDiv.attr('data-tag') === 'bg' && settingDiv.css('display') === 'none') {
settingDiv.show()
} else if (settingInfoDiv.attr('data-tag') === 'bg') {
settingDiv.hide()
} else {
settingInfoDiv.attr('data-tag', 'bg')
settingH2.text('更换背景')
settingInfoDiv.html(biInfo)
$jq('.background-select').click(function () {
set_background($jq(this).attr('data-background-id'))
})
skinInfo.hide()
settingDiv.show()
}
})
skinDiv.click(() => {
if (settingInfoDiv.attr('data-tag') === 'skin' && settingDiv.css('display') === 'none') {
settingDiv.show()
settingDiv.show()
} else if (settingInfoDiv.attr('data-tag') === 'skin') {
settingDiv.show()
settingDiv.hide()
} else {
settingInfoDiv.attr('data-tag', 'skin')
settingH2.text('更换皮肤')
settingInfoDiv.html('' + (GM_getValue('skinCache') ? '' : '首次使用请先更新皮肤缓存'))
$jq('.color-info').hide()
$jq('.url-info').hide()
$jq('select.skin').change(function () {
get_skin($jq(this).find('option:selected').val())
})
$jq('#updateA').click(() => { updateSkin() })
skinInfo.show()
settingDiv.show()
}
})
updateDiv.click(() => { updateSkin() })
hideDiv.click(() => {
sideBarLeft.hide()
})
saveBtn.click(() => {
const cache = get_setting()
GM_setValue('mySetting', cache)
msg('保存成功!')
})
preBtn.click(function () {
const skin_config = {}
$jq.makeArray($jq('input[name="skinBgCode"]')).map(e => {
skin_config[$jq(e).attr('id')] = $jq(e).val()
})
set_skin('customize', skin_config)
})
$('head').bind('DOMNodeInserted', () => {
const prevSetting = GM_getValue('mySetting') || []
const nowSetting = get_setting()
if ($('style[id^=skin-css-').length > 1) $(`style[id^=skin-css-]:not([id=skin-css-${prevSetting[1].id}])`).remove()
else if (($jq('div.room-bg[role="img"]').length > 0 ? prevSetting[0] !== nowSetting[0] : false) || prevSetting[1].id !== nowSetting[1].id) set_all(prevSetting)
})
sideBarLeft.click(() => {
$('head').unbind('DOMNodeInserted')
})
function set_info (e) {
let info = ''
const type = e[0]
const classType = e[0] === 'skin' ? 'skin' : 'background'
for (let i = 1; i < e.length; i++) {
if (e[i]) type === 'skin' ? info += `` : info += ``
}
return info
}
function set_background (id) {
switch (id) {
case '1':
$jq('div.url-info').hide()
$jq('div.color-info').show()
$jq('#colorEnter').click(() => {
if ($jq('div.room-bg[role="img"]').length > 0) $jq('div.room-bg[role="img"]').attr('style', `background-color: ${$jq('input[name="colorCode"]').val()};`)
})
break
case '2':
$jq('div.color-info').hide()
$jq('div.url-info').show()
$jq('#urlEnter').click(() => {
if ($jq('div.room-bg[role="img"]').length > 0) $jq('div.room-bg[role="img"]').attr('style', `background-image: url("${$jq('input[name="urlCode"]').val()}");`)
})
break
default:
$jq('div.color-info').hide()
$jq('div.url-info').hide()
if ($jq('div.room-bg[role="img"]').length > 0) $jq('div.room-bg[role="img"]').attr('style', `background-image: url("${backgroundImage[id].url}");`)
break
}
}
function get_skin (id) {
$('.pre-button').attr('disabled', 'disabled')
switch (id) {
case 'default':
$('[name="skinBgCode"]').val('')
$('style[id^=skin-css-').remove()
$('head').append('')
break
case 'transparent':
$('[name="skinBgCode"]').val('')
set_skin(id, { headInfoBgPic: '#fff0', giftControlBgPic: '#fff0', rankListBgPic: '#fff0', danmakuBgPic: '#fff0', inputBgPic: '#fff0' })
$('#headInfoBgPic').val('#fff0')
$('#giftControlBgPic').val('#fff0')
$('#rankListBgPic').val('#fff0')
$('#danmakuBgPic').val('#fff0')
$('#inputBgPic').val('#fff0')
break
case 'customize':
$('input[name="skinBgCode"]').removeAttr('disabled')
$('.pre-button').removeAttr('disabled')
break
default:
$('[name="skinBgCode"]').val('')
set_skin(id, JSON.parse(get_skin_conf(id, skin).skin_config.replace(/#FF/g, '#')))
}
}
function set_skin (id, skin_config) {
Object.keys(skin_config).forEach(function (key) {
$jq('#' + key).val(skin_config[key])
})
const mainText = skin_config.mainText ? `
.live-skin-coloration-area
.live-skin-main-text {
color: ${skin_config.mainText}!important;
}
.live-skin-coloration-area
.live-skin-main-a-text:link,.live-skin-main-a-text:visited {
color: ${skin_config.mainText}!important;
}
` : ''
const normalText = skin_config.normalText ? `
.live-skin-coloration-area
.live-skin-normal-text {
color: ${skin_config.normalText}!important;
}
.live-skin-coloration-area
.live-skin-normal-a-text {
color: ${skin_config.normalText}!important;
}
.live-skin-coloration-area
.live-skin-normal-a-text:link,.live-skin-normal-a-text:visited {
color: ${skin_config.normalText}!important;
}
` : ''
const highlightContent = skin_config.highlightContent ? `
.live-skin-coloration-area
.live-skin-main-a-text:hover,.live-skin-main-a-text:active {
color: ${skin_config.highlightContent}!important;
}
.live-skin-coloration-area
.live-skin-normal-a-text:hover,.live-skin-normal-a-text:active {
color: ${skin_config.highlightContent}!important;
}
.live-skin-coloration-area
.live-skin-highlight-text {
color: ${skin_config.highlightContent}!important;
}
.live-skin-coloration-area
.live-skin-highlight-bg {
background-color: ${skin_config.highlightContent}!important;
}
.live-skin-coloration-area
.live-skin-highlight-border {
border-color: ${skin_config.highlightContent}!important;
}
.live-skin-coloration-area
.live-skin-highlight-button-bg.bl-button--primary:not(:disabled) {
background-color: ${skin_config.highlightContent};
}
.live-skin-coloration-area
.live-skin-highlight-button-bg.bl-button--primary:hover:not(:disabled) {
background-color: ${skin_config.highlightContent};
}
.live-skin-coloration-area
.live-skin-highlight-button-bg.bl-button--primary:active:not(:disabled) {
background-color: ${skin_config.highlightContent};
}
` : ''
const border = skin_config.border ? `
.live-skin-coloration-area
.live-skin-separate-border {
border-color: ${skin_config.border}!important;
}
.live-skin-coloration-area
.live-skin-separate-area {
background-color: ${skin_config.border}!important;
}
.live-skin-coloration-area
.live-skin-separate-area-hover:hover {
background-color: ${skin_config.border}!important;
}
` : ''
const headInfoBgPic = skin_config.headInfoBgPic
const giftControlBgPic = skin_config.giftControlBgPic
const rankListBgPic = /^#/.test(skin_config.rankListBgPic) ? `#rank-list-ctnr-box,#rank-list-vm {background-color: ${skin_config.rankListBgPic}!important}` : `#rank-list-ctnr-box {background-image: url(${skin_config.rankListBgPic})!important}`
const danmakuBgPic = skin_config.danmakuBgPic ? `.chat-history-panel{${/^#/.test(skin_config.danmakuBgPic) ? `background-color: ${skin_config.danmakuBgPic}!important` : `background-image: url(${skin_config.danmakuBgPic})!important`};}` : ''
const inputBgPic = skin_config.inputBgPic ? `#chat-control-panel-vm{${/^#/.test(skin_config.inputBgPic) ? `background-color: ${skin_config.inputBgPic}!important` : `background-image: url(${skin_config.inputBgPic})!important`};}` : ''
$('style[id^=skin-css-').remove()
$('body').append(`
`)
}
function get_setting () {
const cache = []
if ($jq('div.room-bg[role="img"]').length > 0) cache[0] = $jq('div.room-bg[role="img"]').attr('style')
if ($('style[id^=skin-css-').length > 0) {
const skinId = $('style[id^=skin-css-').attr('id').replace('skin-css-', '')
cache[1] = { id: skinId, style: $('style[id^=skin-css-').html() }
} else {
cache[1] = { id: 'default' }
}
return cache
}
function set_all (setting) {
if (setting[0] && $jq('div.room-bg[role="img"]').length > 0) $jq('div.room-bg[role="img"]').attr('style', setting[0])
if (setting[1]) {
$('style[id^=skin-css-').remove()
$('head').append(``)
}
}
function screen () {
switch ($('div.bilibili-live-player').attr('data-player-state')) {
case 'web-fullscreen':
sideBarLeft.hide()
if (!$('style[id^=skin-css-').html().includes('/*')) $('style[id^=skin-css-').html('/*' + $('style[id^=skin-css-').html() + '*/')
break
case 'normal':
sideBarLeft.show()
if ($('style[id^=skin-css-').html().includes('/*')) $('style[id^=skin-css-').html($('style[id^=skin-css-').html().replace(/\*\/|\/\*/g, ''))
break
case 'fullscreen':
sideBarLeft.hide()
break
default:
break
}
}
$jq(document).click(function (e) {
if ($jq(e.target).attr('data-title') && ($jq(e.target).attr('data-title').includes('全屏'))) screen()
})
$jq(document).dblclick(screen)
$jq(document).keydown(function (e) {
const keyArr = [13, 27, 108]
if (keyArr.indexOf(e.keyCode) > -1) screen()
})
document.addEventListener('fullscreenchange', screen)
function get_skin_conf (id, skin) {
for (const e of skin) {
if (e && parseInt(e.id) === parseInt(id)) return e
}
}
function updateSkin (id = 1) {
msg('正在更新皮肤缓,请耐心等待')
const skinCache = GM_getValue('skinCache') || []
if (!skinCache[id + 3]) {
GM_xmlhttpRequest({
method: 'GET',
url: 'https://api.live.bilibili.com/room/v1/Skin/info?skin_platform=web&skin_version=1&id=' + id,
responseType: 'json',
onload: data => {
const skinConfig = data.response.data
if (data.status === 200 && data.response.code === 0 && Object.prototype.toString.call(skinConfig) === '[object Object]' && skinConfig.id === id) {
skin[skinConfig.id + 3] = {
id: skinConfig.id,
name: skinConfig.skin_name,
skin_config: skinConfig.skin_config
}
console.log('皮肤' + skinConfig.id + '更新成功')
GM_setValue('skinCache', skin)
updateSkin(++id)
} else if (data.status === 200 && data.response.code === 0) {
msg('皮肤缓存更新完成,刷新后可查看新皮肤')
} else {
console.log('皮肤' + id + '更新失败')
console.log(data)
}
}
})
} else {
updateSkin(++id)
}
}
function msg (message = '', status = 'success', timer = 4000) {
$jq('.link-toast').remove()
$jq('body').append(`${message}
`)
setTimeout(() => { $jq('.link-toast').remove() }, timer)
}
GM_addStyle(`
.side-bar-left {
height: 230px;
position: fixed;
left: 0;
bottom: 30%;
padding: 12px 4px;
background-color: #fff;
z-index: 1000000;
border-radius: 0 12px 12px 0;
-webkit-box-shadow: 0 0 20px 0 rgba(0,85,255,.1);
box-shadow: 0 0 20px 0 rgba(0,85,255,.1);
-webkit-transition: height .4s cubic-bezier(.22,.58,.12,.98);
-o-transition: height cubic-bezier(.22,.58,.12,.98) .4s;
transition: height .4s cubic-bezier(.22,.58,.12,.98);
border: 1px solid #e9eaec;
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
.side-bar-btn-div {
width: 56px;
height: 56px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 4px 0;
cursor: pointer;
text-align: center;
padding: 5px 0;
}
.svg-icon-span {
font-size: 26px !important;
margin: 0 auto;
width: 26px;
height: 26px;
}
.size-bar-text-p {
margin: 4px 0 0;
font-size: 12px;
line-height: 16px;
}
.awarding-panel-setting {
left: 80px;
bottom: -200px;
-webkit-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
transform-origin: 0 100%;
width: 500px;
height: 500px;
padding: 24px;
font-size: 12px;
color: #333;
background-color: #fff;
border: 1px solid #e9eaec;
border-radius: 12px;
z-index: 1;
}
.awarding-panel-setting .title {
margin: 0;
font-size: 18px;
font-weight: 400;
color: #23ade5;
}
.awarding-panel-setting .close-btn {
padding: 0;
top: 16px;
right: 16px;
font-size: 16px;
color: #999;
border: none;
background-color: transparent;
}
.awarding-panel-setting .close-btn:hover {
-webkit-transform: scale(1.1) rotate(180deg);
-ms-transform: scale(1.1) rotate(180deg);
transform: scale(1.1) rotate(180deg);
}
.awarding-panel-setting .close-btn {
padding: 0;
top: 16px;
right: 16px;
font-size: 16px;
color: #999;
border: none;
background-color: transparent;
}
.awarding-panel-setting .info-section {
margin-top: 24px;
}
.background-select,.skin-select {
width: 22%;
min-width: 70px;
height: 20px;
margin: 5px;
border-radius: 30px;
text-align: center;
cursor: pointer;
-webkit-transition: all 1s cubic-bezier(.22,.58,.12,.98);
-o-transition: all 1s cubic-bezier(.22,.58,.12,.98);
transition: all 1s cubic-bezier(.22,.58,.12,.98);
vertical-align: middle;
display: inline-block;
}
.hour-rank-info {
line-height: 16px;
padding: 2px 8px;
margin: 0;
font-size: 12px;
color: #fff;
-webkit-transition: width 3s cubic-bezier(.22,.58,.12,.98);
-o-transition: width 3s cubic-bezier(.22,.58,.12,.98);
transition: width 3s cubic-bezier(.22,.58,.12,.98);
min-width: 70px;
height: 20px;
border-radius: 30px;
text-align: center;
cursor: pointer;
}
.code-div {
background-color: hsla(0,0%,100%,.88);
display: block;
height: 32px;
border-style: solid;
border-radius: 4px;
border-color: #e9f2f7;
transition: background-color .2s;
margin-top: 3px;
}
.v-middle-color {
float: none;
color: #222;
font-size: 12px;
overflow: hidden;
height: 32px;
line-height: 32px;
padding: 0;
border: 0;
box-shadow: none;
background-color: transparent;
}
.color-button {
display: block;
position: relative;
right: 0;
width: 48px;
min-width: 0;
cursor: pointer;
height: 32px;
margin: 0;
padding: 0;
border: 0;
color: #00a4db;
}
.color-button:hover {
color: #ff4e8e;
}
.color-code-div {
width: 218px;
}
.url-code-div {
width: 418px;
}
[name="colorCode"] {
width: 146px;
}
[name="urlCode"] {
width: 372px;
}
[name="skinBgCode"] {
width: 63%;
height: 22px;
}
.save-button,.pre-button,.get-config-button {
min-width: 80px;
height: 24px;
font-size: 12px;
background-color: #23ade5;
color: #fff;
border-radius: 4px;
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
line-height: 1;
margin: 0;
padding: 6px 12px;
border: 0;
cursor: pointer;
outline: none;
overflow: hidden;
bottom: 10px;
}
.save-button:hover,.pre-button:hover,.get-config-button:hover {
background-color: #39b5e7;
}
.save-txt {
position: relative;
}
.bottom-div {
position: absolute;
left: 200px;
bottom: 0;
}
.skin-btn,.skin-code-div {
height: 22px;
}
.skin-btn {
float: right;
}
button[disabled] {
cursor: not-allowed;
background-color:#e9eaec;
color:#b4b4b4
}
.link-toast {
z-index:99999999999999;
}
`)
GM_registerMenuCommand('清空设置', () => { GM_setValue('mySetting', null) })
GM_registerMenuCommand('显示/隐藏设置菜单', () => { sideBarLeft.toggle() })
}
}
})($jQuery)