// ==UserScript== // @name 💡 链接速览 // @namespace https://ez118.github.io/ // @version 2.5.0 // @description 快速预览网页链接,鼠标移至链接并按下回车键即可预览。 // @author ZZY_WISU // @match *://*/* // @connect * // @license GPLv3 // @icon data:image/webp;base64,UklGRlIAAABXRUJQVlA4TEYAAAAvFAAFEA8wdtMxwfMf8GAb2baS8xUiyzWzKl5OB0TEVOFS1i8Oeojof2D5xugMRU2YEaFZafeiuZARmQgL76DPwVJD/k8A // @run-at document-end // @grant GM_xmlhttpRequest // @grant GM_addStyle // @require https://unpkg.com/zepto@1.2.0/dist/zepto.min.js // @require https://unpkg.com/@mozilla/readability@0.6.0/Readability.js // ==/UserScript== const contentEleSelList = { "blog.csdn.net": "#article_content", "zhuanlan.zhihu.com": ".Post-Main", "jingyan.baidu.com": "#format-exp", "zhidao.baidu.com": "#qb-content", "www.cnblogs.com": "#topics", "www.sohu.com": "#mp-editor" }; /* 储存特定网站内容优化数据(文章主体的父元素) */ const mediaPrevSupport = [ { "site": "https://v.youku.com/v_show/*.html", "player": "https://player.youku.com/embed/*", "type": "video" }, { "site": "https://v.qq.com/x/page/*.html", "player": "https://v.qq.com/txp/iframe/player.html?vid=*", "type": "video" }, { "site": "https://www.bilibili.com/video/BV*/", "player": "https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=*", "type": "video" }, { "site": "https://www.bilibili.com/video/av*/", "player": "https://www.bilibili.com/blackboard/html5mobileplayer.html?aid=*", "type": "video" }, { "site": "https://www.youtube.com/watch?v=*", "player": "https://www.youtube.com/embed/*", "type": "video" }, { "site": "https://music.163.com/#/song?id=*", "player": "https://music.163.com/outchain/player?type=2&id=*&auto=0&height=66", "type": "music" }, { "site": "https://music.163.com/song?id=*", "player": "https://music.163.com/outchain/player?type=2&id=*&auto=0&height=66", "type": "music" }, { "site": "https://open.spotify.com/track/*", "player": "https://open.spotify.com/embed/track/*", "type": "music" }, { "site": "https://music.apple.com/cn/song/*", "player": "https://embed.music.apple.com/cn/album/*", "type": "music" }, { "site": "https://music.youtube.com/watch?v=*", "player": "https://www.youtube.com/embed/*", "type": "music" } ]; /* 储存支持预览播放视频/预览试听音乐的网站及其嵌入播放器链接 */ function judgeMediaSupport(url) { let jflag = null; $.each(mediaPrevSupport, (index, item) => { if (url.includes(item.site.split("*")[0])) { jflag = { "state": true, "data": item }; } }) return jflag || { "state": false, "data": null }; } function getWebContents(html, url) { /* 去掉影响转换的标签 */ html = html.replace(/.*?<\/script>/gis, "") .replace(/.*?<\/style>/gis, "") .replace(/.*?<\/nav>/gis, "") .replace(/]*src\s*=\s*["']{2}[^>]*>/gi, '') .replace(/]*)onerror\s*=\s*(['"]?[^'">]*['"]?)([^>]*)>/gi, ''); /* 提取正文 */ const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const readability = new Readability(doc); const result = readability.parse(doc); return result.content; } function openReader(url) { /* 打开阅读器 */ /* 阅读器加载提示 */ let closeBtn = $("#userscript-closeBtn").show(); let previewReader = $("#userscript-webPreviewReader").show(); previewReader.html(`

正在载入...
${url}

`); /* 判断当前链接是支持预览的视频网站,并作出对应处理 */ let showMedia = judgeMediaSupport(url); if (showMedia.state) { /* 被支持的视频网站的处理 */ var origUrl = url; var frameUrl = ""; var mediaType = (showMedia.data.type == "video") ? "视频" : "音乐"; /* 将链接参数与嵌入式播放器链接拼接 */ url = url.replace(showMedia.data.site.split("*")[0], ""); url = url + "?#"; url = url.split("#")[0].split("?")[0]; url = url.replace(showMedia.data.site.split("*")[1], ""); frameUrl = showMedia.data.player.replace("*", url); previewReader.html(` `); } else { /* 普通网站的处理 */ GM_xmlhttpRequest({ method: "GET", url: url, headers: { "Content-Type": "application/x-www-form-urlencoded;charset=utf-8" }, onload: (response) => { var result = response.responseText; if (!result) { previewReader.html(`

请求失败
${url}

`); return; } /* 对指定网站进行内容过滤,指定元素获取 */ let orig_result_backup = result; const domain = url.split("/")[2]; if (contentEleSelList[domain]) { try { const selector = contentEleSelList[domain]; result = $(result).find(selector).html(); } catch (e) { console.log("[WebPrvw] 特殊优化出现问题"); } } if (!result) { result = orig_result_backup; } /* 调用解析网页 */ let web_content = getWebContents(result, url); /* 将所有结果添加进阅读器,并显示 */ previewReader.html(`

正文预览

${web_content}
`); }, onerror: () => { previewReader.html(`

请求失败

`); } }); } } function initQuickView() { const domain = window.location.href.split("/")[2]; if (contentEleSelList[domain]) { // 确保按钮挂载到根容器内 const root = $('#userscript-lp-root'); // 避免重复添加 if (root.find('.userscript-quickview-btn').length === 0) { const quickBtn = $("").appendTo(root); quickBtn.click(() => openReader(window.location.href)); } } } function initEvent() { // 获取所有有效的 a 标签 const $links = $('a:not(#userscript-webPreviewReader)'); // 过滤出有效链接(非 javascript: 和 mailto:) const $validLinks = $links.filter(function () { const href = $(this).attr('href'); return href && !href.startsWith('javascript:') && !href.startsWith('mailto:'); }); // 记录当前鼠标悬停的链接 let hoveredLink = null; // 绑定鼠标悬停事件:直接操作 style 属性高亮 + 修改 Title $validLinks.on('mouseover', function () { hoveredLink = this; const $this = $(this); // 1. 处理 Title if (!$this.data('original-title')) { $this.data('original-title', $this.attr('title')); } $this.attr('title', '回车以速览链接'); // 2. 处理高亮 (使用 box-shadow inset,不破坏原有背景) // 保存原有 box-shadow 以防万一,虽然通常链接没有复杂的 shadow if (!$this.data('original-shadow')) { $this.data('original-shadow', $this.css('box-shadow')); } // 设置内阴影高亮,颜色为半透明绿色,适应深浅色背景 $this.css('box-shadow', 'inset 0 0 0 2px rgba(56, 106, 31, 0.5)'); }).on('mouseout', function () { hoveredLink = null; const $this = $(this); // 1. 恢复 Title const originalTitle = $this.data('original-title'); if (originalTitle !== undefined) { $this.attr('title', originalTitle); } else { $this.removeAttr('title'); } // 2. 恢复高亮 const originalShadow = $this.data('original-shadow'); if (originalShadow) { $this.css('box-shadow', originalShadow); } else { $this.css('box-shadow', ''); } }); // 监听 Enter 键 $(document).on('keydown', (e) => { if (e.key.toLowerCase() == 'enter' && hoveredLink) { e.preventDefault(); // 防止触发链接默认跳转 openReader(hoveredLink.href); } }); } /* =========================== */ function init() { /* 初始化 */ /* 插入样式 */ GM_addStyle(` /* ===== 变量定义:仅在根容器上,不污染页面 ===== */ #userscript-lp-root { --bg-color:#FFFFFFAA; --text-color:#386a1f; --border-color:#285a0f; --hover-bg-color:#edf1e5; --active-bg-color:#d7e1cd; --close-btn-bg:#386a1f; --close-btn-text:#FFF; --reader-bg:#fdfdf6; --reader-text-color:#131f0d; --link-color:#386a1f; --link-hover:#487631; --pre-bg-color:#eeeee8; --pre-border-color:#dee5d8; --code-bg-color:#e2e3dd; } @media (prefers-color-scheme:dark) { #userscript-lp-root { --bg-color:#00390a55; --text-color:#7edb7b; --border-color:#7edb7b; --hover-bg-color:#00390aAA; --active-bg-color:#7edb7b; --close-btn-bg:#7edb7b; --close-btn-text:#00390a; --reader-bg:#1a1c19; --reader-text-color:#e2e3dd; --link-color:#7edb7b; --link-hover:#76cd74; --pre-bg-color:#1e201d; --pre-border-color:#424940; --code-bg-color:#42494047; } } /* ===== 根容器本身:不可见但作为定位基准 ===== */ #userscript-lp-root { position:fixed; top:0; left:0; width:0; height:0; z-index:99990; pointer-events:none; } #userscript-lp-root * { pointer-events:auto; } /* ===== 关闭按钮 ===== */ #userscript-lp-root .userscript-closeBtn { position:fixed; top:calc(8% + 5px); right:18px; z-index:100000; background:var(--close-btn-bg); color:var(--close-btn-text); padding:8px 20px; margin:6px; border-radius:30px; font-weight:bold; border:0; border-bottom:1px solid var(--border-color); cursor:pointer; } #userscript-lp-root .userscript-closeBtn:hover { background:var(--link-hover); } /* ===== 阅读器面板 ===== */ #userscript-lp-root .userscript-webPreviewReader { font-size:medium; text-align:left; position:fixed; top:8vh; right:10px; bottom:0px; z-index:99999; width:35%; height:calc(100vh - 8%); min-width:340px; background:var(--reader-bg); color:var(--reader-text-color); overflow:hidden; box-shadow:0 0 0 1px rgba(0,0,0,.1), 0 2px 4px 1px rgba(0,0,0,.18); border-radius:28px 28px 0px 0px; } /* ===== 阅读器内部 ===== */ #userscript-lp-root .FrameShow { width:calc(100% - 16px); height:calc(100% - 120px); min-height:300px; background:var(--code-bg-color); border:none; border-radius:30px; margin:8px 8px; box-shadow:0 .5px 1.5px 0 rgba(0,0,0,.19), 0 0 1px 0 rgba(0,0,0,.039); } #userscript-lp-root #FadeInContainer { overflow-y:scroll; overflow-x:hidden; border-radius:15px 15px 0px 0px; width:100%; height:100%; } #userscript-lp-root .ContentShow { padding:16px; margin:8px; background:var(--code-bg-color); border-radius:30px; overflow:hidden; color:var(--reader-text-color); box-shadow:0 .5px 1.5px 0 rgba(0,0,0,.19), 0 0 1px 0 rgba(0,0,0,.039); } #userscript-lp-root .ContentShow * { background:none!important; background-color:transparent!important; } #userscript-lp-root video{ max-width:92%!important; max-height:85vh!important; position:relative!important; top:0!important; left:0!important; border-radius:10px; height:auto; } #userscript-lp-root img { max-width:92%!important; max-height:85vh!important; position:relative!important; top:0!important; left:0!important; border-radius:10px; height:auto; } #userscript-lp-root video{ max-width:92%!important; max-height:85vh!important; position:relative!important; top:0!important; left:0!important; border-radius:10px; height:auto; } #userscript-lp-root svg { max-width:40%!important; max-height:60vh!important; position:relative!important; top:0!important; left:0!important; border-radius:10px; height:auto; } #userscript-lp-root a { color:var(--link-color); text-decoration:underline 1px solid var(--link-hover); margin:0px 3px; } #userscript-lp-root code { font-family:Consolas,Courier,Courier New,monospace; user-select:text!important; } #userscript-lp-root pre { color:var(--reader-text-color); background:var(--pre-bg-color); width:90%; padding:5px; margin:5px 0px; overflow-y:auto; height:fit-content; border:1px solid var(--pre-border-color); border-radius:5px; user-select:text!important; } #userscript-lp-root code:not(pre code) { color:var(--reader-text-color); background:var(--code-bg-color); border-radius:0.25rem; padding:.125rem .375rem; line-height:1.75; word-wrap:break-word; border:1px solid var(--pre-border-color); } #userscript-lp-root table { width:100%; text-align:left; border-collapse:collapse; border-spacing:0; border:1px solid var(--pre-border-color); border-radius:0.25rem; word-wrap:break-word; } #userscript-lp-root table tr { border:1px solid var(--pre-border-color); } #userscript-lp-root table td { border:1px solid var(--pre-border-color); } `); /* ===== 创建根容器(所有 UI 元素都放在里面) ===== */ if ($("#userscript-lp-root").length === 0) { const root = $('
', { id: 'userscript-lp-root' }).appendTo('body'); /* 阅读器 */ $('
', { class: 'userscript-webPreviewReader', id: 'userscript-webPreviewReader' }).appendTo(root); /* 关闭按钮 */ const closeBtn = $('