// ==UserScript== // @name b站笔记 // @namespace https://bbs.tampermonkey.net.cn/ // @version 3.0.0 // @description 实现功能:1、当视频全屏时让笔记面板嵌入视频页面内,不需要退出全屏,即可进行笔记记录,当视频是非全屏时就恢复官方默认布局让笔记面板出现在视频页面外边,确保笔记与观影互不干扰。2、笔记内容滚动定位:在笔记面板增加顶部直达、底部跳转及滚动条功能,即便长篇笔记也能快速滚动至所需位置。3、笔记面板隐藏:避免关闭笔记后再次打开时需要重新翻找笔记位置的麻烦,隐藏后只需要将鼠标移到视频页面右侧,笔记面板便会自动显示。4、笔记截图弹出放大与面板宽度调整:点击笔记中的截图可以让图片弹出,以便更清晰地查看截图内容,另外也可以直接拖动宽度控制条来调整面板宽度,笔记里截图也会同步放大。5、笔记面板透明度调节。6、插入视频标题到笔记。7、截屏带时间标记:在插入视频截图的同时,自动添加时间标记。8、笔记列表快捷访问:在网页头部点击我的笔记按钮,会弹出一个面板可查看所有视频的笔记,再按钮可以关掉面板。9、将笔记以pdf导出到本地。10、电脑ctrl键快捷打开、隐藏、显示笔记面板,实现一步到位进入编辑状态。11、打开笔记后自动滚动到上次编辑位置并获取光标焦点。12、其他快捷键操作包括:调节透明度、插入当前字幕、插入当前视频标题、插入当前时间标记与视频截图、视频全屏界面调整笔记面板的位置、让笔记编辑区获取光标焦点。13、点击弹幕的复制按钮,将对应弹幕自动粘贴到笔记中 // @author 繁星1678 // @match https://www.bilibili.com/video/* // @match https://www.bilibili.com/* // @icon https://static.hdslb.com/images/favicon.ico // @grant GM_addStyle // @license MIT // @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // ==/UserScript== (function () { 'use strict'; let IsFull = false; let IsJbjClick = false; let bar; let selection; let range; let tm_qd; let IsInsert = false; let IsMyNote = false; let IsNotePcHightChange = false; let isClose = true; let isTmAddLisner = false;//是否设置了插入时间标签点击监听事件 const currentUrl = window.location.href; let isCloseNoteList = false; let noteOpen=false let scrollH=null//前一次隐藏笔记面板前的滚动条高度 let position=null let targetNode=null let inputNumber = ''; // 用于存储输入的数字,调整透明度使用 let isBold = false//插入视频标题或字幕到笔记时是否加粗 let isCtrlPressed = false; // 记录Ctrl键是否按下 let otherKeyPressed = false; // 记录是否按下了其他键 let IsPrintWindowOnLoad = false; // 打印窗口是否已经打开 let imgloadedCount = 0;//图片加载个数 ///////////////////////////////////// // 创建iframe,访问的网页显示在这里面,并将iframe插入到页面中 function createIframeAndIsertDocument() { let iframeS = document.querySelector('.note-list-iframe') // 创建一个 iframe 并设置其样式 let iframe = document.createElement('iframe'); iframe.src = 'https://space.bilibili.com/v/note-list'; iframe.className = 'note-list-iframe'; iframe.style.width = '65%'; iframe.style.height = '80%'; iframe.style.position = 'fixed'; iframe.style.top = '50px'; iframe.style.left = '0px'; iframe.style.border = 'none'; iframe.style.zIndex = '99999'; iframe.style.boxShadow = '0 4px 8px'; iframe.style.borderRadius = '10px'; if (!iframeS) { document.body.appendChild(iframe) ////////// iframe.onload = function () { initDraggable(iframe) // 移除 onload 处理函数,避免重复执行 iframe.onload = null; // 初始化拖动功能 }; ////////// } } function initDraggable(element) { let isDragging = false; let offsetX = 0; let offsetY = 0; element.addEventListener('mousedown', (e) => { // 修改为在 element 上添加监听器 isDragging = true; offsetX = e.clientX - element.offsetLeft; offsetY = e.clientY - element.offsetTop; }); document.addEventListener('mousemove', (e) => { if (isDragging) { element.style.left = (e.clientX - offsetX) + 'px'; element.style.top = (e.clientY - offsetY) + 'px'; } }); document.addEventListener('mouseup', () => { isDragging = false; }); } // 创建笔记列表按钮并添加监听事件 function setNoteListBtn() { let iframe = null let noteListsBtn = document.querySelector('.note-lists'); // 如果存在就设置监听,不存在就创造一个并设置监听 if (noteListsBtn) { // setNoteListsBtnListener(noteListsBtn); // alert('noteListsBtn存在:',noteListsBtn) } else { // alert('noteListsBtn不存在') function createNoteListBtnAndInsertDocument() { let avatar_wrap = document.querySelector('.header-avatar-wrap'); if (avatar_wrap) { noteListsBtn = document.createElement('div'); noteListsBtn.style.display = 'grid'; noteListsBtn.innerHTML = `我的笔记`; noteListsBtn.style.cursor = 'pointer'; noteListsBtn.className = 'note-lists'; avatar_wrap.parentNode.insertBefore(noteListsBtn, avatar_wrap); observer.disconnect(); // setNoteListsBtnListener(noteListsBtn) noteListsBtn.addEventListener('click', function (e) { if (isCloseNoteList) { let iframe = document.querySelector('.note-list-iframe'); document.body.removeChild(iframe); // 笔记列表被关闭,换成我的笔记的图标 noteListsBtn.innerHTML = `我的笔记`; } else { createIframeAndIsertDocument() // 笔记列表被打开,换成关闭笔记的图标 noteListsBtn.innerHTML = `关闭笔记` } isCloseNoteList = !isCloseNoteList; }) } } let observer = new MutationObserver(createNoteListBtnAndInsertDocument) let config = { childList: true, subtree: true } observer.observe(document.body, config) } } if (currentUrl.startsWith('https://www.bilibili.com/')) { setNoteListBtn() } if (currentUrl.indexOf('https://www.bilibili.com/video/') === 0 || currentUrl.startsWith('https://www.bilibili.com/cheese/')) { function isFirefox() { return navigator.userAgent.toLowerCase().indexOf('firefox') > -1; } function isEdge() { // 获取 User Agent 字符串 const userAgent = navigator.userAgent; // 检查 User Agent 字符串中是否包含 "Edg" 或 "Edge" return userAgent.indexOf("Edg") !== -1 || userAgent.indexOf("Edge") !== -1; } // 以pdf格式将笔记内容保存到本地 function saveNoteAsPdf() { // const note_pc = document.querySelector("div.resizable-component.note-pc"); // if (note_pc) { let fullUrl = window.location.href let searchParams = new URLSearchParams(fullUrl.search) // 判断链接中是否存在'note' let isNote = searchParams.has('note') let titleElement = document.querySelector(".video-title.special-text-indent"); let title = titleElement ? (titleElement.getAttribute('data-title').trim() || titleElement.getAttribute('title').trim() || titleElement.textContent).trim() : ''; if (!title) { console.log('无法找到视频标题'); } let url = window.location.href || title; const saveBtn = document.createElement("button"); saveBtn.id = "saveBtn"; saveBtn.textContent = "另存为pdf"; saveBtn.style.width = "auto"; saveBtn.title = "将笔记内容以pdf格式保存到本地"; saveBtn.onclick = saveAsPDF; const style = document.createElement('style'); style.textContent = ` #saveBtn { background-color: #3f72af; color: white; border: none; padding: 2px 1px; vertical-align: middle; text-align: center; text-decoration: none; display: inline-block; font-size: 10px; margin: 4px 2px; cursor: pointer; border-radius: 5px; transition: background-color 0.3s ease; } #saveBtn:hover { background-color: #112d4e; } `; document.head.appendChild(style); setTimeout(() => { let ckbj_btn = document.querySelector('div.list-note-operation'); if (ckbj_btn) { ckbj_btn.addEventListener("click", function (event) { setTimeout(() => { const ql_save_btn = document.querySelector('.ql-save-btn'); if (ql_save_btn) { ql_save_btn.parentNode.appendChild(saveBtn); } }, 5); }) } else { console.log("586 没有找到ckbij按钮") } setTimeout(() => { let ql_save_btn = document.querySelector('.ql-save-btn'); if (ql_save_btn) { ql_save_btn.parentNode.appendChild(saveBtn); return } }, 2000); let ql_save_btn = document.querySelector('.ql-save-btn'); if (ql_save_btn) { ql_save_btn.parentNode.appendChild(saveBtn); return } }, 1000); let newJbjBtn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.video-note-inner'); let jbj_btn_title = newJbjBtn.innerText.trim() if (jbj_btn_title === "记笔记") { newJbjBtn.addEventListener("click", function (event) { setTimeout(() => { const ql_save_btn = document.querySelector('.ql-save-btn'); // ql_save_btn.parentNode.appendChild(saveBtn); if (ql_save_btn) { ql_save_btn.parentNode.appendChild(saveBtn); } }, 60); setTimeout(() => { let ckbj_btn = document.querySelector('div.list-note-operation'); if (ckbj_btn) { ckbj_btn.addEventListener("click", function (event) { setTimeout(() => { const ql_save_btn = document.querySelector('.ql-save-btn'); if (ql_save_btn) { ql_save_btn.parentNode.appendChild(saveBtn); } }, 5); }) } else { console.log("586 没有找到ckbij按钮") } }, 800); }) } else { newJbjBtn.addEventListener("click", function (event) { setTimeout(() => { let ckbj_btn = document.querySelector('div.list-note-operation'); if (ckbj_btn) { ckbj_btn.addEventListener("click", function (event) { setTimeout(() => { const ql_save_btn = document.querySelector('.ql-save-btn'); if (ql_save_btn) { ql_save_btn.parentNode.appendChild(saveBtn); } }, 5); }) } else { console.log("586 没有找到ckbij按钮") } }, 800); }) } function saveAsPDF() { // let imgWidth = 1920; let imgWidth = screen.width; imgWidth = imgWidth * 0.7+'px'; let screenWidth = window.screen.width; let screenHeight = window.screen.height let newWidth = Math.floor(screenWidth * 0.45); let newHeight = screenHeight; const content = document.querySelector(".ql-editor"); if (!content) { console.error('无法找到编辑器内容'); return; } // 创建一个新的窗口,并设置位置 // const printWindow = window.open('', 'Print', 'width=500,height=400,left=350,top=330'); const printWindow = window.open('', 'Print', `width=${newWidth},height=${newHeight},left=0,top=0`); // const printWindow = window.open('', 'Print', 'width=500,height=400,left=350,top=330,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no'); // 将内容复制到新窗口中 printWindow.document.open(); printWindow.document.write(` ${title}
正在加载笔记中的图片,请稍等... 0%
打开视频


${transformContent(content.innerHTML)} `); printWindow.document.close(); let tooltip = printWindow.document.querySelector('.tooltip') // 加载图片时显示进度百分数 let imgs = printWindow.document.querySelectorAll('.img-preview'); if (imgs.length > 0) { let timeoutId; function onTimeout() { tooltip.textContent = '图片加载超时,请重试'; setTimeout(() => { printWindow.close(); }, 1500); } imgs.forEach(img => { img.onload = () => { imgloadedCount++; const progress = Math.floor((imgloadedCount / imgs.length) * 100); tooltip.querySelector('#progress').textContent = `${progress}%`; if (imgloadedCount === imgs.length) { imgloadedCount = 0; clearTimeout(timeoutId); tooltip.querySelector('#progress').textContent = "100%"; setTimeout(() => { tooltip.remove(); printWindow.print(); setTimeout(() => { // console.log('打印完成或取消,开始调整窗口') const adjustedBody = printWindow.document.body; adjustedBody.classList.add('adjusted'); // 添加class以调整模版样式 return; }, 1000); }, 50); } else { } } }) timeoutId = setTimeout(onTimeout, 45000); // 45秒后超时,关闭窗口 }else{ tooltip.remove(); printWindow.print(); } } function transformContent(html) { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const timeTags = doc.querySelectorAll('.time-tag-item__text'); timeTags.forEach(tag => { let textToParse = tag.getAttribute('title') || tag.textContent; // 提取章节编号,如 "P1" const chapterMatch = textToParse.match(/P(\d+)/); let chapter = chapterMatch ? Number(chapterMatch[1]) : -1; // 默认章节为1 if (chapter === -1 || chapter === 1) { chapter = '' } else { chapter = '&p=' + chapter } // 提取时间并转换为秒数 const timeMatch = textToParse.match(/(\d+):(\d+):(\d+)$/) || textToParse.match(/(\d+):(\d+)$/); if (timeMatch) { // console.log('timeMatch:' + timeMatch); // 如果匹配到的是小时:分钟:秒 let hours = 0, minutes = 0, seconds = 0; if (timeMatch.length === 4) { [, hours, minutes, seconds] = timeMatch; } else if (timeMatch.length === 3) { // 如果是分钟:秒 [, minutes, seconds] = timeMatch; } // 计算总秒数 let totalSeconds = (parseInt(hours, 10) * 3600) + (parseInt(minutes, 10) * 60) + parseInt(seconds, 10); // console.log('Total seconds:', totalSeconds); // 可以用于调试输出 // 设置`?t=`参数 const timeParam = '?t=' + totalSeconds; // console.log('时间参数:', timeParam); totalSeconds = '?t=' + totalSeconds // 跳到指定视频的指定时间进行播放 https://www.bilibili.com/video/BV1cq4y1U7sg?t=557.2&p=6 // 创建 URL 对象 const url1 = new URL(window.location.href); // const queryString = url1.search.substring(1); const params = new URLSearchParams(url1.search); // let vdSource = params.get('vd_source'); // 获取基础路径部分(去掉查询字符串和片段标识符) let baseUrl = url1.origin + url1.pathname; if (baseUrl.endsWith('/')) { baseUrl = baseUrl.slice(0, -1); } // console.log('baseurl:' + baseUrl); // 构建新的 URL const newLink = `${tag.textContent}`; tag.outerHTML = newLink; } }); // 处理p标签文字样式 let pElements = doc.querySelectorAll('p'); pElements.forEach(pElement => { const spans = pElement.querySelectorAll('span, strong, u, s'); spans.forEach(span => { // 获取颜色和背景色的匹配结果 let colorMatch = span.classList.value.match(/ql-color-#([a-fA-F0-9]{6})/); let bgMatch = span.classList.value.match(/ql-bg-#([a-fA-F0-9]{6})/); // const cb = span.classList.value.match(/ql-color-(#[0-9a-fA-F]{6})\s+ql-bg-(#[0-9a-fA-F]{6})/); // console.log('colorMatch:' + colorMatch); // console.log('bgMatch:' + bgMatch); if (colorMatch) { span.style.color = `#${colorMatch[1]}`; } if(bgMatch){ span.style.background = `#${bgMatch[1]}`; } }); }); // 处理ul,ol标签中的文字样式 let liElements = doc.querySelectorAll('li'); liElements.forEach(liElement => { const lis = liElement.querySelectorAll('span, strong, u, s'); const lis1 = liElement.querySelectorAll('li'); lis.forEach(li => { let colorMatch = li.classList.value.match(/ql-color-#([a-fA-F0-9]{6})/); let bgMatch = li.classList.value.match(/ql-bg-#([a-fA-F0-9]{6})/); // console.log('li colorMatch:' + colorMatch); // console.log('li bgMatch:' + bgMatch); if (colorMatch) { li.style.color = `#${colorMatch[1]}`; } if(bgMatch){ li.style.background = `#${bgMatch[1]}`; } }) // const cb = span.classList.value.match(/ql-color-(#[0-9a-fA-F]{6})\s+ql-bg-(#[0-9a-fA-F]{6})/); }) return doc.body.innerHTML; } // } } // 主函数,移动按钮、初始化 function moveButtonWhenDetected() { // const jbj_btn = document.querySelector('#arc_toolbar_report > div.video-toolbar-right > div.video-note.video-toolbar-right-item.toolbar-right-note > div.video-note-inner'); let jbj_btn = document.querySelector('div.video-note-inner'); // const qxd_btn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.bpx-player-ctrl-btn.bpx-player-ctrl-quality'); const qxd_btn = document.querySelector('div.bpx-player-ctrl-btn.bpx-player-ctrl-quality'); // let full_btn = document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.bpx-player-ctrl-btn.bpx-player-ctrl-full") let full_btn = document.querySelector("div.bpx-player-ctrl-btn.bpx-player-ctrl-full") let wyqp_btn = document.querySelector("div.bpx-player-ctrl-btn.bpx-player-ctrl-web") let note_pc = document.querySelector("div.resizable-component.note-pc") if (jbj_btn && qxd_btn && full_btn && wyqp_btn && note_pc) { // 防止当笔记面板在视频页面后需要两次右键才能打开右键菜单 // note_pc.addEventListener('contextmenu', event => { // event.stopPropagation() // }) close_btn_event() //使笔记始终保持在网页中固定位置,即使网页上下滚动,笔记始终都可见 GM_addStyle(` .fixed-position { position: fixed !important; min-width: 460px !important; } `); note_pc.classList.add('fixed-position'); qxd_btn.parentNode.insertBefore(jbj_btn, qxd_btn); // 重新设置样式,确保移动后的按钮也有正确的样式 // const newJbjBtn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.video-note-inner'); const newJbjBtn = document.querySelector('div.video-note-inner'); if (newJbjBtn) { // 直接修改style属性来应用样式 newJbjBtn.style.marginRight = '25px'; newJbjBtn.style.cursor = 'pointer'; // 注意:颜色需要确保与CSS中定义的一致,这里直接应用白色 newJbjBtn.style.color = 'white'; newJbjBtn.addEventListener("click", (e) => { // jbjBtnOnclickEvent() setTimeout(() => { jbjBtnOnclickEvent() }, 50); }); // noteEvent() setWidthDivBox() // refreshOpacity() setOpacity() // setBtn() ckbj_btn_event() // saveNoteAsPdf() setTimeout(() => { noteEvent() setTimeout(() => { let url = window.location.href; let searchParams = new URLSearchParams(new URL(url).search); // console.log('searchParams:' + searchParams) noteOpen = searchParams.get('note'); // console.log('noteOpen:' + noteOpen) if(noteOpen){ Screenshot() IsJbjClick=true if(note_pc.style.display != 'none'){ editorScrollToBottom() // setTimeout(() => { // editorScrollToBottom() // }, 4600); } setbar() // setScrollbar() refreshScrollbar() setBtn() setTimeout(() => { InsertBtnEvent() editorEvent() editorScrollToLastY() let editor = document.querySelector("div.note-editor") if(editor){ creatNoteImageClikEvent() }else{ console.log('没有找到编辑器,无法添加图片点击事件') } }, 1200); } }, 200); setBtn() saveNoteAsPdf() }, 200); let full_btn = document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.bpx-player-ctrl-btn.bpx-player-ctrl-full") let wyqp_btn = document.querySelector("div.bpx-player-ctrl-btn.bpx-player-ctrl-web") full_btn.addEventListener("click", function () { setTimeout(() => { full_btn_event() }, 60); // full_btn_event() }) wyqp_btn.addEventListener("click", function () { setTimeout(() => { wyqpBtnEvent() }, 60); }) // ctrl打开、隐藏、显示笔记 document.addEventListener('keydown', function (event) { // 检查是否按下Ctrl键 if (event.key === 'Control') { isCtrlPressed = true; // 标记Ctrl键已按下 otherKeyPressed = false; // 重置其他键的状态 // if(!otherKeyPressed){ // isCtrlPressed = true; // 标记Ctrl键已按下 // otherKeyPressed = false; // 重置其他键的状态 // }//ctrl打开笔记后记录后,需要按两次ctrl才能关闭笔记板 } else{ isCtrlPressed = false; // 如果Ctrl键已按下,并且按下了其他键 otherKeyPressed = true; // 标记按下了其他键 } document.addEventListener('keydown', function (event) { // 检查是否按下Ctrl键 if (event.key != 'Control') { isCtrlPressed = false; // 标记Ctrl键已按下 otherKeyPressed = true; // 重置其他键的状态 } }); }); document.addEventListener('keyup', function (event) { if(event.key != 'Control'){ isCtrlPressed = false; } // 检查是否释放了Ctrl键 if (event.key === 'Control') { // isCtrlPressed = false; if (!otherKeyPressed&&isCtrlPressed) { console.log('单独按下Ctrl键并释放,执行逻辑'); // 在这里执行你的逻辑 let note_pc = document.querySelector("div.resizable-component.note-pc") let jbj_btn = document.querySelector('div.video-note-inner'); let jbj_btn_title = newJbjBtn.innerText.trim() if (jbj_btn) { if (note_pc && note_pc.style.display === 'none' && !IsJbjClick) { jbj_btn.click() setTimeout(() => { let ckbj_btn = document.querySelector('div.list-note-operation'); let editor = document.querySelector("div.note-editor") if (ckbj_btn && !editor) { ckbj_btn.click() } }, 50); } else if (note_pc && note_pc.style.display === 'none' && IsJbjClick) { // console.log('按下了菜单键,笔记被显示') note_pc.style.opacity = '1' note_pc.style.display = 'block' setTimeout(() => { editorScrollToLastY() }, 600); let bfy = document.querySelector('div.bpx-player-video-perch'); let bfyHeight = bfy.getBoundingClientRect().height; let wh = window.innerHeight; // 全屏时bfyHeight>=1080,网页全屏时bfyHeight=wh let isqp = bfyHeight === wh || bfyHeight >= 1080; if (isqp) { // 如果是全屏,将笔记显示在页面中间 // note_pc.style.left = "780px"; // note_pc.style.top = "180px"; if (note_pc.style.left != 0 && note_pc.style.right != 0) { note_pc.style.left = "1006px" } note_pc.style.top = "139px" note_pc.style.width = "460px" note_pc.style.height = "600px" } else { note_pc.style.top = '120px' note_pc.style.left = '855px' note_pc.style.width = "460px" note_pc.style.height = "600px" } } else if (note_pc && note_pc.style.display != 'none') { // console.log('按下了菜单键,笔记被隐藏') note_pc.style.display = 'none' } } else { console.log('未找到jbj_btn') } } // 重置状态 isCtrlPressed = false; // 标记Ctrl键已释放 otherKeyPressed = false; // 重置其他键按下状态 } }); // ctrl+左/下/右键移动笔记面板左、中、右 document.addEventListener('keydown', function (event) { if (event.ctrlKey) { let bfy = document.querySelector('div.bpx-player-video-perch'); // if (!bfy) return; // 如果找不到元素,直接返回 let bfyHeight = bfy.getBoundingClientRect().height; let wh = window.innerHeight; let isqp = bfyHeight === wh || bfyHeight >= 1080; let note_pc = document.querySelector("div.resizable-component.note-pc"); if (event.key === 'ArrowLeft') { event.preventDefault(); if (!note_pc || note_pc.style.display === 'none') return; // 如果找不到或隐藏,直接返回 note_pc.style.left = '0'; // 或者根据实际需要调整 note_pc.style.right = ''; // 清除 right 属性 note_pc.style.width = "460px" note_pc.style.height = "600px" } else if (event.key === 'ArrowRight') { event.preventDefault(); if (!note_pc || note_pc.style.display === 'none') return; // 如果找不到或隐藏,直接返回 note_pc.style.right = '0'; // 或者根据实际需要调整 note_pc.style.left = ''; // 清除 left 属性 note_pc.style.width = "460px" note_pc.style.height = "600px" }else if(event.key === 'ArrowDown'){ event.preventDefault(); if (!note_pc || note_pc.style.display === 'none') return; // 如果找不到或隐藏,直接返回 note_pc.style.left = "1006px" note_pc.style.top = "139px" note_pc.style.width = "460px" note_pc.style.height = "600px" } } }); // ctrl+上键插入当前字幕 document.addEventListener('keydown', async function (event) { if (event.ctrlKey && event.key == "ArrowUp") { isBold = false event.preventDefault(); try { let subtitle = document.querySelector('.bpx-player-subtitle-panel-text')?.textContent if(!subtitle){return} subtitle = '字幕: '+ subtitle if (subtitle) { pasteTextToEditor(subtitle) } } catch (err) { console.error('从剪贴板读取文本时出错:', err); } } }) // ctrl+c键插入当前视频标题 document.addEventListener('keydown', function (event) { if (event.ctrlKey && event.key === 'c') { let editor = document.querySelector('.ql-editor'); // 替换为实际的编辑器元素 // if(editor){ // editor.focus(); // } // 检查是否选中了文本或图片 let selection1 = editor.ownerDocument.defaultView.getSelection().toString().trim(); let selectedImages = note_pc.querySelectorAll(".ql-image-preview.active"); // 如果图片有 selected 类,那么该图片是被选中状态 if (selection1 === "" && selectedImages.length === 0) { event.preventDefault(); let text = copyVideoTitleToClipboard(); // 使用await等待Promise解析 pasteTextToEditor(text) } // 获取当前的选择对象 let selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection if (selection && selection.rangeCount > 0) { range = selection.getRangeAt(0); } } }); // ctrl+x快捷键插入截图 document.addEventListener('keydown', function (event) { if (event.ctrlKey && event.key === 'x') { let editor = document.querySelector('.ql-editor'); // 替换为实际的编辑器元素 // 检查是否选中了文本或图片 // selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 selection = window.getSelection().toString().trim(); // 更安全地获取selection,考虑editor所在的文档上下文 let selectedImages = note_pc.querySelectorAll(".ql-image-preview.active"); // 假设图片有 selected 类表示被选中 if (selection === "" && selectedImages.length === 0) { event.preventDefault(); let tp = document.querySelector("span.ql-capture-btn.ql-bar"); if (tp) { if (selection != undefined && selection > 0 && editor.contains(range.startContainer) || editor.contains(range.endContainer)) { tp.click(); }else{ setCursorAtBottom(editor) tp.click(); } // tp.click(); setTimeout(() => { // scrollH = editor.scrollTop getCursorPositionInEditor(editor) // editor.scrollTo(0, scrollH); }, 50); } selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 if(selection){ range = selection.getRangeAt(0); } } // scrollH = document.querySelector('.ql-editor').scrollTop } }); // 点击弹幕的复制按钮后,自动粘贴到笔记中 // let bfy = document.querySelector('div.bpx-player-video-perch'); document.addEventListener('copy', async (event) => { // console.log('弹幕被复制') let copyEl = event.target; if (copyEl.parentNode.classList.contains("bpx-player-container")) { isBold = false let textNode let dmText let editor = document.querySelector('.ql-editor'); try { dmText = await navigator.clipboard.readText(); // 从剪贴板读取文本 if(!dmText){return} dmText = "弹幕:" + dmText pasteTextToEditor(dmText) // console.log('已复制-', dmText) } catch (err) { console.error('读取剪贴板内容失败:', err); } } }) } observer.disconnect(); } } // 创建MutationObserver实例 const observer = new MutationObserver(moveButtonWhenDetected); // 配置观察选项:子节点变化 const config = { childList: true, subtree: true }; // 开始观察body(或其它合适的容器) observer.observe(document.body, config); // 确保DOMContentLoaded后也尝试执行一次,以防元素一开始就存在 window.addEventListener('DOMContentLoaded', moveButtonWhenDetected); // 获取视频帧地址 function getVideoFrameUrl() { let videoEl = document.querySelector('video'); let currentPlayUrl; let pUrl = window.location.href; let currentTime = videoEl.currentTime; // 四舍五入,小数点保留一位 currentTime = Math.round(currentTime * 10) / 10; // console.log('当前时间:' + currentTime); // 计算小时、分钟、秒 let hours = Math.floor(currentTime / 3600); // 小时 let minutes = Math.floor((currentTime % 3600) / 60); // 分钟 let seconds = Math.floor(currentTime % 60); // 秒 // 创建一个 URL 对象 let url = new URL(pUrl); // 获取基础URL(不包括查询参数) let baseUrl = url.origin + url.pathname; // https://www.bilibili.com/video/BV1RL411T7Ai // console.log('baseUrl:' + baseUrl); // 获取查询参数中的 p 值 let pValue = url.searchParams.get('p'); // '2' if(pValue!=null&&pValue!=undefined){ if (pValue > 1) { currentPlayUrl = baseUrl + '?' + 't=' + currentTime + '&p=' + pValue; } else { currentPlayUrl = baseUrl + '?' + 't=' + currentTime; } }else{ currentPlayUrl = baseUrl + '?' + 't=' + currentTime; } // console.log('951currentPlayUrl:' + currentPlayUrl); // 返回当前播放URL和格式化时间 return { url: currentPlayUrl, time: hours > 0 ? `${hours}:${minutes}:${seconds}` : `${minutes}:${seconds}`, p: pValue!=null&&pValue!=undefined?'P'+pValue:'' }; } // 删除时间戳与图片之间的空格br元素 function deleteBr() { //////////////////////////////////////////// // 获取所有匹配 .ql-image-preview 类的元素 let images = document.querySelectorAll(".ql-image-preview"); // 初始化变量以存储最大数字和对应的元素 let maxNumber = -1; let maxImageElement = null; // 遍历每个元素 images.forEach(image => { // 获取 data-id 属性的值 const dataId = image.getAttribute('data-id'); // 提取数字部分 const number = parseInt(dataId.match(/\d+/)[0], 10); // 比较数字,更新最大数字和对应的元素 if (number > maxNumber) { maxNumber = number; maxImageElement = image; } }); let currentImage = maxImageElement.previousElementSibling; // let currentImage = lastImage.previousElementSibling; if (currentImage && currentImage.tagName === 'P') { currentImage.parentNode.removeChild(currentImage) } else { console.log('没有找到匹配的元素'); } } // 插入截屏的同时也插入时间标记 function Screenshot() { // 插入截屏按钮 setTimeout(() => { let tp = document.querySelector("span.ql-capture-btn.ql-bar"); // 插入时间标记按钮 let tm = document.querySelector("span.ql-tag-btn.ql-bar-btn"); let note_editor = document.querySelector("div.note-editor") if (tp && tm) { tp.removeEventListener("click", (e) => { tm.click() creatNoteImageClikEvent(); // tm.click() setTimeout(() => { deleteBr() }, 1300) }) tp.addEventListener("click", (e) => { tm.click() creatNoteImageClikEvent(); // tm.click() setTimeout(() => { deleteBr() }, 1300) }); let observerActive = false; tm.addEventListener("click", () => { if (observerActive) return; if (IsInsert) return; const insert = () => { let tm_qd = document.querySelector("div.dialog-btn.tag-dialog__btn--confirm"); if (tm_qd) { tm_qd.click(); setTimeout(() => { let editor=document.querySelector('.ql-editor') if(editor){ if(editor.scrollHeight-editor.scrollTop<=900){ // editor.scrollTo(0, editor.scrollHeight); editor.scrollTop = editor.scrollHeight scrollH = editor.scrollHeight } selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 if(selection){ range = selection.getRangeAt(0); }else{ console.log('无法获取选择区') } // 获取当前光标位置并存储在变量中,下次打开笔记同步光标位置 getCursorPositionInEditor(editor) } }, 700); observer.disconnect(); observerActive = false; } }; const observer = new MutationObserver(insert); const config = { childList: true, subtree: true }; observer.observe(note_editor, config); observerActive = true; }); } else { console.log("无法找到截屏按钮或时间标记按钮"); } }, 1000); } function full_btn_event() { // let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); // let bfyHeight = bfy.getBoundingClientRect().height; let note_pc = document.querySelector("div.resizable-component.note-pc") // let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); let bfy = document.querySelector('div.bpx-player-video-perch'); // 防止按菜单键时,焦点在电脑任务栏上取用默认操作 // bfy.focus() let bfyHeight = bfy.getBoundingClientRect().height; // let wh = window.innerHeight; if (note_pc && bfyHeight != 1080 && IsJbjClick) { setNotePanel() } else if (note_pc && bfyHeight == 1080 && IsJbjClick) { let infoflow = document.querySelector("#__infoflow_commercial") let biliMainHeader = document.querySelector("#biliMainHeader") if (infoflow) { infoflow.parentNode.insertBefore(note_pc, infoflow) } else if (biliMainHeader) { biliMainHeader.parentNode.insertBefore(note_pc, biliMainHeader) } else { console.log("没有找到infoflow和biliMainHeader节点") } setTimeout(() => { note_pc.style.left = "1006px" note_pc.style.top = "139px" }, 10); } setTimeout(() => { let editor = document.querySelector('.ql-editor'); if(editor&&editor.style.display!="none"){ editorScrollToLastY() } }, 1); } // 滚动到原来位置函数 function wyqpBtnEvent() { let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); let wh = window.innerHeight; let bfyHeight = bfy.getBoundingClientRect().height; let note_pc = document.querySelector("div.resizable-component.note-pc") // 防止按菜单键时,焦点在电脑任务栏上取用默认操作 // bfy.focus() if (bfyHeight == wh && IsJbjClick) { setNotePanel() } else { if (note_pc && IsJbjClick) { let infoflow = document.querySelector("#__infoflow_commercial") let biliMainHeader = document.querySelector("#biliMainHeader") if (infoflow) { infoflow.parentNode.insertBefore(note_pc, infoflow) } else if (biliMainHeader) { biliMainHeader.parentNode.insertBefore(note_pc, biliMainHeader) } else { console.log("没有找到infoflow和biliMainHeader节点") } setTimeout(() => { note_pc.style.left = "1006px" note_pc.style.top = "139px" }, 10); } } setTimeout(() => { let editor = document.querySelector('.ql-editor'); if(editor&&editor.style.display!="none"){ editorScrollToLastY() } }, 1); } //////////////////////////////////////////// function MyNoteBtnClick() { const userNames = document.querySelectorAll('.user-name'); // 统计这些元素的数量 const count = userNames.length; // 输出结果 // console.log(`user-name 的个数是: ${count}`); for (let i = 0; i < count; i++) { let note_card_container = document.querySelector(`div.note-card-container > div:nth-child(${i + 1})`); if (note_card_container) { note_card_container.addEventListener('click', function () { // IsMyNote = false; // creatNoteImageClikEvent() let MyNoteBtn = document.querySelector("div.note-operation.detail"); if (MyNoteBtn) { MyNoteBtn.addEventListener('click', handleMyNoteBtnClick); } else { console.log('没有找到MyNoteBtn'); } }); } } } function OnNoteListWheel() { let NoteList = document.querySelector("div.note-content > div") if (NoteList) { NoteList.addEventListener('wheel', e => { let MyNoteBtn = document.querySelector("div.note-operation"); if (MyNoteBtn) { MyNoteBtn.addEventListener('click', handleMyNoteBtnClick); } else { console.log('没有找到MyNoteBtn'); } }); } else { console.log('没有找到NoteList'); } } function handleMyNoteBtnClick() { setTimeout(() => { refreshBtn(); back_note_btn_event(); }, 0); } function close_btn_event() { let close_btn = document.querySelector("div.close-note") if (!close_btn) return; close_btn.addEventListener("click", (e) => { isClose = true IsJbjClick = false isTmAddLisner = false }) } // 查看笔记按钮事件 function ckbj_btn_event() { // let note_pc = document.querySelector("resizable-component.note-pc") // note_pc.style.width = "460px" let thumb = document.querySelector("div.ZDscrollbar.custom-scrollbar > div > div") if (thumb) { thumb.style.top = "0" } range = "" let ckbj_btn = document.querySelector('div.list-note-operation'); if (ckbj_btn) { ckbj_btn.addEventListener('click', function () { IsMyNote = true setTimeout(() => { let ql_editor = document.querySelector(".ql-editor") if (ql_editor) { ql_editor.style.overflowY = "auto" ql_editor.style.overflowX = "hidden" } else { console.log("没有找到ql_editor,无法修改滚动条样式") } let note_editor = document.querySelector("div.note-editor") note_editor.style.height = "96%" setTimeout(() => { editorScrollToBottom() }, 50); // editorScrollToBottom() creatNoteImageClikEvent()//点击笔记中图片触发事件 Screenshot() isTmAddLisner = true InsertBtnEvent() refreshScrollbar() back_note_btn_event() editorEvent() setTimeout(() => { InsertBtnEvent() editorScrollToBottom() }, 65); }, 5); }) } } // 从笔记页面后退按钮的事件 function back_note_btn_event() { let back_note_btn = document.querySelector("div.back-note-list") if (back_note_btn) { back_note_btn.addEventListener("click", function () { // IsNotePcHightChange=false isTmAddLisner = false scrollbarDisplay("hide") // BtnDisplay("hide") let note_pc = document.querySelector("div.resizable-component.note-pc") if (note_pc.style.opacity != 1) { note_pc.style.opacity = 1 } // 重置透明度值 let opacitySlider = document.querySelector("div.sliderContainer > input") if (opacitySlider) { opacitySlider.value = 0 } let label2 = document.querySelector("div.sliderContainer > label2") if (label2) { label2.textContent = '0%' } // ckbj_btn_event() }) } else { console.log("没有找到back_note_btn") } } // 添加各种点击记笔记的监听事件 function jbjBtnOnclickEvent() { let thumb = document.querySelector("div.ZDscrollbar.custom-scrollbar > div > div") if (thumb) { thumb.style.top = "0" } if(!isClose){ let note_pc = document.querySelector("div.resizable-component.note-pc") if(note_pc&¬e_pc.style.display==='none'){ note_pc.style.display = 'block' } } range = "" isClose = false IsJbjClick = true let opacitySlider = document.querySelector("div.sliderContainer > input") if (opacitySlider) { opacitySlider.value = 0 } let label2 = document.querySelector("div.sliderContainer > label2") if (label2) { label2.textContent = '0%' } let note_list = document.querySelector("div.note-list") if (note_list) { note_list.style.height = '96%'; } let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); let ql_editor = document.querySelector(".ql-editor") if (ql_editor) { ql_editor.style.overflowY = "auto" ql_editor.style.overflowX = "hidden" } let bfyHeight = bfy.getBoundingClientRect().height; let wh = window.innerHeight; if (bfyHeight == wh) { setNotePanel() } noteEvent() refreshBar() // 笔记宽度 // refreshWidthDivBox() // 笔记透明度 // refreshOpacity() close_btn_event() let newJbjBtn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.video-note-inner'); let jbj_btn_title = newJbjBtn.innerText.trim() let note_pc = document.querySelector("div.resizable-component.note-pc"); if (note_pc) { note_pc.style.width = "460px" note_pc.style.height = '600px' note_pc.addEventListener('mouseover', (e) => { note_pc.addEventListener('wheel', (e) => { e.stopPropagation(); }) }) note_pc.addEventListener('mousedown', (e) => { note_pc.addEventListener('wheel', (e) => { e.stopPropagation(); }) }) note_pc.addEventListener('mouseup', (e) => { note_pc.addEventListener('wheel', (e) => { e.stopPropagation(); }) }) } else { console.log("1028:没有找到note_pc") } if (note_pc.style.opacity != 1) { note_pc.style.opacity = 1 } if (jbj_btn_title === "记笔记") { // console.log("1 if (jbj_btn_title == 记笔记)执行") IsMyNote = true isTmAddLisner = true setTimeout(() => { let note_editor = document.querySelector("div.note-editor") if(note_editor){ note_editor.style.height = "96%" editorEvent() back_note_btn_event() // 给笔记中图片添加点击事件,点击图片弹出 creatNoteImageClikEvent() // 插入截屏的同时插入时间标记 Screenshot() // editorEvent() InsertBtnEvent() editorScrollToBottom() refreshScrollbar() } }, 100); } else { OnNoteListWheel() MyNoteBtnClick() scrollbarDisplay("hide") } let bar = document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch > div.custom-bar-class") // let bfyHeight = bfy.getBoundingClientRect().height; if (bfyHeight >= 1080) { bar.style.display = "block" } } // 1.笔记面板宽度控制条相关 // 判断WidthDivBoxExist是否存在如果不存在则添加宽度控制条,存在则删除后重新添加才能不出错保持监听事件有效 function refreshWidthDivBox() { let widthDivBox = document.querySelector("div.width-control-box") if (!widthDivBox) { setWidthDivBox() } } // 设置宽度控制条 function setWidthDivBox() { let note_pc = document.querySelector("div.resizable-component.note-pc") note_pc.style.width = "460px" //使笔记始终保持在网页中固定位置,即使网页上下滚动,笔记始终都可见 GM_addStyle(` .fixed-position { position: fixed !important; } `); note_pc.classList.add('fixed-position'); // 创建一个新的div来容纳滑块和标签,并添加类名 let widthDivBox = document.createElement('div'); widthDivBox.className = 'width-control-box'; widthDivBox.style.width = '405px'; widthDivBox.style.marginLeft = '25px'; // widthDivBox.style.height = '15px'; widthDivBox.style.height = '1.5%'; // widthDivBox.style.marginBottom = '1.4%'; // 创建并设置宽度滑块左侧标签,并添加类名 let widthLab1 = document.createElement('label'); widthLab1.className = 'width-slider-label'; widthLab1.textContent = '宽度'; widthLab1.style.fontSize = '15px'; widthLab1.style.borderRadius = "10px"; widthLab1.style.marginRight = '2.5px'; widthLab1.style.color = "rgb(19, 72, 87)"; // 创建并设置宽度滑块右侧标签,并添加类名 let widthLab2 = document.createElement('label'); widthLab2.className = 'width-slider-value'; // widthLab2.textContent = '800px'; widthLab2.textContent = '460px'; widthLab2.style.borderRadius = "10px"; widthLab2.style.color = "rgb(19, 72, 87)"; widthLab1.style.marginRight = '2.5px'; widthLab2.style.fontSize = '15px'; // widthLab2.style.right = '0'; // 创建宽度滑块,并添加类名 let widthSlider = document.createElement('input'); widthSlider.className = 'width-slider'; widthSlider.type = 'range'; widthSlider.min = '460'; widthSlider.max = '1912'; widthSlider.step = '1'; // widthSlider.value = note_pc.offsetWidth.toString(); // 初始值为当前宽度 widthSlider.value = '460'; // 初始值为当前宽度 // 设置宽度滑块样式 widthSlider.style.marginRight = '2.5px'; widthSlider.style.height = "8px"; widthSlider.style.width = "300px"; widthSlider.style.outline = "none"; widthSlider.style.backgroundColor = "#003300"; // widthSlider.style.backgroundColor = "skyblue"; widthSlider.style.opacity = "1"; widthSlider.style.cursor = "pointer"; widthLab1.addEventListener('mousedown', function (e) { e.preventDefault(); e.stopPropagation(); }) widthLab2.addEventListener('mousedown', function (e) { e.preventDefault(); e.stopPropagation(); }) setTimeout(() => { // 添加事件监听器来响应滑块的变化 // 笔记中有图片时,图片宽度也需要单独调节 const img = document.getElementsByClassName('ql-image-preview'); const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.attributeName === 'style') { const width = parseInt(note_pc.style.width.replace('px', ''), 10); widthSlider.value = width; widthLab2.textContent = width + 'px'; // widthLab2.textContent = 460 + 'px'; } }); }); // 观察note_pc的style属性 observer.observe(note_pc, { attributes: true, attributeFilter: ['style'] }); widthSlider.addEventListener("input", function (e) { e.preventDefault(); e.stopPropagation(); let value = widthSlider.value; note_pc.style.width = value + 'px'; if (img) { for (let i = 0; i < img.length; i++) { // 为当前元素设置宽度 img[i].style.width = value + 'px'; } } widthLab2.textContent = value + 'px'; }); }, 50); // 将元素添加到DOM中 widthDivBox.appendChild(widthLab1); widthDivBox.appendChild(widthSlider); widthDivBox.appendChild(widthLab2); let note_content = document.querySelector("div.note-content") if (note_content) { note_content.parentNode.insertBefore(widthDivBox, note_content); } else { console.log("note_content元素不存在") } } // 2.笔记内容高度控制条 // 刷新笔记面板内容高度控制条 function refreshScrollbar() { // 类名:ZDscrollbar if (isFirefox()) { // console.log('这是火狐浏览器,不需要添加滚动条'); return; } if(isEdge()){ // console.log('这是Edge浏览器,不需要添加滚动条'); return; } let note_pc = document.querySelector("div.resizable-component.note-pc") if (!note_pc) return; let scrollbar = document.querySelector("div.ZDscrollbar.custom-scrollbar") if (scrollbar && scrollbar.style.display == "none") { scrollbarDisplay("show") refreshScrollBarListener(scrollbar) } else if (!scrollbar) { setScrollbar() } function refreshScrollBarListener(s) { function alteration() { let contentHeight; let scrollbar = s; let isDragging = false; let dragStartPos = 0; // dragStartPos = 0; let editor = document.querySelector('.ql-editor'); if (!editor) { // console.log("1246:未找到 editor 元素") } let track = document.querySelector("div.ZDscrollbar.custom-scrollbar > div") let thumb = document.querySelector("div.ZDscrollbar.custom-scrollbar > div > div") if (!IsNotePcHightChange) { thumb.style.top = '0'; } // thumb.style.top = '0'; let scrollbarHeight; let note_pcHeight; track.addEventListener('mouseover', () => { contentHeight = editor.scrollHeight; note_pcHeight = editor.clientHeight; scrollbarHeight = scrollbar.clientHeight; }); editor.addEventListener('mouseover', () => { contentHeight = editor.scrollHeight; note_pcHeight = editor.clientHeight; scrollbarHeight = scrollbar.clientHeight; }); editor.addEventListener('mouseover', () => { contentHeight = editor.scrollHeight; note_pcHeight = editor.clientHeight; scrollbarHeight = scrollbar.clientHeight; }); editor.addEventListener('scroll', () => { // contentHeight = editor.scrollHeight; // scrollbarHeight = scrollbar.clientHeight; // note_pcHeight = editor.clientHeight; let scrollTop = editor.scrollTop; let thumbTop = (scrollTop / (contentHeight - note_pcHeight)) * (scrollbarHeight - thumb.clientHeight); thumb.style.top = `${thumbTop}px`; }); // let isDragging = false; // let dragStartPos = 0; // dragStartPos = 0; thumb.addEventListener('mousedown', (e) => { e.preventDefault(); // 取消默认操作,阻止链接跳转 e.stopPropagation(); // 阻止事件冒泡到其他监听器 isDragging = true; dragStartPos = e.clientY - thumb.offsetTop; }); thumb.addEventListener('mouseover', (e) => { thumb.style.opacity = '1'; }); thumb.addEventListener('mouseout', (e) => { thumb.style.opacity = '0.3'; }); document.addEventListener('mouseup', () => { isDragging = false; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; let newTop = Math.max(0, Math.min(scrollbarHeight - thumb.clientHeight, e.clientY - dragStartPos)); thumb.style.top = `${newTop}px`; let scrollFraction = newTop / (scrollbarHeight - thumb.clientHeight); editor.scrollTop = scrollFraction * (contentHeight - note_pcHeight); }); } const ro = new ResizeObserver(entries => { IsNotePcHightChange = true entries.forEach(entry => { alteration(); // console.log(`note_pc高度发生变化 ${entry.contentRect.height}`); }); }); ro.observe(note_pc); } } function scrollbarDisplay(displayState) { if (isFirefox()) { // console.log('这是火狐浏览器'); return; } if(isEdge()){ // console.log('这是Edge浏览器'); return; } let scrollbar = document.querySelector("div.ZDscrollbar.custom-scrollbar") if (scrollbar === null) { console.error(" Scrollbar element not found."); return; } if (displayState === "hide") { scrollbar.style.display = "none"; } else if (displayState === "show") { scrollbar.style.display = "block"; } else { console.warn("Invalid display state. Expected 'hide' or 'show'."); } } // 设置笔记内容高度控制条 function setScrollbar() { if (isFirefox()) { // console.log('这是火狐浏览器'); return; } if(isEdge()){ // console.log('这是Edge浏览器'); return; } let note_pc = document.querySelector("div.resizable-component.note-pc") if (note_pc === null) { console.error("没有找到note_pc"); return; } const scrollbar = document.createElement('div'); scrollbar.className = 'ZDscrollbar'; scrollbar.classList.add('custom-scrollbar'); scrollbar.style.position = 'absolute'; // scrollbar.style.top = note_pc.style.top; scrollbar.style.top = '0'; scrollbar.style.width = '12px'; scrollbar.style.height = '100%'; scrollbar.style.right = '-13px'; const track = document.createElement('div'); track.className = 'track'; track.style.width = '100%'; track.style.height = '100%'; track.style.backgroundColor = "#f0f0f0"; track.style.borderRadius = '3px'; const thumb = document.createElement('div'); thumb.className = 'thumb'; thumb.style.position = 'relative'; thumb.style.width = '100%'; thumb.style.backgroundColor = "#888"; thumb.style.borderRadius = '5px'; thumb.style.opacity = '0.3'; thumb.style.height = '49px'; // 鼠标移到thumb后光标变成小手: thumb.style.cursor = 'pointer'; track.appendChild(thumb); scrollbar.appendChild(track); // bjk_box.parentNode.appendChild(scrollbar); note_pc.appendChild(scrollbar); // alteration() setTimeout(() => { let ckbj_btn = document.querySelector('div.list-note-operation'); if(ckbj_btn){ ckbj_btn.addEventListener('click',()=>{ note_pc.style.width = '460px' alteration() }) }else{ note_pc.style.width = '460px' alteration() } }, 3000); function alteration() { if (isFirefox()) { // console.log('这是火狐浏览器'); return; } if(isEdge()){ // console.log('这是Edge浏览器'); return; } let editor = document.querySelector('.ql-editor'); let contentHeight; let scrollbarHeight; let note_pcHeight; if (!IsNotePcHightChange) { thumb.style.top = '0'; } // thumb.style.top = '0'; track.addEventListener('mouseover', () => { contentHeight = editor.scrollHeight; note_pcHeight = editor.clientHeight; scrollbarHeight = scrollbar.clientHeight; }); editor.addEventListener('mouseover', () => { contentHeight = editor.scrollHeight; note_pcHeight = editor.clientHeight; scrollbarHeight = scrollbar.clientHeight; }); editor.addEventListener('scroll', () => { let scrollTop = editor.scrollTop; let thumbTop = (scrollTop / (contentHeight - note_pcHeight)) * (scrollbarHeight - thumb.clientHeight); thumb.style.top = `${thumbTop}px`; }); let isDragging = false; let dragStartPos = 0; isDragging = false; dragStartPos = 0; thumb.addEventListener('mousedown', (e) => { e.preventDefault(); // 取消默认操作,阻止链接跳转 e.stopPropagation(); // 阻止事件冒泡到其他监听器 isDragging = true; dragStartPos = e.clientY - thumb.offsetTop; }); thumb.addEventListener('mouseover', (e) => { thumb.style.opacity = '1'; }); thumb.addEventListener('mouseout', (e) => { thumb.style.opacity = '0.3'; }); document.addEventListener('mouseup', () => { isDragging = false; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; let newTop = Math.max(0, Math.min(scrollbarHeight - thumb.clientHeight, e.clientY - dragStartPos)); thumb.style.top = `${newTop}px`; let scrollFraction = newTop / (scrollbarHeight - thumb.clientHeight); editor.scrollTop = scrollFraction * (contentHeight - note_pcHeight); }); } note_pc = document.querySelector("div.resizable-component.note-pc") const ro = new ResizeObserver(entries => { IsNotePcHightChange = true entries.forEach(entry => { alteration(); // console.log(`note_pc高度发生变化 ${entry.contentRect.height}`); }); }); ro.observe(note_pc); } // 3.透明度控制条 // 刷新笔记面板内容高度控制条 function refreshOpacity() { let OpacityBox = document.querySelector("div.sliderContainer") if (OpacityBox) { return } else { setOpacity() } } function setOpacity() { let opacitySliderBox = document.createElement('div'); opacitySliderBox.className = 'sliderContainer'; // 添加类名 opacitySliderBox.style.width = '405px'; opacitySliderBox.style.marginLeft = '25px'; // opacitySliderBox.style.height = '15px'; opacitySliderBox.style.height = '3%'; opacitySliderBox.style.marginTop = '10px'; // opacitySliderBox.style.marginBottom = '1%'; opacitySliderBox.style.marginBottom = '10px'; // opacitySliderBox.style.backgroundColor = '#000000'; let lab1 = document.createElement('label');////// lab1.className = 'sliderLabel1'; // 添加类名 lab1.textContent = '透明'; lab1.style.fontSize = '15px'; lab1.style.borderRadius = "10px"; lab1.style.marginRight = '2.5px'; // lab1.style.color = "#000000"; lab1.style.color = "#020205"; let lab2 = document.createElement('label'); lab2.className = 'sliderLabel2'; // 添加类名 lab2.textContent = '0%'; lab2.style.borderRadius = "10px"; // lab2.style.color = "#000000"; lab2.style.color = "#020205"; // lab2.style.background = '#663366'; lab2.style.right = '50px'; // 可能需要调整,因为right属性通常与position属性一起使用 lab2.style.fontSize = '15px'; lab2.style.fontWeight = "bold"; let opacitySlider = document.createElement('input'); opacitySlider.className = 'opacitySlider'; // 添加类名 opacitySlider.type = 'range'; opacitySlider.min = '0'; opacitySlider.max = '0.99'; opacitySlider.step = '0.01'; opacitySlider.value = '0'; // 滑块样式 opacitySlider.style.marginRight = '2.5px'; opacitySlider.style.height = "8px"; opacitySlider.style.width = "300px"; opacitySlider.style.outline = "none"; opacitySlider.style.backgroundColor = "#000000"; opacitySlider.style.color = "#000000"; opacitySlider.style.opacity = "1"; opacitySlider.style.cursor = "pointer"; // 将元素添加到DOM中 opacitySliderBox.appendChild(lab1); opacitySliderBox.appendChild(opacitySlider); opacitySliderBox.appendChild(lab2); let note_pc = document.querySelector("div.resizable-component.note-pc"); // 透明度滑动调整 opacitySlider.addEventListener("input", function (e) { e.preventDefault(); e.stopPropagation(); let value = opacitySlider.value; note_pc.style.opacity = 1 - value; // 调整透明度 let text_value = Math.round(value * 100); lab2.textContent = text_value + '%'; }); // 鼠标移入透明度调节滑块时,弹窗提示鼠标所x在位置透明度数值 opacitySlider.addEventListener('mousemove', function (event) { // 获取滑块的宽度和鼠标的位置 let rect = opacitySlider.getBoundingClientRect(); let offsetX = event.clientX - rect.left; let sliderWidth = rect.width; // 计算滑块的值 let value = (offsetX / sliderWidth) * (opacitySlider.max - opacitySlider.min) + opacitySlider.min; value = Math.round(value * 100); // 保留两位小数 opacitySlider.title = '透明度调整为: ' + value + "%"; }); // 将组件添加到页面中 let width_control_box = document.querySelector("div.width-control-box"); width_control_box.insertAdjacentElement('afterend', opacitySliderBox); } // 监听键盘事件 document.addEventListener('keydown', function (event) { if (event.altKey && (event.key >= '0' && event.key <= '9')) { event.preventDefault(); // 阻止在其他输入区域的默认行为 event.stopPropagation(); let note_pc = document.querySelector("div.resizable-component.note-pc") let opacitySlider = document.querySelector('.opacitySlider') let editor = document.querySelector("div.ql-editor") if(editor){ editor.blur() } // 添加输入的数字 inputNumber += event.key; // 如果输入的第一个数字是 0,直接设置透明度为 0 if (inputNumber.length === 1 && inputNumber[0] === '0') { note_pc.style.opacity = 1; // 设置为 0% 透明度 document.querySelector('.sliderLabel2').textContent = '0%'; // 更新显示 opacitySlider.value=0 inputNumber = ''; // 重置输入 return; // 结束事件处理 } // 限制输入为两位数字 if (inputNumber.length === 2) { // 让笔记面板失去焦点,避免调整透明度时在笔记面板输入字符 // if(editor){ // editor.blur() // } inputNumber = inputNumber.slice(-2); // 保留最后两位 let opacityValue = parseFloat(inputNumber) / 100; // 将输入值转换为 0-1 范围的透明度 if (opacityValue >= 0 && opacityValue <= 1) { note_pc.style.opacity = 1 - opacityValue; // 设置透明度 document.querySelector('.sliderLabel2').textContent = inputNumber + '%'; // 更新显示 opacitySlider.value = opacityValue; // 同步更新滑块的值 inputNumber = ''; } } } }); //静态 仅适用于笔记面板未隐藏状态,按alr键设置editor光标焦点 function setEditorFocus(editor){ if(editor){ if(!isEditorFocused(editor)){ if(targetNode!=null&&targetNode!=undefined&&position!=null&&position!=undefined&&position!=-1){ if(editor.scrollHeight-editor.scrollTop<=900){ setCursorAtBottom(editor) editor.scrollTop=editor.scrollHeight }else{ setCursorAtNodePosition(editor, targetNode, position) } }else{ editor.scrollTop=editor.scrollHeight // setCursorAtBottom(editor) } }else{ let bfy = document.querySelector('div.bpx-player-video-perch'); scrollH = editor.scrollTop editor.blur() bfy.focus() } // editor.focus() scrollH = editor.scrollTop getCursorPositionInEditor(editor) } } // 清空输入状态 document.addEventListener('keyup', function (event) { if (event.key === 'Alt') { // 清空输入数字 let editor = document.querySelector("div.ql-editor") inputNumber = ''; setTimeout(() => { setEditorFocus(editor) }, 50) } }); /////////////////////////////////测试线//////////////////////////////////// // 4.到顶部/到底部按钮 function refreshBtn() { let BtnBox = document.querySelector("div.note-header.drag-el > div.scrollButtonWrapper") if (BtnBox) { BtnDisplay('show') refreshBtnlistener() return; } else { setBtn() } } function BtnDisplay(displayState) { let BtnBox = document.querySelector("div.scrollButtonWrapper") if (!BtnBox) { return; } if (displayState == "hide") { BtnBox.style.display = "none"; } else if (displayState == "show") { BtnBox.style.display = "block"; } } function setBtn() { let btnContainer = document.createElement('div'); btnContainer.className = 'scrollButtonWrapper'; // 添加类名 btnContainer.style.left = "150px"; btnContainer.style.position = "absolute"; btnContainer.style.backgroundColor = "transparent"; // 设置背景为透明 // 创建到顶部按钮 let toTopBtn = document.createElement("button"); toTopBtn.className = 'scrollToTopBtn'; // 添加类名 toTopBtn.style.backgroundImage = "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjNjY2NjY2IiBkPSJNNSA1VjRoMTR2MXptNi41IDE1VjkuNjA4bC0zLjEgMy4xTDcuNjkyIDEyTDEyIDcuNjkyTDE2LjMwOCAxMmwtLjcwOC43MDhsLTMuMS0zLjFWMjB6Ii8+PC9zdmc+')"; // 使用 Base64 编码的图片 toTopBtn.style.backgroundSize = "cover"; // 使背景图片覆盖整个按钮 toTopBtn.style.width = "22px"; // 设置按钮宽度 toTopBtn.style.height = "25px"; // 设置按钮高度 toTopBtn.style.border = "none"; // 移除按钮边框 toTopBtn.style.cursor = "pointer"; // 设置鼠标悬停样式 toTopBtn.title = '到顶部'; toTopBtn.style.marginRight = "5px" toTopBtn.style.backgroundColor = "transparent"; // 创建到底部按钮 let toBottomBtn = document.createElement("button"); toBottomBtn.className = 'scrollToBottomBtn'; // 添加类名 toBottomBtn.style.backgroundImage = "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjNjY2NjY2IiBkPSJNNSAyMHYtMWgxNHYxem03LTMuNjkyTDcuNjkyIDEybC43MDgtLjcwOGwzLjEgMy4xVjRoMXYxMC4zOTJsMy4xLTMuMWwuNzA4LjcwOHoiLz48L3N2Zz4=')"; // 使用 Base64 编码的图片 toBottomBtn.style.backgroundSize = "cover"; // 使背景图片覆盖整个按钮 toBottomBtn.style.width = "22px"; // 设置按钮宽度 toBottomBtn.style.height = "25px"; // 设置按钮高度 toBottomBtn.style.border = "none"; // 移除按钮边框 toBottomBtn.style.cursor = "pointer"; // 设置鼠标悬停样式 toBottomBtn.title = '到底部'; toBottomBtn.style.marginRight = "5px" toBottomBtn.style.backgroundColor = "transparent"; // 创建隐藏按钮 let hideBtn = document.createElement("button"); hideBtn.className = 'hide'; // 添加类名 hideBtn.style.backgroundImage = "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjNjY2NjY2IiBkPSJtOS44MDggMTQuODhsLTQuNzQgNC43NDdxLS4xNDcuMTQ2LS4zNDUuMTU2dC0uMzYzLS4xNTZ0LS4xNjYtLjM1N3QuMTY2LS4zNTZsNC43NC00Ljc0MUg2LjU1OHEtLjIxMyAwLS4zNTYtLjE0NHEtLjE0NC0uMTQ0LS4xNDQtLjM1N3QuMTQ0LS4zNTZ0LjM1Ni0uMTQzSDEwcS4zNDMgMCAuNTc2LjIzMnQuMjMyLjU3NnYzLjQ0MnEwIC4yMTMtLjE0NC4zNTZ0LS4zNTcuMTQ0dC0uMzU2LS4xNDR0LS4xNDMtLjM1NnpNMTQuOSA5Ljc5aDIuNTQycS4yMTMgMCAuMzU3LjE0NHEuMTQzLjE0My4xNDMuMzU2dC0uMTQzLjM1NnQtLjM1Ny4xNDRIMTRxLS4zNDMgMC0uNTc1LS4yMzN0LS4yMzMtLjU3NVY2LjUzOXEwLS4yMTMuMTQ0LS4zNTd0LjM1Ny0uMTQzdC4zNTYuMTQzdC4xNDMuMzU3VjkuMDhsNC43NC00Ljc0NnEuMTQ3LS4xNDYuMzQ1LS4xNTZ0LjM2NC4xNTZxLjE2NS4xNjUuMTY1LjM1NnEwIC4xOTItLjE2Ni4zNTd6Ii8+PC9zdmc+')"; // 使用 Base64 编码的图片 hideBtn.style.backgroundSize = "cover"; // 使背景图片覆盖整个按钮 hideBtn.style.width = "22px"; // 设置按钮宽度 hideBtn.style.height = "25px"; // 设置按钮高度 hideBtn.style.border = "none"; // 移除按钮边框 hideBtn.style.cursor = "pointer"; // 设置鼠标悬停样式 hideBtn.title = '隐藏-隐藏后鼠标移到视频右边框可显示笔记'; hideBtn.style.backgroundColor = "transparent"; // 将按钮添加到容器中 btnContainer.appendChild(toTopBtn); btnContainer.appendChild(toBottomBtn); btnContainer.appendChild(hideBtn); let newJbjBtn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.video-note-inner'); let jbj_btn_title = newJbjBtn.innerText.trim() if (jbj_btn_title === "记笔记") { newJbjBtn.addEventListener("click", (e) => { setTimeout(() => { let note_message = document.querySelector("div.status-bar.note-message") // let close_note = document.querySelector("div.close-note") // 将容器添加到gkbj_btn的父节点中 if (note_message) { // alert('找到了公开笔记按钮') note_message.parentNode.insertBefore(btnContainer, note_message); setTimeout(() => { setBtnEvent(); }, 0); // setBtnEvent(); } else { console.log('没找到公开笔记按钮') } }, 100); }) } else { newJbjBtn.addEventListener("click", (e) => { let ckbj_btn = document.querySelector('div.list-note-operation'); if (ckbj_btn) { ckbj_btn.addEventListener("click", (e) => { setTimeout(() => { let note_message = document.querySelector("div.status-bar.note-message") // let close_note = document.querySelector("div.close-note") // 将容器添加到gkbj_btn的父节点中 if (note_message) { // alert('找到了公开笔记按钮') note_message.parentNode.insertBefore(btnContainer, note_message); setTimeout(() => { setBtnEvent(); }, 0); // setBtnEvent(); } else { console.log('没找到公开笔记按钮') } }, 5); }) } else { console.log('1648 没找到公开笔记按钮') } }) } setTimeout(() => { let ckbj_btn = document.querySelector('div.list-note-operation'); ckbj_btn.addEventListener("click", (e) => { let note_message = document.querySelector("div.status-bar.note-message") // let close_note = document.querySelector("div.close-note") // 将容器添加到gkbj_btn的父节点中 if (note_message) { // alert('找到了公开笔记按钮') note_message.parentNode.insertBefore(btnContainer, note_message); setTimeout(() => { setBtnEvent(); }, 0); // setBtnEvent(); } else { console.log('没找到公开笔记按钮') } }) setTimeout(() => { let note_message = document.querySelector("div.status-bar.note-message") if(note_message){ note_message.parentNode.insertBefore(btnContainer, note_message); setTimeout(() => { setBtnEvent(); }, 0); } }, 3000); let note_message = document.querySelector("div.status-bar.note-message") if(note_message){ note_message.parentNode.insertBefore(btnContainer, note_message); setTimeout(() => { setBtnEvent(); }, 0); } }, 300); // 设置事件监听器 function setBtnEvent() { let editor = document.querySelector("div.ql-editor") toBottomBtn.addEventListener("click", (e) => { editor.scrollTo(0, editor.scrollHeight); // scrollH = document.querySelector('.ql-editor').scrollTop // scrollH = document.querySelector('.ql-editor').scrollTop let thumb = document.querySelector("div.ZDscrollbar.custom-scrollbar > div > div") let scrollbar = document.querySelector("div.ZDscrollbar.custom-scrollbar") if (thumb) { thumb.style.top = scrollbar.clientHeight - thumb.clientHeight + "px" // refreshScrollBarListener(scrollbar) } setCursorAtBottom(editor) e.stopPropagation(); }); toTopBtn.addEventListener("click", (e) => { editor.scrollTo(0, 0); // scrollH = document.querySelector('.ql-editor').scrollTop let scrollbar = document.querySelector("div.ZDscrollbar.custom-scrollbar") let thumb = document.querySelector("div.ZDscrollbar.custom-scrollbar > div > div") if (thumb) { thumb.style.top = "0px" // refreshScrollBarListener(scrollbar) } setCursorAtTop(editor) e.stopPropagation(); }); hideBtn.addEventListener('click', (e) => { let editor = document.querySelector('.ql-editor'); if (editor) { scrollH = editor.scrollTop getCursorPositionInEditor(editor) } // let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); let NotePanel = document.querySelector("div.resizable-component.note-pc") // scrollH = document.querySelector('.ql-editor').scrollTop NotePanel.style.display = "none"; }); editor.addEventListener('click', (e) => { // e.preventDefault(); e.stopPropagation(); }); } }; function refreshBtnlistener() { let editor = document.querySelector("div.ql-editor") let toBottomBtn = document.querySelector("button.scrollToBottomBtn") let toTopBtn = document.querySelector("button.scrollToTopBtn") toBottomBtn.addEventListener("click", (e) => { editor.scrollTo(0, editor.scrollHeight); // scrollH = document.querySelector('.ql-editor').scrollTop let scrollbar = document.querySelector("div.ZDscrollbar.custom-scrollbar") if (scrollbar) { // refreshScrollBarListener(scrollbar) } editor.stopPropagation(); }); toTopBtn.addEventListener("click", (e) => { editor.scrollTo(0, 0); // scrollH = document.querySelector('.ql-editor').scrollTop let scrollbar = document.querySelector("div.ZDscrollbar.custom-scrollbar") if (scrollbar) { // refreshScrollBarListener(scrollbar) } e.stopPropagation(); }); editor.addEventListener('click', (e) => { // e.preventDefault(); e.stopPropagation(); }); let hideBtn = document.querySelector(".hide") if (hideBtn) { hideBtn.addEventListener('click', (e) => { let editor = document.querySelector('.ql-editor'); if(editor){ scrollH = editor.scrollTop getCursorPositionInEditor(editor) } // scrollH = document.querySelector('.ql-editor').scrollTop let NotePanel = document.querySelector("div.resizable-component.note-pc") NotePanel.style.display = "none"; }); } } // 5.移动笔记面板: // 此函数的作用是点击jbj_btn时设置,当视频全屏状态点击记笔记按钮时将笔记面板放到视频播放页里面 function setNotePanel() { let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); let NotePanel = document.querySelector("div.resizable-component.note-pc"); // 类名resizable-component note-pc // NotePanel.style.minWidth = '455px' // NotePanel.style.width = "460px" // NotePanel.style.height = "600px" // NotePanel.style.position = "fixed !important";//这行代码使笔记保持在固定位置,即使网页向下滚动笔记都在原来位置且可见 // NotePanel.style.zIndex = "99999" NotePanel.style.background = "rgba(0, 0, 100, 0.1)"; // let bfyRect = bfy.getBoundingClientRect(); // let NotePanelRect = NotePanel.getBoundingClientRect(); // let bfyCenterX = bfyRect.left + bfyRect.width / 2; // let bfyCenterY = bfyRect.top + bfyRect.height / 2; // let NotePanelWidth = NotePanelRect.width; // let NotePanelHeight = NotePanelRect.height; // let NotePanelLeft = bfyCenterX - NotePanelWidth / 2; // let NotePanelTop = bfyCenterY - NotePanelHeight / 2; // NotePanel.style.left = NotePanelLeft + 'px'; // NotePanel.style.top = NotePanelTop + 'px'; // NotePanel.style.position = "fixed" // NotePanel.style.left = "780px"; // NotePanel.style.top = "180px"; NotePanel.style.left = "1006px" NotePanel.style.top = "139px" NotePanel.style.width = "460px" NotePanel.style.height = "600px" bfy.appendChild(NotePanel) NotePanel.addEventListener('click', function (event) { // event.preventDefault(); event.stopPropagation(); }) NotePanel.addEventListener('dblclick', function (event) { // event.preventDefault(); event.stopPropagation(); }); // editorScrollToBottom() // 鼠标移到NotePanel里面设置监听事件阻止滚轮事件冒泡,防止鼠标滚轮影响视频的音量 NotePanel.addEventListener('mouseenter', () => { NotePanel.addEventListener('wheel', (e) => { e.stopPropagation(); }) }) }; // 6.弧形按钮; function refreshBar() { let bar = document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch > div.custom-bar-class") if (bar && bar.style.display == "none") { // return; bar.style.display = "block"; refreshBarListener() } else { setbar() } } function refreshBarListener() { let note_pc = document.querySelector("div.resizable-component.note-pc") bar.addEventListener('mouseover', (e) => { // bar.title = "鼠标移开可显示笔记" setTimeout(() => { let NotePanel = document.querySelector("div.resizable-component.note-pc") // NotePanel.style.left = NotePanel_x if (NotePanel.style.display == "none") { NotePanel.style.display = "block" } }, 0) }) bar.addEventListener('click', (e) => { // e.preventDefault(); e.stopPropagation(); if (isClose) { let newJbjBtn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.video-note-inner'); newJbjBtn.click(); } }); } // 滚动到底部函数 function editorScrollToBottom() { setTimeout(() => { let ql_editor = document.querySelector(".ql-editor"); if (ql_editor) { // 将滚动位置设置为内容的底部 // ql_editor.scrollTo(0, ql_editor.scrollHeight); ql_editor.scrollTop = ql_editor.scrollHeight // 将焦点设置到 ql_editor // 创建一个范围并将光标移动到末尾 setCursorAtBottom(ql_editor) getCursorPositionInEditor(ql_editor) } else { console.log("没有找到 ql_editor"); } }, 180); } //滚动到顶部函数 function editorScrollToTop() { setTimeout(() => { let ql_editor = document.querySelector(".ql-editor"); if (ql_editor) { // 将滚动位置设置为内容的底部 ql_editor.scrollTo(0, 0) // 将焦点设置到 ql_editor // 创建一个范围并将光标移动到末尾 setCursorAtTop(ql_editor) } else { console.log("没有找到 ql_editor"); } }, 180); } //滚动到上次编辑时的位置函数 function editorScrollToLastY() { // console.log("2262:scrollH:",scrollH) if(scrollH!=null&&scrollH!=undefined){ let editor=document.querySelector('.ql-editor') // document.querySelector('.ql-editor').focus() // console.log("editorScrollToLastY 上中scrollH:",scrollH) if(!editor){ return } if(scrollH===editor.scrollHeight){ editorScrollToBottom() }else if(scrollH===0){ editorScrollToBottom() // editorScrollToTop() }else{ // editor.scrollTo(0, scrollH) editor.scrollTop = scrollH setCursorAtNodePosition(editor, targetNode, position) // editor.focus() } }else{ editorScrollToBottom() } } function setbar() { let bfy = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch'); // if (bfy.clientHeight < 1076) { return } let bar0 = document.querySelector("#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-video-perch > div.custom-bar-class") if (bar0) return; let bar = document.createElement('div'); // 添加类名到bar元素 bar.classList.add('custom-bar-class'); // 你可以将'custom-bar-class'替换为你想要的任何类名 bar.style.cursor = 'pointer'; bar.style.borderRadius = "100% 0 0 100%"; bar.style.width = '60px'; bar.style.height = '80%'; bar.style.background = "rgba(33, 55, 61, 0.07)"; // bar.style.background = "#1C1C1C"; // bar.style.opacity = "0"; bar.style.position = 'absolute'; bar.style.right = '0'; bar.style.top = '0'; // bar.style.opacity = "0.05" bfy.appendChild(bar); let isBarClicked = false; bar.addEventListener('mouseover', (e) => { setTimeout(() => { let NotePanel = document.querySelector("div.resizable-component.note-pc") if (NotePanel.style.display == "none" && IsJbjClick) { NotePanel.style.opacity = "1"; NotePanel.style.display = "block" editorScrollToLastY() // setTimeout(() => { // editorScrollToLastY() // }, 50); // 滚动到上一次隐藏笔记面板时的位置 let bfy = document.querySelector('div.bpx-player-video-perch'); let bfyHeight = bfy.getBoundingClientRect().height; let wh = window.innerHeight; // 全屏时bfyHeight>=1080,网页全屏时bfyHeight=wh let isqp = bfyHeight === wh || bfyHeight >= 1080; if (isqp) { // 如果是全屏,将笔记显示在页面中间 // NotePanel.style.left = "780px"; // NotePanel.style.top = "180px"; if(note_pc.style.left!=0&¬e_pc.style.right!=0){ NotePanel.style.left = "1006px" } NotePanel.style.top = "139px" NotePanel.style.width = "460px" NotePanel.style.height = "600px" }else{ NotePanel.style.top='120px' NotePanel.style.left='855px' NotePanel.style.height = "600px" NotePanel.style.width = "460px" } } }, 0) }) bar.addEventListener('click', (e) => { // e.preventDefault(); e.stopPropagation(); if (isClose) { let newJbjBtn = document.querySelector('#bilibili-player > div > div > div.bpx-player-primary-area > div.bpx-player-video-area > div.bpx-player-control-wrap > div.bpx-player-control-entity > div.bpx-player-control-bottom > div.bpx-player-control-bottom-right > div.video-note-inner'); newJbjBtn.click(); } }); } // 7.插入标题按钮及相关事件 // 粘贴标题文本到笔记编辑指定区 function pasteTextToEditor(text) { if(text==null||text==undefined){ return } let editor = document.querySelector('.ql-editor'); // 替换为实际的编辑器元素 let textNode let strongNode // 创建一个 元素,并将文本设置为加粗内容 if (isBold) { // 创建一个 元素,视频标题专用 let pUrl = window.location.href strongNode = document.createElement('strong') // strongNode.textContent = text; // 设置加粗节点的文本 // textNode = strongNode; // 将加粗节点赋值给 textNode // textNode.style.cursor = 'pointer'; let aEl = document.createElement('a'); aEl.className = 'video-title-link' // aEl.href = '#'; aEl.href = pUrl aEl.textContent = text aEl.target = '_self' strongNode.appendChild(aEl); textNode = strongNode } else { // 创建一个普通的文本节点 字幕、弹幕专用的 let aEl1 = document.createElement('a'); // let currentPlayUrl,time = getVideoFrameUrl() let { p,url: currentPlayUrl, time } = getVideoFrameUrl() // console.log('粘贴函数currentPlayUrl:',currentPlayUrl) aEl1.href = currentPlayUrl p!=''&&p!=null&&p!=undefined?aEl1.textContent = text+'('+p+'-'+time+')':aEl1.textContent = text+'('+time+')' // aEl1.textContent = p+'-'+time+'-'+text aEl1.target = '_self' aEl1.className = 'zdm-link' textNode = aEl1 } // 获取当前的选择范围 // let selection = window.getSelection(); // let range = selection.getRangeAt(0); // selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 // if(selection){ // range = selection.getRangeAt(0); // } // 插入该节点到范围中 if (selection != undefined && selection > 0 && editor.contains(range.startContainer) || editor.contains(range.endContainer)) { range.insertNode(textNode); // 调整范围的位置 // range.setStartAfter(textNode); // range.setEndAfter(textNode); // 清除之前的选择,并重新设置选择范围 setTimeout(() => { selection.removeAllRanges(); selection.addRange(range); }, 50); } else { setCursorAtBottom(editor) setTimeout(() => { editor.appendChild(textNode); // range.setStartAfter(textNode); // range.setEndAfter(textNode); setTimeout(() => { selection.removeAllRanges(); selection.addRange(range); }, 50); }, 150); } // setCursorAtBottom(editor) // 确保编辑器有焦点 // 异步操作以确保 DOM 更新完成 setTimeout(() => { if(editor.scrollHeight-editor.scrollTop<=600){ // editor.scrollTo(0, editor.scrollHeight); editor.scrollTop = editor.scrollHeight scrollH = editor.scrollHeight } // selection = window.getSelection(); setTimeout(() => { // selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 // if (selection) { // range = selection.getRangeAt(0); // selection.addRange(range); // } // editor.scrollTo(0, editor.scrollHeight); // 获取当前光标位置并存储在变量中 // scrollH = editor.scrollTop; getCursorPositionInEditor(editor); // 假设这是自定义函数 }, 0); }, 50); } // 复制视频标题文本到剪贴板 // async function copyVideoTitleToClipboard() function copyVideoTitleToClipboard() { let title=''; isBold=true let multi_page = document.querySelector("#multi_page") if (!multi_page) { title = document.querySelector("#viewbox_report > div.video-info-title > div > h1")?.getAttribute('title').trim(); } else { let path = 'li.on>a, li.watched.on>a'; // 修改选择器语法以正确应用"或"逻辑 // // 获取 span 元素中的文本内容 let pageNum = document.querySelector(path)?.getAttribute('href'); let newPageNumber; let match = pageNum.match(/p=(\d+)/); if (match) { // match[1] 存储的是正则表达式中第一个括号内匹配的内容,即数字部分 let pageNumber = match[1]; // 将数字转换为 "P" 加上 数字,并在后面加上空格 newPageNumber = 'P' + pageNumber + ' '; } title = document.querySelector(path)?.getAttribute('title'); title = newPageNumber + " " + title } return title } // 设置插入标题按钮 function InsertBtnEvent() { let insertBox = document.querySelector("#web-toolbar > div > div") if (insertBox) { insertBox.style.display = 'inline-block'; return; } let bcBtn = document.querySelector("span.ql-save-btn"); if (!bcBtn) return; let bcBtnBox = document.querySelector("#web-toolbar > div") GM_addStyle(` .styled-button { background-color: #007bff; color: #393e46; // padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.08); } `); let insertBtn = document.createElement('button'); // let insertBox = document.createElement('div'); insertBox = document.createElement('div'); insertBox.className = 'insert-box'; insertBtn.className = 'styled-button'; // insertBtn.id = 'insert-btn'; insertBtn.style.top = '0' insertBtn.innerText = 'P'; // insertBtn.style.color = '#393e46'; // 设置字体颜色为黑色 insertBtn.style.fontWeight = 'bold'; // 设置字体加粗 insertBtn.style.fontSize = "20px" insertBox.style.display = 'inline-block'; insertBox.style.position = 'relative'; // insertBtn.classList.add('custom-button-insert'); // 假设类名为 'custom-button' insertBtn.title = "插入视频标题" insertBox.appendChild(insertBtn); bcBtnBox.insertBefore(insertBox, bcBtn) insertBtn.removeEventListener('click', insertTitleInEditor); insertBtn.addEventListener('click', async function () { insertTitleInEditor() }); async function insertTitleInEditor(){ try { let text = await copyVideoTitleToClipboard(); // 使用await等待Promise解析 setTimeout(() => { pasteTextToEditor(text); // 确保pasteTextToEditor接收实际的文本内容 }, 0); // pasteTextToEditor(text); // 确保pasteTextToEditor接收实际的文本内容 } catch (err) { console.error('从剪贴板读取文本时出错:', err); } } } // 获取光标在editor的位置 function getCursorPositionInEditor(editor) { let selection = window.getSelection(); // 检查是否有选中内容 if (selection.rangeCount > 0) { let range = selection.getRangeAt(0); // 获取起始节点 let startNode = range.startContainer; let startOffset = range.startOffset; // 如果光标在editor内部 if (editor.contains(startNode)) { // let position = 0; position = 0; // 计算光标相对于editor开头的位置 if (startNode.nodeType === Node.TEXT_NODE) { position = Array.from(startNode.parentNode.childNodes).slice(0, Array.prototype.indexOf.call(startNode, startNode)).reduce((acc, node) => acc + (node.nodeType === Node.TEXT_NODE ? node.length : 0), 0) + startOffset; } targetNode = startNode return { position: position, node: startNode // 返回光标所在的节点 }; } } return { position: -1, // 如果没有选中内容或光标不在editor中,返回-1 node: null // 如果光标不在editor中,返回null }; } // 将光标设置到 editor 的指定位置 function setCursorAtNodePosition(editor, targetNode, offset) { // let range = document.createRange(); // let selection = window.getSelection(); // // 清空当前选择 selection.removeAllRanges(); // 确保目标节点存在,并且偏移量在该节点的有效范围内 if (targetNode) { // 设置光标位置 range.setStart(targetNode, offset); // 设置光标起始位置 range.collapse(true); // 将光标设为所选位置,不选中内容 selection.addRange(range); // 添加新的光标位置 editor.focus(); // 将焦点设置到编辑器 } else { console.error("无法设置光标位置:目标节点不存在或偏移量无效。"); } } // 判断editor是否失去焦点 function isEditorFocused(editor) { return editor === document.activeElement; } // 将光标设置到 editor 底部 function setCursorAtBottom(editor) { // let range1 = editor.createRange(); let range1 = document.createRange(); // let selection1 = window.getSelection(); let selection1 = editor.ownerDocument.defaultView.getSelection() // let range1 = selection.getRangeAt(0);; // 选择 editor 内容的开始位置 range1.selectNodeContents(editor); range1.collapse(false); // 设为 false,光标移到底部 selection1.removeAllRanges(); // 移除当前选择 selection1.addRange(range1); // 添加新的光标位置 editor.focus(); // 将焦点设置到编辑器 getCursorPositionInEditor(editor) } // 将光标设置到 editor 顶部 function setCursorAtTop(editor) { let range1 = document.createRange(); // let selection1 = window.getSelection(); let selection1 = editor.ownerDocument.defaultView.getSelection() // 选择 editor 内容的开始位置 range1.selectNodeContents(editor); range1.collapse(true); // 设为 false,光标移到顶部 selection1.removeAllRanges(); // 移除当前选择 selection1.addRange(range1); // 添加新的光标位置 editor.focus(); // 将焦点设置到编辑器 getCursorPositionInEditor(editor) } // 在笔记编辑器中添加滚动监听器,鼠标事件,鼠标滚轮滚动,键盘按下事件 function editorEvent() { // let editor = document.querySelector('.ql-editor[contenteditable="true"]'); let editor = document.querySelector('.ql-editor'); let note_pc = document.querySelector("div.resizable-component.note-pc") // console.log("editor", editor); if (!editor) { console.log("editorEvent没有找到 editor"); return } // 当editor失去焦点时,鼠标移入后自动获取焦点,并设置光标到之前的位置 editor.addEventListener('mouseenter', function (event) { if(!isEditorFocused(editor)){ if(targetNode!=null&&targetNode!=undefined&&position!=null&&position!=undefined&&position!=-1){ if(editor.scrollHeight-editor.scrollTop<=900){ setCursorAtBottom(editor) editor.scrollTop=editor.scrollHeight }else{ setCursorAtNodePosition(editor, targetNode, position) } }else{ editor.scrollTop=editor.scrollHeight // setCursorAtBottom(editor) } } }) editor.addEventListener('mouseleave', function (event) { scrollH = editor.scrollTop selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 if(selection){ range = selection.getRangeAt(0); } // console.log("document被点击", scrollH) getCursorPositionInEditor(editor) }) editor.addEventListener('scroll', function () { getCursorPositionInEditor(editor) if (editor.scrollTop + editor.clientHeight >= editor.scrollHeight) { // 在内容到底部时设置光标在底 setCursorAtBottom(editor); } else if (editor.scrollTop === 0) { setCursorAtTop(editor) } if (editor.scrollTop != 0) { scrollH = editor.scrollTop } selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 if (selection) { range = selection.getRangeAt(0); } }); editor.addEventListener("click", function (event) { selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 if(selection){ range = selection.getRangeAt(0); } // console.log("点击的range", range); // scrollH = document.querySelector('.ql-editor').scrollTop scrollH = editor.scrollTop getCursorPositionInEditor(editor) // editor.scrollTo(0, scrollH); }) document.addEventListener("click", function (event) { scrollH = editor.scrollTop }); editor.addEventListener('keydown', function (event) { if(!event.altKey){ setTimeout(() => { scrollH = editor.scrollTop editor.scrollTo(0, scrollH); selection = editor.ownerDocument.defaultView.getSelection(); // 更安全地获取selection,考虑editor所在的文档上下文 if(selection){ range = selection.getRangeAt(0); } getCursorPositionInEditor(editor) }, 50); } }) } // 笔记面板鼠标监听事件双击隐藏 function noteEvent() { let note_pc = document.querySelector("div.resizable-component.note-pc"); if (note_pc) { // 左键双击隐藏 function hideNote(){ note_pc.addEventListener("dblclick", function (event) { // 阻止冒泡 isClose=false event.stopPropagation(); event.preventDefault(); // 检查是否选中了文本或图片 let selection = window.getSelection().toString().trim(); let selectedImages = note_pc.querySelectorAll(".ql-image-preview.active"); // 假设图片有 selected 类表示被选中 if (selection === "" && selectedImages.length === 0) { // 如果没有选中文本或图片,隐藏 note_pc note_pc.style.display = "none"; } }); } hideNote() } } // 点进笔记列表后获取笔记列表中的所有图片元素,为每个图片元素添加点击事件 function creatNoteImageClikEvent() { setTimeout(() => { let imgElements let zoomedImage = document.querySelector('.zoomed-image'); let bpx = document.querySelector('.bpx-player-container'); // bfx 非全屏 data-screen="normal" 全屏data-screen="full" 网页全屏data-screen="web" let data_screen = bpx.getAttribute('data-screen') function imageClickListener() { // 获取所有图片元素 imgElements = document.querySelectorAll('.ql-image-preview .img-preview'); for (let i = 0; i < imgElements.length; i++) { const image = imgElements[i]; image.style.cursor = 'pointer'; image.title = "弹出" image.addEventListener('mousedown', handleImageClick); } let isDragging = false; let offsetX, offsetY; function handleImageClick(event) { const image = event.currentTarget; zoomedImage.src = image.src; // 动态设置 zoomedImage 的 src const rect = image.getBoundingClientRect(); const originalWidth = image.offsetWidth; const originalHeight = image.offsetHeight; const offsetX = 120; const offsetY = 300; const x = rect.left + window.scrollX + (originalWidth / 2) + offsetX; const y = rect.top + window.scrollY + (originalHeight / 2) - offsetY; // 设置放大图片的位置 // zoomedImage.style.left = `${x - (originalWidth * 0.5)}px`; // 根据原始图片的宽度调整位置 // zoomedImage.style.top = `${y - (originalHeight * 0.5)}px`; // 根据原始图片的高度调整位置 // zoomedImage.style.left = '-380'; // 根据原始图片的宽度调整位置 // zoomedImage.style.top = '80px'; // 根据原始图片的高度调整位置 zoomedImage.style.display = 'block'; zoomedImage.style.opacity = '1'; // 添加鼠标悬停和离开事件监听器 zoomedImage.addEventListener('mouseover', handleZoomedImageMouseOver); zoomedImage.addEventListener('dblclick', handleZoomedImageDblclick); // 添加拖动事件监听器 zoomedImage.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', endDrag); let data_screen = bpx.getAttribute('data-screen') if (data_screen == 'full' || data_screen == 'web') { document.body.removeChild(zoomedImage); bpx.appendChild(zoomedImage); } else { bfx.removeChild(zoomedImage); document.body.appendChild(zoomedImage); } } function handleZoomedImageMouseOver() { zoomedImage.style.transform = 'scale(0.7)'; // 初始放大比例 zoomedImage.title = '双击关闭'; } function handleZoomedImageDblclick() { zoomedImage.style.opacity = '0'; setTimeout(() => { zoomedImage.style.display = 'none'; zoomedImage.removeEventListener('mouseover', handleZoomedImageMouseOver); zoomedImage.removeEventListener('mouseout', handleZoomedImageDblclick); }, 300); // 与 transition 时间一致 } function startDrag(event) { isDragging = true; offsetX = event.clientX - zoomedImage.offsetLeft; offsetY = event.clientY - zoomedImage.offsetTop; } function drag(event) { if (isDragging) { zoomedImage.style.left = `${event.clientX - offsetX}px`; zoomedImage.style.top = `${event.clientY - offsetY}px`; } } function endDrag() { isDragging = false; } } if (!zoomedImage) { // let bfy = document.getElementsByClassName("bpx-player-video-area")[0] // 创建一个新的图片元素,用于显示放大后的图片 zoomedImage = document.createElement('img'); zoomedImage.className = 'zoomed-image'; zoomedImage.style.position = 'fixed'; zoomedImage.style.left='-360px'; zoomedImage.style.top='-100px'; zoomedImage.style.display = 'none'; zoomedImage.style.zIndex = 1000; zoomedImage.style.cursor = 'pointer'; zoomedImage.style.maxWidth = 'none'; // 确保图片不受容器限制 zoomedImage.style.maxHeight = 'none'; // 确保图片不受容器限制 zoomedImage.style.transform = 'scale(0.7)'; // 初始放大比例 zoomedImage.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; // alert("首次加载图片放大插件:" + data_screen) if (data_screen == 'full' || data_screen == 'web') { bpx.appendChild(zoomedImage); imageClickListener() } else { document.body.appendChild(zoomedImage); imageClickListener() } // imageClickListener() } else { // alert("非首次加载图片放大插件:" + data_screen) if (data_screen == 'full' || data_screen == 'web') { bpx.appendChild(zoomedImage); } imageClickListener() } }, 1800); } }//是183行这个结束括号 if (currentUrl.indexOf('https://www.bilibili.com/video/') === 0 || currentUrl.startsWith('https://www.bilibili.com/cheese/') // Your code here... })();