公众号阅读助手

微信公众号文章菜单选项,展示一些有用的选项

  1. // ==UserScript==
  2. // @name 公众号阅读助手
  3. // @name:zh-CN 公众号阅读助手
  4. // @name:en Wechat Article Menu
  5. // @description 微信公众号文章菜单选项,展示一些有用的选项
  6. // @description:zh-CN 微信公众号文章菜单选项,展示一些有用的选项
  7. // @description:en Wechat Article Menu, Show Some Useful Options
  8. // @namespace https://www.runningcheese.com
  9. // @version 1.7
  10. // @author RunningCheese
  11. // @match https://mp.weixin.qq.com/s/*
  12. // @match https://mp.weixin.qq.com/s?*
  13. // @run-at document-start
  14. // @icon https://t1.gstatic.cn/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://mp.weixin.qq.com
  15. // @license MIT
  16. // ==/UserScript==
  17.  
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. // 小书签代码开始
  23. (function() {
  24. 'use strict';
  25.  
  26. // 创建浮动窗口
  27. const panel = document.createElement('div');
  28. panel.id = 'wx-reader-panel';
  29. panel.style.cssText = 'position:fixed;top:12%;left:20%;background:#fff;border:none;border-radius:8px;padding:4px;width:200px;box-shadow:0 4px 12px rgba(0,0,0,0.25);z-index:999999;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;display:none;';
  30.  
  31. // 增强样式隔离性
  32. const styleElement = document.createElement('style');
  33. styleElement.textContent = `
  34. .wx-reader-icon {
  35. cursor: pointer;
  36. margin-left: 5px;
  37. vertical-align: middle;
  38. opacity: 0.7;
  39. transition: opacity 0.2s;
  40. display: inline-flex;
  41. align-items: center;
  42. }
  43. .wx-reader-icon:hover {
  44. opacity: 1;
  45. }
  46. `;
  47. document.head.appendChild(styleElement);
  48.  
  49. // 创建工具图标
  50. function createToolIcon() {
  51. const icon = document.createElement('span');
  52. icon.className = 'wx-reader-icon';
  53. icon.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  54. <defs>
  55. <linearGradient id="toolGradient" x1="0%" y1="0%" x2="100%" y2="100%">
  56. <stop offset="0%" stop-color="#1E88E5" />
  57. <stop offset="100%" stop-color="#1565C0" />
  58. </linearGradient>
  59. </defs>
  60. <rect x="2" y="2" width="20" height="20" rx="4" ry="4" fill="url(#toolGradient)"/>
  61. <path d="M6 9h12v1.5H6V9zm0 3h12v1.5H6V12zm0 3h12v1.5H6V15z" fill="white"/>
  62. </svg>`;
  63. icon.title = "微信阅读助手";
  64.  
  65. icon.addEventListener('click', function(e) {
  66. e.stopPropagation();
  67. panel.style.display = 'block';
  68.  
  69. // 调整面板位置到图标附近
  70. const rect = icon.getBoundingClientRect();
  71. panel.style.top = (rect.bottom + window.scrollY + 10) + 'px';
  72. panel.style.left = (rect.left + window.scrollX - 100) + 'px';
  73. });
  74.  
  75. return icon;
  76. }
  77.  
  78. // 添加图标到页面
  79. function addToolIcon() {
  80. // 微信公众号文章页面的选择器
  81. const selectors = ['#js_ip_wording', '#publish_time', '#js_author_name', '.rich_media_meta_list'];
  82.  
  83. let targetElement = null;
  84.  
  85. // 查找合适的元素放置图标
  86. for (const selector of selectors) {
  87. const element = document.querySelector(selector);
  88. if (element) {
  89. targetElement = element;
  90. break;
  91. }
  92. }
  93.  
  94. // 如果找到目标元素,添加图标
  95. if (targetElement && !targetElement.querySelector('.wx-reader-icon')) {
  96. const icon = createToolIcon();
  97. targetElement.appendChild(icon);
  98. }
  99. }
  100.  
  101. // 创建标题栏
  102. const titleBar = document.createElement('div');
  103. titleBar.style.cssText = 'display:flex;justify-content:space-between;align-items:center;padding:4px 10px;font-size:14px;color:#333;border-bottom:1px solid #eee;margin-bottom:2px;cursor:move;border-radius:8px 8px 0 0;';
  104.  
  105. // 创建标题文本
  106. const titleText = document.createElement('span');
  107. titleText.textContent = '▼ 微信阅读助手';
  108. titleText.style.cssText = 'flex:1;';
  109. titleBar.appendChild(titleText);
  110.  
  111. // 创建关闭按钮
  112. const closeBtn = document.createElement('span');
  113. closeBtn.textContent = '×';
  114. closeBtn.style.cssText = 'cursor:pointer;color:#999;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all 0.2s ease;margin-left:10px;';
  115.  
  116. closeBtn.addEventListener('mouseover', () => closeBtn.style.backgroundColor = '#dadada');
  117. closeBtn.addEventListener('mouseout', () => closeBtn.style.backgroundColor = '');
  118. closeBtn.addEventListener('click', (e) => {
  119. e.stopPropagation();
  120. panel.style.display = 'none';
  121. });
  122.  
  123. titleBar.appendChild(closeBtn);
  124.  
  125. // 拖动相关变量和事件
  126. let startX = 0, startY = 0, startLeft = 0, startTop = 0, isDragging = false;
  127.  
  128. titleBar.addEventListener('mousedown', function(e) {
  129. if (e.target === closeBtn) return;
  130. isDragging = true;
  131. startX = e.clientX;
  132. startY = e.clientY;
  133. startLeft = parseInt(window.getComputedStyle(panel).left);
  134. startTop = parseInt(window.getComputedStyle(panel).top);
  135. e.preventDefault();
  136. });
  137.  
  138. function mouseMoveHandler(e) {
  139. if (!isDragging) return;
  140. const deltaX = e.clientX - startX;
  141. const deltaY = e.clientY - startY;
  142. panel.style.left = (startLeft + deltaX) + 'px';
  143. panel.style.top = (startTop + deltaY) + 'px';
  144. }
  145.  
  146. function mouseUpHandler() {
  147. isDragging = false;
  148. }
  149.  
  150. document.addEventListener('mousemove', mouseMoveHandler);
  151. document.addEventListener('mouseup', mouseUpHandler);
  152.  
  153. // 双击Esc关闭窗口
  154. let lastEscTime = 0;
  155. document.addEventListener('keydown', function(evt) {
  156. if (evt.key === 'Escape') {
  157. const now = Date.now();
  158. if (now - lastEscTime <= 300) {
  159. panel.style.display = 'none';
  160. }
  161. lastEscTime = now;
  162. }
  163. });
  164.  
  165. // 功能菜单项
  166. const menuItems = [
  167. {title: '1、原始链接', code: 'prompt(\'原始链接:\', \'https://mp.weixin.qq.com/s?__biz=\'+biz+\'&idx=1&mid=\'+mid+\'&sn=\'+sn)'},
  168. {title: '2、文章摘要', code: 'summary = document.querySelector(\'meta[name="description"]\').content; prompt(\'文章摘要:\',summary)'},
  169. {title: '3、文章封面', code: 'const cover = document.querySelector(\'meta[property="twitter:image"]\').content; window.open(cover, "_blank");'},
  170. {title: '4、历史消息链接', code: 'prompt(\'历史消息链接:\',\'https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=\'+biz+\'#wechat_redirect\')'},
  171. {title: '5、查看所有图片', code: 'const images = Array.from(document.querySelectorAll("img")).filter(img => (img.src || img.dataset.src) && !(img.src && img.src.startsWith("data:image/svg+xml")) && !(img.dataset.src && img.dataset.src.startsWith("data:image/svg+xml"))); if(images.length === 0) { alert("未找到图片"); return; } const win = window.open("", "_blank"); win.document.write("<html><head><title>网页所有图片</title><style>body{margin:20px auto;font-family:sans-serif;max-width:700px;}img{max-width:100%;margin:10px 0;border:1px solid #eee;padding:5px;}</style></head><body><h2>网页所有图片("+images.length+"张)</h2>"); images.forEach((img, i) => { const src = img.src || img.dataset.src; win.document.write(`<p>${i+1}.</p><img src="${src}" />`); }); win.document.write("</body></html>"); win.document.close();'}
  172. ];
  173.  
  174. // 创建菜单项
  175. menuItems.forEach((item) => {
  176. const menuItem = document.createElement('div');
  177. menuItem.style.cssText = 'cursor:pointer;padding:4px 10px;transition:all 0.2s ease;border-radius:6px;font-size:14px;color:#333;display:flex;align-items:center';
  178. menuItem.textContent = item.title;
  179.  
  180. menuItem.onmouseover = () => menuItem.style.backgroundColor = '#dadada';
  181. menuItem.onmouseout = () => menuItem.style.backgroundColor = '';
  182.  
  183. if (item.code) {
  184. menuItem.onclick = (e) => {
  185. e.preventDefault();
  186. try {
  187. const func = new Function(`return (function(){${item.code}})();`);
  188. func();
  189. } catch (err) {
  190. console.error('执行代码时出错:', err);
  191. }
  192. };
  193. }
  194.  
  195. panel.appendChild(menuItem);
  196. });
  197.  
  198. // 添加到页面 - 将标题栏放在最上面
  199. panel.insertBefore(titleBar, panel.firstChild);
  200. document.body.appendChild(panel);
  201.  
  202. // 添加点击页面其他区域关闭面板
  203. document.addEventListener('click', function(e) {
  204. if (!panel.contains(e.target) && !e.target.classList.contains('wx-reader-icon')) {
  205. panel.style.display = 'none';
  206. }
  207. });
  208.  
  209. // 添加工具图标
  210. setTimeout(addToolIcon, 1000);
  211.  
  212. // 监听DOM变化,确保在动态加载的页面上也能添加图标
  213. const observer = new MutationObserver(function(mutations) {
  214. mutations.forEach(function(mutation) {
  215. if (mutation.addedNodes.length > 0) {
  216. setTimeout(addToolIcon, 500);
  217. }
  218. });
  219. });
  220.  
  221. observer.observe(document.body, { childList: true, subtree: true });
  222. })();
  223. // 小书签代码结束
  224. })();