Makima 发表于 2026-2-21 21:23:01

【脚本】一键复制文字图片

本帖最后由 Makima 于 2026-2-21 21:31 编辑

一般来说复制一段内容,里面的图片不会复制过去本脚本可以同时复制文字和图片其中的图片会转化为插入图片的格式
类似的:【脚本】双击右键复制勋章图片@Name @Match
// ==UserScript==
// @name         GM一键复制图片
// @version      1.0
// @description复制时自动将图片转换为插入图片的格式
// @author       M
// @match      https://www.gamemale.com/*
// @run-at       document-start
// @grant      none
// ==/UserScript==

(function() {
    'use strict';

    function getImageRealUrl(img) {
      let imgUrl = img.src;

      const lazyAttrs = ['data-original', 'data-src', 'file', 'data-url', 'src'];
      for (let attr of lazyAttrs) {
            const url = img.getAttribute(attr);
            if (url && url.trim() !== '' && !url.startsWith('data:image')) {
                imgUrl = url;
                break;
            }
      }

      try {
            if (imgUrl && !imgUrl.startsWith('http')) {
                imgUrl = new URL(imgUrl, window.location.origin).href;
            }
      } catch (e) {}

      return imgUrl || null;
    }

    function hasImagesInSelection(selection) {
      if (!selection || selection.rangeCount === 0) return false;

      try {
            const range = selection.getRangeAt(0);
            const container = document.createElement('div');
            container.appendChild(range.cloneContents());
            return container.getElementsByTagName('img').length > 0;
      } catch (e) {
            return false;
      }
    }

    function isUnwantedText(text) {
      if (!text) return false;
      const unwantedPatterns = [
            /下载附件/,
            /保存到相册/,
            /图片尺寸/,
            /\d+\.\d{2}\s*KB/,
            /\d+\s*x\s*\d+\s*像素/,
            /下载次数:?\s*\d+/,
            /本帖最后由.*编辑/,
            /发表于\s*\d{4}-\d{1,2}-\d{1,2}/,
            /来自:/
      ];

      return unwantedPatterns.some(pattern => pattern.test(text));
    }

    function cleanUnwantedNodes(container) {
      const nodesToRemove = [];

      const walker = document.createTreeWalker(
            container,
            NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT,
            {
                acceptNode: function(node) {
                  if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.tagName === 'IMG') {
                            return NodeFilter.FILTER_SKIP;
                        }

                        if (node.className && typeof node.className === 'string') {
                            if (node.className.includes('attinfo') ||
                              node.className.includes('tip') ||
                              node.className.includes('attnm') ||
                              node.className.includes('xg1') ||
                              node.className.includes('patt') ||
                              node.className.includes('authi')) {
                              return NodeFilter.FILTER_ACCEPT;
                            }
                        }

                        if (node.tagName === 'SPAN' || node.tagName === 'DIV' || node.tagName === 'EM') {
                            const text = node.textContent || '';
                            if (isUnwantedText(text) && !node.querySelector('img')) {
                              return NodeFilter.FILTER_ACCEPT;
                            }
                        }
                  }

                  if (node.nodeType === Node.TEXT_NODE) {
                        const text = node.textContent || '';
                        if (isUnwantedText(text)) {
                            return NodeFilter.FILTER_ACCEPT;
                        }
                  }

                  return NodeFilter.FILTER_SKIP;
                }
            }
      );

      let node;
      while (node = walker.nextNode()) {
            nodesToRemove.push(node);
      }

      nodesToRemove.forEach(node => {
            if (node.parentNode) {
                if (node.nodeType === Node.TEXT_NODE) {
                  node.parentNode.removeChild(node);
                } else {
                  if (!node.querySelector('img')) {
                        node.parentNode.removeChild(node);
                  }
                }
            }
      });

      return container;
    }

    function removeEmptyNodes(container) {
      let changed;
      do {
            changed = false;
            const emptyNodes = [];

            const walker = document.createTreeWalker(
                container,
                NodeFilter.SHOW_ELEMENT,
                {
                  acceptNode: function(node) {
                        if (node.tagName !== 'IMG' &&
                            node.tagName !== 'BR' &&
                            node.children.length === 0 &&
                            (!node.textContent || node.textContent.trim() === '')) {
                            return NodeFilter.FILTER_ACCEPT;
                        }
                        return NodeFilter.FILTER_SKIP;
                  }
                }
            );

            let node;
            while (node = walker.nextNode()) {
                emptyNodes.push(node);
            }

            emptyNodes.forEach(node => {
                if (node.parentNode) {
                  node.parentNode.removeChild(node);
                  changed = true;
                }
            });
      } while (changed);

      return container;
    }

    function processCopyEvent(e) {
      const selection = window.getSelection();

      if (!selection || selection.rangeCount === 0) return;

      const hasImages = hasImagesInSelection(selection);

      if (!hasImages && (!selection.toString() || selection.toString().trim() === '')) return;

      try {
            const range = selection.getRangeAt(0);
            const container = document.createElement('div');
            container.appendChild(range.cloneContents());

            const images = container.getElementsByTagName('img');
            const imageCount = images.length;

            if (imageCount === 0 && !hasImages) {
                if (container.textContent.trim()) {
                  e.clipboardData.setData('text/plain', selection.toString());
                  e.clipboardData.setData('text/html', container.innerHTML);
                  e.preventDefault();
                }
                return;
            }

            for (let i = images.length - 1; i >= 0; i--) {
                const img = images;
                const imgUrl = getImageRealUrl(img);

                if (imgUrl) {
                  const imgText = `${imgUrl}`;
                  const textNode = document.createTextNode(imgText);

                  if (img.parentNode) {
                        img.parentNode.replaceChild(textNode, img);
                  }
                } else {
                  const imgText = `${img.src}`;
                  const textNode = document.createTextNode(imgText);

                  if (img.parentNode) {
                        img.parentNode.replaceChild(textNode, img);
                  }
                }
            }

            cleanUnwantedNodes(container);
            removeEmptyNodes(container);

            let processedText = container.textContent || container.innerText || '';

            processedText = processedText
                .split('\n')
                .map(line => line.trim())
                .filter(line => line.length > 0)
                .join('\n')
                .replace(/\n{3,}/g, '\n\n');

            if (imageCount > 0 && processedText.trim() === '') {
                const imgTexts = [];
                for (let i = 0; i < imageCount; i++) {
                  const img = images;
                  const imgUrl = getImageRealUrl(img) || img.src;
                  imgTexts.push(`${imgUrl}`);
                }
                processedText = imgTexts.join('\n');
            }

            const processedHtml = container.innerHTML;

            if (processedText) {
                e.clipboardData.setData('text/plain', processedText);
                e.clipboardData.setData('text/html', processedHtml);
                e.preventDefault();
            }
      } catch (error) {
            console.error('复制处理错误:', error);
      }
    }

    function addCopyListener() {
      document.removeEventListener('copy', processCopyEvent, true);
      document.addEventListener('copy', processCopyEvent, true);
    }

    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', addCopyListener);
    } else {
      addCopyListener();
    }
})();

Sister_Rao 发表于 2026-2-21 21:27:26

好方便的功能!
之前一直觉得不能直接复制图片太麻烦了,lz简直神来的:victory:

娱乐法师火布偶 发表于 2026-2-21 21:29:25

系列帖子就可以直接复制来复用图片了

crabee 发表于 2026-2-21 21:31:20

感觉编辑帖子会更舒服了,也是利好发帖型坛友了{:6_175:}

名都到啊 发表于 2026-2-21 21:34:12

发帖的时候一复制图片就会看见一块错误空白,这下好惹,很方便~!

凯诺斯 发表于 2026-2-21 21:36:30

同时复制文字和图片真是很方便惹,可以不用分开操作两次了

因本 发表于 2026-2-21 21:40:46

神奇,应该很适合从草稿箱中复制,然后从外面直接发新帖,以规避草稿箱不触发勋章的bug

一只随行 发表于 2026-2-21 21:42:27

确实这样子的话有些帖子发起来就更方便了哇,省下了复制图片的很多步骤{:6_184:}

PURO_ 发表于 2026-2-21 21:45:52

有这个脚本发帖更加便捷了呢,不用自己再排一遍帖子的格式了https://img.gamemale.com/album/202508/31/092111u1rzt6h6tzeezd11.jpg

380664191 发表于 2026-2-21 21:50:00

有点厉害啦,比双击复制图片更加方便一些(*´・v・)

cinder 发表于 2026-2-21 21:50:47

感覺對我最大的用處是拿來偷壇友們的表情包.XD

lishan 发表于 2026-2-21 22:03:27

太方便了, 有时候论坛gif图片很难一次性复制, 用这个试试能不能批量保存~

熊赳赳 发表于 2026-2-21 22:04:07

这脚本让复制图文更方便了,省去手动插入图片的麻烦惹

Se7en 发表于 2026-2-21 22:11:38

這個腳本挺好用的,編輯帖子的時候會很方便。

Burry 发表于 2026-2-21 22:26:08

一键复制图片文字的脚本,十分的便利呢,感谢分享。

zibatco2 发表于 2026-2-21 22:53:44

能够同时一键复制图片和文字感觉很方便的插件脚本惹~感谢楼主大佬分享啦{:4_91:}

相见忧 发表于 2026-2-21 23:08:51

https://img.gamemale.com/album/202509/04/083047t3sjzml6szil4o26.gif感觉会是一个很方便的功能,文字和图片一起复制

毛茸茸兽兽 发表于 2026-2-21 23:42:13

省略了几个步骤欸(´×ω×`)咱之前都是分开进行的

娱乐伙伴琴键猴 发表于 2026-2-22 00:41:59

节省了一些操作步骤,让发帖更快速了

盘上雷 发表于 2026-2-22 00:48:07

这下可以先写好再复制,不用额外再插入图片了
页: [1] 2
查看完整版本: 【脚本】一键复制文字图片