GameMale
登陆 / 注册 搜索

USERCENTER

SEARCHSITE

搜索

查看: 783|回复: 31
收起左侧

[实用工具] 【脚本】一键复制文字图片

  [复制链接] |关注本帖

GM活动员

众志成城光之少女の魔法书背带鸭马上發Futūrum(未来)神奇宝贝大师球♬狂舞终乐章♬亭亭如盖

     楼主| Makima 发表于 前天 21:23 | 显示全部楼层 |阅读模式 <


    一般来说复制一段内容,里面的图片不会复制过去
    本脚本可以同时复制文字和图片
    其中的图片会转化为插入图片的格式

    类似的:
    @Name @Match
    1. // ==UserScript==
    2. // @name         GM一键复制图片
    3. // @version      1.0
    4. // @description  复制时自动将图片转换为插入图片的格式
    5. // @author       M
    6. // @match        https://www.gamemale.com/*
    7. // @run-at       document-start
    8. // @grant        none
    9. // ==/UserScript==

    10. (function() {
    11.     'use strict';

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

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

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

    27.         return imgUrl || null;
    28.     }

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

    31.         try {
    32.             const range = selection.getRangeAt(0);
    33.             const container = document.createElement('div');
    34.             container.appendChild(range.cloneContents());
    35.             return container.getElementsByTagName('img').length > 0;
    36.         } catch (e) {
    37.             return false;
    38.         }
    39.     }

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

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

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

    57.         const walker = document.createTreeWalker(
    58.             container,
    59.             NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT,
    60.             {
    61.                 acceptNode: function(node) {
    62.                     if (node.nodeType === Node.ELEMENT_NODE) {
    63.                         if (node.tagName === 'IMG') {
    64.                             return NodeFilter.FILTER_SKIP;
    65.                         }

    66.                         if (node.className && typeof node.className === 'string') {
    67.                             if (node.className.includes('attinfo') ||
    68.                                 node.className.includes('tip') ||
    69.                                 node.className.includes('attnm') ||
    70.                                 node.className.includes('xg1') ||
    71.                                 node.className.includes('patt') ||
    72.                                 node.className.includes('authi')) {
    73.                                 return NodeFilter.FILTER_ACCEPT;
    74.                             }
    75.                         }

    76.                         if (node.tagName === 'SPAN' || node.tagName === 'DIV' || node.tagName === 'EM') {
    77.                             const text = node.textContent || '';
    78.                             if (isUnwantedText(text) && !node.querySelector('img')) {
    79.                                 return NodeFilter.FILTER_ACCEPT;
    80.                             }
    81.                         }
    82.                     }

    83.                     if (node.nodeType === Node.TEXT_NODE) {
    84.                         const text = node.textContent || '';
    85.                         if (isUnwantedText(text)) {
    86.                             return NodeFilter.FILTER_ACCEPT;
    87.                         }
    88.                     }

    89.                     return NodeFilter.FILTER_SKIP;
    90.                 }
    91.             }
    92.         );

    93.         let node;
    94.         while (node = walker.nextNode()) {
    95.             nodesToRemove.push(node);
    96.         }

    97.         nodesToRemove.forEach(node => {
    98.             if (node.parentNode) {
    99.                 if (node.nodeType === Node.TEXT_NODE) {
    100.                     node.parentNode.removeChild(node);
    101.                 } else {
    102.                     if (!node.querySelector('img')) {
    103.                         node.parentNode.removeChild(node);
    104.                     }
    105.                 }
    106.             }
    107.         });

    108.         return container;
    109.     }

    110.     function removeEmptyNodes(container) {
    111.         let changed;
    112.         do {
    113.             changed = false;
    114.             const emptyNodes = [];

    115.             const walker = document.createTreeWalker(
    116.                 container,
    117.                 NodeFilter.SHOW_ELEMENT,
    118.                 {
    119.                     acceptNode: function(node) {
    120.                         if (node.tagName !== 'IMG' &&
    121.                             node.tagName !== 'BR' &&
    122.                             node.children.length === 0 &&
    123.                             (!node.textContent || node.textContent.trim() === '')) {
    124.                             return NodeFilter.FILTER_ACCEPT;
    125.                         }
    126.                         return NodeFilter.FILTER_SKIP;
    127.                     }
    128.                 }
    129.             );

    130.             let node;
    131.             while (node = walker.nextNode()) {
    132.                 emptyNodes.push(node);
    133.             }

    134.             emptyNodes.forEach(node => {
    135.                 if (node.parentNode) {
    136.                     node.parentNode.removeChild(node);
    137.                     changed = true;
    138.                 }
    139.             });
    140.         } while (changed);

    141.         return container;
    142.     }

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

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

    146.         const hasImages = hasImagesInSelection(selection);

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

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

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

    154.             if (imageCount === 0 && !hasImages) {
    155.                 if (container.textContent.trim()) {
    156.                     e.clipboardData.setData('text/plain', selection.toString());
    157.                     e.clipboardData.setData('text/html', container.innerHTML);
    158.                     e.preventDefault();
    159.                 }
    160.                 return;
    161.             }

    162.             for (let i = images.length - 1; i >= 0; i--) {
    163.                 const img = images[i];
    164.                 const imgUrl = getImageRealUrl(img);

    165.                 if (imgUrl) {
    166.                     const imgText = `[img]${imgUrl}[/img]`;
    167.                     const textNode = document.createTextNode(imgText);

    168.                     if (img.parentNode) {
    169.                         img.parentNode.replaceChild(textNode, img);
    170.                     }
    171.                 } else {
    172.                     const imgText = `[img]${img.src}[/img]`;
    173.                     const textNode = document.createTextNode(imgText);

    174.                     if (img.parentNode) {
    175.                         img.parentNode.replaceChild(textNode, img);
    176.                     }
    177.                 }
    178.             }

    179.             cleanUnwantedNodes(container);
    180.             removeEmptyNodes(container);

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

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

    188.             if (imageCount > 0 && processedText.trim() === '') {
    189.                 const imgTexts = [];
    190.                 for (let i = 0; i < imageCount; i++) {
    191.                     const img = images[i];
    192.                     const imgUrl = getImageRealUrl(img) || img.src;
    193.                     imgTexts.push(`[img]${imgUrl}[/img]`);
    194.                 }
    195.                 processedText = imgTexts.join('\n');
    196.             }

    197.             const processedHtml = container.innerHTML;

    198.             if (processedText) {
    199.                 e.clipboardData.setData('text/plain', processedText);
    200.                 e.clipboardData.setData('text/html', processedHtml);
    201.                 e.preventDefault();
    202.             }
    203.         } catch (error) {
    204.             console.error('复制处理错误:', error);
    205.         }
    206.     }

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

    211.     if (document.readyState === 'loading') {
    212.         document.addEventListener('DOMContentLoaded', addCopyListener);
    213.     } else {
    214.         addCopyListener();
    215.     }
    216. })();
    复制代码


    评分

    参与人数 3血液 +6 追随 +3 堕落 +1 收起 理由
    xineiyangtuo + 1 感谢分享
    万俟 + 5 + 1 + 1 三连献上
    cinder + 1 + 1 恭贺新春!

    查看全部评分

    回复

    使用道具 举报

    『正在入住GM村』GM論壇初心者勛章绷带内裤?最终幻想XVI牧羊人福卡·锰紫[8]

      Sister_Rao 发表于 前天 21:27 | 显示全部楼层 <
      好方便的功能!
      之前一直觉得不能直接复制图片太麻烦了,lz简直神来的
      回复

      使用道具 举报

      福卡·曙红[4]福卡·澄黄[1]福卡·锰紫[7]棱霜靴【新春限定】果体 隆白骨大法师塞拉斯鎏彩万幢男巫之歌女巫之路

        娱乐法师火布偶 发表于 前天 21:29 | 显示全部楼层 <
        系列帖子就可以直接复制来复用图片了
        回复

        使用道具 举报

        这天我们之间是粉色的抉择You Can Pet BlaiddSCP-s-1889-第五页圣金魔典夜魔护符收到情书福卡·曙红[5]福卡·澄黄[4]福卡·锰紫[7]

          crabee 发表于 前天 21:31 | 显示全部楼层 <
          感觉编辑帖子会更舒服了,也是利好发帖型坛友了
          回复

          使用道具 举报

          马上發福卡·锰紫[3]福卡·澄黄[6]福卡·曙红[3]水泡术萨赫的蛋糕

            名都到啊 发表于 前天 21:34 | 显示全部楼层 <
            发帖的时候一复制图片就会看见一块错误空白,这下好惹,很方便~!
            回复

            使用道具 举报

            福卡·曙红[6]福卡·澄黄[8]福卡·锰紫[3]炼金之心『随时随地开启!』破损的旧书『随时随地开启!』雪王的心脏人鱼之泪苏格兰圆脸胖鸡[Pro Max]

              凯诺斯 发表于 前天 21:36 | 显示全部楼层 <
              同时复制文字和图片真是很方便惹,可以不用分开操作两次了
              回复

              使用道具 举报

              果体蝙蝠侠塞拉斯威尔·格雷厄姆城市的站台(日)被冰封的板甲隐秘的讯息注满魔力的靴子可鲁贝洛斯逆流

                因本 发表于 前天 21:40 | 显示全部楼层 <
                神奇,应该很适合从草稿箱中复制,然后从外面直接发新帖,以规避草稿箱不触发勋章的bug
                回复

                使用道具 举报

                性感男神GM永远的守护者幽浮起司煲车厢特供 · 热巧 450ml图腾饼干『酒馆蛋煲』桂花米糕『南瓜拿铁』男巫之歌缘起星空

                  一只随行 发表于 前天 21:42 | 显示全部楼层 <
                  确实这样子的话有些帖子发起来就更方便了哇,省下了复制图片的很多步骤
                  回复

                  使用道具 举报

                  福卡·曙红[1]福卡·澄黄[4]福卡·锰紫[7]【夏日限定】夏日的泰凯斯永远的克叔狮醒山河成为蝙蝠侠【新春限定】果体 隆果体76小狮欢舞

                    PURO_ 发表于 前天 21:45 | 显示全部楼层 <
                    有这个脚本发帖更加便捷了呢,不用自己再排一遍帖子的格式了
                    回复

                    使用道具 举报

                    呆猫位面引航器马上發附魔金苹果雷霆晶球神秘商店贵宾卡思绪骤聚

                      380664191 发表于 前天 21:50 | 显示全部楼层 <
                      回复

                      使用道具 举报

                      男巫之歌【新春限定】果体 隆成为蝙蝠侠小镇的站台马上發福卡·曙红[2]福卡·澄黄[8]福卡·锰紫[1]永远的克叔裸体克里斯

                        cinder 发表于 前天 21:50 | 显示全部楼层 <
                        回复

                        使用道具 举报

                        【新春限定】果体 隆里昂‧S‧甘乃迪死亡化身男用贞操带苏格兰圆脸胖鸡[Pro Max]人鱼之泪冒险用指南针不曾寄出的信件永冻土

                          lishan 发表于 前天 22:03 | 显示全部楼层 <
                          回复

                          使用道具 举报

                          史莱哲林史莱姆牧场荒野大镖客:救赎 II丹雀衔五穗,人间始丰登月光骑士龙神巴哈姆特丹妮莉丝·坦格利安都市:天际线2跨过这道墙卡洛斯·奥利维拉

                            熊赳赳 发表于 前天 22:04 | 显示全部楼层 <
                            回复

                            使用道具 举报

                            【新春限定】果体 隆炼金之心索尔·奥丁森新春福袋杰森‧斯坦森失明盗梦空间超人骑兽之子

                              Se7en 发表于 前天 22:11 | 显示全部楼层 <
                              回复

                              使用道具 举报

                              黑暗交易業火死鬥魔法不朽·传奇不熄不舍的挽留帅气的本・比格十年一梦炽焰咆哮虎炙热的格拉迪欧拉斯永浴爱河男巫之歌

                                Burry 发表于 前天 22:26 | 显示全部楼层 <
                                回复

                                使用道具 举报

                                帅气的本・比格Amicus羽环鳐可鲁贝洛斯【新春限定】果体 隆弗雷迪玩偶新神的赐福小镇的站台肉乖乖永远的克叔

                                  zibatco2 发表于 前天 22:53 | 显示全部楼层 <
                                  回复

                                  使用道具 举报

                                  福卡·曙红[4]福卡·澄黄[0]福卡·锰紫[8]诺曼底号『冰雕马拉橇』禁断秘典『伊黎丝的赞美词』『不败之花』失窃不朽之恋

                                    相见忧 发表于 前天 23:08 | 显示全部楼层 <
                                    回复

                                    使用道具 举报

                                    我的天使GM吸血伯爵吃饱金币的Doge苏格兰圆脸胖鸡小小舞台守卫: 坚守眼位永浴爱河肉垫手套御医神兔『搓粉团珠』

                                      毛茸茸兽兽 发表于 前天 23:42 | 显示全部楼层 <
                                      回复

                                      使用道具 举报

                                      鎏彩万幢传奇都市:天际线2刀锋女王 - 归宿丹妮莉丝·坦格利安官复原职实现梦想丹雀衔五穗,人间始丰登Zootopia最终幻想XVI

                                        娱乐伙伴琴键猴 发表于 昨天 00:41 | 显示全部楼层 <
                                        回复

                                        使用道具 举报

                                        泰比里厄斯时间尽头的虚空猎个痛快!弗雷迪玩偶双重身份阿努比斯信徒帅气的本・比格月影狼炽焰咆哮虎妙手空空

                                          盘上雷 发表于 昨天 00:48 | 显示全部楼层 <
                                          回复

                                          使用道具 举报

                                          您需要登录后才可以回帖 登录 | 立即注册

                                          本版积分规则

                                          关闭

                                          站长公告上一条 /2 下一条

                                          文字版|手机版|小黑屋|GameMale

                                          GMT+8, 2026-2-23 12:10 , Processed in 0.158525 second(s), 149 queries , Redis On.

                                          Copyright © 2013-2026 GameMale

                                          All Rights Reserved.

                                          快速回复 返回列表