// ==UserScript== // @name bilibili plus // @version 0.4 // @description 提供新版B站截图、获取封面、逐帧等功能,以及默认宽屏、默认无弹幕等模式 // @namespace https://greasyfork.org/zh-CN/users/215623-christian-chen // @author 化猫之宿 // @encoding utf-8 // // @match *://www.bilibili.com/video/* // @match *://www.bilibili.com/bangumi/play/* // // @compatible chrome 54+ // @compatible firefox 49+ // // @grant GM_getValue // @grant GM_setValue // @downloadURL none // ==/UserScript== !function(modules) { var installedModules = {}; function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; var module = installedModules[moduleId] = { i: moduleId, l: !1, exports: {} }; return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), module.l = !0, module.exports; } __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = function(exports, name, getter) { __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { enumerable: !0, get: getter }); }, __webpack_require__.r = function(exports) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(exports, "__esModule", { value: !0 }); }, __webpack_require__.t = function(value, mode) { if (1 & mode && (value = __webpack_require__(value)), 8 & mode) return value; if (4 & mode && "object" == typeof value && value && value.__esModule) return value; var ns = Object.create(null); if (__webpack_require__.r(ns), Object.defineProperty(ns, "default", { enumerable: !0, value: value }), 2 & mode && "string" != typeof value) for (var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); return ns; }, __webpack_require__.n = function(module) { var getter = module && module.__esModule ? function() { return module.default; } : function() { return module; }; return __webpack_require__.d(getter, "a", getter), getter; }, __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }, __webpack_require__.p = "", __webpack_require__(__webpack_require__.s = 0); }([ function(module, exports) { ({ inject: function(is_userscript) { let user_settings, fps, side_bar, root, player_area, counter; fps = 29.97, counter = 0, user_settings = JSON.parse(document.documentElement.dataset.localsettings); const set = (setting, new_value) => { "user_settings" !== setting ? user_settings[setting] = new_value : user_settings = setting, document.documentElement.dataset.localsettings = JSON.stringify(user_settings); }, key = { fullscreenEnabled: 0, fullscreenchange: 1 }, webkit = [ "webkitFullscreenEnabled", "webkitfullscreenchange" ], moz = [ "mozFullScreenEnabled", "mozfullscreenchange" ], vendor = "fullscreenEnabled" in document && Object.keys(key) || webkit[0] in document && webkit || moz[0] in document && moz || [], fscreen = { addEventListener: (type, handler, options) => document.addEventListener(vendor[key[type]], handler, options), removeEventListener: (type, handler, options) => document.removeEventListener(vendor[key[type]], handler, options), get onfullscreenchange() { return document[`on${vendor[key.fullscreenchange]}`.toLowerCase()]; }, set onfullscreenchange(handler) { return document[`on${vendor[key.fullscreenchange]}`.toLowerCase()] = handler; } }, eventButtons = e => { for (let el = e.target; el !== e.currentTarget; el = el.parentElement) el.classList.contains("button-pic") && getThumb(), el.classList.contains("button-screen") && getScreenshot(), el.classList.contains("button-next") && seekFrame("forward", 29.97), el.classList.contains("button-pre") && seekFrame("backward", 29.97), el.classList.contains("button-mode-wide") && modeWide(el), el.classList.contains("button-mode-nodanmu") && modeNoDanmaku(el), el.classList.contains("button-mode-dropdown") && modeDown(el); }, eventKeys = e => { switch (e.code.toLowerCase()) { case "period": root.querySelector(".button-next").click(); break; case "comma": root.querySelector(".button-pre").click(); } }; function modeWide(e, flag = !0) { let player, btn_wide; (player = document.querySelector("#bilibiliPlayer")) && !player.classList.contains("mode-widescreen") && (btn_wide = player.querySelector(".bilibili-player-video-btn-widescreen")) && !btn_wide.classList.contains("closed") && btn_wide.click(), e.querySelectorAll(".button-mode-svg").forEach(element => { element.classList.toggle("svg-display"); }), flag && (user_settings.MODE_WIDE ? user_settings.MODE_WIDE = !1 : user_settings.MODE_WIDE = !0, user_settings.MODE_WIDE && user_settings.MODE_DOWN && modeDown(e.parentNode.querySelector(".button-mode-dropdown")), set("MODE_WIDE", user_settings.MODE_WIDE)); } function modeDown(e, flag = !0) { let side_column, expand; (side_column = document.querySelector(".bui-collapse-wrap")) && side_column.classList.contains("bui-collapse-wrap-folded") && (expand = side_column.querySelector(".bui-collapse-arrow")).click(), e.querySelectorAll(".button-mode-svg").forEach(element => { element.classList.toggle("svg-display"); }), flag && (user_settings.MODE_DOWN ? user_settings.MODE_DOWN = !1 : user_settings.MODE_DOWN = !0, user_settings.MODE_DOWN && user_settings.MODE_WIDE && modeWide(e.parentNode.querySelector(".button-mode-wide")), set("MODE_DOWN", user_settings.MODE_DOWN)); } const modeNoDanmaku = (e, flag = !0) => { let button_danmaku; (button_danmaku = document.querySelector(".bui-checkbox")) && button_danmaku.checked && button_danmaku.click(), e.querySelectorAll(".button-mode-svg").forEach(element => { element.classList.toggle("svg-display"); }), flag && (user_settings.MODE_DANMU_CLOSE ? user_settings.MODE_DANMU_CLOSE = !1 : user_settings.MODE_DANMU_CLOSE = !0, set("MODE_DANMU_CLOSE", user_settings.MODE_DANMU_CLOSE)); }, pauseVideo = video => { let btnStart; btnStart = document.querySelector(".bilibili-player-video-btn-start"), player_area && !player_area.classList.contains("video-state-pause") ? btnStart.click() : video.pause(); }, popPage = (obj, x, y) => { let popOut, width, height, pop_url; return width = x, height = y, "string" == typeof obj ? (pop_url = obj, popOut = window.open(pop_url, "popOut", "width=" + width + ",height=" + height)) : "object" == typeof obj && (popOut = window.open("", "_blank", "width=" + width + ",height=" + height)).document.body.appendChild(obj), popOut.focus(), popOut; }, getScreenshot = () => { let video, canvas, context, width, height, pop, style; video = document.querySelector("video"), context = (canvas = document.createElement("canvas")).getContext("2d"), width = video.videoWidth, height = video.videoHeight, canvas.width = width, canvas.height = height, context.drawImage(video, 0, 0, width, height), pauseVideo(video), pop = popPage(canvas, width, height), (style = document.createElement("style")).type = "text/css", style.innerHTML = "body {\n margin: 0;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: #ccc;\n }\n canvas {\n max-width: 100%;\n max-height: 100%;\n }", pop.document.head.appendChild(style); }, getThumb = () => { let thumbnail_url; (thumbnail_url = (thumbnail_url = document.querySelector('[itemprop="thumbnailUrl"]')) && thumbnail_url.getAttribute("content")) ? popPage(thumbnail_url, 881, 551) : alert("未找到缩略图!"); }, seekFrame = (direction, fps) => { let video; video = document.querySelector("video"), pauseVideo(video), "forward" === direction ? video.currentTime = video.currentTime + 1 / fps : "backward" === direction && (video.currentTime = video.currentTime - 1 / fps); }, handleEvents = root_el => { root_el.addEventListener("click", eventButtons), root_el.querySelector(".button-mode").addEventListener("mouseenter", function(e) { this.querySelector(".show-mode").style.display = "block", e.stopPropagation(); }), root_el.querySelector(".button-mode").addEventListener("mouseleave", function(e) { this.querySelector(".show-mode").style.display = "none", e.stopPropagation(); }); const eventClick = () => { window.removeEventListener("keydown", eventKeys); }; player_area.addEventListener("click", e => { window.addEventListener("keydown", eventKeys), document.addEventListener("click", eventClick, { once: !0 }), e.stopPropagation(); }), fscreen.addEventListener("fullscreenchange", function() { player_area.parentNode.classList.contains("mode-fullscreen") || (settings => { let player, btn_wide; settings.MODE_WIDE && (player = document.querySelector("#bilibiliPlayer")) && !player.classList.contains("mode-widescreen") && (btn_wide = player.querySelector(".bilibili-player-video-btn-widescreen")) && !btn_wide.classList.contains("closed") && btn_wide.click(); })(user_settings); }); }, main = () => { if (root = document.querySelector(".bilibili-player-video-danmaku-root"), player_area = document.querySelector(".bilibili-player-area"), side_bar = document.querySelector(".bui-collapse-wrap"), root && side_bar && player_area) (() => { let button_next, button_pre, button_pic, button_screen, button_mode; document.querySelector(".button-next") || ((button_next = document.createElement("div")).className = "bilibili-player-video-danmaku-setting bilibili-player-video-danmaku-switch button-pre", button_next.innerHTML = '\n \n \n \n \n \n 逐帧后退 <', (button_pre = document.createElement("div")).className = "bilibili-player-video-danmaku-setting bilibili-player-video-danmaku-switch button-next", button_pre.innerHTML = '\n \n \n \n \n \n 逐帧前进 >', (button_pic = document.createElement("div")).className = "bilibili-player-video-danmaku-setting bilibili-player-video-danmaku-switch button-pic", button_pic.innerHTML = '\n \n \n \n \n \n 缩略图', (button_screen = document.createElement("div")).className = "bilibili-player-video-danmaku-setting bilibili-player-video-danmaku-switch button-screen", button_screen.innerHTML = '\n \n \n \n \n \n 截图', (button_mode = document.createElement("div")).className = "bilibili-player-video-danmaku-setting bilibili-player-video-danmaku-switch button-mode", button_mode.innerHTML = '\n \n \n \n \n \n ', root.prepend(button_mode, button_pic, button_screen, button_next, button_pre)); })(), handleEvents(root), (settings => { let button_mode; button_mode = root.querySelector(".button-mode"), settings.MODE_WIDE && modeWide(button_mode.querySelector(".button-mode-wide"), !1), settings.MODE_DANMU_CLOSE && modeNoDanmaku(button_mode.querySelector(".button-mode-nodanmu"), !1), settings.MODE_DOWN && modeDown(button_mode.querySelector(".button-mode-dropdown"), !1); })(user_settings), new MutationObserver(() => { counter = 0, setTimeout(main, 100); }).observe(document.querySelector(".bilibili-player-video"), { childList: !0 }); else { if (++counter > 30) return; setTimeout(main, 300); } }; main(); }, setup: function() { let css_holder, holder; (css_holder = document.createElement("style")).type = "text/css", css_holder.innerHTML = ".show-mode {\n display: flex;\n flex-direction: column;\n align-items: center;\n position: absolute;\n z-index: 71;\n bottom: 46px;\n left: -40px;\n background-color: rgba(0, 0, 0, 0.8);\n font-size: 12px;\n padding: 5px 15px;\n color: hsla(0,0%,100%,.8);\n fill: hsla(0,0%,100%,.8);\n cursor: auto;\n }\n \n .mode-fullscreen .show-mode {\n left: -30px;\n }\n .mode-fullscreen .show-mode .show-mode-bridge {\n position: absolute;\n left: 0;\n height: 25px;\n width: 110px;\n }\n \n .button-mode-selects {\n width: 100%;\n height: 46px;\n cursor: pointer;\n text-align: left;\n }\n \n .button-mode-selects.opened {\n fill:#00a1d6; \n }\n \n .button-mode-selects:hover {\n color: hsla(0,0%,100%,1);\n fill: hsla(0,0%,100%,1);\n }\n .button-mode-selects.opened:hover {\n color: hsla(0,0%,100%,1);\n fill:#00a1d6; \n }\n \n .button-mode-svg {\n display: inline-block;\n font-size: 0;\n vertical-align: middle;\n height: 32px;\n width: 32px;\n }\n \n .bp-svgicon svg {\n width: 100%;\n height: 100%;\n }\n \n .button-mode-text {\n display: inline-block;\n height: 16px;\n line-height: 16px;\n padding-left: 10px;\n }\n \n .svg-display {\n display: none;\n }", (holder = document.createElement("script")).textContent = `(${this.inject}(${this.is_userscript}))`, document.head.appendChild(css_holder), document.documentElement.appendChild(holder); }, conveyMeassge: function() { let data_key, gate, sets, observe, default_settings; data_key = "localsettings", gate = document.documentElement, default_settings = { MODE_WIDE: !1, MODE_DANMU_CLOSE: !1, MODE_DOWN: !1 }, (sets = JSON.parse(gate.dataset.localsettings || null)) || (gate.dataset.localsettings = JSON.stringify(this.GM_getValue(this.data, default_settings))), (observe = new MutationObserver(() => { this.GM_setValue(this.data, JSON.parse(gate.dataset.localsettings || null)); })).observe(gate, { attributes: !0, attributeFilter: [ "data-localsettings" ] }); }, ini: function() { this.is_userscript = "object" == typeof GM_info, this.data = "userSettings", this.GM_setValue = GM_setValue, this.GM_getValue = GM_getValue, this.conveyMeassge(), this.setup(); } }).ini(); } ]);