Skip to content

Instantly share code, notes, and snippets.

@Neboer
Last active September 5, 2023 14:27
Show Gist options
  • Save Neboer/bff07c2e4e8aefe0aadb302ea35e660f to your computer and use it in GitHub Desktop.
Save Neboer/bff07c2e4e8aefe0aadb302ea35e660f to your computer and use it in GitHub Desktop.
给b站添加“截图”按钮的油猴脚本
'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