您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
export bilibili video note
// ==UserScript== // @name 导出 B 站视频笔记 // @namespace bilibili-video-note-export // @version 0.1.0 // @author showlotus // @description export bilibili video note // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @match https://www.bilibili.com/video/* // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/index.js // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== (t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const o=document.createElement("style");o.textContent=t,document.head.append(o)})(' *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }#bilibili-video-note-export .ml-\\[10px\\]{margin-left:10px}#bilibili-video-note-export .box-border{box-sizing:border-box}#bilibili-video-note-export .block{display:block}#bilibili-video-note-export .flex{display:flex}#bilibili-video-note-export .h-\\[85px\\]{height:85px}#bilibili-video-note-export .cursor-pointer{cursor:pointer}#bilibili-video-note-export .flex-col{flex-direction:column}#bilibili-video-note-export .items-center{align-items:center}#bilibili-video-note-export .justify-between{justify-content:space-between}#bilibili-video-note-export .gap-1{gap:.25rem}#bilibili-video-note-export .gap-2{gap:.5rem}#bilibili-video-note-export .rounded-md{border-radius:.375rem}#bilibili-video-note-export .border{border-width:1px}#bilibili-video-note-export .border-b{border-bottom-width:1px}#bilibili-video-note-export .border-l-0{border-left-width:0px}#bilibili-video-note-export .border-r-0{border-right-width:0px}#bilibili-video-note-export .border-t{border-top-width:1px}#bilibili-video-note-export .border-solid{border-style:solid}#bilibili-video-note-export .border-\\[\\#00aeec\\]{--tw-border-opacity: 1;border-color:rgb(0 174 236 / var(--tw-border-opacity, 1))}#bilibili-video-note-export .border-\\[\\#e3e5e7\\]{--tw-border-opacity: 1;border-color:rgb(227 229 231 / var(--tw-border-opacity, 1))}#bilibili-video-note-export .bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}#bilibili-video-note-export .px-3{padding-left:.75rem;padding-right:.75rem}#bilibili-video-note-export .px-5{padding-left:1.25rem;padding-right:1.25rem}#bilibili-video-note-export .py-1{padding-top:.25rem;padding-bottom:.25rem}#bilibili-video-note-export .py-3{padding-top:.75rem;padding-bottom:.75rem}#bilibili-video-note-export .text-sm{font-size:.875rem;line-height:1.25rem}#bilibili-video-note-export .text-\\[\\#00aeec\\]{--tw-text-opacity: 1;color:rgb(0 174 236 / var(--tw-text-opacity, 1))}.note-pc .note-container .note-header{min-height:62px}.note-pc .note-container .note-content.bilibili-video-note-export__after-note-export{height:calc(100% - 147px)}.note-pc .note-container .note-up.note-detail-up{margin-bottom:0!important}.note-pc .note-container .editor-innter{margin-top:16px!important}.note-pc.is-exporting,.note-pc.is-copying{height:auto!important}.note-pc.is-exporting #bilibili-video-note-export__export-image,.note-pc.is-copying #bilibili-video-note-export__copy-image{cursor:not-allowed;pointer-events:none;background-color:#00b5f6!important;color:#fff!important}.note-pc.is-exporting #bilibili-video-note-export__export-image:after{content:"\u5BFC\u51FA\u4E2D..."}.note-pc.is-copying #bilibili-video-note-export__copy-image:after{content:"\u590D\u5236\u4E2D..."}.note-pc.is-exporting .note-operation,.note-pc.is-copying .note-operation{display:none!important}.note-pc.is-exporting #bilibili-video-note-export>div,.note-pc.is-copying #bilibili-video-note-export>div{position:relative}.note-pc.is-exporting #bilibili-video-note-export>div:after,.note-pc.is-copying #bilibili-video-note-export>div:after{content:"";position:absolute;bottom:-1px;left:0;width:30%;height:1px;background:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.2) 20%,#00aeec 50%,rgba(255,255,255,.2) 80%,transparent 100%);animation:loading 1.75s ease-in-out infinite alternate}@keyframes loading{0%{transform:translate(-50%)}50%{transform:translate(calc(85 / 30 * 100%))}to{transform:translate(-50%)}}#bilibili-video-note-export .after\\:content-\\[attr\\(data-text\\)\\]:after{--tw-content: attr(data-text);content:var(--tw-content)}#bilibili-video-note-export .hover\\:border-transparent:hover{border-color:transparent}#bilibili-video-note-export .hover\\:bg-\\[\\#00b5f6\\]:hover{--tw-bg-opacity: 1;background-color:rgb(0 181 246 / var(--tw-bg-opacity, 1))}#bilibili-video-note-export .hover\\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))} '); (function (modernScreenshot) { 'use strict'; var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); const $ = (selector) => { return document.querySelector(selector); }; const $$ = (selector) => { return document.querySelectorAll(selector); }; const logger = { debug: (...args) => { return; }, info: (...args) => { console.info("%c[bilibili-video-note-export]", "color: #2196F3", ...args); }, warn: (...args) => { console.warn("%c[bilibili-video-note-export]", "color: #FF9800", ...args); }, error: (...args) => { console.error("%c[bilibili-video-note-export]", "color: #F44336", ...args); } }; const watchElementVisibility = (selector, callback, options = { immediate: true }) => { const getEl = () => { return typeof selector === "string" ? document.querySelector(selector) : selector; }; const intersectionObserver = new IntersectionObserver( (entries) => { const entry = entries[0]; if (entry.isIntersecting) { callback(true); } else { callback(false); } }, { // 当元素进入视口时触发 threshold: 0.01 } ); const mutationObserver = new MutationObserver(() => { const el2 = getEl(); if (el2) { intersectionObserver.unobserve(el2); intersectionObserver.observe(el2); } }); mutationObserver.observe(document.body, { childList: true, subtree: true }); const el = getEl(); if (el && options.immediate) { const rect = el.getBoundingClientRect(); const isVisible = rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth); if (isVisible) { callback(true); } } return () => { intersectionObserver.disconnect(); mutationObserver.disconnect(); }; }; const convertImagesToBase64 = async (el) => { const images = Array.from(el.querySelectorAll("img")); for (const img of images) { const src = img.src; img.removeAttribute("loading"); if (src.startsWith("data:")) continue; try { const response = await fetch(src, { mode: "cors" }); const blob = await response.blob(); const base64 = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(blob); }); if (img.parentElement && img.parentElement.tagName.toLowerCase() === "picture") { const sources = img.parentElement.querySelectorAll("source"); sources.forEach((source) => source.setAttribute("srcset", base64)); } img.src = base64; } catch (err) { logger.warn(`无法转换图片为 base64:${src}`, err); } } }; const copyScreenshotToClipboard = async (el) => { await convertImagesToBase64(el); const blob = await modernScreenshot.domToBlob(el, { type: "image/png" }); const item = new ClipboardItem({ [blob.type]: blob }); await navigator.clipboard.write([item]); logger.info("图片已复制到剪贴板"); }; const exportScreenshotToImage = async (el) => { await convertImagesToBase64(el); return modernScreenshot.domToImage(el, { debug: true, progress: (current, total) => { } }).then((img) => { const link = document.createElement("a"); link.download = document.title + "-笔记截图.png"; link.href = img.src; document.body.appendChild(link); link.click(); document.body.removeChild(link); }); }; const mount = () => { const APP_ID = "bilibili-video-note-export"; const root = document.createElement("div"); root.setAttribute("id", APP_ID); let unwatchNoteDetail; const unwatchNotePc = watchElementVisibility("div.note-pc", (isNotePcShow) => { if (!isNotePcShow) { return; } if (unwatchNoteDetail) return; unwatchNoteDetail = watchElementVisibility("div.note-detail", (noteDetailShow) => { var _a, _b, _c, _d, _e, _f; if (noteDetailShow) { const el = $(`div#${APP_ID}`); if (el) { el.style.display = "block"; (_a = $("div.note-container div.note-content")) == null ? void 0 : _a.classList.add( "bilibili-video-note-export__after-note-export" ); (_b = $("div.note-container div.ql-editor")) == null ? void 0 : _b.setAttribute( "id", "bilibili-video-note-export__ql-editor" ); const exportStyle = _GM_getValue("export-style", "default"); if (exportStyle === "simple") { (_c = $("div#bilibili-video-note-export__ql-editor")) == null ? void 0 : _c.classList.remove("ql-editor"); } else { (_d = $("div#bilibili-video-note-export__ql-editor")) == null ? void 0 : _d.classList.add("ql-editor"); } const includeAuthorInfo = _GM_getValue("include-author-info", true); if (includeAuthorInfo) { $("div.note-container div.note-up.note-detail-up").style.display = "flex"; } else { $("div.note-container div.note-up.note-detail-up").style.display = "none"; } return; } root.innerHTML = /* html */ ` <div class="h-[85px] py-3 px-5 flex flex-col justify-between gap-1 box-border bg-white border-t border-b border-solid border-l-0 border-r-0 border-[#e3e5e7] text-sm"> <div class="flex gap-2"> <span>样式:</span> <div class="flex gap-2 items-center"> <input type="radio" id="bilibili-video-note-export__default-style" name="export-style" value="default" checked /> <label for="bilibili-video-note-export__default-style">默认样式</label> </div> <div class="flex gap-2 items-center"> <input type="radio" id="bilibili-video-note-export__simple-style" name="export-style" value="simple" /> <label for="bilibili-video-note-export__simple-style">简洁样式</label> </div> <div class="flex gap-2 items-center ml-[10px]"> <input type="checkbox" id="bilibili-video-note-export__include-author-info" name="include-author-info" checked /> <label for="bilibili-video-note-export__include-author-info">包含发布者</label> </div> </div> <div class="flex items-center gap-2"> <span>操作:</span> <div id="bilibili-video-note-export__copy-image" class="py-1 px-3 border-[#00aeec] border-solid border rounded-md text-[#00aeec] cursor-pointer hover:bg-[#00b5f6] hover:border-transparent hover:text-white after:content-[attr(data-text)]" data-text="复制为图片"></div> <div id="bilibili-video-note-export__export-image" class="py-1 px-3 border-[#00aeec] border-solid border rounded-md text-[#00aeec] cursor-pointer hover:bg-[#00b5f6] hover:border-transparent hover:text-white after:content-[attr(data-text)]" data-text="导出为图片"></div> </div> </div> `; (_e = $("div.note-container")) == null ? void 0 : _e.insertBefore(root, $("div.note-container div.note-content")); $$('input[name="export-style"]').forEach((radio) => { radio.addEventListener("change", (e) => { const target = e.target; if (target.value === "simple") { $("div#bilibili-video-note-export__ql-editor").classList.remove("ql-editor"); } else { $("div#bilibili-video-note-export__ql-editor").classList.add("ql-editor"); } _GM_setValue("export-style", target.value); }); }); $('input[name="include-author-info"]').addEventListener("change", (e) => { const target = e.target; if (target.checked) { $("div.note-container div.note-up.note-detail-up").style.display = "flex"; } else { $("div.note-container div.note-up.note-detail-up").style.display = "none"; } _GM_setValue("include-author-info", target.checked); }); $("div#bilibili-video-note-export__copy-image").addEventListener("click", async () => { $("div.note-pc").classList.add("is-copying"); await copyScreenshotToClipboard($("div.note-container div.note-content")); $("div.note-pc").classList.remove("is-copying"); }); $("div#bilibili-video-note-export__export-image").addEventListener("click", async () => { logger.debug("导出为图片", { exportStyle: _GM_getValue("export-style", "default"), includeAuthorInfo: _GM_getValue("include-author-info", true) }); $("div.note-pc").classList.add("is-exporting"); await exportScreenshotToImage($("div.note-container div.note-content")); $("div.note-pc").classList.remove("is-exporting"); }); } else { (_f = $("div.note-container div.note-content")) == null ? void 0 : _f.classList.remove( "bilibili-video-note-export__after-note-export" ); const el = $(`div#${APP_ID}`); if (el) { el.style.display = "none"; } } }); }); logger.info("插件运行中..."); return () => { var _a, _b; (_a = $("div.note-container div.note-content")) == null ? void 0 : _a.classList.remove( "bilibili-video-note-export__after-note-export" ); $("div.note-pc").classList.remove("is-copying", "is-exporting"); (_b = $(`div#${APP_ID}`)) == null ? void 0 : _b.remove(); unwatchNotePc(); unwatchNoteDetail == null ? void 0 : unwatchNoteDetail(); }; }; mount(); })(modernScreenshot);