GameMale
登陆 / 注册 搜索

USERCENTER

SEARCHSITE

搜索

查看: 4366|回复: 83
收起左侧

[扩展] GM论坛勋章博物馆属性复制助手

  [复制链接] |关注本帖

组件大师

     楼主| 咸鱼鱼 发表于 2025-4-30 10:53:56 | 显示全部楼层 |阅读模式 <

    目前大家往勋章博物馆贴属性,多采用截图的形式
    导致有两个缺点:
    1. 获取的图片不是gif而是静态图片,不能完整地展示勋章卡面
    2. 如果勋章描述是英文、日文、火星文、摩尔斯电码之类的内容,手打和文字识别起来有亿亿点困难
    3. 图片太长太大,不够美观
    现在既然我是勋章博物馆的站员了,那么我就应该负起责任
    于是基于黑达克之前的勋章属性格式,我写了一个脚本
    方便大家在勋章博物馆贴属性的时候,快速的获取勋章卡面和属性,同时也避免打错字之类的情况发生

    安装这个脚本时候,可以在我的勋章界面,或者帖子中任意一个勋章点击Ctrl+右键
    粘贴板里面暂存了对应勋章的勋章卡面图片链接 + 勋章描述 + 勋章属性
    其中勋章卡面是直接使用了勋章的图片链接,所以无需右键另存为图片再重新上传
    其中勋章属性因为不知道是手动升级还是自动升级,所以给出了两种格式供大家手动删除

    在新勋章上新的时间点推出这个脚本,希望大家都安装使用
    使用方法:在我的勋章界面和帖子内的勋章,
    ctrl+鼠标右键,复制好属性,然后找个地方粘贴即可
    在升级的时候右键保存一下属性和图片链接
    先暂存到本地的TXT和Word文档内,等勋章博物馆发了勋章贴之后再贴属性
    此外推荐大家使用纯文本编辑模式,这样能保证格式更不容易受到影响


    效果演示


    @Name @Match
    1. // ==UserScript==
    2. // @name         GM论坛勋章博物馆属性复制助手
    3. // @namespace    http://tampermonkey.net/
    4. // @version      1.2
    5. // @description  使用方法,ctrl+鼠标右键,复制
    6. // @author       YourName
    7. // @match        https://www.gamemale.com/wodexunzhang-showxunzhang.html?action=my
    8. // @match        https://www.gamemale.com/thread-*
    9. // @match        https://www.gamemale.com/forum.php?mod=viewthread&tid=*
    10. // @grant        none
    11. // @icon         https://www.gamemale.com/template/mwt2/extend/img/favicon.ico
    12. // ==/UserScript==

    13. (function () {
    14.     'use strict'

    15.     document.addEventListener('contextmenu', async (e) => {
    16.         if (!e.ctrlKey) return
    17.         e.preventDefault()

    18.         try {
    19.             const target = findValidTarget(e.target)
    20.             if (!target) return

    21.             // 统一数据采集
    22.             const rawData = collectRawData(target)
    23.             // 统一数据处理
    24.             const formattedData = processRawData(rawData)
    25.             console.log(formattedData)
    26.             const result = formatFinalData(formattedData)

    27.             await navigator.clipboard.writeText(result)
    28.             showFeedback('✅ 数据已复制')
    29.         } catch (err) {
    30.             console.error('处理失败:', err)
    31.             showFeedback('⚠ 数据提取失败')
    32.         }
    33.     })

    34.     // 统一数据采集
    35.     function collectRawData(target) {
    36.         const isCase1 = target.matches('img[tip]')
    37.         const isCase2 = target.matches('.mytip')

    38.         if (isCase1) {
    39.             return {
    40.                 type: 'case1',
    41.                 imgSrc: target.src,
    42.                 tipHtml: target.getAttribute('tip'),
    43.                 element: target
    44.             }
    45.         }

    46.         if (isCase2) {
    47.             const myblok = target.closest('.myblok')
    48.             return {
    49.                 type: 'case2',
    50.                 imgSrc: myblok?.querySelector('.myimg img')?.src,
    51.                 titleHtml: target.querySelector('.mingcheng')?.innerHTML,
    52.                 descriptionText: target.querySelector('.shuoming')?.textContent,
    53.                 attributes: Array.from(target.querySelectorAll('.jiage.shuxing'))
    54.                     .map(p => p.innerHTML),
    55.                 element: myblok
    56.             }
    57.         }

    58.         throw new Error('未知的数据类型')
    59.     }

    60.     // 统一数据处理
    61.     function processRawData(rawData) {
    62.         // 公共字段
    63.         const baseData = {
    64.             imgSrc: rawData.imgSrc || '无图片地址',
    65.             nextLevel: null
    66.         }

    67.         // 类型专属处理
    68.         if (rawData.type === 'case1') {
    69.             const doc = new DOMParser().parseFromString(rawData.tipHtml, 'text/html')
    70.             return {
    71.                 ...baseData,
    72.                 titleHtml: doc.querySelector('h4')?.innerHTML || '',
    73.                 descriptionText: doc.querySelector('p:not(.wode_shuxing p)')?.textContent || '',
    74.                 attributes: Array.from(doc.querySelectorAll('.wode_shuxing p'))
    75.                     .map(p => p.innerHTML),
    76.                 nextLevel: findNextLevel(doc)
    77.             }
    78.         }

    79.         if (rawData.type === 'case2') {
    80.             return {
    81.                 ...baseData,
    82.                 titleHtml: rawData.titleHtml || '',
    83.                 descriptionText: rawData.descriptionText || '',
    84.                 attributes: rawData.attributes,
    85.                 nextLevel: findNextLevel(rawData.element)
    86.             }
    87.         }
    88.     }

    89.     // 统一字段格式化
    90.     function formatFinalData(processedData) {
    91.         const formattedData = [
    92.             `[img]${processedData.imgSrc}[/img]`,
    93.             `[font=黑体][b]${formatTitle(processedData.titleHtml)}[/b][/font]`,
    94.             `[font=仿宋,仿宋_GB2312][b][color=Gray]${formatDescription(processedData.descriptionText)}[/color][/b][/font]`,
    95.             `[font=楷体,楷体_GB2312][b]${formatAttributes(processedData.attributes)}[/b][/font]` +
    96.             (processedData.nextLevel ? `[font=微软雅黑][b]▕▏[/b][/font][font=楷体, 楷体_GB2312][b]升级条件:${processedData.nextLevel}[/b][/font]` : ''),
    97.         ].filter(Boolean)

    98.         // 添加空行,避免影响后面的格式
    99.         // 看不出来,还是算了吧
    100.         // formattedData.push('')

    101.         return formattedData.join('\n')
    102.     }

    103.     // 格式化函数组
    104.     function formatTitle(html) {
    105.         return html
    106.             .replace(/<\/?h4>/g, '')
    107.             .replace(/<b>/g, '')
    108.             .replace(/<\/b>/g, ' ')
    109.     }

    110.     function formatDescription(text) {
    111.         return text.trim().replace(/\s+/g, ' ')
    112.     }

    113.     function formatAttributes(attrs = []) {
    114.         // 分类存储数据
    115.         const { trigger, reply, post } = attrs.reduce((acc, item) => {
    116.             const text = item.replace(/\s+|(&nbsp;)+/g, ' ').replace(/ (\+|-)/g, '$1').trim()

    117.             // 提取触发概率
    118.             if (text.includes('触发几率')) {
    119.                 acc.trigger = text.match(/\d+%/) || []
    120.                 return acc
    121.             }

    122.             // 分类回帖/发帖属性
    123.             const [type, ...values] = text.split(' ')
    124.             if (type === '回帖') acc.reply.push(...values)
    125.             if (type === '发帖') acc.post.push(...values)

    126.             return acc
    127.         }, { trigger: '', reply: [], post: [] })

    128.         // console.log(trigger, reply, post)

    129.         // 构建结果字符串
    130.         const parts = []
    131.         if (trigger) parts.push(trigger)
    132.         if (reply.length) parts.push(`回帖${reply.join(' ')}`)
    133.         if (post.length) parts.push(`发帖${post.join(' ')}`)

    134.         if (attrs.length === 0) {
    135.             return '无属性'
    136.         } else {
    137.             return parts.join('、').replace(/(%)、/, '$1 ')
    138.         }
    139.     }

    140.     // 辅助函数
    141.     function findValidTarget(startElement) {
    142.         if (startElement.matches('img[tip]')) return startElement

    143.         const myblok = startElement.closest('.myblok')
    144.         if (myblok) {
    145.             const mytip = myblok.querySelector('.mytip')
    146.             if (mytip) return mytip
    147.         }

    148.         throw new Error('未找到有效数据元素')
    149.     }

    150.     // 消耗xx属性,或者属性≥xx
    151.     function findNextLevel(element) {
    152.         const nextLevelDiv = Array.from(element.querySelectorAll('.wode_shuxing, .jiage'))
    153.             .find(el => el.textContent.includes('下一级'))

    154.         if (!nextLevelDiv) return null

    155.         // 清理文本
    156.         const processedText = nextLevelDiv.textContent
    157.             .replace(/下一级/g, '')
    158.             .replace(/&nbsp;/g, ' ')
    159.             .replace(/\s+/g, ' ')
    160.             .trim()

    161.         // 使用正则匹配【属性名 数字/数字】格式
    162.         const matches = processedText.match(/([\u4e00-\u9fa5]+)\s*(\d+)\/(-?\d+)/)


    163.         if (!matches) return null

    164.         const attribute = matches[1] // 属性名(如发帖数、金币等)
    165.         const requiredValue = matches[3] // 斜杠后的数字(如404)

    166.         return `消耗${requiredValue}${attribute} 或者 ${attribute}≥${requiredValue}`
    167.     }

    168.     function showFeedback(message) {
    169.         showPrompt(null, null, `<i>${message}</i>`, 2000)
    170.     }
    171. })()
    复制代码


    此外我最近也抽空把几乎所有的博物馆勋章都进行了整理
    主要内容是,如果你的帖子包含的所有的属性、卡面、描述的其中之一,且不是截图的形式,都会被我置顶方便查看
    如果一个勋章的属性、卡面、描述,由多个回帖人共同提供,我则会自己弄一份整合版方便置顶,
    目前还有以下勋章缺乏完整的属性、卡面、描述。放在折叠的部分,期待有缘人补充
    (过于古老的故事类和奖品类勋章未统计,因为发行量稀少且难以补充)




    最后希望大家多多支持我的工作,把勋章博物馆弄得整整齐齐漂漂亮亮的
    同时发现这是我的第100个主题帖,那就爆500金币庆祝一下吧

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x

    评分

    参与人数 27血液 +81 追随 +27 堕落 +15 收起 理由
    相见忧 + 1 赞一个!
    a0015100151 + 5 + 1 很给力!
    you9632587 + 5 + 1
    书の妖怪 + 3 + 1 很给力!
    sanweny + 3 + 1 + 1 很给力!
    zibatco2 + 3 + 1 + 1 赞一个!
    瓦尼 + 1 很给力!
    星之子 + 5 + 1 + 1 (*/ω\*)
    xvyi + 3 + 1
    wubingyonglei + 1 很给力!

    查看全部评分

    回复

    使用道具 举报

    『逆境中的幸运女神』『冰雕马拉橇』『梦旅存根』『厢庭望远』璀璨金币不洁圣子小丑与格雷与星光璀璨幸运女神的微笑

      亚洛斯 发表于 2025-4-30 11:05:30 | 显示全部楼层 <

      回帖奖励 +10 枚金币

      很棒的脚本,一键复制用来填充博物馆属性很方便也很快捷,妈妈再也不用担心我发属性贴被抢先了(
      回复

      使用道具 举报

      猫咪点唱机吸血魔蝠弗雷迪玩偶传奇虚空之海的鲸呆猫苏醒的格罗姆守卫: 坚守眼位金钱马车月影狼

        SweetUncle 发表于 2025-4-30 11:05:57 | 显示全部楼层 <

        回帖奖励 +10 枚金币

        支持鱼宝喵~脚本对于整理勋章属性格式规范很有用噢~
        感谢鱼宝宝的大JB,很美味想再吃一点,吃干抹净捏
        回复

        使用道具 举报

        You Can Pet Blaidd業火死鬥传奇卡利亚权杖极·龙の意生金蛋的鹅虚空之海的鲸竹取物语结晶化法杖

          找乐子企鹅仔 发表于 2025-4-30 11:06:39 | 显示全部楼层 <

          回帖奖励 +10 枚金币

          回复

          使用道具 举报

            万俟 发表于 2025-4-30 11:07:50 | 显示全部楼层 <
            回复

            使用道具 举报

            发条八音盒弗雷迪玩偶桂花米糕雄躯的昇格隔墙有眼莱因哈特·威尔海姆克里斯·埃文斯魯杰羅·弗雷迪索林·临终一役

              死水 发表于 2025-4-30 11:08:18 | 显示全部楼层 <
              回复

              使用道具 举报

              業火死鬥传奇检定场弗雷迪玩偶桂花米糕虚空之海的鲸【圣诞限定】心心念念小雪人吃饱金币的Doge缘起星空鎏彩万幢

                柏芸 发表于 2025-4-30 11:09:08 | 显示全部楼层 <

                回帖奖励 +10 枚金币

                和以往比起来确实要方便复制卡面和勋章描述多了,而且有了统一的工具也不用担心杂乱,非常棒的脚本,有机会我也要出一份力
                回复

                使用道具 举报

                蒂法·洛克哈特鎏彩万幢Dante最终幻想XVI荒野大镖客:救赎 II雪王的心脏不曾寄出的信件漂洋小船

                  Daddy控 发表于 2025-4-30 11:09:08 | 显示全部楼层 <
                  回复

                  使用道具 举报

                  桂花米糕冬之歌

                    莲一 发表于 2025-4-30 11:09:26 | 显示全部楼层 <

                    回帖奖励 +10 枚金币

                    勋章博物馆的大大们辛苦啦,这下降低了门槛之后感觉缺失的卡面广大的坛友也会慢慢补齐的
                    回复

                    使用道具 举报

                    桂花米糕索尔·奥丁森干涸的圣杯无尽的怀表原初の珍珠雄躯的昇格蜂蜂小甜心不灭的蓝宝石永远的克叔萨菲罗斯

                      泥潭蘑菇 发表于 2025-4-30 11:10:46 | 显示全部楼层 <

                      回帖奖励 +10 枚金币

                      回复

                      使用道具 举报

                      弗雷迪玩偶发条八音盒桂花米糕鎏彩万幢女巫之路虚空之海的鲸【新春限定】果体 隆『召唤好运的角笛』永远的克叔業火死鬥

                        娱乐法师火布偶 发表于 2025-4-30 11:10:47 | 显示全部楼层 <
                        回复

                        使用道具 举报

                        发条八音盒弗雷迪玩偶夏日柯基炽焰咆哮虎perrito幸福的小阿尔传奇克苏鲁的仆从御医神兔呆猫

                          Magicskull 发表于 2025-4-30 11:17:22 | 显示全部楼层 <

                          回帖奖励 +10 枚金币

                          回复

                          使用道具 举报

                          漂洋小船冒险用指南针破损的旧书人鱼之泪雪王的心脏苏格兰圆脸胖鸡[Pro Max]丛林的鸟飞走了不曾寄出的信件幽灵竹筒『随时随地开启!』

                            凯诺斯 发表于 2025-4-30 11:17:42 | 显示全部楼层 <
                            回复

                            使用道具 举报

                            炼金之心遗忘之水神秘商店贵宾卡祈祷术史莱哲林敖蜃星黑暗交易召唤古代战士水泡术雷霆晶球

                              你好再见 发表于 2025-4-30 11:24:29 | 显示全部楼层 <
                              回复

                              使用道具 举报

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

                                一只随行 发表于 2025-4-30 11:25:32 | 显示全部楼层 <
                                回复

                                使用道具 举报

                                弗雷迪玩偶巨力橡果桂花米糕发条八音盒『落樱缤纷』『召唤好运的角笛』『灰域来音』『眼榴』『不败之花』『泥潭颂唱者』

                                  notunicorna 发表于 2025-4-30 11:26:14 | 显示全部楼层 <

                                  回帖奖励 +10 枚金币

                                  这是只会提取当前等级的信息嘛
                                  回复

                                  使用道具 举报

                                  You Can Pet Blaidd炽焰咆哮虎百万核爆業火死鬥传奇不灭狂雷牛局长博戈【夏日限定】夏日的泰凯斯灯载情绵实现梦想

                                    臭熊猫 发表于 2025-4-30 11:35:58 | 显示全部楼层 <

                                    回帖奖励 +10 枚金币

                                    这个好,虽然之前点击进入勋章详情页那个也很好用,如果能复制的话更快更直观不用多开页面了
                                    回复

                                    使用道具 举报

                                    萨赫的蛋糕发条八音盒弗雷迪玩偶裸体克里斯人到中年格拉迪欧拉斯明日之子【圣诞限定】心心念念小雪人黑曜石赤螯蝎虚空之海的鲸

                                      cinder 发表于 2025-4-30 11:41:46 | 显示全部楼层 <

                                      回帖奖励 +10 枚金币

                                      回复

                                      使用道具 举报

                                      『不败之花』『狄文卡德的残羽』龙鳞石近地夜航永亘环神奇宝贝大师球璀璨闪蝶鎏彩万幢

                                        kkiss 发表于 2025-4-30 11:46:39 | 显示全部楼层 <
                                        回复

                                        使用道具 举报

                                        发条八音盒弗雷迪玩偶丹妮莉丝·坦格利安时间尽头的虚空传奇苏格兰圆脸胖鸡You Can Pet Blaidd实现梦想索林·临终一役鎏彩万幢

                                          Inari 发表于 2025-4-30 12:02:25 | 显示全部楼层 <
                                          回复

                                          使用道具 举报

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

                                          本版积分规则

                                          关闭

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

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

                                          GMT+8, 2025-12-7 08:53 , Processed in 0.167730 second(s), 146 queries , Redis On.

                                          Copyright © 2013-2025 GameMale

                                          All Rights Reserved.

                                          快速回复 返回列表