Last active
September 5, 2023 14:27
-
-
Save Neboer/bff07c2e4e8aefe0aadb302ea35e660f to your computer and use it in GitHub Desktop.
给b站添加“截图”按钮的油猴脚本
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// ==UserScript== | |
// @name BiliBili截图工具 | |
// @namespace http://tampermonkey.net/ | |
// @version 1.1 | |
// @description 完全本地化的、在对bilibili视频进行截图的工具。 | |
// @author Neboer | |
// @match https://www.bilibili.com/video/* | |
// @icon https://www.bilibili.com/favicon.ico | |
// @grant none | |
// ==/UserScript== | |
// https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518 | |
function htmlToElement(html) { | |
var template = document.createElement('template'); | |
html = html.trim(); // Never return a text node of whitespace as the result | |
template.innerHTML = html; | |
return template.content.firstChild; | |
} | |
let screenshot_button_html = `<div class="bpx-player-dm-setting"> | |
<span class="bpx-common-svg-icon"> | |
<svg viewBox="64 64 896 896" xmlns="http://www.w3.org/2000/svg"> | |
<path fill-rule="evenodd" | |
d="M864 260H728l-32.4-90.8a32.07 32.07 0 0 0-30.2-21.2H358.6c-13.5 0-25.6 8.5-30.1 21.2L296 260H160c-44.2 0-80 35.8-80 80v456c0 44.2 35.8 80 80 80h704c44.2 0 80-35.8 80-80V340c0-44.2-35.8-80-80-80zM512 716c-88.4 0-160-71.6-160-160s71.6-160 160-160 160 71.6 160 160-71.6 160-160 160zm-96-160a96 96 0 1 0 192 0 96 96 0 1 0-192 0z"> | |
</path> | |
</svg> | |
</span> | |
</div>`; | |
let screenshot_button = htmlToElement(screenshot_button_html); | |
// https://stackoverflow.com/a/15832662 | |
function downloadURI(uri, name) { | |
var link = document.createElement("a"); | |
link.download = name; | |
link.href = uri; | |
document.body.appendChild(link); | |
link.click(); | |
document.body.removeChild(link); | |
link.remove(); | |
} | |
// https://stackoverflow.com/a/13765373 | |
function get_screenshot_of_video(video_obj) { | |
let canvas = document.createElement('canvas'); | |
canvas.width = video_obj.videoWidth; | |
canvas.height = video_obj.videoHeight; | |
let ctx = canvas.getContext('2d'); | |
ctx.drawImage(video_obj, 0, 0, canvas.width, canvas.height); | |
return canvas; | |
} | |
function download_canvas_image(canvas) { | |
let screenshot_url = canvas.toDataURL('image/png'); | |
downloadURI(screenshot_url, "screenshot.png"); | |
} | |
// https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard | |
function copy_canvas_image(canvas) { | |
canvas.toBlob(function (blob) { | |
const item = new ClipboardItem({ "image/png": blob }); | |
navigator.clipboard.write([item]); | |
}); | |
} | |
function insert_screenshot_button(toolbox_root_element, toolbox_danmu_input_box_element) { | |
toolbox_root_element.insertBefore(screenshot_button, toolbox_danmu_input_box_element) | |
} | |
// 注意,此脚本的运行时期要改为document-start! | |
function waitForElm(selector_list) { | |
let result_list = new Array(selector_list.length).fill(null) | |
// request all elements in selector, if all elements are set, then return true. | |
function collect_selection() { | |
selector_list.forEach((value, index) => { | |
if (!result_list[index]) { | |
let search_result = document.querySelector(value); | |
if (search_result) result_list[index] = search_result | |
} | |
}) | |
} | |
function check_list_complete() { | |
return !result_list.some(item => item === null); | |
} | |
return new Promise(resolve => { | |
collect_selection() | |
if (!check_list_complete()) { | |
const observer = new MutationObserver(() => { | |
collect_selection() | |
if (check_list_complete()) { | |
resolve(result_list); | |
observer.disconnect(); | |
} | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}); | |
} else { | |
resolve(result_list) | |
} | |
}); | |
} | |
waitForElm(['.bpx-player-video-wrap video', '.bpx-player-dm-root', '.bpx-player-video-inputbar']).then(elements => { | |
let [bilibili_video_element, toolbox_element, toolbox_danmu_input_box_element] = elements; | |
// 单击复制,双击下载。 | |
screenshot_button.onclick = () => { | |
let screenshot_canvas = get_screenshot_of_video(bilibili_video_element) | |
copy_canvas_image(screenshot_canvas) | |
} | |
screenshot_button.ondblclick = () => { | |
let screenshot_canvas = get_screenshot_of_video(bilibili_video_element) | |
download_canvas_image(screenshot_canvas) | |
} | |
insert_screenshot_button(toolbox_element, toolbox_danmu_input_box_element) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment