// ==UserScript== // @name Bilibili Touch // @namespace http://tampermonkey.net/ // @version 3.4 // @description Touch optimizations and UI improvements for Bilibili // @author Grant Howard // @match *://*.bilibili.com/* // @match *://*.bilibili.com // @grant unsafeWindow // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAC0CAYAAAA9zQYyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAH0mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0wMi0yNVQxNDo1NzozOCswODowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOC0wMi0yNVQxNDo1NzozOCswODowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTgtMDItMjVUMTQ6NTc6MzgrMDg6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODY3MDMzY2UtZjdlMy0wYTRiLWE5YWItODE3ZTI2ZmNlYTMyIiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6YWFhN2UzZTQtM2MzOS0yOTQ4LWI1OTgtYTEzM2ZjMTMxNDMyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6YjRjNGFjZWUtZjQyYS0yMTQwLTlmMzgtY2NlZTc3YmY2ZTM1IiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkhpc3Rvcnk9IjIwMTgtMDItMjVUMTQ6NTc6MTArMDg6MDAmI3g5O+aWh+S7tiDmnKrmoIfpopgtMiDlt7LmiZPlvIAmI3hBO+W7uueriyYjeDk75paw5bu6OiDmlofmoaMmI3hBO0ZBTFNFJiN4QTvmqKHlvI86IFJHQiDpopzoibLmqKHlvI8mI3hBO+WuveW6pjogMi41IOiLseWvuCYjeEE76auY5bqmOiAyLjUg6Iux5a+4JiN4QTvmr4/oi7Hlr7gg5YiG6L6o546HOiA3MiYjeEE75YOP57Sg6ZW/5a695q+UOiAxJiN4QTvloavlhYU6IOmAj+aYjiYjeEE75rex5bqmOiA4JiN4QTvphY3nva7mlofku7Y6IOKAnG5vbmXigJ0mI3hBO+WPguiAg+e6vzog5pegJiN4QTsyMTcmI3hBOyYjeEE757KY6LS0JiN4QTvnspjotLQmI3g5O+a2iOmZpOmUr+m9vzog5pegJiN4QTvkuLo6IOWDj+e0oCYjeEE7JiN4QTsyMDE4LTAyLTI1VDE0OjU3OjM4KzA4OjAwJiN4OTvmlofku7YgQzpcVXNlcnNcVGhlMThcUGljdHVyZXNcR3JhcGhpY3NcYmlsaWJpbGkgbG9nbyBzbWFsbC5wbmcg5bey5a2Y5YKoJiN4QTvlrZjlgqgmI3g5OyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YjRjNGFjZWUtZjQyYS0yMTQwLTlmMzgtY2NlZTc3YmY2ZTM1IiBzdEV2dDp3aGVuPSIyMDE4LTAyLTI1VDE0OjU3OjM4KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIg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 // @require https://static.hdslb.com/js/jquery.min.js // @require https://raw.githubusercontent.com/briangonzalez/rgbaster.js/master/rgbaster.min.js // ==/UserScript== (self$ => { const colors = { red: "#E53935", pink: "#F06292", purple: "#AB47BC", deepPurple: "#7E57C2", indigo: "#7986CB", blue: "#1E88E5", lightBlue: "#00A0D8", cyan: "#00ACC1", teal: "#26A69A", green: "#66BB6A", lightGreen: "#8BC34A", lime: "#CDDC39", yellow: "#FFEB3B", amber: "#FFC107", orange: "#FF9800", deepOrange: "#FF5722", brown: "#795548", grey: "#757575", blueGrey: "#607D8B" }; // User settings will overwrite default settings below const userSettings = { customStyleColor: colors.pink, showBanner: false, useDarkMode: true }; const settings = { // remove ads removeAds: true, // max retry count used for query elements maxQueryRetry: 30, // query retry interval (ms) queryInterval: 500, // touch support for nav bar (not compatible with Edge) touchNavBar: true, // (Experimental) touch support for video player touchVideoPlayer: true, // redirect to original sites in watchlater list watchLaterRedirect: true, // auto expand danmaku list expandDanmakuList: true, // use new styles for nav bar and player useNewStyles: true, // [New Styles] // set theme color (must in #rrggbb format, not compatible with Edge) customStyleColor: colors.pink, // [New Styles] // set background blur opacity of nav bar blurBackgroundOpacity: 0.382, // [New Styles] // (Not Implemented) use dark mode useDarkMode: true, // [New Styles] // (Experimental) use new nav bar in old sites overrideNavBar: true, // [New Styles -> Override Nav Bar] // show top banner showBanner: true // [Not used] // (Experimental) use dominant color of banner image // useDominantColor: false }; for (const key in userSettings) { settings[key] = userSettings[key]; } const $ = unsafeWindow.$ || self$; const waitForQuery = () => { const MaxRetry = settings.maxQueryRetry; let retry = 0; const tryQuery = (query, condition, action, failed) => { if (retry >= MaxRetry) { if (failed) { failed(); } } else { const result = query(); if (condition(result)) { action(result); } else { retry++; setTimeout(() => tryQuery(query, condition, action, failed), settings.queryInterval); } } }; return tryQuery; }; const getEventHandler = (element, event) => { return element.data("events")[event][0].handler; }; const getPosition = element => { let x = 0; let y = 0; while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { x += element.offsetLeft - element.scrollLeft; y += element.offsetTop - element.scrollTop; element = element.offsetParent; } return { x: x, y: y }; }; class Swiper { constructor(element) { this.action = new SwipeAction(element); this.onTouchStart = undefined; this.onTouchEnd = undefined; this._direction = null; element.addEventListener("touchstart", e => { this._xDown = e.touches[0].clientX; this._yDown = e.touches[0].clientY; if (this.onTouchStart) { this.onTouchStart(e); } }); element.addEventListener("touchmove", e => { if (!this._xDown || !this._yDown) { return; } const xUp = e.touches[0].clientX; const yUp = e.touches[0].clientY; const elementPosition = getPosition(element); const position = { x: (e.touches[0].pageX - elementPosition.x) / element.clientWidth, y: (e.touches[0].pageY - elementPosition.y) / element.clientHeight, width: element.clientWidth, height: element.clientHeight }; const xDiff = this._xDown - xUp; const yDiff = this._yDown - yUp; if (!this._direction) { let direction = ""; if (Math.abs(xDiff) > Math.abs(yDiff)) { direction = "horizontal"; } else { direction = "vertical"; } this._direction = direction; e.preventDefault(); } else { if (this._direction === "vertical") { this.action.startAction(this._direction, yDiff, position); } else if (this._direction === "horizontal") { this.action.startAction(this._direction, -xDiff, position); } e.preventDefault(); } }); element.addEventListener("touchend", e => { this._xDown = null; this._yDown = null; this._direction = null; if (this.onTouchEnd) { this.onTouchEnd(e); } }); } } class SwipeAction { constructor(element) { this.lowSpeedForward = undefined; this.lowSpeedBackward = undefined; this.mediumSpeedForward = undefined; this.mediumSpeedBackward = undefined; this.highSpeedForward = undefined; this.highSpeedBackward = undefined; this.lowVolumeUp = undefined; this.lowVolumeDown = undefined; this.mediumVolumeUp = undefined; this.mediumVolumeDown = undefined; this.highVolumeUp = undefined; this.highVolumeDown = undefined; this.speedCancel = undefined; this.volumeCancel = undefined; this.minSwipeDistance = 20; this.onActionStart = undefined; this.onActionEnd = undefined; this._element = element; this._touchStart = false; this._startPosition = null; this._lastAction = null; element.addEventListener("touchstart", () => { this._touchStart = true; }); element.addEventListener("touchend", () => { this._startPosition = null; this.onActionEnd && this.onActionEnd(this._lastAction); this._lastAction = null; }); } startAction(direction, distance, position) { if (this._touchStart) { this.onActionStart && this.onActionStart(); this._startPosition = position; this._touchStart = false; } if (direction === "vertical") { if (Math.abs(distance) < this.minSwipeDistance) { this.volumeCancel && this.volumeCancel(); this._lastAction = null; } else { let volumeFactor = 0; let upHandler = undefined; let downHandler = undefined; if (this._startPosition.x < 1 / 3) { volumeFactor = 0.4; upHandler = this.lowVolumeUp; downHandler = this.lowVolumeDown; } else if (this._startPosition.x >= 1 / 3 && this._startPosition.x <= 2 / 3) { volumeFactor = 1; upHandler = this.mediumVolumeUp; downHandler = this.mediumVolumeDown; } else { volumeFactor = 2; upHandler = this.highVolumeUp; downHandler = this.highVolumeDown; } if (distance > 0) { const volumeChange = Math.round( volumeFactor * 100 * (distance - this.minSwipeDistance) / (1.5 * position.height) ); upHandler && upHandler(volumeChange); this._lastAction = { type: "volume", volume: volumeChange }; } else { const volumeChange = Math.round( volumeFactor * 100 * (distance + this.minSwipeDistance) / (1.5 * position.height) ); downHandler && downHandler(volumeChange); this._lastAction = { type: "volume", volume: volumeChange }; } } } else if (direction === "horizontal") { if (position.y < 1 / 3 && (position.x < 0.1 || position.x > 0.9) || Math.abs(distance) < this.minSwipeDistance) { this.speedCancel && this.speedCancel(); this._lastAction = null; } else { let speedFactor = 0; let forwardHandler = undefined; let backwardHandler = undefined; if (this._startPosition.y < 1 / 3) { speedFactor = 0.05; forwardHandler = this.lowSpeedForward; backwardHandler = this.lowSpeedBackward; } else if (this._startPosition.y >= 1 / 3 && this._startPosition.y <= 2 / 3) { speedFactor = 0.2; forwardHandler = this.mediumSpeedForward; backwardHandler = this.mediumSpeedBackward; } else { speedFactor = 1; forwardHandler = this.highSpeedForward; backwardHandler = this.highSpeedBackward; } if (distance > 0) { const seconds = (distance - this.minSwipeDistance) * speedFactor; forwardHandler && forwardHandler(seconds); this._lastAction = { type: "playback", seconds: seconds }; } else { const seconds = (distance + this.minSwipeDistance) * speedFactor; backwardHandler && backwardHandler(seconds); this._lastAction = { type: "playback", seconds: seconds }; } } } } } class VideoShot { constructor(totalTime) { this.interval = totalTime < 5 * 100 ? 5 : totalTime / 100; this.firstShot = { css: { backgroundPosition: "-160px 0px" }, x: -160, y: 0, position: 2 }; this.lastShot = { css: { backgroundPosition: "-1440px -810px" }, x: -1440, y: -810, position: 100 }; this.imageXLength = 10; this.imageYLength = 10; this.imageXSize = 160; this.imageYSize = 90; this.imageUrl = null; this.imageIndex = []; } init(input) { const matches = input.prop("value").match(/aid=([\d]+)&cid=([\d]+)/); const aid = matches[1]; const cid = matches[2]; $.ajax({ type: "GET", url: `https://api.bilibili.com/x/player/videoshot?aid=${aid}&cid=${cid}&index=1`, success: obj => { const data = obj.data; this.imageXLength = data.img_x_len; this.imageYLength = data.img_y_len; this.imageXSize = data.img_x_size; this.imageYSize = data.img_y_size; this.imageIndex = data.index; this.imageUrl = data.image[0]; this.firstShot = { css: {}, x: -this.imageXSize, y: 0, position: 1 }; this.firstShot.css.backgroundPosition = `${this.firstShot.x}px ${this.firstShot.y}px`; this.lastShot = { css: {}, x: -this.imageXSize * (this.imageXLength - 1), y: -this.imageYSize * (this.imageYLength - 1), position: 99 }; this.lastShot.css.backgroundPosition = `${this.lastShot.x}px ${this.lastShot.y}px`; } }); } _getStyle(position) { if (position <= this.firstShot.position) { return this.firstShot.css; } else if (position >= this.lastShot.position) { return this.lastShot.css; } else { const x = -160 * (position % 10 - 1); const y = -90 * (position >= 100 ? 9 : Math.trunc(position / 10)); return { backgroundPosition: `${x}px ${y}px` }; } } getStyle(time) { const position = Math.round(time / interval); return this._getStyle(position); } } $(document).ready(() => { // Remove ads if (settings.removeAds) { waitForQuery()( () => $("#slide_ad"), it => it.length > 0, it => it.css("display", "none") ); waitForQuery()( () => $("#home_popularize"), it => it.length > 0, it => it.css("display", "none") ); waitForQuery()( () => $(".gg-floor-module"), it => it.length > 0, it => it.css("display", "none") ); } // Touch nav bar if (settings.touchNavBar) { waitForQuery()( () => $("ul.fr>li.nav-item").not(".profile-info"), it => it.length === 6, navItems => { const navTouch = (_, nav) => { const $nav = $(nav); $nav.css("cursor", "pointer"); const a = $nav.find("a.t"); a.removeAttr("href"); }; navItems.each(navTouch); } ); } // Touch video player const touchVideoPlayer = () => { waitForQuery()( () => $(".bilibili-player-video-web-fullscreen"), it => it.length > 0, fullscreenButton => { if (!fullscreenButton.hasClass("bilibili-player-video-btn") && $(".bilibili-player-video-btn-fullscreen").data("events")) { const clickHandler = getEventHandler( $(".bilibili-player-video-btn-fullscreen"), "click"); fullscreenButton .detach() .insertAfter(".bilibili-player-video-btn-widescreen") .addClass("bilibili-player-video-btn") .on("click", clickHandler); } } ); waitForQuery()( () => $(".bilibili-player-iconfont,.bilibili-player-video-quality-menu"), it => it.length > 0, icons => icons.unbind("click") ); waitForQuery()( () => $(".bilibili-player-video"), it => it.length > 0 && $("video").length > 0, player => { if ($(".touch-video-box").length === 0) { $(".bilibili-player-video-subtitle").before(`
`); const swiper = new Swiper(player.get(0)); const text = document.getElementsByClassName("touch-video-info")[0]; const box = document.getElementsByClassName("touch-video-box")[0]; swiper.action.speedCancel = () => { text.innerHTML = `松开手指,取消进退`; }; swiper.action.volumeCancel = () => { text.innerHTML = `松开手指,取消调整`; }; swiper.action.onActionStart = () => { box.style.display = "flex"; text.innerHTML = ""; }; const fixed = (number, precision = 1) => { const str = number.toString(); const index = str.indexOf("."); if (index !== -1) { if (str.length - index > precision + 1) { return str.substring(0, index + precision + 1); } else { return str; } } else { return str + ".0"; } }; const secondsToTime = sec => { sec = Math.abs(sec); const hours = Math.floor(sec / 3600); const minutes = Math.floor((sec - hours * 3600) / 60); const seconds = sec - hours * 3600 - minutes * 60; let result = fixed(seconds) + "秒"; if (minutes > 0) { result = minutes + "分" + result; } if (hours > 0) { result = hours + "小时" + result; } return result; }; const secondsToHms = sec => { sec = Math.abs(sec); const hours = Math.floor(sec / 3600); const minutes = Math.floor((sec - hours * 3600) / 60); const seconds = sec - hours * 3600 - minutes * 60; let result = (seconds < 10 ? "0" : "") + fixed(seconds); result = (minutes < 10 ? "0" : "") + minutes + ":" + result; result = (hours < 10 ? "0" : "") + hours + ":" + result; return result; }; const video = $("video"); const videoDuration = video.prop("duration"); //const videoshot = new VideoShot(videoDuration); const speedChange = speed => { return sec => { const current = video.prop("currentTime"); let info = `
${speed}速进度: ${sec > 0 ? "+" : "-"}`; const commonInfoPart = `
`; const finalTime = current + sec; if (finalTime > videoDuration) { info += `${secondsToTime(videoDuration - current)}${commonInfoPart}${secondsToHms(current)} → ${secondsToHms(videoDuration)} (100%)`; } else if (finalTime < 0) { info += `${secondsToTime(current)}${commonInfoPart}${secondsToHms(current)} → ${secondsToHms(0)} (0%)`; } else { info += `${secondsToTime(sec)}${commonInfoPart}${secondsToHms(current)} → ${secondsToHms(finalTime)} (${fixed(100 * finalTime / videoDuration)}%)`; } text.innerHTML = info + `
`; //$(".videoshot").css(videoshot.getStyle(finalTime)); }; }; swiper.action.lowSpeedBackward = speedChange("低"); swiper.action.lowSpeedForward = speedChange("低"); swiper.action.mediumSpeedBackward = speedChange("中"); swiper.action.mediumSpeedForward = speedChange("中"); swiper.action.highSpeedBackward = speedChange("高"); swiper.action.highSpeedForward = speedChange("高"); const volumeChange = speed => { return volume => { const current = Math.round(video.prop("volume") * 100); let info = `
${speed}速音量: ${volume > 0 ? "+" : "-"}`; const commonInfoPart = `
`; const finalVolume = current + volume; if (finalVolume > 100) { info += `${100 - current}${commonInfoPart}${current} → 100`; } else if (finalVolume < 0) { info += `${current}${commonInfoPart}${current} → 0`; } else { info += `${Math.abs(volume)}${commonInfoPart}${current} → ${finalVolume}`; } text.innerHTML = info + `
`; }; }; swiper.action.lowVolumeUp = volumeChange("低"); swiper.action.lowVolumeDown = volumeChange("低"); swiper.action.mediumVolumeUp = volumeChange("中"); swiper.action.mediumVolumeDown = volumeChange("中"); swiper.action.highVolumeUp = volumeChange("高"); swiper.action.highVolumeDown = volumeChange("高"); swiper.action.onActionEnd = action => { box.style.display = "none"; text.innerHTML = ""; if (action) { if (action.type === "volume") { let volume = video.prop("volume"); volume += action.volume / 100; if (volume < 0) { volume = 0; } else if (volume > 1) { volume = 1; } video.prop("volume", volume); $(".bilibili-player-video-volume-num").text(Math.round(volume * 100)); $(".bpui-slider-progress").css("height", volume * 100 + "%"); $(".bpui-slider-handle").css("bottom", (35 + volume * 230) / 3 + "%"); if (volume === 0) { $(".icon-24soundoff").show(); $(".icon-24soundlarge").hide(); $(".icon-24soundsmall").hide(); } else if (volume >= 0.5) { $(".icon-24soundoff").hide(); $(".icon-24soundlarge").show(); $(".icon-24soundsmall").hide(); } else { $(".icon-24soundoff").hide(); $(".icon-24soundlarge").hide(); $(".icon-24soundsmall").show(); } } else if (action.type === "playback") { let time = video.prop("currentTime"); time += action.seconds; if (time < 0) { time = 0; } else if (time > videoDuration) { time = videoDuration; } video.prop("currentTime", time); } } }; } } ); if ($("#bilibili-touch-video-player").length === 0) { const videoPlayerStyles = ``; $("body").after(videoPlayerStyles); } // waitForQuery()( // () => $(".bilibili-player-video-progress-detail-img"), // it => it.length > 0, // videoshot => // { // } // ); }; touchVideoPlayer(); // Watch later redirect const watchlaterRedirect = () => { if (settings.watchLaterRedirect) { const redirectLinks = items => { if (items.attr("href").indexOf("watchlater") !== 0) { const watchlaterList = items .map((_, it) => "https://www.bilibili.com/" + $(it) .attr("href") .match(/av[\d]+/)[0]); items.each((index, it) => $(it).attr("href", watchlaterList[index]).attr("target", "_blank")); } }; waitForQuery()( () => $(".av-item>a"), it => it.length > 0, items => redirectLinks(items) ); waitForQuery()( () => $("div.watch-later-m>ul>div>li>a"), it => it.length > 0, items => redirectLinks(items) ); waitForQuery()( () => $(".read-more.mr"), it => it.length > 0, it => it.remove() ); waitForQuery()( () => $(".read-more-grp>.read-more"), it => it.length > 0, it => it.css({ float: "none", width: "auto" }) ); if (document.URL.indexOf("watchlater") !== -1 && document.URL.match(/av[\d]+/)) { const av = document.URL.match(/av[\d]+/)[0]; if (av) { document.URL.replace(`https://www.bilibili.com/${av}`); } } } }; watchlaterRedirect(); // Expand danmaku list const expandDanmakuList = () => { if (settings.expandDanmakuList) { waitForQuery()( () => $(".bui-collapse-header"), it => it.length > 0, button => { if (parseInt($(".bui-collapse-body").css("height")) === 0 && $(".bui-collapse-arrow-text").text() === "展开") { button.click(); } } ); } }; expandDanmakuList(); $(document).ajaxComplete(() => { expandDanmakuList(); watchlaterRedirect(); touchVideoPlayer(); }); // Styles if (settings.useNewStyles) { waitForQuery()( () => $(".nav-search-keyword"), it => it.length > 0, textBox => textBox.attr("placeholder", "搜索") ); waitForQuery()( () => $(".custom-scrollbar"), it => it.length > 0, it => it.removeClass("custom-scrollbar") ); // waitForQuery()( // () => $("li.home>a"), // it => it.length > 0 && it.css("font-size").indexOf("12px") !== -1, // it => it.css("font-size", "0px") // ); const getForeground = () => { const regex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(settings.customStyleColor); const color = regex ? { r: parseInt(regex[1], 16), g: parseInt(regex[2], 16), b: parseInt(regex[3], 16) } : undefined; if (color) { const grey = 1 - (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255; if (grey < 0.35) { return "#000"; } else { return "#fff"; } } else { return "#fff"; } }; const updateDarkModeColor = () => { if (settings.useDarkMode) { const foreground = getForeground(); const darkStyles = ``; $("#bilibili-new-style-dark").remove(); $("body").after(darkStyles); } }; const updateStyleColor = () => { const foreground = getForeground(); const navbar = document.getElementsByClassName("bili-wrapper")[0]; let useFlexStyles = false; if (navbar instanceof Element) { useFlexStyles = parseInt(window.getComputedStyle(navbar).height) === 50; } let styles = ""; if (useFlexStyles) { styles = ``; } else { styles = ``; if (settings.overrideNavBar) { waitForQuery()( () => $(".search"), it => it.length > 0 && $(".nav-con.fr").length > 0, textBox => { textBox.detach() .insertAfter(".nav-con.fr"); } ); waitForQuery()( () => $("input.search-keyword"), it => it.length > 0, textBox => textBox.attr("placeholder", "搜索") ); const navBarStyles = ``; $("body").after(navBarStyles); if (!settings.showBanner) { const bannerStyles = ``; $("body").after(bannerStyles); } } } $("#bilibili-new-style").remove(); $("body").after(styles); }; const updateColors = () => { updateDarkModeColor(); updateStyleColor(); }; updateColors(); // if (settings.useDominantColor && !(settings.overrideNavBar && !settings.showBanner)) // { // waitForQuery()( // () => $("#banner_link"), // it => it.length > 0 && it.css("background-image") !== "none", // image => // { // const src = image.css("background-image").match(/url\("(.+)"\)/)[1]; // RGBaster.colors(src, { // success: color => // { // settings.customStyleColor = color.dominant; // updateColors(); // } // }); // } // ); // } } }); })(window.jQuery.noConflict(true));