Greasy Fork is available in English.
鼠标点击时##加载原图✔,可直接对缩略图进行操作✔,拖拽、右键复制✔,粘贴到TIM等软件✔。 ※实现方式※ 去除地址后缀例如"@!web-comment-note.avif"。 ※涵盖范围※ 动态图片/专栏图片等;视频封面/用户头像。 ※浏览器兼容※ 360极速浏览器✔,已知火狐浏览器部分右键和拖拽功能不够兼容。 ※吐槽※ 为什么TIM不支持直接粘贴,不支持原本的avif格式??
// ==UserScript== // @name 优化B站图片操作,点击时查看/复制/打开原始图片 // @namespace https://github.com/SineObama // @homepage https://github.com/SineObama/bilibili-player-auto-set-playtype // @version 0.2.2.20241201 // @description 鼠标点击时##加载原图✔,可直接对缩略图进行操作✔,拖拽、右键复制✔,粘贴到TIM等软件✔。 ※实现方式※ 去除地址后缀例如"@!web-comment-note.avif"。 ※涵盖范围※ 动态图片/专栏图片等;视频封面/用户头像。 ※浏览器兼容※ 360极速浏览器✔,已知火狐浏览器部分右键和拖拽功能不够兼容。 ※吐槽※ 为什么TIM不支持直接粘贴,不支持原本的avif格式?? // @author SineObama // @match *://*.bilibili.com/* // @icon https://www.bilibili.com/favicon.ico // @grant none // @license MIT // ==/UserScript== // 匹配图片后缀并去除,常见格式".jpg@!web-comment-note.avif" // 但还发现首页视频封面: https://i1.hdslb.com/bfs/archive/f1a23a1724f7450dfbcc5e4d69cfb2c127c8a90e.jpg@672w_378h_1c_!web-home-common-cover // 图片封面: https://i1.hdslb.com/bfs/banner/a6ade099505ec03f3ac616510bbf08d0972b88ec.png@800w_512h_!web-home-carousel-cover.avif?mirror_report_swipe=1 // 格式有点多,放弃逐个匹配了,直接去掉全部吧 var imgSuffixReg = /(?<=\.[a-z]+)@.*?$/; // 右键上下文菜单时触发,以便下一步进行复制之前完成修改 document.addEventListener('contextmenu', removeImgSuffix); // 拖拽时触发,修改url地址 document.addEventListener('dragstart', replaceDragUrl); // 利用 mousedown 在拖拽之前修改元素地址,经测试在 Notepad++ 替换不需要这个,而 Obsidian 需要 document.addEventListener('mousedown', removeImgSuffix); // 拖拽到TIM始终无法正常,用 mousedown 事件也不行,其他情况用拖拽事件即可满足 // 尝试过 event.dataTransfer.items[1].type = 'image/png'; // 也没用 function removeImgSuffix(event) { var el = event.target; console.debug('点击的元素:', el.tagName, el); if (el.tagName === 'IMG') { doRemoveImgSuffix(el); return; } // 视频封面 a > div.b-img > picture.b-img__inner > img 已知适用于: // https://space.bilibili.com/30987652/video // https://t.bilibili.com/ // https://www.bilibili.com/video/BV1ZBzhYREVs var bImgs = el.parentNode.getElementsByClassName('b-img'); if (bImgs.length === 1) { var img = bImgs[0].getElementsByTagName('img')[0]; if (img) { doRemoveImgSuffix(img); return; } } // 尝试若干方法找到唯一的图片元素 var imgs; // 尝试从父节点乱找 imgs = el.parentNode.getElementsByTagName('img'); if (imgs.length === 1) { doRemoveImgSuffix(imgs[0]); return; } // 评论区用户popup卡片中的头像 bili-user-profile 内部是 DocumentFragment 发现存在 renderRoot 属性可以找到它 // 最后是内部元素 #avatar > img var rRoot = el.renderRoot; if (rRoot) { el = rRoot.getElementById('avatar'); } // 直接找唯一图片 imgs = el.getElementsByTagName('img'); if (imgs.length === 1) { doRemoveImgSuffix(imgs[0]); return; } } function doRemoveImgSuffix(el) { // 优先选取 picture 元素下当前使用的 source 元素的图片地址 var imageUrl = el.currentSrc || el.src; console.debug('点击的图片元素地址:', imageUrl); if (imgSuffixReg.test(imageUrl)) { var imageUrlNew = imageUrl.replace(imgSuffixReg, ''); if (replaceImgSrc(el, imageUrl, imageUrlNew)) { console.debug('已去除图片地址后缀:', imageUrlNew); } } } function replaceDragUrl(event) { // 获取图片或链接(场景下)的地址 var imageUrl = event.dataTransfer.getData('url'); if (imageUrl && imgSuffixReg.test(imageUrl)) { console.debug('拖拽的图片地址:', imageUrl); var imageUrlNew = imageUrl.replace(imgSuffixReg, ''); event.dataTransfer.setData('url', imageUrlNew); console.debug('已去除图片地址后缀:', imageUrlNew); } } function replaceImgSrc(el, imageUrl, imageUrlNew) { // 父级为 picture 元素经测试需要修改其中 source 元素的地址才能使复制的地址生效 var parentNode = el.parentNode; if (parentNode && parentNode.nodeName === 'PICTURE') { // 对于多个 source 元素,不确定他会用哪个,所以都##改掉 var flag = false; for (var i = 0; i < parentNode.children.length; i++) { var child = parentNode.children[i]; if (child && child.tagName === 'SOURCE' && imageUrl.indexOf(imageUrlNew > -1)) { child.srcset = imageUrlNew; flag = true; } } return flag; } else { // 一般图片直接替换 el.src = imageUrlNew; return true; } }