Delete Yunzai/plugins/miao-plugin
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- Yunzai/plugins/miao-plugin/.gitignore +0 -20
- Yunzai/plugins/miao-plugin/CHANGELOG.md +0 -377
- Yunzai/plugins/miao-plugin/LICENSE +0 -21
- Yunzai/plugins/miao-plugin/README.md +0 -106
- Yunzai/plugins/miao-plugin/apps/admin.js +0 -204
- Yunzai/plugins/miao-plugin/apps/character.js +0 -36
- Yunzai/plugins/miao-plugin/apps/character/AvatarCard.js +0 -132
- Yunzai/plugins/miao-plugin/apps/character/AvatarWife.js +0 -188
- Yunzai/plugins/miao-plugin/apps/character/ImgUpload.js +0 -258
- Yunzai/plugins/miao-plugin/apps/gacha.js +0 -26
- Yunzai/plugins/miao-plugin/apps/gacha/Gacha.js +0 -90
- Yunzai/plugins/miao-plugin/apps/gacha/GachaData.js +0 -444
- Yunzai/plugins/miao-plugin/apps/help.js +0 -23
- Yunzai/plugins/miao-plugin/apps/help/Help.js +0 -77
- Yunzai/plugins/miao-plugin/apps/help/HelpTheme.js +0 -68
- Yunzai/plugins/miao-plugin/apps/index.js +0 -16
- Yunzai/plugins/miao-plugin/apps/poke.js +0 -17
- Yunzai/plugins/miao-plugin/apps/profile.js +0 -143
- Yunzai/plugins/miao-plugin/apps/profile/ProfileArtis.js +0 -96
- Yunzai/plugins/miao-plugin/apps/profile/ProfileChange.js +0 -299
- Yunzai/plugins/miao-plugin/apps/profile/ProfileCommon.js +0 -77
- Yunzai/plugins/miao-plugin/apps/profile/ProfileDetail.js +0 -299
- Yunzai/plugins/miao-plugin/apps/profile/ProfileList.js +0 -184
- Yunzai/plugins/miao-plugin/apps/profile/ProfileRank.js +0 -280
- Yunzai/plugins/miao-plugin/apps/profile/ProfileStat.js +0 -73
- Yunzai/plugins/miao-plugin/apps/profile/ProfileUtils.js +0 -78
- Yunzai/plugins/miao-plugin/apps/profile/ProfileWeapon.js +0 -36
- Yunzai/plugins/miao-plugin/apps/stat.js +0 -37
- Yunzai/plugins/miao-plugin/apps/stat/AbyssStat.js +0 -164
- Yunzai/plugins/miao-plugin/apps/stat/AbyssSummary.js +0 -137
- Yunzai/plugins/miao-plugin/apps/stat/AbyssTeam.js +0 -190
- Yunzai/plugins/miao-plugin/apps/stat/HutaoApi.js +0 -73
- Yunzai/plugins/miao-plugin/apps/wiki.js +0 -29
- Yunzai/plugins/miao-plugin/apps/wiki/Calendar.js +0 -414
- Yunzai/plugins/miao-plugin/apps/wiki/CalendarSr.js +0 -303
- Yunzai/plugins/miao-plugin/apps/wiki/CharMaterial.js +0 -18
- Yunzai/plugins/miao-plugin/apps/wiki/CharTalent.js +0 -114
- Yunzai/plugins/miao-plugin/apps/wiki/CharWiki.js +0 -105
- Yunzai/plugins/miao-plugin/apps/wiki/CharWikiData.js +0 -108
- Yunzai/plugins/miao-plugin/components/App.js +0 -133
- Yunzai/plugins/miao-plugin/components/Cfg.js +0 -56
- Yunzai/plugins/miao-plugin/components/Common.js +0 -17
- Yunzai/plugins/miao-plugin/components/Data.js +0 -292
- Yunzai/plugins/miao-plugin/components/Format.js +0 -25
- Yunzai/plugins/miao-plugin/components/MiaoError.js +0 -17
- Yunzai/plugins/miao-plugin/components/Version.js +0 -109
- Yunzai/plugins/miao-plugin/components/cfg/CfgData.js +0 -47
- Yunzai/plugins/miao-plugin/components/common/Elem.js +0 -86
- Yunzai/plugins/miao-plugin/components/common/Plugin.js +0 -103
- Yunzai/plugins/miao-plugin/components/common/Render.js +0 -42
Yunzai/plugins/miao-plugin/.gitignore
DELETED
@@ -1,20 +0,0 @@
|
|
1 |
-
*.psd
|
2 |
-
.idea
|
3 |
-
/tools/char-data-sprider.js
|
4 |
-
/components/cfg.json
|
5 |
-
/resources/miao-res-plus/
|
6 |
-
/components/setting.json
|
7 |
-
/config.js
|
8 |
-
*.css.map
|
9 |
-
/resources/character-img/*/upload/
|
10 |
-
/resources/help/help-list.js
|
11 |
-
/resources/help/help-cfg.js
|
12 |
-
/resources/help/theme/*
|
13 |
-
!/resources/help/theme/default
|
14 |
-
/config/character.js
|
15 |
-
/config/profile.js
|
16 |
-
/config/help.js
|
17 |
-
/config/cfg.js
|
18 |
-
/resources/profile/super-character/*
|
19 |
-
/resources/profile/normal-character/*
|
20 |
-
/node_modules/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/CHANGELOG.md
DELETED
@@ -1,377 +0,0 @@
|
|
1 |
-
# 2.4.8
|
2 |
-
|
3 |
-
* 星铁面板支持面板变换功能
|
4 |
-
* 面板变换支持更换圣遗物套装,例如`#甘雨换乐团`、`#镜流换快枪手封印站`
|
5 |
-
* 微调面板页面的部分样式
|
6 |
-
|
7 |
-
# 2.4.1 ~ 2.4.7
|
8 |
-
|
9 |
-
* 初步支持星铁面板数据获取与展示
|
10 |
-
* 可使用`#星铁更新面板`来获取面板信息,通过`#希儿面板`来进行查看
|
11 |
-
* 星铁面板展示圣遗物评分,评分功能尚未完全完成,分值与样式不为最终版本
|
12 |
-
* 部分角色的伤害计算,以及圣遗物评分功能仍在补全中
|
13 |
-
* 星铁面板天赋展示更新,支持展示行迹信息
|
14 |
-
* 请配合使用Miao-Yunzai 3.1.0可达到最佳效果
|
15 |
-
* Miao-Yunzai可使用`*`来代填`#星铁`前缀,能区分游戏使用不同UID
|
16 |
-
* 其他Yunzai版本出现原神与星铁UID混淆情况为正常情况,请手动切换UID或命令后附加UID查询
|
17 |
-
* 角色数据及资源更新
|
18 |
-
* 增加原神4.0~4.2的角色信息,可通过`#水神天赋`、`#水神图鉴`查看
|
19 |
-
* 更新星铁1.2~1.3的角色数据与资源
|
20 |
-
* 伤害计算更新
|
21 |
-
* 增加林尼、卡夫卡、银狼的伤害计算**@Aluxes**
|
22 |
-
* 增加原神4.0相关的武器计算 **@SmallK111407**
|
23 |
-
* 增加菲米尼、符玄、玲可、三月七、娜塔莎、罗刹、黑塔的伤害计算 **@Aluxes**
|
24 |
-
* 初步增加星铁的排名功能 **@Simplxss**
|
25 |
-
* 增加`#喵喵api`命令,用于查看喵ApiToken的有效期
|
26 |
-
* 增加`#星铁日历`功能 **@Aluxes**
|
27 |
-
* 增加`#重载面板`功能,用于手工修改面板数据后主动读取
|
28 |
-
* 停用旧面板格式数据,非AttrIDs格式的数据不会展示,部分角色面板数据不展示是正常情况,重新更新面板数据即可
|
29 |
-
* 一些已知问题修复
|
30 |
-
|
31 |
-
# 2.4.0
|
32 |
-
|
33 |
-
* 增加`#角色记录``#抽卡统计`功能,可在`#喵喵设置`中开启
|
34 |
-
* `#角色记录`、`#武器记录`、`#常驻记录` 可查看对应池子的抽卡记录
|
35 |
-
* `#角色统计`、`#武器统计` 可按卡池汇总统计抽卡记录
|
36 |
-
* `#全部统计` 可将所有抽卡信息汇总展示
|
37 |
-
* 其余`#抽卡帮助`等相关功能均为Yunzai原生功能
|
38 |
-
* 面板服务增加国内专属面板服务 MiniGG-API
|
39 |
-
* 由小灰灰大佬**@MiniGrayGay**与Enka官方合作部署
|
40 |
-
* 国内节点,免费开放,请求速度会比Enka更快
|
41 |
-
* MiaoApi面板服务更新
|
42 |
-
* 使用新版接口获取面板,大幅提高响应速度
|
43 |
-
* 使用statsIds存储圣遗物数据,能够更精确的计算角色属性
|
44 |
-
* `#喵喵设置`中可区分国服、B服、外服分别设置面板服务器,具体参见喵喵设置
|
45 |
-
* `#面板`、`#角色`等页面使用Q版头像(@QuAn_、Misaaa),可在#喵喵设置 中关闭
|
46 |
-
* 增加白术、卡维的角色信息,可通过`#白术天赋`、`#白术图鉴`等查看
|
47 |
-
* 部分已知问题调整或优化
|
48 |
-
* 圣遗物、天赋更新策略及更新逻辑优化
|
49 |
-
* 面板更新的提醒文案逻辑优化
|
50 |
-
* `#雷神面板` 属性部分样式调整,增加圣遗物评分权重展示
|
51 |
-
* 圣遗物评级的分数上限微调
|
52 |
-
* 增加3.6新圣遗物数据及资源
|
53 |
-
* 增加绮良良的角色信息,可通过`#绮良良天赋`、`#绮良良图鉴`等查看
|
54 |
-
* 面板服务增加由**Snap Hutao**提供的Enka转发代理,可通过`#喵喵设置面板服务4`进行选择
|
55 |
-
* 面板详情的圣遗物词条增加词条数展示
|
56 |
-
* 角色面板使用平均词条值作为词条数计算基础
|
57 |
-
* 部分角色资源文件结构调整
|
58 |
-
|
59 |
-
# 2.3.0
|
60 |
-
|
61 |
-
* 重写底层面板、角色数据获取与保存逻辑
|
62 |
-
* 底层完全兼容面板及Mys数据,对于miao-plugin的大部分场景可做到数据通用
|
63 |
-
* 角色数据及天赋增加缓存逻辑,有缓存数据情况下可在ck失效/验证码等情况下正常使用大部分功能
|
64 |
-
* 全量使用通过圣遗物属性计算得到的面板数据
|
65 |
-
* 面板底层数据结构及存储逻辑优化,兼容老版本数据
|
66 |
-
* Enka服务下使用statsIds存储圣遗物数据,能够更精确的计算角色属性
|
67 |
-
* 增加`#角色`功能,查询并展示Mys角色信息
|
68 |
-
* Yunzai需要跟随游戏版本升级的功能会逐步在miao-plugin中提供,以保障基础功能相对长期可用
|
69 |
-
* 大部分功能目前默认关闭,可在`#喵喵设置`中设置并开启
|
70 |
-
* 为`#喵喵设置`增加更多配置项
|
71 |
-
* 允许禁用非实装角色资料,关闭可禁用非实装角色资料及面板替换
|
72 |
-
* 允许禁用面板替换功能
|
73 |
-
* 允许禁用获取角色或面板原图功能
|
74 |
-
* 可选择面板服务,可选喵喵Api优先(需具备Token)或Enka优先
|
75 |
-
* 可设置群排名人数、圣遗物列表展示数 **@SmallK111407**
|
76 |
-
* 角色信息及伤害计算更新
|
77 |
-
* 更新迪希雅、米卡的最新天赋与命座数据
|
78 |
-
* 增加瑶瑶伤害计算
|
79 |
-
* 其他功能及界面优化,部分已知问题调整
|
80 |
-
* `#上传深渊` 界面与样式调整
|
81 |
-
* `#刷新排名`、`#禁用排名`、`#启用排名`可由群管理员进行管理
|
82 |
-
* 增加`#删除面板`命令,目前限绑定CK用户使用删除自己UID数据,Bot主人可删除任意UID数据
|
83 |
-
|
84 |
-
# 2.2.0
|
85 |
-
|
86 |
-
* 增加面板替换功能,可通过命令更换面板的圣遗物、武器、天赋命座等,用于伤害计算
|
87 |
-
* `#雷神面板换稻光换90级满命` / `#刻晴面板换雷神圣遗物` 等命令
|
88 |
-
* 更多命令参见 `#面板帮助`,请根据需求吟唱。后续会提供更细致的咒语详解
|
89 |
-
* 增加角色面板立绘图相关命令 **@cvs**
|
90 |
-
* 支持`#上传刻晴面板图`上传
|
91 |
-
* 新增`#刻晴面板图列表`
|
92 |
-
* 可通过指令查询当前可看的面板立绘
|
93 |
-
* 立绘支持`#原图`指令
|
94 |
-
* 角色立绘支持随机,用于面板场景
|
95 |
-
* 图像支持webp及png格式
|
96 |
-
* 普通立绘:**resources/profile/normal-character/**
|
97 |
-
* 彩蛋立绘(满命/ACE/三皇冠):**resources/profile/super-character/**
|
98 |
-
* 单张立绘请放置在普通&彩蛋目录下,以**角色全名**为**文件名**,例如**刻晴.webp**
|
99 |
-
* 如需多张随机,请在普通&彩蛋目录下,以**角色全名**为**目录**名,任意文件名为文件名,例如 **刻晴/1.png**
|
100 |
-
* 较低版本的Yunzai可能无法正常使用miao-plugin
|
101 |
-
* 部分底层结构升级
|
102 |
-
* 去除插件内自带的V2/V3兼容逻辑,使用runtime进行V2/V3兼容,如使用遇到问题请升级至最新版Yunzai
|
103 |
-
* 底层增加面板计算逻辑, 圣遗物数据底层存储格式与处理逻辑初步升级
|
104 |
-
* 圣遗物主词条评分规则微调,可能会影响部分角色评分
|
105 |
-
* 元素杯属性不符会触发主词缀评分惩罚
|
106 |
-
* 充能主词条不再触发主词缀评分惩罚
|
107 |
-
* 增加`#启用排名``#禁用排名`命令,可在全局启用排名情况下,在特定群内禁用排名功能
|
108 |
-
* 更新迪希雅、米卡、瑶瑶、艾尔海森的信息,可通过`#瑶瑶天赋`、`#瑶瑶图鉴`等查看
|
109 |
-
* 增加散兵、艾尔海森 **@panganqi**、珐露珊的伤害计算
|
110 |
-
* 增加归终、米卡的角色图像
|
111 |
-
* 其他一些已知问题修正与样式优化
|
112 |
-
|
113 |
-
# 2.1.0
|
114 |
-
|
115 |
-
* 增加群内排名功能
|
116 |
-
* 默认关闭,如需启用可通过 `#喵喵设置排名开启`进行打开
|
117 |
-
* 统计为bot本地统计,只统计在群内主动查看过的面板数据
|
118 |
-
* 可通过 `#面板`、`#心海面板`、`#更新面板`等命令来触发排名数据更新
|
119 |
-
* 增加命令 `#刷新排名`,获取群成员面板数据,刷新当前排名 **@munnks**
|
120 |
-
* `#雷神排名` 使用个人头像作为排行头像展示(首次使用可使用 `#刷新排名`以更新uid信息)
|
121 |
-
* 增加排名相关命令
|
122 |
-
* 增加 `#最强雷神`、`#最高分甘雨`命令,查看当前统计中最高练度/最高圣遗物评分的面板数据
|
123 |
-
* 增加 `#雷神排名`、`#甘雨圣遗物排名`命令,查看当前群中角色的排名数据
|
124 |
-
* 增加 `#重置排名`、`#重置刻晴排名`命令,来重置当前群的排名统计
|
125 |
-
* 面板及伤害计算升级
|
126 |
-
* `#雷神面板`圣遗物支持展示强化次数
|
127 |
-
* `#面板`会展示角色名命座信息
|
128 |
-
* 底层元素反应计算逻辑更新 **@冷落**
|
129 |
-
* 增加纳西妲的伤害计算
|
130 |
-
* `#喵喵设置` 部分配置项及功能改进
|
131 |
-
* 删除一些无效或暂不支持的配置项
|
132 |
-
* 配置存储位置变更为**config/cfg.js**。原设置会自动迁移
|
133 |
-
* 喵喵设置中增加排名限制门槛,支持限制 有16个角色数据/包含御三家角色 才能参与排名,防止被非群成员uid刷榜
|
134 |
-
* `#日历` 页面样式微调,功能升级
|
135 |
-
* 日历中会展示角色生日
|
136 |
-
* 日历会展示本日可刷天赋角色列表
|
137 |
-
* 增加3.3角色信息及图片,可通过 `#散兵天赋`、`#珐露珊命座`查看
|
138 |
-
* 一些样式及功能点优化
|
139 |
-
* 优化character的进入判定逻辑,防止一些额外的log触发
|
140 |
-
* 角色相关命令在V3下会联合V3的角色别名一同查询
|
141 |
-
* `#深渊组队`使用新版胡桃API进行组队信息获取
|
142 |
-
* 增加命令 `#最强排行`、`#最高分排行` 查看群排行
|
143 |
-
* 增加莱依拉的伤害计算及圣遗物评分权重
|
144 |
-
|
145 |
-
# 2.0.0
|
146 |
-
|
147 |
-
* 底层架构升级,以V3为主要版本,V2做兼容处理
|
148 |
-
* `#深渊配队`、`#戳一戳` 适配V3
|
149 |
-
* `#喵喵帮助`配置功能升级
|
150 |
-
* 支持自定义帮助皮肤包,皮肤目录为**resources/help/theme**
|
151 |
-
* 若有多套皮肤包,默认随机使用,可通过**config/help.js**指定
|
152 |
-
* 支持配帮助文字颜色及容器颜色与透明度
|
153 |
-
* 支持图片毛玻璃效果,默认开启,可通过配置关闭
|
154 |
-
* `注意1:` 如之前更改过底图可能会在更新后失效,可将自定义底图放置在新建的皮肤包目录内
|
155 |
-
* `注意2:` 为统一配置目录,帮助配置文件迁移至**config/help.js**,如之前自定义过配置文件,help-cfg.js仍能够识别,但建议移至新配置目录以使用后续更多功能
|
156 |
-
* `#面板练度统计` 功能调整,样式重写
|
157 |
-
* 样式由深色调整为浅色方案
|
158 |
-
* 在未绑定CK时,使用本地面板数据展示练度信息
|
159 |
-
* 重写 `#刻晴`、`#老婆`的角色卡片
|
160 |
-
* 样式整体升级,展示信息重新排版
|
161 |
-
* 未绑定CK时,会同时使用本地面板数据进行展示
|
162 |
-
* `#上传深渊`队伍人数少于4人时展示样式优化
|
163 |
-
* MysApi内部逻辑重写
|
164 |
-
* 在未绑定CK时,会使用本地面板数据综合计算,以使信息展示更完备
|
165 |
-
* 优化V3下获取Uid及CK的逻辑,防止一些情况下触发报错
|
166 |
-
* 武器、圣遗物 meta数据及图像资源逻辑更新
|
167 |
-
* 重构武器及圣遗物的底层处理逻辑,重构页面引用图像资源的逻辑
|
168 |
-
* 图像资源更新为webp格式
|
169 |
-
* 增加多莉的伤害计算
|
170 |
-
* 其他已知Bug修复
|
171 |
-
|
172 |
-
# 1.11.0
|
173 |
-
|
174 |
-
* 面板圣遗物评分初步增加流派判定能力
|
175 |
-
* 实验性,尚未完全稳定,可能会导致一些角色圣遗物评分变化,如遇问题请反馈
|
176 |
-
* 目前实验暴力芭芭拉、血牛钟离的判定
|
177 |
-
* `#刻晴面板`、`#芭芭拉圣遗物`支持展示角色时装
|
178 |
-
* 如果角色装备了时装,面板的角色图会展示时装立绘
|
179 |
-
* 需要重新 `#更新面板`以获取时装数据
|
180 |
-
* 增加赛诺、妮露、坎蒂丝的角色信息,可以通过 `#妮露天赋`、`#妮露命座`查看角色信息了
|
181 |
-
* 角色面板支持旅行者,暂未支持伤害计算及圣遗物评分
|
182 |
-
* 需要重新更新旅行者的面板数据
|
183 |
-
* `#雷主天赋`、`#草主命座`功能升级
|
184 |
-
* 页面样式微调,内部处理逻辑升级
|
185 |
-
* 支持旅行者天赋及命座信息查看
|
186 |
-
* 增加 `#心海图鉴`功能,可查看突破材料及常用武器
|
187 |
-
* 功能尚未完全稳定,信息还在继续补全中
|
188 |
-
* 如无需使用,master可通过 `#喵喵设置图鉴关闭`关闭,防止覆盖图鉴插件等图鉴功能
|
189 |
-
* 框架底层角色相关逻辑重构,角色图像资源迁移为webp格式
|
190 |
-
* 若遇到图像资源无法正常展示,可联系喵喵反馈
|
191 |
-
|
192 |
-
# 1.10.0
|
193 |
-
|
194 |
-
* 新增 `#面板练度统计`功能
|
195 |
-
* 可展示当前角色天赋及圣遗物练度信息
|
196 |
-
* 需要用户绑定Cookie,圣遗物评分需要本地获取并查看过对应角色面板
|
197 |
-
* `#上传深渊`使用图片渲染深渊结果,同时可被 `#喵喵深渊`触发
|
198 |
-
* 可展示本期深渊的全部角色信息,包括组队、天赋及圣遗物
|
199 |
-
* 数据会上传至胡桃Api进行伤害排名,并展示在页面内
|
200 |
-
* 可在 `#喵喵设置`中启用 `#喵喵深渊`作为默认 `#深渊`,默认关闭
|
201 |
-
* 启用后不会覆盖 `#上期深渊`以及 `#深渊12层`具体楼层的命令
|
202 |
-
* `#面板`、`#更新面板`命令使用图片渲染结果
|
203 |
-
* `#雷神面板`展示数据API及更新时间
|
204 |
-
* Enka面板服务支持配置代理 **@永恒的小黑屋**
|
205 |
-
* 如需配置可在**miao-plugin/config/profile.js**文件中配置
|
206 |
-
* `#更新面板`支持配置更新API,适配Enka新校验逻辑
|
207 |
-
* B服角色使用Enka服务进行面板信息获取
|
208 |
-
* 感谢Enka官方 **@Algoinde**的官方授权及UA**校**验
|
209 |
-
* 感谢 **@MiniGrayGay**提供的Enka服务中转,若面板更新失败可尝试在**miao-plugin/config/profile.js**文件中配置切换更新API
|
210 |
-
* 更新面板增加单用户更新间隔控制,默认5分钟
|
211 |
-
* `#深渊出场率`、`#角色持有率` 增加样本数量展示,增加数据使用授权提示
|
212 |
-
* 部分角色的圣遗物评分增加充能的词条评分权重
|
213 |
-
* 重构部分components、models逻辑,重构部分伤害计算逻辑
|
214 |
-
* 伤害计算支持除旅行者外的全部角色
|
215 |
-
* 伤害计算暂未包含3.0新元素反应,后续统一补充
|
216 |
-
|
217 |
-
# 1.9.0
|
218 |
-
|
219 |
-
* 初步适配Yunzai V3
|
220 |
-
* 部分功能可能无法正常使用,会逐步适配
|
221 |
-
* 部分依赖MysApi查询的功能在V3下暂时只支持查自己
|
222 |
-
* 增加提纳里、柯莱、多莉的资料及角色图像
|
223 |
-
* 可通过 `#柯莱天赋`、`#柯莱命座`查看资料
|
224 |
-
* 增加 `#深渊使用率`命令,数据源自DGP-Studio胡桃API
|
225 |
-
* 新增 `#上传深渊数据`命令
|
226 |
-
* 上传自己角色的深渊挑战数据及角色列表,并展示在本期深渊中伤害与承伤排名
|
227 |
-
* 上传数据用于 `#角色持有率 #深渊出场率`等统计,可使统计更加及时准确
|
228 |
-
* 数据统计及服务来自DGP-Studio胡桃API
|
229 |
-
* 增加 `#添加刻晴图像`命令,感谢 **@叶**
|
230 |
-
* 可通过命令上传添加指定角色图片,上传至 **resources/character-img/刻晴/upload**
|
231 |
-
* 请将图像与命令一同发送,后续会支持at图像及命令后发送图像
|
232 |
-
* `#刻晴` 角色卡片功能升级
|
233 |
-
* `#老婆设置刻晴,心海`不再检查是否具有角色或展示在米游社展柜
|
234 |
-
* `#刻晴` 角色卡片优先使用面板数据进行展示,无面板数据时使用米游社数据
|
235 |
-
* 在未能获取到角色数据时也会展示角色卡片
|
236 |
-
* 支持戳一戳返回喵喵版角色卡片,暂不支持V3 Yunzai
|
237 |
-
* 需要使用喵喵分支Yunzai以支持此能力,如需切换可在Yunzai根目录输入下方命令后更新重启
|
238 |
-
* `git remote set-url origin https://gitee.com/yoimiya-kokomi/Yunzai-Bot`
|
239 |
-
* 可通过 `#喵喵设置` 关闭戳一戳
|
240 |
-
* 支持定义新角色及别名
|
241 |
-
* 新增角色 派蒙、瑶瑶、白术、伐难、应达、散兵、女士、萍姥姥、仆人、少女、富人、博士、木偶、丑角、队长、妮露、纳西妲 的角色配置及图片
|
242 |
-
* 自定义角色可使用 `#派蒙` `#派蒙图片`触发图片��看,`#女儿设置派蒙`进行设置。后续会支持更多场景
|
243 |
-
* 如需扩展可在喵喵config/character.js中定义
|
244 |
-
* `#喵喵帮助`增加对自定义配置文件的支持
|
245 |
-
* 角色伤害计算增加 鹿野院平藏、烟绯
|
246 |
-
* `#喵喵日历`现在可通过 `#日历 #日历列表`触发
|
247 |
-
|
248 |
-
# 1.8.0
|
249 |
-
|
250 |
-
* `#角色面板`、`#圣遗物列表` 使用新的圣遗物评分逻辑计算评分
|
251 |
-
* 新的圣遗物评分规针对不同角色进行了细化,对不同角色的评分进行了拉齐
|
252 |
-
* 不同角色基于不同词条权重进行计算。感谢 **@糖炒栗子 @秋声 @49631073**等的权重梳理
|
253 |
-
* 增加 `#雷神圣遗物`命令
|
254 |
-
* 展示指定角色圣遗物及评分计算详情
|
255 |
-
* 展示新版圣遗物评分逻辑与计算规则
|
256 |
-
* 增加 `#原图`命令,可获取喵喵角色卡片原图,感谢 **@牧星长** 提供功能
|
257 |
-
* 对由 `#老婆 #刻晴`发出的角色卡片图回复 `#原图`可获取对应图像
|
258 |
-
* `#角色面板`现在支持B服角色数据获取
|
259 |
-
* 数据来自喵喵API,目前开放调用无需Token,仅限喵喵插件用户使用
|
260 |
-
* 已知问题:角色天赋的皇冠及命座加成效果显示可能有问题,后期fix
|
261 |
-
* `#录入角色面板` 功能恢复
|
262 |
-
* 可对已有面板数据的角色手工输入更改面板属性,用于伤害测算
|
263 |
-
* 例如 `#录入雷神面板 暴击80,暴伤250`
|
264 |
-
* 暂不支持设置武器、圣遗物、命座、天赋。后续会增加支持
|
265 |
-
* 部分页面样式调整及功能优化
|
266 |
-
* `#角色持有率` 等增加提示说明
|
267 |
-
* `#圣遗物列表` 展示个数提升至28,且根据新版圣遗物评分规则进行词条高亮
|
268 |
-
* `#喵喵更新` 的自动重启功能适配node app方式启动的Yunzai-Bot,感谢 **@SirlyDreamer**
|
269 |
-
* 角色图像增加小清新开关,默认关闭
|
270 |
-
* 对增量包内的角色图像进行分级,较为清凉的图像独立管理
|
271 |
-
* 勇士们可使用 `#喵喵设置小清新开启` 启用
|
272 |
-
* 伤害计算增加扩散、感电的计算逻辑,感谢 **@49631073**的逻辑梳理
|
273 |
-
* `#角色面板` 伤害计算增加部分角色,目前支持
|
274 |
-
* 长柄武器:雷神、胡桃、魈、钟离、香菱
|
275 |
-
* 法器:神子、心海、可莉、凝光、芭芭拉、莫娜
|
276 |
-
* 弓:甘雨、宵宫、公子,九条,迪奥娜、安柏、皇女、温迪、夜兰
|
277 |
-
* 单手剑:绫人、绫华、刻晴、阿贝多、行秋、班尼特、七七、凯亚、琴、万叶ⁿᵉʷ、久岐忍ⁿᵉʷ
|
278 |
-
* 双手剑:一斗、优菈、迪卢克、诺艾尔、重云
|
279 |
-
|
280 |
-
# 1.7.0
|
281 |
-
|
282 |
-
* `#更新面板` 功能升级
|
283 |
-
* 该功能可直接使用,不再需要token
|
284 |
-
* 在查询新用户时会自动使用,自动使用的CD 12小时
|
285 |
-
* 支持国际服UID,目前暂不支持2及5开头的UID
|
286 |
-
* 服务来自enka api,部分网络可能无法请求,请科学处理,后续会增加转发服务。
|
287 |
-
* 由于服务逻辑与之前数据不一致,部分角色的属性及伤害计算可能会不准确,如有发现请反馈给喵喵
|
288 |
-
* `#面板`、`#更新面板`、`#角色面板`、`#角色伤害`、`#圣遗物列表`不再需要绑定cookie,支持查他人
|
289 |
-
* 使用 `#面板`命令可查看已获取面板数据的角色列表
|
290 |
-
* 默认查询自己UID,同时也可通过命令+uid方式指定查询对象
|
291 |
-
* 由于整体逻辑变化,喵喵1.6.0之前更新的面板数据无法查看,需要重新更新数据
|
292 |
-
* 增加 `#喵喵面板设置`命令,可更精细的设置是否允许好友/临时对话/群使用面板功能
|
293 |
-
* 由 `#录入xx面板` 录入的数据暂时屏蔽
|
294 |
-
* `#角色面板`、`#喵喵日历` 部分细节样式调整
|
295 |
-
* `#角色面板` 伤害计算增加部分角色,目前支持
|
296 |
-
* 长柄武器:雷神、胡桃、魈、钟离、香菱
|
297 |
-
* 法器:神子、心海、可莉、凝光、芭芭拉、莫娜ⁿᵉʷ
|
298 |
-
* 弓:甘雨、宵宫、公子,九条,迪奥娜、安柏、皇女ⁿᵉʷ、温迪ⁿᵉʷ、夜兰ⁿᵉʷ
|
299 |
-
* 单手剑:绫人、绫华、刻晴、阿贝多、行秋、班尼特、七七、凯亚、琴ⁿᵉʷ
|
300 |
-
* 双手剑:一斗、优菈、迪卢克、诺艾尔、重云
|
301 |
-
|
302 |
-
# 1.6.0
|
303 |
-
|
304 |
-
* `#喵喵设置` 支持设置 面板查询 的功能开关
|
305 |
-
* `#喵喵版本` 使用图片展示更新信息
|
306 |
-
* `#喵喵日历` 升级
|
307 |
-
* 增加 `#喵喵日历列表`命令,以列表形式展示活动信息
|
308 |
-
* 增加从活动详情信息中解析活动日期的逻辑,使一些活动日期更加准确
|
309 |
-
* 增加鹿野院平藏的角色信息,可通过 `#平藏天赋`、`#平藏命座`查看信息
|
310 |
-
* 其他升级调整
|
311 |
-
* `#深渊出场率`、`#角色持有率` 等页面功能及样式微调
|
312 |
-
* `#角色面板` 伤害计算增加双手剑计算逻辑,增加物伤计算逻辑
|
313 |
-
* 页面版权信息展示Yunzai及喵喵版本号
|
314 |
-
* `#角色面板` 伤害计算增加部分角色,目前支持
|
315 |
-
* 长柄武器:雷神、胡桃、魈、钟离、香菱
|
316 |
-
* 法器:神子、心海、可莉ⁿᵉʷ、凝光ⁿᵉʷ、芭芭拉ⁿᵉʷ
|
317 |
-
* 弓:甘雨、宵宫、公子,九条ⁿᵉʷ,迪奥娜ⁿᵉʷ、安柏ⁿᵉʷ
|
318 |
-
* 单手剑:��人、绫华、刻晴、阿贝多、行秋、班尼特、七七ⁿᵉʷ、凯亚ⁿᵉʷ
|
319 |
-
* 双手剑:一斗ⁿᵉʷ、优菈ⁿᵉʷ、迪卢克ⁿᵉʷ、诺艾尔ⁿᵉʷ、重云ⁿᵉʷ
|
320 |
-
|
321 |
-
# 1.5.0
|
322 |
-
|
323 |
-
* 增加 `#喵喵日历` 功能
|
324 |
-
* 【!请注意!】此功能需要安装moment库,请在Yunzai安装目录下运行 `npm install moment`后再进行升级
|
325 |
-
* 展示当前进行中及即将开始的活动,包括深境螺旋
|
326 |
-
* `#角色面板` 伤害计算目前支持
|
327 |
-
* 长柄武器:雷神、胡桃、魈、钟离、香菱ⁿᵉʷ
|
328 |
-
* 法器:神子、心海
|
329 |
-
* 弓:甘雨、宵宫、公子
|
330 |
-
* 单手剑:绫人、绫华、刻晴、阿贝多ⁿᵉʷ、行秋ⁿᵉʷ、班尼特ⁿᵉʷ
|
331 |
-
* 底层升级:抽象了部分公共组件为tpl模板以提高复用度,css改为less处理
|
332 |
-
|
333 |
-
# 1.4.0
|
334 |
-
|
335 |
-
* 增加 `#深渊配队` 功能
|
336 |
-
* 根据当前账号的角色练度及本期深渊出场数据,推荐较匹配的配队方案
|
337 |
-
* 深渊出场数据来自DGP-Studio胡桃API
|
338 |
-
* 配队方案仅供参考
|
339 |
-
* `#角色面板` 伤害计算新增部分角色
|
340 |
-
* 目前支持:雷神、胡桃、魈、神子、甘雨、宵宫、公子、绫人、绫华、心海、钟离
|
341 |
-
* `#角色面板` 一些功能升级与调整
|
342 |
-
* 支持对治疗量、护盾量的计算与展示
|
343 |
-
* 修复冰融化、少女4等buff等buff遗漏或错误导致的伤害计算偏差
|
344 |
-
* `#老婆` 功能支持对jpeg格式的图片格式识别
|
345 |
-
|
346 |
-
# 1.3.0
|
347 |
-
|
348 |
-
* 增加 `#雷神伤害` 功能
|
349 |
-
* 可计算圣遗物副词条置换带来的伤害变化,可用于圣遗物副词条侧重方向的参考
|
350 |
-
* 可以查看指定角色伤害计算的Buff列表
|
351 |
-
* `#角色面板` 伤害计算新增部分角色
|
352 |
-
* 目前支持:雷神、胡桃、魈、神子、甘雨、宵宫、公子、绫人、绫华
|
353 |
-
* `#角色面板` 功能升级
|
354 |
-
* 优化无角色面板数据时的引导
|
355 |
-
* 优化返回的图像格式及分辨率,平衡响应速度及显示效果
|
356 |
-
* 增加 `#圣遗物列表` 功能,对已经获取面板的所有角色圣遗物进行评分,并展示高评分的圣遗物列表
|
357 |
-
* 增加 `#角色面板列表` / `#角色面板帮助` 命令
|
358 |
-
* 增加 `#更新胡桃面板` 命令,获取单个角色面板数据,每天可更新5次
|
359 |
-
* 更改 `#更新全部面板` 命令,获取角色展柜全部8个角色,每天可更新3次
|
360 |
-
|
361 |
-
# 1.2.0
|
362 |
-
|
363 |
-
* `#角色面板` 增加伤害计算功能
|
364 |
-
* 目前支持角色:雷神、胡桃、魈、神子、甘雨
|
365 |
-
* 可通过 `#怪物等级85` 命令设定怪物等级,以获得更准确的计算结果
|
366 |
-
* 计算伤害为满Buff情况,后续会出更详细的Buff及计算展示
|
367 |
-
* `#获取游戏角色详情`命令在服务侧增加基于UID的天频度限制
|
368 |
-
* 增加 `#喵喵更新` 功能
|
369 |
-
* 感谢 @碎月 @清秋 的代码支持
|
370 |
-
* 若更新成功会重启Yunzai,需要Yunzai以 npm run start 模式启动
|
371 |
-
* 尚未经充分测试,请有一定容错能力的勇士尝试
|
372 |
-
* 增加 `#喵喵版本`命令查询版本信息
|
373 |
-
|
374 |
-
# 1.1.0
|
375 |
-
|
376 |
-
* 增加 `#喵喵帮助`用于查看帮助命令
|
377 |
-
* 增加 `#喵喵设置`用于设置喵喵相关功能
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/LICENSE
DELETED
@@ -1,21 +0,0 @@
|
|
1 |
-
MIT License
|
2 |
-
|
3 |
-
Copyright (c) 2023 Yoimiya
|
4 |
-
|
5 |
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
-
of this software and associated documentation files (the "Software"), to deal
|
7 |
-
in the Software without restriction, including without limitation the rights
|
8 |
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
-
copies of the Software, and to permit persons to whom the Software is
|
10 |
-
furnished to do so, subject to the following conditions:
|
11 |
-
|
12 |
-
The above copyright notice and this permission notice shall be included in all
|
13 |
-
copies or substantial portions of the Software.
|
14 |
-
|
15 |
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
-
SOFTWARE.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/README.md
DELETED
@@ -1,106 +0,0 @@
|
|
1 |
-
# Miao-Plugin 说明
|
2 |
-
|
3 |
-
`miao-plugin`是一个`Yunzai-Bot`的升级插件,提供包括角色面板、角色查询等角色相关功能。
|
4 |
-
|
5 |
-
具体功能可在安装插件后 通过 `#喵喵帮助` 进行查看。如需进行设置则可通过 `#喵喵设置` 命令进行管理。
|
6 |
-
|
7 |
-
---
|
8 |
-
|
9 |
-
## 安装与更新
|
10 |
-
|
11 |
-
### 使用Git安装(推荐)
|
12 |
-
|
13 |
-
请将 miao-plugin 放置在 Yunzai-Bot 的 plugins 目录下,重启 Yunzai-Bot 后即可使用。
|
14 |
-
|
15 |
-
请使用 git 进行安装,以方便后续升级。在 Yunzai-Bot 根目录夹打开终端,运行下述指令之一
|
16 |
-
|
17 |
-
```
|
18 |
-
// 使用gitee
|
19 |
-
git clone --depth=1 https://gitee.com/yoimiya-kokomi/miao-plugin.git ./plugins/miao-plugin/
|
20 |
-
pnpm install -P
|
21 |
-
|
22 |
-
// 使用github
|
23 |
-
git clone --depth=1 https://github.com/yoimiya-kokomi/miao-plugin.git ./plugins/miao-plugin/
|
24 |
-
pnpm install -P
|
25 |
-
```
|
26 |
-
|
27 |
-
进行安装。安装完毕后,管理员只需发送 `#喵喵更新` 即可自动更新 miao-plugin。
|
28 |
-
|
29 |
-
### 手工下载安装(不推荐)
|
30 |
-
|
31 |
-
手工下载安装包,解压后将`miao-plugin-master`更名为`miao-plugin`,然后放置在Yunzai的plugins目录内
|
32 |
-
|
33 |
-
虽然此方式能够使用,但无法使用`#喵喵更新`进行更新,不利于后续升级,故不推荐使用
|
34 |
-
|
35 |
-
---
|
36 |
-
|
37 |
-
## Yunzai版本与支持
|
38 |
-
|
39 |
-
`miao-plugin` 支持V3 / V2 版本的Yunzai-Bot
|
40 |
-
|
41 |
-
* [Miao-Yunzai](https://github.com/yoimiya-kokomi/Miao-Yunzai) : 喵版Yunzai [Gitee](https://gitee.com/yoimiya-kokomi/Miao-Yunzai)
|
42 |
-
/ [Github](https://github.com/yoimiya-kokomi/Miao-Yunzai) ,本体不含签到功能,功能迭代较多,与miao-plugin打通,只建议新部署/迁移
|
43 |
-
* [Yunzai-V3](https://github.com/yoimiya-kokomi/Yunzai-Bot) :Yunzai V3 - 喵喵维护版,icqq版本,与原版Yunza功能基本一致,会保持卡池更新,功能相对稳定,可从原版Yunzai换源直接升级
|
44 |
-
* [Yunzai-V3](https://gitee.com/Le-niao/Yunzai-Bot) :Yunzai V3 - 乐神原版,oicq版本,可能会遇到登录问题
|
45 |
-
|
46 |
-
---
|
47 |
-
|
48 |
-
## 功能说明
|
49 |
-
|
50 |
-
### #雷神面板
|
51 |
-
|
52 |
-
使用指令 `#面板帮助` 即可了解如何使用此功能。
|
53 |
-
|
54 |
-
#### #更新面板
|
55 |
-
|
56 |
-
`#更新面板` 依赖于面板查询API,面板服务由 http://enka.network/ 提供。
|
57 |
-
|
58 |
-
> 查询功能经Enka官方授权([issue#63](https://github.com/yoimiya-kokomi/miao-plugin/issues/63#issuecomment-1199348789)),感谢Enka提供的面板查询服务
|
59 |
-
>
|
60 |
-
> 如果可以的话,也请在Patreon上支持Enka,或提供闲置的原神账户,具体可在[Enka官网](http://enka.network/) Discord联系
|
61 |
-
>
|
62 |
-
> [issue#63](https://github.com/yoimiya-kokomi/miao-plugin/issues/63#issuecomment-1199734496)
|
63 |
-
|
64 |
-
> 可尝试使用`MiniGG-Api`面板服务 [@MiniGrayGay](https://github.com/MiniGrayGay)<br>
|
65 |
-
> 发送 `#喵喵设置面板服务332` 修改国服&B服的面板查询由 `MiniGG-Api` 处理
|
66 |
-
|
67 |
-
#### #雷神伤害
|
68 |
-
|
69 |
-
喵喵面板附带的伤害计算功能由喵喵本地计算。如计算有偏差 #雷神伤害 查看伤害加成信息,如确认伤害计算有误可提供伤害录屏截图及uid进行反馈
|
70 |
-
|
71 |
-
#### #雷神圣遗物
|
72 |
-
|
73 |
-
圣遗物评分为喵喵版评分规则
|
74 |
-
|
75 |
-
---
|
76 |
-
|
77 |
-
**在有一定阅读理解能力基础下,建议阅读 [CHANGELOG.md](CHANGELOG.md) 以了解更多内容。**
|
78 |
-
|
79 |
-
其余文档咕咕咕中
|
80 |
-
|
81 |
-
---
|
82 |
-
|
83 |
-
# 免责声明
|
84 |
-
|
85 |
-
1. `miao-plugin`自身的UI与代码均开放,无需征得特殊同意,可任意使用。能备注来源最好,但不强求
|
86 |
-
2. 以上声明但仅代表`miao-plugin`自身的范畴,请尊重Yunzai本体及其他插件作者的努力,勿将Yunzai及其他插件用于以盈利为目的的场景
|
87 |
-
3. miao-plugin的图片与其他素材均来自于网络,仅供交流学习使用,如有侵权请联系,会立即删除
|
88 |
-
|
89 |
-
# 资源
|
90 |
-
|
91 |
-
* [Miao-Yunzai](https://github.com/yoimiya-kokomi/Miao-Yunzai) : 喵版Yunzai [Gitee](https://gitee.com/yoimiya-kokomi/Miao-Yunzai)
|
92 |
-
/ [Github](https://github.com/yoimiya-kokomi/Miao-Yunzai)
|
93 |
-
* [Yunzai-V3](https://github.com/yoimiya-kokomi/Yunzai-Bot) :Yunzai V3 - 喵喵维护版(使用 icqq)
|
94 |
-
* [Yunzai-V3](https://gitee.com/Le-niao/Yunzai-Bot) :Yunzai V3 - 乐神原版(使用 oicq)
|
95 |
-
* [miao-plugin](https://github.com/yoimiya-kokomi/miao-plugin) : 喵喵插件 [Gitee](https://gitee.com/yoimiya-kokomi/miao-plugin)
|
96 |
-
/ [Github](https://github.com/yoimiya-kokomi/miao-plugin)
|
97 |
-
|
98 |
-
# 其他&感谢
|
99 |
-
|
100 |
-
* [Enka.Network](https://enka.network/): 感谢Enka提供的面板服务
|
101 |
-
* [Snap.Hutao](https://hut.ao/) : 感谢 DGP Studio 开发的 [胡桃 API](https://github.com/DGP-Studio/Snap.Hutao.Server)
|
102 |
-
* QQ群(暂时停止新加入,请见谅)
|
103 |
-
* Yunzai-Bot 官方QQ群:213938015
|
104 |
-
* 喵喵Miao-Plugin QQ群:607710456
|
105 |
-
* [爱发电](https://afdian.net/@kokomi) :欢迎老板打赏,喵~
|
106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/admin.js
DELETED
@@ -1,204 +0,0 @@
|
|
1 |
-
import fs from 'fs'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import { exec } from 'child_process'
|
4 |
-
import { Cfg, Common, Data, Version, App } from '#miao'
|
5 |
-
import fetch from 'node-fetch'
|
6 |
-
|
7 |
-
let keys = lodash.map(Cfg.getCfgSchemaMap(), (i) => i.key)
|
8 |
-
let app = App.init({
|
9 |
-
id: 'admin',
|
10 |
-
name: '喵喵设置',
|
11 |
-
desc: '喵喵设置'
|
12 |
-
})
|
13 |
-
|
14 |
-
let sysCfgReg = new RegExp(`^#喵喵设置\\s*(${keys.join('|')})?\\s*(.*)$`)
|
15 |
-
|
16 |
-
app.reg({
|
17 |
-
updateRes: {
|
18 |
-
rule: /^#喵喵(强制)?(更新图像|图像更新)$/,
|
19 |
-
fn: updateRes,
|
20 |
-
desc: '【#管理】更新素材'
|
21 |
-
},
|
22 |
-
update: {
|
23 |
-
rule: /^#喵喵(强制)?更新$/,
|
24 |
-
fn: updateMiaoPlugin,
|
25 |
-
desc: '【#管理】喵喵更新'
|
26 |
-
},
|
27 |
-
sysCfg: {
|
28 |
-
rule: sysCfgReg,
|
29 |
-
fn: sysCfg,
|
30 |
-
desc: '【#管理】系统设置'
|
31 |
-
},
|
32 |
-
miaoApiInfo: {
|
33 |
-
rule: /^#喵喵api$/,
|
34 |
-
fn: miaoApiInfo,
|
35 |
-
desc: '【#管理】喵喵Api'
|
36 |
-
}
|
37 |
-
})
|
38 |
-
|
39 |
-
export default app
|
40 |
-
|
41 |
-
const _path = process.cwd()
|
42 |
-
const resPath = `${_path}/plugins/miao-plugin/resources/`
|
43 |
-
const plusPath = `${resPath}/miao-res-plus/`
|
44 |
-
|
45 |
-
const checkAuth = async function (e) {
|
46 |
-
if (!e.isMaster) {
|
47 |
-
e.reply(`只有主人才能命令喵喵哦~
|
48 |
-
(*/ω\*)`)
|
49 |
-
return false
|
50 |
-
}
|
51 |
-
return true
|
52 |
-
}
|
53 |
-
|
54 |
-
async function sysCfg (e) {
|
55 |
-
if (!await checkAuth(e)) {
|
56 |
-
return true
|
57 |
-
}
|
58 |
-
|
59 |
-
let cfgReg = sysCfgReg
|
60 |
-
let regRet = cfgReg.exec(e.msg)
|
61 |
-
let cfgSchemaMap = Cfg.getCfgSchemaMap()
|
62 |
-
|
63 |
-
if (!regRet) {
|
64 |
-
return true
|
65 |
-
}
|
66 |
-
|
67 |
-
if (regRet[1]) {
|
68 |
-
// 设置模式
|
69 |
-
let val = regRet[2] || ''
|
70 |
-
|
71 |
-
let cfgSchema = cfgSchemaMap[regRet[1]]
|
72 |
-
if (cfgSchema.input) {
|
73 |
-
val = cfgSchema.input(val)
|
74 |
-
} else {
|
75 |
-
val = cfgSchema.type === 'num' ? (val * 1 || cfgSchema.def) : !/关闭/.test(val)
|
76 |
-
}
|
77 |
-
Cfg.set(cfgSchema.cfgKey, val)
|
78 |
-
}
|
79 |
-
|
80 |
-
let schema = Cfg.getCfgSchema()
|
81 |
-
let cfg = Cfg.getCfg()
|
82 |
-
let imgPlus = fs.existsSync(plusPath)
|
83 |
-
|
84 |
-
// 渲染图像
|
85 |
-
return await Common.render('admin/index', {
|
86 |
-
schema,
|
87 |
-
cfg,
|
88 |
-
imgPlus,
|
89 |
-
isMiao: Version.isMiao
|
90 |
-
}, { e, scale: 1.4 })
|
91 |
-
}
|
92 |
-
|
93 |
-
async function updateRes (e) {
|
94 |
-
if (!await checkAuth(e)) {
|
95 |
-
return true
|
96 |
-
}
|
97 |
-
let isForce = e.msg.includes('强制')
|
98 |
-
let command = ''
|
99 |
-
if (fs.existsSync(`${resPath}/miao-res-plus/`)) {
|
100 |
-
e.reply('开始尝试更新,请耐心等待~')
|
101 |
-
command = 'git pull'
|
102 |
-
if (isForce) {
|
103 |
-
command = 'git checkout . && git pull'
|
104 |
-
}
|
105 |
-
exec(command, { cwd: `${resPath}/miao-res-plus/` }, function (error, stdout, stderr) {
|
106 |
-
console.log(stdout)
|
107 |
-
if (/(Already up[ -]to[ -]date|已经是最新的)/.test(stdout)) {
|
108 |
-
e.reply('目前所有图片都已经是最新了~')
|
109 |
-
return true
|
110 |
-
}
|
111 |
-
let numRet = /(\d*) files changed,/.exec(stdout)
|
112 |
-
if (numRet && numRet[1]) {
|
113 |
-
e.reply(`报告主人,更新成功,此次更新了${numRet[1]}个图片~`)
|
114 |
-
return true
|
115 |
-
}
|
116 |
-
if (error) {
|
117 |
-
e.reply('更新失败!\nError code: ' + error.code + '\n' + error.stack + '\n 请稍后重试。')
|
118 |
-
} else {
|
119 |
-
e.reply('图片加量包更新成功~')
|
120 |
-
}
|
121 |
-
})
|
122 |
-
} else {
|
123 |
-
command = `git clone https://gitee.com/yoimiya-kokomi/miao-res-plus.git "${resPath}/miao-res-plus/" --depth=1`
|
124 |
-
e.reply('开始尝试安装图片加量包,可能会需要一段时间,请耐心等待~')
|
125 |
-
exec(command, function (error, stdout, stderr) {
|
126 |
-
if (error) {
|
127 |
-
e.reply('角色图片加量包安装失败!\nError code: ' + error.code + '\n' + error.stack + '\n 请稍后重试。')
|
128 |
-
} else {
|
129 |
-
e.reply('角色图片加量包安装成功!您后续也可以通过 #喵喵更新图像 命令来更新图像')
|
130 |
-
}
|
131 |
-
})
|
132 |
-
}
|
133 |
-
return true
|
134 |
-
}
|
135 |
-
|
136 |
-
let timer
|
137 |
-
|
138 |
-
async function updateMiaoPlugin (e) {
|
139 |
-
if (!await checkAuth(e)) {
|
140 |
-
return true
|
141 |
-
}
|
142 |
-
let isForce = e.msg.includes('强制')
|
143 |
-
let command = 'git pull'
|
144 |
-
if (isForce) {
|
145 |
-
command = 'git checkout . && git pull'
|
146 |
-
e.reply('正在执行强制更新操作,请稍等')
|
147 |
-
} else {
|
148 |
-
e.reply('正在执行更新操作,请稍等')
|
149 |
-
}
|
150 |
-
exec(command, { cwd: `${_path}/plugins/miao-plugin/` }, function (error, stdout, stderr) {
|
151 |
-
if (/(Already up[ -]to[ -]date|已经是最新的)/.test(stdout)) {
|
152 |
-
e.reply('目前已经是最新版喵喵了~')
|
153 |
-
return true
|
154 |
-
}
|
155 |
-
if (error) {
|
156 |
-
e.reply('喵喵更新失败!\nError code: ' + error.code + '\n' + error.stack + '\n 请稍后重试。')
|
157 |
-
return true
|
158 |
-
}
|
159 |
-
e.reply('喵喵更新成功,正在尝试重新启动Yunzai以应用更新...')
|
160 |
-
timer && clearTimeout(timer)
|
161 |
-
Data.setCacheJSON('miao:restart-msg', {
|
162 |
-
msg: '重启成功,新版喵喵已经生效',
|
163 |
-
qq: e.user_id
|
164 |
-
}, 30)
|
165 |
-
timer = setTimeout(function () {
|
166 |
-
let command = 'npm run start'
|
167 |
-
if (process.argv[1].includes('pm2')) {
|
168 |
-
command = 'npm run restart'
|
169 |
-
}
|
170 |
-
exec(command, function (error, stdout, stderr) {
|
171 |
-
if (error) {
|
172 |
-
e.reply('自动重启失败,请手动重启以应用新版喵喵。\nError code: ' + error.code + '\n' + error.stack + '\n')
|
173 |
-
Bot.logger.error(`重启失败\n${error.stack}`)
|
174 |
-
return true
|
175 |
-
} else if (stdout) {
|
176 |
-
Bot.logger.mark('重启成功,运行已转为后台,查看日志请用命令:npm run log')
|
177 |
-
Bot.logger.mark('停止后台运行命令:npm stop')
|
178 |
-
process.exit()
|
179 |
-
}
|
180 |
-
})
|
181 |
-
}, 1000)
|
182 |
-
})
|
183 |
-
return true
|
184 |
-
}
|
185 |
-
|
186 |
-
async function miaoApiInfo (e) {
|
187 |
-
if (!await checkAuth(e)) {
|
188 |
-
return true
|
189 |
-
}
|
190 |
-
let { diyCfg } = await Data.importCfg('profile')
|
191 |
-
let { qq, token } = (diyCfg?.miaoApi || {})
|
192 |
-
if (!qq || !token) {
|
193 |
-
return e.reply('未正确填写miaoApi token,请检查miao-plugin/config/profile.js文件')
|
194 |
-
}
|
195 |
-
if (token.length !== 32) {
|
196 |
-
return e.reply('miaoApi token格式错误')
|
197 |
-
}
|
198 |
-
let req = await fetch(`http://miao.games/api/info?qq=${qq}&token=${token}`)
|
199 |
-
let data = await req.json()
|
200 |
-
if (data.status !== 0) {
|
201 |
-
return e.reply('token检查错误,请求失败')
|
202 |
-
}
|
203 |
-
e.reply(data.msg)
|
204 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/character.js
DELETED
@@ -1,36 +0,0 @@
|
|
1 |
-
import { uploadCharacterImg } from './character/ImgUpload.js'
|
2 |
-
import { getOriginalPicture } from './profile/ProfileUtils.js'
|
3 |
-
import Avatar from './character/AvatarCard.js'
|
4 |
-
import Wife from './character/AvatarWife.js'
|
5 |
-
import { App } from '#miao'
|
6 |
-
|
7 |
-
let app = App.init({
|
8 |
-
id: 'character',
|
9 |
-
name: '角色查询'
|
10 |
-
})
|
11 |
-
|
12 |
-
app.reg({
|
13 |
-
character: {
|
14 |
-
rule: /^#喵喵角色卡片$/,
|
15 |
-
fn: Avatar.render,
|
16 |
-
check: Avatar.check,
|
17 |
-
name: '角色卡片'
|
18 |
-
},
|
19 |
-
uploadImg: {
|
20 |
-
rule: /^#*(喵喵)?(上传|添加)(.+)(照片|写真|图片|图像)\s*$/,
|
21 |
-
fn: uploadCharacterImg,
|
22 |
-
name: '上传角色写真'
|
23 |
-
},
|
24 |
-
wife: {
|
25 |
-
rule: Wife.reg,
|
26 |
-
fn: Wife.render,
|
27 |
-
describe: '#老公 #老婆 查询'
|
28 |
-
},
|
29 |
-
originalPic: {
|
30 |
-
rule: /^#?(获取|给我|我要|求|发|发下|发个|发一下)?原图(吧|呗)?$/,
|
31 |
-
fn: getOriginalPicture,
|
32 |
-
describe: '【#原图】 回复角色卡片,可获取原图'
|
33 |
-
}
|
34 |
-
})
|
35 |
-
|
36 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/character/AvatarCard.js
DELETED
@@ -1,132 +0,0 @@
|
|
1 |
-
import { Character, MysApi, Player } from '#miao.models'
|
2 |
-
import { Cfg, Common } from '#miao'
|
3 |
-
import lodash from 'lodash'
|
4 |
-
import moment from 'moment'
|
5 |
-
|
6 |
-
let Avatar = {
|
7 |
-
render (e) {
|
8 |
-
if (!e.char) {
|
9 |
-
return false
|
10 |
-
}
|
11 |
-
return Avatar.renderAvatar(e, e.char?.name)
|
12 |
-
},
|
13 |
-
async renderAvatar (e, avatar, renderType = 'card') {
|
14 |
-
// 如果传递的是名字,则获取
|
15 |
-
if (typeof (avatar) === 'string') {
|
16 |
-
// 检查角色
|
17 |
-
let char = Character.get(avatar)
|
18 |
-
if (!char) {
|
19 |
-
return false
|
20 |
-
}
|
21 |
-
let mys = await MysApi.init(e)
|
22 |
-
if (!mys) return true
|
23 |
-
if (!char.isRelease) {
|
24 |
-
avatar = { id: char.id, name: char.name, detail: false }
|
25 |
-
} else {
|
26 |
-
let player = Player.create(e)
|
27 |
-
await player.refreshMysDetail(1)
|
28 |
-
await player.refreshTalent(char.id, 1)
|
29 |
-
avatar = player.getAvatar(char.id)
|
30 |
-
if (!avatar) {
|
31 |
-
avatar = { id: char.id, name: char.name, detail: false }
|
32 |
-
}
|
33 |
-
}
|
34 |
-
}
|
35 |
-
return await Avatar.renderCard(e, avatar, renderType)
|
36 |
-
},
|
37 |
-
|
38 |
-
async renderCard (e, avatar, renderType = 'card') {
|
39 |
-
let char = Character.get(avatar.id)
|
40 |
-
if (!char) {
|
41 |
-
return false
|
42 |
-
}
|
43 |
-
let bg = char.getCardImg(Cfg.get('charPicSe', false))
|
44 |
-
if (renderType === 'photo') {
|
45 |
-
e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/${bg.img}`))
|
46 |
-
return true
|
47 |
-
}
|
48 |
-
let uid = e.uid || (e.targetUser && e.targetUser.uid)
|
49 |
-
let data = {}
|
50 |
-
let custom = char.isCustom
|
51 |
-
let isRelease = char.isRelease
|
52 |
-
if (isRelease && avatar.hasData) {
|
53 |
-
data = avatar.getDetail()
|
54 |
-
data.imgs = char.imgs
|
55 |
-
data.source = avatar._source
|
56 |
-
data.artis = avatar.getArtisDetail()
|
57 |
-
data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm')
|
58 |
-
if (data.hasTalent) {
|
59 |
-
data.talent = avatar.talent
|
60 |
-
data.talentMap = ['a', 'e', 'q']
|
61 |
-
// 计算皇冠个数
|
62 |
-
data.crownNum = lodash.filter(lodash.map(data.talent, (d) => d.original), (d) => d >= 10).length
|
63 |
-
}
|
64 |
-
} else {
|
65 |
-
data = char.getData('id,name,sName')
|
66 |
-
}
|
67 |
-
|
68 |
-
let width = 600
|
69 |
-
let imgCss = ''
|
70 |
-
let scale = 1.2
|
71 |
-
if (bg.mode === 'left') {
|
72 |
-
const height = 480
|
73 |
-
width = height * bg.width / bg.height
|
74 |
-
imgCss = `img.bg{width:auto;height:${height}px;}`
|
75 |
-
scale = 1.45
|
76 |
-
}
|
77 |
-
// 渲染图像
|
78 |
-
let msgRes = await Common.render('character/character-card', {
|
79 |
-
saveId: uid,
|
80 |
-
uid,
|
81 |
-
bg,
|
82 |
-
widthStyle: `<style>html,body,#container{width:${width}px} ${imgCss}</style>`,
|
83 |
-
mode: bg.mode,
|
84 |
-
custom,
|
85 |
-
isRelease,
|
86 |
-
data
|
87 |
-
}, { e, scale, retMsgId: true })
|
88 |
-
if (msgRes) {
|
89 |
-
// 如果消息发送成功,就将message_id和图片路径存起来,3小时过期
|
90 |
-
const message_id = [e.message_id]
|
91 |
-
if (Array.isArray(msgRes.message_id)) {
|
92 |
-
message_id.push(...msgRes.message_id)
|
93 |
-
} else {
|
94 |
-
message_id.push(msgRes.message_id)
|
95 |
-
}
|
96 |
-
for (const i of message_id) {
|
97 |
-
await redis.set(`miao:original-picture:${i}`, JSON.stringify({ type: 'character', img: bg.img }), { EX: 3600 * 3 })
|
98 |
-
}
|
99 |
-
}
|
100 |
-
return true
|
101 |
-
},
|
102 |
-
check (e) {
|
103 |
-
let msg = e.original_msg || e.msg
|
104 |
-
if (!msg || !/^#/.exec(msg)) {
|
105 |
-
return false
|
106 |
-
}
|
107 |
-
if (!Common.cfg('avatarCard')) {
|
108 |
-
return false
|
109 |
-
}
|
110 |
-
let uidRet = /[0-9]{9}/.exec(msg)
|
111 |
-
if (uidRet) {
|
112 |
-
e.uid = uidRet[0]
|
113 |
-
msg = msg.replace(uidRet[0], '')
|
114 |
-
}
|
115 |
-
let name = msg.replace(/#|老婆|老公|卡片/g, '').trim()
|
116 |
-
|
117 |
-
// cache gsCfg
|
118 |
-
Character.gsCfg = Character.gsCfg || e?.runtime?.gsCfg
|
119 |
-
|
120 |
-
let char = Character.get(name.trim())
|
121 |
-
|
122 |
-
if (!char) {
|
123 |
-
return false
|
124 |
-
}
|
125 |
-
|
126 |
-
e.msg = '#喵喵角色卡片'
|
127 |
-
e.char = char
|
128 |
-
return true
|
129 |
-
}
|
130 |
-
|
131 |
-
}
|
132 |
-
export default Avatar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/character/AvatarWife.js
DELETED
@@ -1,188 +0,0 @@
|
|
1 |
-
// #老婆
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import { Common } from '#miao'
|
4 |
-
import { Character, MysApi, Player } from '#miao.models'
|
5 |
-
import Avatar from './AvatarCard.js'
|
6 |
-
|
7 |
-
const relationMap = {
|
8 |
-
wife: {
|
9 |
-
keyword: '老婆,媳妇,妻子,娘子,宝贝'.split(','),
|
10 |
-
type: 0
|
11 |
-
},
|
12 |
-
husband: {
|
13 |
-
keyword: '老公,丈夫,夫君,郎君,死鬼'.split(','),
|
14 |
-
type: 1
|
15 |
-
},
|
16 |
-
gf: {
|
17 |
-
keyword: '女朋友,女友,女神,女王,女票'.split(','),
|
18 |
-
type: 0
|
19 |
-
},
|
20 |
-
bf: {
|
21 |
-
keyword: '男朋友,男友,男神,男票'.split(','),
|
22 |
-
type: 1
|
23 |
-
},
|
24 |
-
daughter: {
|
25 |
-
keyword: '女儿,闺女,小宝贝'.split(','),
|
26 |
-
type: 2
|
27 |
-
},
|
28 |
-
son: {
|
29 |
-
keyword: '儿子,犬子'.split(','),
|
30 |
-
type: 3
|
31 |
-
}
|
32 |
-
}
|
33 |
-
|
34 |
-
const relation = lodash.flatMap(relationMap, (d) => d.keyword)
|
35 |
-
const wifeReg = `^#?\\s*(${relation.join('|')})\\s*(设置|选择|指定|列表|查询|列表|是|是谁|照片|相片|图片|写真|图像)?\\s*([^\\d]*)\\s*(\\d*)$`
|
36 |
-
|
37 |
-
async function getAvatarList (player, type) {
|
38 |
-
await player.refreshMysDetail()
|
39 |
-
let list = []
|
40 |
-
player.forEachAvatar((avatar) => {
|
41 |
-
if (type !== false) {
|
42 |
-
if (!avatar.char.checkWifeType(type)) {
|
43 |
-
return true
|
44 |
-
}
|
45 |
-
}
|
46 |
-
list.push(avatar)
|
47 |
-
})
|
48 |
-
|
49 |
-
if (list.length <= 0) {
|
50 |
-
return false
|
51 |
-
}
|
52 |
-
let sortKey = 'level,fetter,weapon_level,rarity,weapon_rarity,cons,weapon_affix_level'
|
53 |
-
list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(','))
|
54 |
-
return list
|
55 |
-
}
|
56 |
-
|
57 |
-
const Wife = {
|
58 |
-
reg: wifeReg,
|
59 |
-
async render (e) {
|
60 |
-
let msg = e.msg || ''
|
61 |
-
if (!msg && !e.isPoke) return false
|
62 |
-
|
63 |
-
if (e.isPoke) {
|
64 |
-
if (!Common.cfg('avatarPoke')) {
|
65 |
-
return false
|
66 |
-
}
|
67 |
-
} else if (!Common.cfg('avatarCard')) {
|
68 |
-
return false
|
69 |
-
}
|
70 |
-
|
71 |
-
let msgRet = (new RegExp(wifeReg)).exec(msg)
|
72 |
-
if (e.isPoke) {
|
73 |
-
msgRet = []
|
74 |
-
} else if (!msgRet) {
|
75 |
-
return false
|
76 |
-
}
|
77 |
-
let target = msgRet[1]
|
78 |
-
let action = msgRet[2] || '卡片'
|
79 |
-
let actionParam = msgRet[3] || ''
|
80 |
-
|
81 |
-
if (!'设置,选择,挑选,指定'.split(',').includes(action) && actionParam) {
|
82 |
-
return false
|
83 |
-
}
|
84 |
-
|
85 |
-
let targetCfg = lodash.find(relationMap, (cfg, key) => {
|
86 |
-
cfg.key = key
|
87 |
-
return cfg.keyword.includes(target)
|
88 |
-
})
|
89 |
-
if (!targetCfg && !e.isPoke) return true
|
90 |
-
|
91 |
-
let avatarList = []
|
92 |
-
let avatar = {}
|
93 |
-
let wifeList = []
|
94 |
-
|
95 |
-
let mys = await MysApi.init(e)
|
96 |
-
if (!mys || !mys.uid) {
|
97 |
-
return true
|
98 |
-
}
|
99 |
-
let player = Player.create(e)
|
100 |
-
let selfUser = mys.selfUser
|
101 |
-
let isSelf = true
|
102 |
-
let renderType = (action === '卡片' ? 'card' : 'photo')
|
103 |
-
let addRet = []
|
104 |
-
switch (action) {
|
105 |
-
case '卡片':
|
106 |
-
case '照片':
|
107 |
-
case '相片':
|
108 |
-
case '图片':
|
109 |
-
case '写真':
|
110 |
-
// 展示老婆卡片
|
111 |
-
// 如果选择过,则进行展示
|
112 |
-
if (!e.isPoke) {
|
113 |
-
wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, [])
|
114 |
-
// 存在设置
|
115 |
-
if (wifeList && wifeList.length > 0 && isSelf && !e.isPoke) {
|
116 |
-
if (wifeList[0] === '随机') {
|
117 |
-
// 如果选择为全部,则从列表中随机选择一个
|
118 |
-
avatarList = await getAvatarList(player, targetCfg.type, mys)
|
119 |
-
let avatar = lodash.sample(avatarList)
|
120 |
-
return Avatar.renderAvatar(e, avatar, renderType)
|
121 |
-
} else {
|
122 |
-
// 如果指定过,则展示指定角色
|
123 |
-
return Avatar.renderAvatar(e, lodash.sample(wifeList), renderType)
|
124 |
-
}
|
125 |
-
}
|
126 |
-
}
|
127 |
-
// 如果未指定过,则从列表中排序并随机选择
|
128 |
-
avatarList = await getAvatarList(player, e.isPoke ? false : targetCfg.type, mys)
|
129 |
-
if (avatarList && avatarList.length > 0) {
|
130 |
-
avatar = lodash.sample(avatarList)
|
131 |
-
return await Avatar.renderAvatar(e, avatar, renderType)
|
132 |
-
}
|
133 |
-
e.reply('在当前米游社公开展示的角色中未能找到适合展示的角色..')
|
134 |
-
return true
|
135 |
-
case '设置':
|
136 |
-
case '选择':
|
137 |
-
case '挑选':
|
138 |
-
case '指定':
|
139 |
-
if (!isSelf) {
|
140 |
-
e.reply('只能指定自己的哦~')
|
141 |
-
return true
|
142 |
-
}
|
143 |
-
// 选择老婆
|
144 |
-
actionParam = actionParam.replace(/(,|、|;|;)/g, ',')
|
145 |
-
wifeList = actionParam.split(',')
|
146 |
-
if (lodash.intersection(['全部', '任意', '随机', '全都要'], wifeList).length > 0) {
|
147 |
-
addRet = ['随机']
|
148 |
-
} else {
|
149 |
-
wifeList = lodash.map(wifeList, (name) => {
|
150 |
-
let char = Character.get(name)
|
151 |
-
if (char && char.checkWifeType(targetCfg.type)) {
|
152 |
-
return char.name
|
153 |
-
}
|
154 |
-
})
|
155 |
-
wifeList = lodash.filter(lodash.uniq(wifeList), (d) => !!d)
|
156 |
-
addRet = wifeList
|
157 |
-
if (addRet.length === 0) {
|
158 |
-
e.reply(`在可选的${targetCfg.keyword[0]}列表中未能找到 ${actionParam} ~`)
|
159 |
-
return true
|
160 |
-
}
|
161 |
-
}
|
162 |
-
await selfUser.setCfg(`wife.${targetCfg.key}`, addRet)
|
163 |
-
e.reply(`${targetCfg.keyword[0]}已经设置:${addRet.join(',')}`)
|
164 |
-
return true
|
165 |
-
case '列表':
|
166 |
-
case '是':
|
167 |
-
case '是谁':
|
168 |
-
// 查看当前选择老婆
|
169 |
-
if (!isSelf) {
|
170 |
-
e.reply('只能查看自己的哦~')
|
171 |
-
return true
|
172 |
-
}
|
173 |
-
wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, [])
|
174 |
-
if (wifeList && wifeList.length > 0) {
|
175 |
-
e.reply(`你的${targetCfg.keyword[0]}是:${wifeList.join(',')}`)
|
176 |
-
} else {
|
177 |
-
e.reply(`尚未设置,回复#${targetCfg.keyword[0]}设置+角色名 来设置,如果设置多位请用逗号间隔`)
|
178 |
-
}
|
179 |
-
break
|
180 |
-
}
|
181 |
-
return true
|
182 |
-
},
|
183 |
-
async poke (e) {
|
184 |
-
return await Wife.render(e)
|
185 |
-
}
|
186 |
-
}
|
187 |
-
|
188 |
-
export default Wife
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/character/ImgUpload.js
DELETED
@@ -1,258 +0,0 @@
|
|
1 |
-
import fs from 'fs'
|
2 |
-
import { promisify } from 'util'
|
3 |
-
import { pipeline } from 'stream'
|
4 |
-
import MD5 from 'md5'
|
5 |
-
import fetch from 'node-fetch'
|
6 |
-
import lodash from 'lodash'
|
7 |
-
import { Cfg, Data } from '#miao'
|
8 |
-
import { Character } from '#miao.models'
|
9 |
-
|
10 |
-
const resPath = process.cwd() + '/plugins/miao-plugin/resources/'
|
11 |
-
let regex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:照片|写真|图片|图像)\s*$/
|
12 |
-
let profileRegex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:面板图)\s*$/
|
13 |
-
let isProfile = false
|
14 |
-
|
15 |
-
export async function uploadCharacterImg (e) {
|
16 |
-
let promise = await isAllowedToUploadCharacterImage(e)
|
17 |
-
if (!promise) {
|
18 |
-
return false
|
19 |
-
}
|
20 |
-
|
21 |
-
let imageMessages = []
|
22 |
-
let msg = e.msg
|
23 |
-
let regRet = regex.exec(msg)
|
24 |
-
if (msg.includes('面板')) {
|
25 |
-
isProfile = true
|
26 |
-
regRet = profileRegex.exec(msg)
|
27 |
-
} else {
|
28 |
-
isProfile = false
|
29 |
-
}
|
30 |
-
|
31 |
-
// 通过解析正则获取消息中的角色名
|
32 |
-
if (!regRet || !regRet[1]) {
|
33 |
-
return false
|
34 |
-
}
|
35 |
-
let char = Character.get(regRet[1])
|
36 |
-
if (!char || !char.name) {
|
37 |
-
return false
|
38 |
-
}
|
39 |
-
let name = char.name
|
40 |
-
for (let val of e.message) {
|
41 |
-
if (val.type === 'image') {
|
42 |
-
imageMessages.push(val)
|
43 |
-
}
|
44 |
-
}
|
45 |
-
if (imageMessages.length === 0) {
|
46 |
-
let source
|
47 |
-
if (e.getReply) {
|
48 |
-
source = await e.getReply()
|
49 |
-
} else if (e.source) {
|
50 |
-
if (e.group?.getChatHistory) {
|
51 |
-
// 支持at图片添加,以及支持后发送
|
52 |
-
source = (await e.group.getChatHistory(e.source?.seq, 1)).pop()
|
53 |
-
} else if (e.friend?.getChatHistory) {
|
54 |
-
source = (await e.friend.getChatHistory((e.source?.time + 1), 1)).pop()
|
55 |
-
}
|
56 |
-
}
|
57 |
-
if (source) {
|
58 |
-
for (let val of source.message) {
|
59 |
-
if (val.type === 'image') {
|
60 |
-
imageMessages.push(val)
|
61 |
-
} else if (val.type === 'xml' || val.type === 'forward') {// 支持合并转发消息内置的图片批量上传,喵喵 喵喵喵? 喵喵喵喵
|
62 |
-
let resid
|
63 |
-
try {
|
64 |
-
resid = val.data.match(/m_resid="(\d|\w|\/|\+)*"/)[0].replace(/m_resid=|"/g, '')
|
65 |
-
} catch (err) {
|
66 |
-
console.log('Miao合并上传:转换id获取')
|
67 |
-
resid = val.id
|
68 |
-
}
|
69 |
-
if (!resid) break
|
70 |
-
let message = await e.bot.getForwardMsg(resid)
|
71 |
-
for (const item of message) {
|
72 |
-
for (const i of item.message) {
|
73 |
-
if (i.type === 'image') {
|
74 |
-
imageMessages.push(i)
|
75 |
-
}
|
76 |
-
}
|
77 |
-
}
|
78 |
-
}
|
79 |
-
}
|
80 |
-
}
|
81 |
-
}
|
82 |
-
if (imageMessages.length <= 0) {
|
83 |
-
e.reply('消息中未找到图片,请将要发送的图片与消息一同发送或引用要添加的图像..')
|
84 |
-
return true
|
85 |
-
}
|
86 |
-
await saveImages(e, name, imageMessages)
|
87 |
-
return true
|
88 |
-
}
|
89 |
-
|
90 |
-
async function saveImages (e, name, imageMessages) {
|
91 |
-
let imgMaxSize = e?.groupConfig?.imgMaxSize || 5
|
92 |
-
let pathSuffix = `character-img/${name}/upload`
|
93 |
-
if (isProfile) pathSuffix = `profile/normal-character/${name}`
|
94 |
-
let path = resPath + pathSuffix
|
95 |
-
|
96 |
-
if (!fs.existsSync(path)) {
|
97 |
-
Data.createDir("resources/" + pathSuffix, 'miao')
|
98 |
-
}
|
99 |
-
let senderName = lodash.truncate(e.sender.card, { length: 8 })
|
100 |
-
let imgCount = 0
|
101 |
-
let urlMap = {}
|
102 |
-
for (let val of imageMessages) {
|
103 |
-
if (!val.url || urlMap[val.url]) {
|
104 |
-
continue
|
105 |
-
}
|
106 |
-
urlMap[val.url] = true
|
107 |
-
const response = await fetch(val.url)
|
108 |
-
if (!response.ok) {
|
109 |
-
e.reply('图片下载失败。')
|
110 |
-
return true
|
111 |
-
}
|
112 |
-
if (response.headers.get('size') > 1024 * 1024 * imgMaxSize) {
|
113 |
-
e.reply([segment.at(e.user_id, senderName), '添加失败:图片太大了。'])
|
114 |
-
return true
|
115 |
-
}
|
116 |
-
let fileName = ""
|
117 |
-
let fileType = "png"
|
118 |
-
if (val.file) {
|
119 |
-
fileName = val.file.substring(0, val.file.lastIndexOf('.'))
|
120 |
-
fileType = val.file.substring(val.file.lastIndexOf('.') + 1)
|
121 |
-
}
|
122 |
-
if (response.headers.get('content-type') === 'image/gif') {
|
123 |
-
fileType = 'gif'
|
124 |
-
}
|
125 |
-
if (isProfile) fileType = 'webp'
|
126 |
-
let imgPath = `${path}/${fileName}.${fileType}`
|
127 |
-
const streamPipeline = promisify(pipeline)
|
128 |
-
await streamPipeline(response.body, fs.createWriteStream(imgPath))
|
129 |
-
|
130 |
-
// 使用md5作为文件名
|
131 |
-
let buffers = fs.readFileSync(imgPath)
|
132 |
-
let base64 = Buffer.from(buffers, 'base64').toString()
|
133 |
-
let md5 = MD5(base64)
|
134 |
-
let newImgPath = `${path}/${md5}.${fileType}`
|
135 |
-
if (fs.existsSync(newImgPath)) {
|
136 |
-
fs.unlink(newImgPath, (err) => {
|
137 |
-
console.log('unlink', err)
|
138 |
-
})
|
139 |
-
}
|
140 |
-
fs.rename(imgPath, newImgPath, () => {
|
141 |
-
})
|
142 |
-
imgCount++
|
143 |
-
Bot.logger.mark(`添加成功: ${newImgPath}`)
|
144 |
-
}
|
145 |
-
e.reply([segment.at(e.user_id, senderName), `\n成功添加${imgCount}张${name}${isProfile ? '面板图' : '图片'}。`])
|
146 |
-
return true
|
147 |
-
}
|
148 |
-
|
149 |
-
async function isAllowedToUploadCharacterImage (e) {
|
150 |
-
let sendMsg = /上传|添加/.test(e.msg) ? '添加' : '删除'
|
151 |
-
if (!e.message) {
|
152 |
-
return false
|
153 |
-
}
|
154 |
-
if (!e.msg) {
|
155 |
-
return false
|
156 |
-
}
|
157 |
-
// master直接返回true
|
158 |
-
if (e.isMaster) {
|
159 |
-
return true
|
160 |
-
}
|
161 |
-
if (e.isPrivate) {
|
162 |
-
e.reply(`只有主人才能${sendMsg}...`)
|
163 |
-
return false
|
164 |
-
}
|
165 |
-
let groupId = e.group_id
|
166 |
-
if (!groupId) {
|
167 |
-
return false
|
168 |
-
}
|
169 |
-
const addLimit = e.groupConfig?.imgAddLimit || 2
|
170 |
-
const isAdmin = ['owner', 'admin'].includes(e.sender.role)
|
171 |
-
if (addLimit === 2) {
|
172 |
-
e.reply(`只有主人才能${sendMsg}...`)
|
173 |
-
return false
|
174 |
-
}
|
175 |
-
if (addLimit === 1 && !isAdmin) {
|
176 |
-
e.reply(`只有管理员才能${sendMsg}...`)
|
177 |
-
return false
|
178 |
-
}
|
179 |
-
return true
|
180 |
-
}
|
181 |
-
|
182 |
-
// 仅支持面板图删除
|
183 |
-
export async function delProfileImg (e) {
|
184 |
-
let promise = await isAllowedToUploadCharacterImage(e)
|
185 |
-
if (!promise) {
|
186 |
-
return false
|
187 |
-
}
|
188 |
-
let char = Character.get(e.msg.replace(/#|面板图|列表|上传|删除|\d+/g, '').trim())
|
189 |
-
if (!char || !char.name) {
|
190 |
-
return false
|
191 |
-
}
|
192 |
-
let name = char.name
|
193 |
-
let pathSuffix = `profile/normal-character/${name}`
|
194 |
-
let path = resPath + pathSuffix
|
195 |
-
let num = e.msg.match(/\d+/)
|
196 |
-
if (!num) {
|
197 |
-
e.reply(`删除哪张捏?请输入数字序列号,可输入【#${name}面板图列表】查看序列号`)
|
198 |
-
return
|
199 |
-
}
|
200 |
-
try {
|
201 |
-
let imgs = fs.readdirSync(`${path}`).filter((file) => {
|
202 |
-
return /\.(png|webp)$/.test(file)
|
203 |
-
})
|
204 |
-
fs.unlinkSync(`${path}/${imgs[num - 1]}`)
|
205 |
-
e.reply('删除成功')
|
206 |
-
} catch (err) {
|
207 |
-
e.reply('删除失败,请检查序列号是否正确')
|
208 |
-
}
|
209 |
-
return true
|
210 |
-
}
|
211 |
-
|
212 |
-
export async function profileImgList (e) {
|
213 |
-
let msglist = []
|
214 |
-
let char = Character.get(e.msg.replace(/#|面板图列表/g, ''))
|
215 |
-
if (!char || !char.name) {
|
216 |
-
return false
|
217 |
-
}
|
218 |
-
if ([1, 0].includes(Cfg.get('originalPic') * 1)) {
|
219 |
-
e.reply('已禁止获取面板图列表')
|
220 |
-
return true
|
221 |
-
}
|
222 |
-
let name = char.name
|
223 |
-
let pathSuffix = `profile/normal-character/${name}`
|
224 |
-
let path = resPath + pathSuffix
|
225 |
-
if (!fs.existsSync(path)) {
|
226 |
-
e.reply(`暂无${char.name}的角色面板图`)
|
227 |
-
return true
|
228 |
-
}
|
229 |
-
try {
|
230 |
-
let imgs = fs.readdirSync(`${path}`).filter((file) => {
|
231 |
-
return /\.(png|webp)$/.test(file)
|
232 |
-
})
|
233 |
-
msglist.push({
|
234 |
-
message: [`当前查看的是${name}面板图,共${imgs.length}张,可输入【#删除${name}面板图(序列号)】进行删除`],
|
235 |
-
})
|
236 |
-
for (let i = 0; i < imgs.length; i++) {
|
237 |
-
// 合并转发最多99? 但是我感觉不会有这么多先不做处理
|
238 |
-
console.log(`${path}${imgs[i]}`)
|
239 |
-
msglist.push({
|
240 |
-
message: [`${i + 1}.`, segment.image(`file://${path}/${imgs[i]}`)],
|
241 |
-
})
|
242 |
-
}
|
243 |
-
let msg
|
244 |
-
if (e.group?.makeForwardMsg) {
|
245 |
-
msg = await e.group.makeForwardMsg(msglist)
|
246 |
-
} else if (e.friend?.makeForwardMsg) {
|
247 |
-
msg = await e.friend.makeForwardMsg(msglist)
|
248 |
-
} else {
|
249 |
-
msg = await Bot.makeForwardMsg(msglist)
|
250 |
-
}
|
251 |
-
let msgRsg = await e.reply(msg)
|
252 |
-
if (!msgRsg) e.reply('风控了,可私聊查看', true)
|
253 |
-
} catch (err) {
|
254 |
-
logger.error(err)
|
255 |
-
e.reply(`暂无${char.name}的角色面板图~`)
|
256 |
-
}
|
257 |
-
return true
|
258 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/gacha.js
DELETED
@@ -1,26 +0,0 @@
|
|
1 |
-
import Gacha from './gacha/Gacha.js'
|
2 |
-
import { App, Cfg } from '#miao'
|
3 |
-
|
4 |
-
let app = App.init({
|
5 |
-
id: 'gacha',
|
6 |
-
name: '抽卡统计'
|
7 |
-
})
|
8 |
-
app.reg({
|
9 |
-
detail: {
|
10 |
-
name: '抽卡记录',
|
11 |
-
fn: Gacha.detail,
|
12 |
-
rule: /^#*喵喵(抽卡|抽奖|角色|武器|常驻|up)+池?(记录|祈愿|分析)$/,
|
13 |
-
yzRule: /^#*(抽卡|抽奖|角色|武器|常驻|up)+池?(记录|祈愿|分析)$/,
|
14 |
-
yzCheck: () => Cfg.get('gachaStat', false)
|
15 |
-
},
|
16 |
-
stat: {
|
17 |
-
name: '抽卡统计',
|
18 |
-
fn: Gacha.stat,
|
19 |
-
rule: /^#*喵喵(全部|抽卡|抽奖|角色|武器|常驻|up|版本)+池?统计$/,
|
20 |
-
yzRule: /^#*(全部|抽卡|抽奖|角色|武器|常驻|up|版本)+池?统计$/,
|
21 |
-
yzCheck: () => Cfg.get('gachaStat', false)
|
22 |
-
|
23 |
-
}
|
24 |
-
})
|
25 |
-
|
26 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/gacha/Gacha.js
DELETED
@@ -1,90 +0,0 @@
|
|
1 |
-
import { Common } from '#miao'
|
2 |
-
import { getTargetUid } from '../profile/ProfileCommon.js'
|
3 |
-
import GachaData from './GachaData.js'
|
4 |
-
import { Character, Player } from '#miao.models'
|
5 |
-
|
6 |
-
let Gacha = {
|
7 |
-
async detail (e) {
|
8 |
-
let msg = e.msg.replace(/#|抽卡|记录|祈愿|分析|池/g, '')
|
9 |
-
let type = 301
|
10 |
-
switch (msg) {
|
11 |
-
case 'up':
|
12 |
-
case '抽卡':
|
13 |
-
case '角色':
|
14 |
-
case '抽奖':
|
15 |
-
type = 301
|
16 |
-
break
|
17 |
-
case '常驻':
|
18 |
-
type = 200
|
19 |
-
break
|
20 |
-
case '武器':
|
21 |
-
type = 302
|
22 |
-
break
|
23 |
-
}
|
24 |
-
let uid = e.uid || await getTargetUid(e)
|
25 |
-
let qq = e.user_id
|
26 |
-
if (!uid || !qq) {
|
27 |
-
return false
|
28 |
-
}
|
29 |
-
|
30 |
-
let gacha = GachaData.analyse(e.user_id, uid, type)
|
31 |
-
if (!gacha) {
|
32 |
-
e.reply(`UID:${uid} 本地暂无抽卡信息,请通过【#抽卡帮助】获得绑定帮助...`)
|
33 |
-
return true
|
34 |
-
}
|
35 |
-
await Common.render('gacha/gacha-detail', {
|
36 |
-
save_id: uid,
|
37 |
-
uid,
|
38 |
-
gacha,
|
39 |
-
face: Gacha.getFace(uid)
|
40 |
-
}, { e, scale: 1.4, retMsgId: true })
|
41 |
-
},
|
42 |
-
async stat (e) {
|
43 |
-
let msg = e.msg.replace(/#|统计|分析|池/g, '')
|
44 |
-
let type = 'up'
|
45 |
-
if (/武器/.test(msg)) {
|
46 |
-
type = 'weapon'
|
47 |
-
} else if (/角色/.test(msg)) {
|
48 |
-
type = 'char'
|
49 |
-
} else if (/常驻/.test(msg)) {
|
50 |
-
type = 'normal'
|
51 |
-
} else if (/全部/.test(msg)) {
|
52 |
-
type = 'all'
|
53 |
-
}
|
54 |
-
let uid = e.uid || await getTargetUid(e)
|
55 |
-
let qq = e.user_id
|
56 |
-
if (!uid || !qq) {
|
57 |
-
return false
|
58 |
-
}
|
59 |
-
let gacha = GachaData.stat(e.user_id, uid, type)
|
60 |
-
if (!gacha) {
|
61 |
-
e.reply(`UID:${uid} 本地暂无抽卡信息,请通过【#抽卡帮助】获得绑定帮助...`)
|
62 |
-
return true
|
63 |
-
}
|
64 |
-
await Common.render('gacha/gacha-stat', {
|
65 |
-
save_id: uid,
|
66 |
-
uid,
|
67 |
-
gacha,
|
68 |
-
face: Gacha.getFace(uid)
|
69 |
-
}, { e, scale: 1.4 })
|
70 |
-
},
|
71 |
-
|
72 |
-
getFace (uid) {
|
73 |
-
let player = Player.create(uid)
|
74 |
-
|
75 |
-
let faceChar = Character.get(player.face || 10000014)
|
76 |
-
let imgs = faceChar?.imgs
|
77 |
-
if (!imgs?.face) {
|
78 |
-
imgs = Character.get(10000079).imgs
|
79 |
-
}
|
80 |
-
return {
|
81 |
-
banner: imgs?.banner,
|
82 |
-
face: imgs?.face,
|
83 |
-
qFace: imgs?.qFace,
|
84 |
-
name: player.name || '旅行者',
|
85 |
-
sign: player.sign,
|
86 |
-
level: player.level
|
87 |
-
}
|
88 |
-
}
|
89 |
-
}
|
90 |
-
export default Gacha
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/gacha/GachaData.js
DELETED
@@ -1,444 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import { Data } from '#miao'
|
3 |
-
import { Character, Weapon } from '#miao.models'
|
4 |
-
import { poolDetail } from '../../resources/meta/info/index.js'
|
5 |
-
import moment from 'moment'
|
6 |
-
|
7 |
-
let poolVersion = []
|
8 |
-
lodash.forEach(poolDetail, (ds) => {
|
9 |
-
poolVersion.push({
|
10 |
-
...ds,
|
11 |
-
start: new Date(ds.from),
|
12 |
-
end: new Date(ds.to)
|
13 |
-
})
|
14 |
-
})
|
15 |
-
let last = poolVersion[poolVersion.length - 1]
|
16 |
-
// 为未知卡池做兼容
|
17 |
-
poolVersion.push({
|
18 |
-
version: '新版本',
|
19 |
-
half: '?',
|
20 |
-
from: last.to,
|
21 |
-
to: '2025-12-31 23:59:59',
|
22 |
-
start: last.end,
|
23 |
-
end: new Date('2025-12-31 23:59:59')
|
24 |
-
})
|
25 |
-
|
26 |
-
let GachaData = {
|
27 |
-
|
28 |
-
// 获取JSON数据
|
29 |
-
readJSON (qq, uid, type) {
|
30 |
-
let logJson = []
|
31 |
-
// 获取本地数据 进行数据合并
|
32 |
-
logJson = Data.readJSON(`/data/gachaJson/${qq}/${uid}/${type}.json`, 'root')
|
33 |
-
let itemMap = {}
|
34 |
-
let nameMap = {}
|
35 |
-
let items = []
|
36 |
-
let ids = {}
|
37 |
-
lodash.forEach(logJson, (ds) => {
|
38 |
-
if (!nameMap[ds.name]) {
|
39 |
-
if (ds.item_type === '武器') {
|
40 |
-
let weapon = Weapon.get(ds.name)
|
41 |
-
if (weapon) {
|
42 |
-
nameMap[ds.name] = weapon.id
|
43 |
-
itemMap[weapon.id] = {
|
44 |
-
type: 'weapon',
|
45 |
-
count: 0,
|
46 |
-
...weapon.getData('star,name,abbr,img')
|
47 |
-
}
|
48 |
-
} else {
|
49 |
-
nameMap[ds.name] = 403
|
50 |
-
itemMap[403] = {
|
51 |
-
type: 'weapon',
|
52 |
-
count: 0,
|
53 |
-
star: 3,
|
54 |
-
name: '未知',
|
55 |
-
abbr: '未知',
|
56 |
-
img: ''
|
57 |
-
}
|
58 |
-
}
|
59 |
-
} else if (ds.item_type === '角色') {
|
60 |
-
let char = Character.get(ds.name)
|
61 |
-
if (char) {
|
62 |
-
nameMap[ds.name] = char.id
|
63 |
-
itemMap[char.id] = {
|
64 |
-
type: 'char',
|
65 |
-
count: 0,
|
66 |
-
...char.getData('star,name,abbr,img:face')
|
67 |
-
}
|
68 |
-
} else {
|
69 |
-
nameMap[ds.name] = 404
|
70 |
-
itemMap[404] = {
|
71 |
-
type: 'char',
|
72 |
-
count: 0,
|
73 |
-
star: 4,
|
74 |
-
name: '未知',
|
75 |
-
abbr: '未知',
|
76 |
-
img: ''
|
77 |
-
}
|
78 |
-
}
|
79 |
-
}
|
80 |
-
}
|
81 |
-
let id = nameMap[ds.name]
|
82 |
-
if (!id || !itemMap[id] || (ds.id && ids[ds.id])) {
|
83 |
-
return true
|
84 |
-
}
|
85 |
-
ids[ds.id] = true
|
86 |
-
items.push({
|
87 |
-
id,
|
88 |
-
logId: ds.id,
|
89 |
-
time: new Date(ds.time)
|
90 |
-
})
|
91 |
-
})
|
92 |
-
items = items.sort((a, b) => b.time - a.time)
|
93 |
-
return { items, itemMap }
|
94 |
-
},
|
95 |
-
|
96 |
-
// 卡池分析
|
97 |
-
analyse (qq, uid, type) {
|
98 |
-
let logData = GachaData.readJSON(qq, uid, type)
|
99 |
-
let fiveLog = []
|
100 |
-
let fourLog = []
|
101 |
-
let fiveNum = 0
|
102 |
-
let fourNum = 0
|
103 |
-
let fiveLogNum = 0
|
104 |
-
let fourLogNum = 0
|
105 |
-
let noFiveNum = 0
|
106 |
-
let noFourNum = 0
|
107 |
-
let wai = 0 // 歪
|
108 |
-
let weaponNum = 0
|
109 |
-
let weaponFourNum = 0
|
110 |
-
let bigNum = 0
|
111 |
-
let allNum = 0
|
112 |
-
|
113 |
-
let itemMap = logData.itemMap
|
114 |
-
if (logData.items.length === 0) {
|
115 |
-
return false
|
116 |
-
}
|
117 |
-
let currVersion
|
118 |
-
lodash.forEach(logData.items, (item) => {
|
119 |
-
if (!currVersion || (item.time < currVersion.start)) {
|
120 |
-
currVersion = GachaData.getVersion(item.time)
|
121 |
-
}
|
122 |
-
|
123 |
-
allNum++
|
124 |
-
let ds = itemMap[item.id]
|
125 |
-
let { star, type } = ds
|
126 |
-
ds.count++
|
127 |
-
if (star === 4) {
|
128 |
-
fourNum++
|
129 |
-
if (noFourNum === 0) {
|
130 |
-
noFourNum = fourLogNum
|
131 |
-
}
|
132 |
-
fourLogNum = 0
|
133 |
-
if (fourLog[ds.name]) {
|
134 |
-
fourLog[ds.name]++
|
135 |
-
} else {
|
136 |
-
fourLog[ds.name] = 1
|
137 |
-
}
|
138 |
-
if (type === 'weapon') {
|
139 |
-
weaponFourNum++
|
140 |
-
}
|
141 |
-
}
|
142 |
-
fourLogNum++
|
143 |
-
|
144 |
-
if (star === 5) {
|
145 |
-
fiveNum++
|
146 |
-
if (fiveLog.length > 0) {
|
147 |
-
fiveLog[fiveLog.length - 1].count = fiveLogNum
|
148 |
-
} else {
|
149 |
-
noFiveNum = fiveLogNum
|
150 |
-
}
|
151 |
-
fiveLogNum = 0
|
152 |
-
let isUp = false
|
153 |
-
// 歪了多少个
|
154 |
-
if (type === 'char') {
|
155 |
-
if (!currVersion.hasOwnProperty("char5") || currVersion.char5.includes(ds.name)) {
|
156 |
-
isUp = true
|
157 |
-
} else {
|
158 |
-
wai++
|
159 |
-
}
|
160 |
-
} else {
|
161 |
-
if (currVersion.weapon5.includes(ds.name)) {
|
162 |
-
isUp = true
|
163 |
-
} else {
|
164 |
-
wai++
|
165 |
-
}
|
166 |
-
}
|
167 |
-
|
168 |
-
fiveLog.push({
|
169 |
-
id: item.id,
|
170 |
-
isUp,
|
171 |
-
date: moment(item.time).format('MM-DD')
|
172 |
-
})
|
173 |
-
}
|
174 |
-
fiveLogNum++
|
175 |
-
})
|
176 |
-
|
177 |
-
if (fiveLog.length > 0) {
|
178 |
-
fiveLog[fiveLog.length - 1].count = fiveLogNum
|
179 |
-
} else {
|
180 |
-
// 没有五星
|
181 |
-
noFiveNum = allNum
|
182 |
-
}
|
183 |
-
|
184 |
-
// 四星最多
|
185 |
-
let fourItem = lodash.filter(lodash.values(itemMap), (ds) => ds.star === 4)
|
186 |
-
fourItem.push({ name: '无', count: 0 })
|
187 |
-
fourItem = fourItem.sort((a, b) => b.count - a.count)
|
188 |
-
|
189 |
-
// 平均5星
|
190 |
-
let fiveAvg = 0
|
191 |
-
let fourAvg = 0
|
192 |
-
if (fiveNum > 0) {
|
193 |
-
fiveAvg = ((allNum - noFiveNum) / fiveNum).toFixed(2)
|
194 |
-
}
|
195 |
-
// 平均四星
|
196 |
-
if (fourNum > 0) {
|
197 |
-
fourAvg = ((allNum - noFourNum) / fourNum).toFixed(2)
|
198 |
-
}
|
199 |
-
|
200 |
-
// 有效抽卡
|
201 |
-
let isvalidNum = 0
|
202 |
-
if (fiveNum > 0 && fiveNum > wai) {
|
203 |
-
if (fiveLog.length > 0 && !fiveLog[0].isUp) {
|
204 |
-
isvalidNum = (allNum - noFiveNum - fiveLog[0].count) / (fiveNum - wai)
|
205 |
-
} else {
|
206 |
-
isvalidNum = (allNum - noFiveNum) / (fiveNum - wai)
|
207 |
-
}
|
208 |
-
isvalidNum = isvalidNum.toFixed(2)
|
209 |
-
}
|
210 |
-
|
211 |
-
let upYs = isvalidNum * 160
|
212 |
-
if (upYs >= 10000) {
|
213 |
-
upYs = (upYs / 10000).toFixed(2) + 'w'
|
214 |
-
} else {
|
215 |
-
upYs = upYs.toFixed(0)
|
216 |
-
}
|
217 |
-
|
218 |
-
// 小保底不歪概率
|
219 |
-
let noWaiRate = 0
|
220 |
-
if (fiveNum > 0) {
|
221 |
-
noWaiRate = (fiveNum - bigNum - wai) / (fiveNum - bigNum)
|
222 |
-
noWaiRate = (noWaiRate * 100).toFixed(1)
|
223 |
-
}
|
224 |
-
|
225 |
-
if (noFiveNum > 0) {
|
226 |
-
fiveLog.unshift({
|
227 |
-
id: 888,
|
228 |
-
isUp: true,
|
229 |
-
count: noFiveNum,
|
230 |
-
date: moment().format('MM-DD')
|
231 |
-
})
|
232 |
-
itemMap['888'] = {
|
233 |
-
name: '已抽',
|
234 |
-
star: 5,
|
235 |
-
abbr: '已抽',
|
236 |
-
img: 'gacha/imgs/no-avatar.webp'
|
237 |
-
}
|
238 |
-
}
|
239 |
-
|
240 |
-
return {
|
241 |
-
stat: {
|
242 |
-
allNum,
|
243 |
-
noFiveNum,
|
244 |
-
noFourNum,
|
245 |
-
fiveNum,
|
246 |
-
fourNum,
|
247 |
-
fiveAvg,
|
248 |
-
fourAvg,
|
249 |
-
wai,
|
250 |
-
isvalidNum,
|
251 |
-
weaponNum,
|
252 |
-
weaponFourNum,
|
253 |
-
upYs
|
254 |
-
},
|
255 |
-
maxFour: fourItem[0],
|
256 |
-
fiveLog,
|
257 |
-
noWaiRate,
|
258 |
-
items: itemMap
|
259 |
-
}
|
260 |
-
},
|
261 |
-
|
262 |
-
// 卡池统计
|
263 |
-
stat (qq, uid, type) {
|
264 |
-
let items = []
|
265 |
-
let itemMap = {}
|
266 |
-
let hasVersion = true
|
267 |
-
let loadData = function (poolId) {
|
268 |
-
let gachaData = GachaData.readJSON(qq, uid, poolId)
|
269 |
-
items = items.concat(gachaData.items)
|
270 |
-
lodash.extend(itemMap, gachaData.itemMap || {})
|
271 |
-
}
|
272 |
-
if (['up', 'char', 'all'].includes(type)) {
|
273 |
-
loadData(301)
|
274 |
-
}
|
275 |
-
if (['up', 'weapon', 'all'].includes(type)) {
|
276 |
-
loadData(302)
|
277 |
-
}
|
278 |
-
if (['all', 'normal'].includes(type)) {
|
279 |
-
hasVersion = false
|
280 |
-
loadData(200)
|
281 |
-
}
|
282 |
-
|
283 |
-
items = items.sort((a, b) => b.time - a.time)
|
284 |
-
|
285 |
-
let versionData = []
|
286 |
-
let currVersion
|
287 |
-
|
288 |
-
if (lodash.isEmpty(items)) {
|
289 |
-
return false
|
290 |
-
}
|
291 |
-
|
292 |
-
let getCurr = function () {
|
293 |
-
if (currVersion && !lodash.isEmpty(currVersion)) {
|
294 |
-
let cv = currVersion
|
295 |
-
let temp = {
|
296 |
-
version: cv.version,
|
297 |
-
half: cv.half,
|
298 |
-
from: hasVersion ? moment(new Date(cv.from)).format('YY-MM-DD') : '',
|
299 |
-
to: hasVersion ? moment(new Date(cv.to)).format('YY-MM-DD') : '',
|
300 |
-
upIds: {}
|
301 |
-
}
|
302 |
-
let upName = {}
|
303 |
-
let items = []
|
304 |
-
let poolNames = []
|
305 |
-
lodash.forEach(cv.char5, (name) => {
|
306 |
-
upName[name] = true
|
307 |
-
let char = Character.get(name)
|
308 |
-
poolNames.push(char.abbr)
|
309 |
-
})
|
310 |
-
lodash.forEach(cv.weapon5, (name) => {
|
311 |
-
upName[name] = true
|
312 |
-
})
|
313 |
-
let w5Num = 0
|
314 |
-
let w5UpNum = 0
|
315 |
-
let c5Num = 0
|
316 |
-
let c5UpNum = 0
|
317 |
-
let c4Num = 0
|
318 |
-
let w4Num = 0
|
319 |
-
let w3Num = 0
|
320 |
-
lodash.forEach(cv.items, (num, id) => {
|
321 |
-
let item = itemMap[id]
|
322 |
-
let isUp = upName[item.name]
|
323 |
-
let star = item.star
|
324 |
-
if (isUp) {
|
325 |
-
temp.upIds[id] = item.name
|
326 |
-
}
|
327 |
-
items.push({ id, num, star: item.star, isUp: temp.upIds[id] ? 1 : 0 })
|
328 |
-
if (item.type === 'char') {
|
329 |
-
if (star === 5) {
|
330 |
-
c5Num += num
|
331 |
-
isUp && (c5UpNum += num)
|
332 |
-
} else {
|
333 |
-
c4Num += num
|
334 |
-
}
|
335 |
-
}
|
336 |
-
if (item.type === 'weapon') {
|
337 |
-
if (star === 5) {
|
338 |
-
w5Num += num
|
339 |
-
isUp && (w5UpNum += num)
|
340 |
-
} else {
|
341 |
-
star === 4 ? (w4Num += num) : (w3Num += num)
|
342 |
-
}
|
343 |
-
}
|
344 |
-
})
|
345 |
-
temp.name = poolNames.join(' / ')
|
346 |
-
temp.items = lodash.sortBy(items, ['star', 'num', 'isUp']).reverse()
|
347 |
-
temp.stats = {
|
348 |
-
w5Num,
|
349 |
-
w5UpNum,
|
350 |
-
c5Num,
|
351 |
-
c5UpNum,
|
352 |
-
c4Num,
|
353 |
-
w4Num,
|
354 |
-
w3Num,
|
355 |
-
upNum: w5UpNum + c5UpNum,
|
356 |
-
star5Num: w5Num + c5Num,
|
357 |
-
star4Num: w4Num + c4Num,
|
358 |
-
totalNum: w5Num + w4Num + w3Num + c5Num + c4Num
|
359 |
-
}
|
360 |
-
return temp
|
361 |
-
}
|
362 |
-
}
|
363 |
-
|
364 |
-
lodash.forEach(items, (ds) => {
|
365 |
-
if (!currVersion || (ds.time < currVersion.start && hasVersion)) {
|
366 |
-
if (currVersion) {
|
367 |
-
versionData.push(getCurr())
|
368 |
-
}
|
369 |
-
let v = GachaData.getVersion(ds.time, hasVersion)
|
370 |
-
if (!hasVersion) {
|
371 |
-
v.version = type === 'all' ? '全部统计' : '常驻池'
|
372 |
-
}
|
373 |
-
if (!v) {
|
374 |
-
return true
|
375 |
-
}
|
376 |
-
currVersion = {
|
377 |
-
...v,
|
378 |
-
items: {}
|
379 |
-
}
|
380 |
-
}
|
381 |
-
if (!currVersion.items[ds.id]) {
|
382 |
-
currVersion.items[ds.id] = 1
|
383 |
-
} else {
|
384 |
-
currVersion.items[ds.id]++
|
385 |
-
}
|
386 |
-
})
|
387 |
-
versionData.push(getCurr())
|
388 |
-
|
389 |
-
let stat = {}
|
390 |
-
lodash.forEach(versionData, (ds) => {
|
391 |
-
lodash.forEach(ds.stats, (num, key) => {
|
392 |
-
if (!stat[key]) {
|
393 |
-
stat[key] = num
|
394 |
-
} else {
|
395 |
-
stat[key] += num
|
396 |
-
}
|
397 |
-
})
|
398 |
-
})
|
399 |
-
stat.avgUpNum = stat.upNum === 0 ? 0 : ((stat.totalNum / stat.upNum).toFixed(1))
|
400 |
-
|
401 |
-
return {
|
402 |
-
versionData,
|
403 |
-
itemMap,
|
404 |
-
totalStat: stat
|
405 |
-
}
|
406 |
-
},
|
407 |
-
|
408 |
-
getVersion (time, hasVersion = true) {
|
409 |
-
if (hasVersion) {
|
410 |
-
for (let ds of poolVersion) {
|
411 |
-
if (time > ds.start && time < ds.end) {
|
412 |
-
return ds
|
413 |
-
}
|
414 |
-
}
|
415 |
-
}
|
416 |
-
return {
|
417 |
-
version: hasVersion === false ? '全部' : '未知',
|
418 |
-
half: '',
|
419 |
-
char5: [],
|
420 |
-
char4: [],
|
421 |
-
weapon5: [],
|
422 |
-
weapon4: []
|
423 |
-
}
|
424 |
-
},
|
425 |
-
|
426 |
-
getItem (ds) {
|
427 |
-
if (ds.item_type === '武器') {
|
428 |
-
let weapon = Weapon.get(ds.name)
|
429 |
-
return {
|
430 |
-
type: 'weapon',
|
431 |
-
count: 0,
|
432 |
-
...weapon.getData('id,star,name,abbr,img')
|
433 |
-
}
|
434 |
-
} else if (ds.item_type === '角色') {
|
435 |
-
let char = Character.get(ds.name)
|
436 |
-
return {
|
437 |
-
type: 'char',
|
438 |
-
count: 0,
|
439 |
-
...char.getData('id,star,name,abbr,face')
|
440 |
-
}
|
441 |
-
}
|
442 |
-
}
|
443 |
-
}
|
444 |
-
export default GachaData
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/help.js
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
import Help from './help/Help.js'
|
2 |
-
import { App } from '#miao'
|
3 |
-
|
4 |
-
let app = App.init({
|
5 |
-
id: 'help',
|
6 |
-
name: '喵喵帮助',
|
7 |
-
desc: '喵喵帮助'
|
8 |
-
})
|
9 |
-
|
10 |
-
app.reg({
|
11 |
-
help: {
|
12 |
-
rule: /^#?(喵喵)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$/,
|
13 |
-
fn: Help.render,
|
14 |
-
desc: '【#帮助】 #喵喵帮助'
|
15 |
-
},
|
16 |
-
version: {
|
17 |
-
rule: /^#?喵喵版本$/,
|
18 |
-
fn: Help.version,
|
19 |
-
desc: '【#帮助】 喵喵版本介绍'
|
20 |
-
}
|
21 |
-
})
|
22 |
-
|
23 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/help/Help.js
DELETED
@@ -1,77 +0,0 @@
|
|
1 |
-
import { Cfg, Common, Data, Version } from '#miao'
|
2 |
-
import fs from 'fs'
|
3 |
-
import lodash from 'lodash'
|
4 |
-
import HelpTheme from './HelpTheme.js'
|
5 |
-
|
6 |
-
const _path = process.cwd()
|
7 |
-
const helpPath = `${_path}/plugins/miao-plugin/resources/help`
|
8 |
-
|
9 |
-
const Help = {
|
10 |
-
async render (e) {
|
11 |
-
if (!/喵喵/.test(e.msg) && !Cfg.get('help', false)) {
|
12 |
-
return false
|
13 |
-
}
|
14 |
-
|
15 |
-
let custom = {}
|
16 |
-
let help = {}
|
17 |
-
if (fs.existsSync(`${helpPath}/help-cfg.js`)) {
|
18 |
-
console.log('miao-plugin: 检测到存在help-cfg.js配置\n建议将help-cfg.js移为config/help.js或重新复制config/help_default.js进行配置~')
|
19 |
-
help = await import(`file://${helpPath}/help-cfg.js?version=${new Date().getTime()}`)
|
20 |
-
} else if (fs.existsSync(`${helpPath}/help-list.js`)) {
|
21 |
-
console.log('miao-plugin: 检测到存在help-list.js配置,建议将help-list.js移为config/help.js或重新复制config/help_default.js进行配置~')
|
22 |
-
help = await import(`file://${helpPath}/help-list.js?version=${new Date().getTime()}`)
|
23 |
-
}
|
24 |
-
|
25 |
-
let { diyCfg, sysCfg } = await Data.importCfg('help')
|
26 |
-
|
27 |
-
// 兼容一下旧字段
|
28 |
-
if (lodash.isArray(help.helpCfg)) {
|
29 |
-
custom = {
|
30 |
-
helpList: help.helpCfg,
|
31 |
-
helpCfg: {}
|
32 |
-
}
|
33 |
-
} else {
|
34 |
-
custom = help
|
35 |
-
}
|
36 |
-
|
37 |
-
let helpConfig = lodash.defaults(diyCfg.helpCfg || {}, custom.helpCfg, sysCfg.helpCfg)
|
38 |
-
let helpList = diyCfg.helpList || custom.helpList || sysCfg.helpList
|
39 |
-
|
40 |
-
let helpGroup = []
|
41 |
-
|
42 |
-
lodash.forEach(helpList, (group) => {
|
43 |
-
if (group.auth && group.auth === 'master' && !e.isMaster) {
|
44 |
-
return true
|
45 |
-
}
|
46 |
-
|
47 |
-
lodash.forEach(group.list, (help) => {
|
48 |
-
let icon = help.icon * 1
|
49 |
-
if (!icon) {
|
50 |
-
help.css = 'display:none'
|
51 |
-
} else {
|
52 |
-
let x = (icon - 1) % 10
|
53 |
-
let y = (icon - x - 1) / 10
|
54 |
-
help.css = `background-position:-${x * 50}px -${y * 50}px`
|
55 |
-
}
|
56 |
-
})
|
57 |
-
|
58 |
-
helpGroup.push(group)
|
59 |
-
})
|
60 |
-
let themeData = await HelpTheme.getThemeData(diyCfg.helpCfg || {}, sysCfg.helpCfg || {})
|
61 |
-
return await Common.render('help/index', {
|
62 |
-
helpCfg: helpConfig,
|
63 |
-
helpGroup,
|
64 |
-
...themeData,
|
65 |
-
element: 'default'
|
66 |
-
}, { e, scale: 1.2 })
|
67 |
-
},
|
68 |
-
|
69 |
-
async version (e) {
|
70 |
-
return await Common.render('help/version-info', {
|
71 |
-
currentVersion: Version.version,
|
72 |
-
changelogs: Version.changelogs,
|
73 |
-
elem: 'cryo'
|
74 |
-
}, { e, scale: 1.2 })
|
75 |
-
}
|
76 |
-
}
|
77 |
-
export default Help
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/help/HelpTheme.js
DELETED
@@ -1,68 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import fs from 'fs'
|
3 |
-
import { Data } from '#miao'
|
4 |
-
|
5 |
-
let HelpTheme = {
|
6 |
-
async getThemeCfg (theme, exclude) {
|
7 |
-
let dirPath = './plugins/miao-plugin/resources/help/theme/'
|
8 |
-
let ret = []
|
9 |
-
let names = []
|
10 |
-
let dirs = fs.readdirSync(dirPath)
|
11 |
-
lodash.forEach(dirs, (dir) => {
|
12 |
-
if (fs.existsSync(`${dirPath}${dir}/main.png`)) {
|
13 |
-
names.push(dir)
|
14 |
-
}
|
15 |
-
})
|
16 |
-
if (lodash.isArray(theme)) {
|
17 |
-
ret = lodash.intersection(theme, names)
|
18 |
-
} else if (theme === 'all') {
|
19 |
-
ret = names
|
20 |
-
}
|
21 |
-
if (exclude && lodash.isArray(exclude)) {
|
22 |
-
ret = lodash.difference(ret, exclude)
|
23 |
-
}
|
24 |
-
if (ret.length === 0) {
|
25 |
-
ret = ['default']
|
26 |
-
}
|
27 |
-
let name = lodash.sample(ret)
|
28 |
-
let resPath = '{{_res_path}}/help/theme/'
|
29 |
-
return {
|
30 |
-
main: `${resPath}${name}/main.png`,
|
31 |
-
bg: fs.existsSync(`${dirPath}${name}/bg.jpg`) ? `${resPath}${name}/bg.jpg` : `${resPath}default/bg.jpg`,
|
32 |
-
style: (await Data.importModule(`resources/help/theme/${name}/config.js`, 'miao')).style || {}
|
33 |
-
}
|
34 |
-
},
|
35 |
-
async getThemeData (diyStyle, sysStyle) {
|
36 |
-
let helpConfig = lodash.extend({}, sysStyle, diyStyle)
|
37 |
-
let colCount = Math.min(5, Math.max(parseInt(helpConfig?.colCount) || 3, 2))
|
38 |
-
let colWidth = Math.min(500, Math.max(100, parseInt(helpConfig?.colWidth) || 265))
|
39 |
-
let width = Math.min(2500, Math.max(800, colCount * colWidth + 30))
|
40 |
-
let theme = await HelpTheme.getThemeCfg(diyStyle.theme || sysStyle.theme, diyStyle.themeExclude || sysStyle.themeExclude)
|
41 |
-
let themeStyle = theme.style || {}
|
42 |
-
let ret = [`
|
43 |
-
body{background-image:url(${theme.bg});width:${width}px;}
|
44 |
-
.container{background-image:url(${theme.main});width:${width}px;}
|
45 |
-
.help-table .td,.help-table .th{width:${100 / colCount}%}
|
46 |
-
`]
|
47 |
-
let css = function (sel, css, key, def, fn) {
|
48 |
-
let val = Data.def(themeStyle[key], diyStyle[key], sysStyle[key], def)
|
49 |
-
if (fn) {
|
50 |
-
val = fn(val)
|
51 |
-
}
|
52 |
-
ret.push(`${sel}{${css}:${val}}`)
|
53 |
-
}
|
54 |
-
css('.help-title,.help-group', 'color', 'fontColor', '#ceb78b')
|
55 |
-
css('.help-title,.help-group', 'text-shadow', 'fontShadow', 'none')
|
56 |
-
css('.help-desc', 'color', 'descColor', '#eee')
|
57 |
-
css('.cont-box', 'background', 'contBgColor', 'rgba(43, 52, 61, 0.8)')
|
58 |
-
css('.cont-box', 'backdrop-filter', 'contBgBlur', 3, (n) => diyStyle.bgBlur === false ? 'none' : `blur(${n}px)`)
|
59 |
-
css('.help-group', 'background', 'headerBgColor', 'rgba(34, 41, 51, .4)')
|
60 |
-
css('.help-table .tr:nth-child(odd)', 'background', 'rowBgColor1', 'rgba(34, 41, 51, .2)')
|
61 |
-
css('.help-table .tr:nth-child(even)', 'background', 'rowBgColor2', 'rgba(34, 41, 51, .4)')
|
62 |
-
return {
|
63 |
-
style: `<style>${ret.join('\n')}</style>`,
|
64 |
-
colCount
|
65 |
-
}
|
66 |
-
}
|
67 |
-
}
|
68 |
-
export default HelpTheme
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/index.js
DELETED
@@ -1,16 +0,0 @@
|
|
1 |
-
import character from './character.js'
|
2 |
-
import profile from './profile.js'
|
3 |
-
import stat from './stat.js'
|
4 |
-
import wiki from './wiki.js'
|
5 |
-
import poke from './poke.js'
|
6 |
-
import help from './help.js'
|
7 |
-
import admin from './admin.js'
|
8 |
-
import gacha from './gacha.js'
|
9 |
-
|
10 |
-
let apps = { character, poke, profile, stat, wiki, gacha, admin, help }
|
11 |
-
let rules = {} // v3
|
12 |
-
for (let key in apps) {
|
13 |
-
rules[`${key}`] = apps[key].v3App()
|
14 |
-
}
|
15 |
-
|
16 |
-
export { rules as apps }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/poke.js
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
import Wife from './character/AvatarWife.js'
|
2 |
-
import { App } from '#miao'
|
3 |
-
|
4 |
-
let app = App.init({
|
5 |
-
id: 'poke',
|
6 |
-
name: '戳一戳',
|
7 |
-
event: 'poke'
|
8 |
-
})
|
9 |
-
|
10 |
-
app.reg({
|
11 |
-
pockWife: {
|
12 |
-
fn: Wife.poke,
|
13 |
-
describe: '#老公 #老婆 查询'
|
14 |
-
}
|
15 |
-
})
|
16 |
-
|
17 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile.js
DELETED
@@ -1,143 +0,0 @@
|
|
1 |
-
import { profileHelp } from './profile/ProfileCommon.js'
|
2 |
-
import { profileArtisList } from './profile/ProfileArtis.js'
|
3 |
-
import ProfileDetail from './profile/ProfileDetail.js'
|
4 |
-
import ProfileStat from './profile/ProfileStat.js'
|
5 |
-
import ProfileList from './profile/ProfileList.js'
|
6 |
-
import { uploadCharacterImg, delProfileImg, profileImgList } from './character/ImgUpload.js'
|
7 |
-
import { enemyLv } from './profile/ProfileUtils.js'
|
8 |
-
import { groupRank, resetRank, refreshRank, manageRank } from './profile/ProfileRank.js'
|
9 |
-
import { App, Cfg } from '#miao'
|
10 |
-
|
11 |
-
let app = App.init({
|
12 |
-
id: 'profile',
|
13 |
-
name: '角色面板'
|
14 |
-
})
|
15 |
-
|
16 |
-
app.reg({
|
17 |
-
profileList: {
|
18 |
-
name: '面板角色列表',
|
19 |
-
desc: '查看当前已获取面板数据的角色列表',
|
20 |
-
fn: ProfileList.render,
|
21 |
-
rule: /^#(星铁|原神)?(面板角色|角色面板|面板)(列表)?\s*(\d{9})?$/
|
22 |
-
},
|
23 |
-
|
24 |
-
profileDetail: {
|
25 |
-
name: '角色面板',
|
26 |
-
fn: ProfileDetail.detail,
|
27 |
-
rule: /^#*([^#]+)\s*(详细|详情|面板|面版|圣遗物|武器[1-7]?|伤害([1-9]+\d*)?)\s*(\d{9})*(.*[换变改].*)?$/
|
28 |
-
},
|
29 |
-
|
30 |
-
profileChange: {
|
31 |
-
name: '角色面板计算',
|
32 |
-
fn: ProfileDetail.detail,
|
33 |
-
rule: /^#.+换.+$/
|
34 |
-
},
|
35 |
-
|
36 |
-
groupProfile: {
|
37 |
-
name: '群内最强',
|
38 |
-
fn: groupRank,
|
39 |
-
rule: /^#(群|群内)?(排名|排行)?(最强|最高|最高分|最牛|第一|极限)+.+/
|
40 |
-
},
|
41 |
-
|
42 |
-
resetRank: {
|
43 |
-
name: '重置排名',
|
44 |
-
fn: resetRank,
|
45 |
-
rule: /^#(重置|重设)(.*)(排名|排行)$/
|
46 |
-
},
|
47 |
-
|
48 |
-
refreshRank: {
|
49 |
-
name: '重置排名',
|
50 |
-
fn: refreshRank,
|
51 |
-
rule: /^#(刷新|更新|重新加载)(群内|群|全部)*(排名|排行)$/
|
52 |
-
},
|
53 |
-
|
54 |
-
manageRank: {
|
55 |
-
name: '打开关闭',
|
56 |
-
fn: manageRank,
|
57 |
-
rule: /^#(开启|打开|启用|关闭|禁用)(群内|群|全部)*(排名|排行)$/
|
58 |
-
},
|
59 |
-
|
60 |
-
rankList: {
|
61 |
-
name: '面板排名榜',
|
62 |
-
fn: groupRank,
|
63 |
-
rule: /^#(群|群内)?.+(排名|排行)(榜)?$/
|
64 |
-
},
|
65 |
-
|
66 |
-
artisList: {
|
67 |
-
name: '面板圣遗物列表',
|
68 |
-
fn: profileArtisList,
|
69 |
-
rule: /^#圣遗物列表\s*(\d{9})?$/
|
70 |
-
},
|
71 |
-
|
72 |
-
profileStat: {
|
73 |
-
name: '面板练度统计',
|
74 |
-
fn: ProfileStat.stat,
|
75 |
-
rule: /^#(面板|喵喵)练度统计$/,
|
76 |
-
yzRule: /^#*(我的)*(技能|天赋|武器|角色|练度|五|四|5|4|星)+(汇总|统计|列表)(force|五|四|5|4|星)*[ |0-9]*$/,
|
77 |
-
yzCheck: () => Cfg.get('profileStat', false)
|
78 |
-
},
|
79 |
-
|
80 |
-
avatarList: {
|
81 |
-
name: '角色查询',
|
82 |
-
fn: ProfileStat.avatarList,
|
83 |
-
rule: /^#喵喵(角色|查询)[ |0-9]*$/,
|
84 |
-
yzRule: /^(#(角色|查询|查询角色|角色查询|人物)[ |0-9]*$)|(^(#*uid|#*UID)\+*[1|2|5-9][0-9]{8}$)|(^#[\+|+]*[1|2|5-9][0-9]{8})/,
|
85 |
-
yzCheck: () => Cfg.get('avatarList', false)
|
86 |
-
},
|
87 |
-
|
88 |
-
profileHelp: {
|
89 |
-
name: '角色面板帮助',
|
90 |
-
fn: profileHelp,
|
91 |
-
rule: /^#(角色|换|更换)?面[板版]帮助$/
|
92 |
-
},
|
93 |
-
|
94 |
-
enemyLv: {
|
95 |
-
name: '敌人等级',
|
96 |
-
fn: enemyLv,
|
97 |
-
describe: '【#角色】 设置伤害计算中目标敌人的等级',
|
98 |
-
rule: /^#(敌人|怪物)等级\s*\d{1,3}\s*$/
|
99 |
-
},
|
100 |
-
|
101 |
-
profileRefresh: {
|
102 |
-
name: '面板更新',
|
103 |
-
describe: '【#角色】 获取游戏橱窗详情数据',
|
104 |
-
fn: ProfileList.refresh,
|
105 |
-
rule: /^#(星铁|原神)?(全部面板更新|更新全部面板|获取游戏角色详情|更新面板|面板更新)\s*(\d{9})?$/
|
106 |
-
},
|
107 |
-
|
108 |
-
uploadImg: {
|
109 |
-
name: '上传面板图',
|
110 |
-
describe: '【#上传刻晴面板图】 上传角色面板图',
|
111 |
-
fn: uploadCharacterImg,
|
112 |
-
rule: /^#?\s*(?:上传|添加)(.+)(?:面板图)\s*$/
|
113 |
-
},
|
114 |
-
|
115 |
-
delProfile: {
|
116 |
-
name: '删除面板图',
|
117 |
-
describe: '【#删除刻晴面板图1】 删除指定角色面板图(序号)',
|
118 |
-
fn: delProfileImg,
|
119 |
-
rule: /^#?\s*(?:移除|清除|删除)(.+)(?:面板图)(\d){1,}\s*$/
|
120 |
-
},
|
121 |
-
|
122 |
-
profileImgList: {
|
123 |
-
name: '面板图列表',
|
124 |
-
describe: '【#刻晴面板图列表】 删除指定角色面板图(序号)',
|
125 |
-
fn: profileImgList,
|
126 |
-
rule: /^#?\s*(.+)(?:面板图列表)\s*$/
|
127 |
-
},
|
128 |
-
|
129 |
-
profileDel: {
|
130 |
-
name: '删除面板',
|
131 |
-
describe: '【#角色】 删除游戏橱窗详情数据',
|
132 |
-
fn: ProfileList.del,
|
133 |
-
rule: /^#(删除全部面板|删除面板|删除面板数据)\s*(\d{9})?$/
|
134 |
-
},
|
135 |
-
|
136 |
-
profileReload:{
|
137 |
-
name: '重新加载面板',
|
138 |
-
fn:ProfileList.reload,
|
139 |
-
rule: /^#(星铁|原神)?(加载|重新加载|重载)面板\s*(\d{9})?$/
|
140 |
-
}
|
141 |
-
})
|
142 |
-
|
143 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileArtis.js
DELETED
@@ -1,96 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* 角色圣遗物评分详情
|
3 |
-
*
|
4 |
-
* */
|
5 |
-
import lodash from 'lodash'
|
6 |
-
import { Cfg, Common } from '#miao'
|
7 |
-
import { getTargetUid, profileHelp, getProfileRefresh } from './ProfileCommon.js'
|
8 |
-
import { Artifact, Character, ProfileArtis, Player } from '#miao.models'
|
9 |
-
|
10 |
-
/*
|
11 |
-
* 角色圣遗物面板
|
12 |
-
* */
|
13 |
-
export async function profileArtis (e) {
|
14 |
-
let { uid, avatar } = e
|
15 |
-
let profile = e._profile || await getProfileRefresh(e, avatar)
|
16 |
-
if (!profile) {
|
17 |
-
return true
|
18 |
-
}
|
19 |
-
if (!profile.hasArtis()) {
|
20 |
-
e.reply('未能获得圣遗物详情,请重新获取面板信息后查看')
|
21 |
-
return true
|
22 |
-
}
|
23 |
-
let char = profile.char
|
24 |
-
let { game } = char
|
25 |
-
let charCfg = profile.artis.getCharCfg()
|
26 |
-
|
27 |
-
let { attrMap } = Artifact.getMeta()
|
28 |
-
|
29 |
-
let artisDetail = profile.getArtisMark()
|
30 |
-
let artisKeyTitle = ProfileArtis.getArtisKeyTitle()
|
31 |
-
|
32 |
-
// 渲染图像
|
33 |
-
return await Common.render('character/artis-mark', {
|
34 |
-
uid,
|
35 |
-
elem: char.elem,
|
36 |
-
splash: profile.costumeSplash,
|
37 |
-
data: profile,
|
38 |
-
costume: profile.costume ? '2' : '',
|
39 |
-
artisDetail,
|
40 |
-
artisKeyTitle,
|
41 |
-
attrMap,
|
42 |
-
charCfg,
|
43 |
-
game,
|
44 |
-
changeProfile: e._profileMsg
|
45 |
-
}, { e, scale: 1.3 })
|
46 |
-
}
|
47 |
-
|
48 |
-
/*
|
49 |
-
* 圣遗物列表
|
50 |
-
* */
|
51 |
-
export async function profileArtisList (e) {
|
52 |
-
let uid = await getTargetUid(e)
|
53 |
-
if (!uid) {
|
54 |
-
return true
|
55 |
-
}
|
56 |
-
|
57 |
-
let artis = []
|
58 |
-
let player = Player.create(uid)
|
59 |
-
player.forEachAvatar((avatar) => {
|
60 |
-
let profile = avatar.getProfile()
|
61 |
-
if (!profile) {
|
62 |
-
return true
|
63 |
-
}
|
64 |
-
let name = profile.name
|
65 |
-
let char = Character.get(name)
|
66 |
-
if (!profile.hasData || !profile.hasArtis()) {
|
67 |
-
return true
|
68 |
-
}
|
69 |
-
let profileArtis = profile.getArtisMark()
|
70 |
-
lodash.forEach(profileArtis.artis, (arti, idx) => {
|
71 |
-
arti.charWeight = profileArtis.charWeight
|
72 |
-
arti.avatar = name
|
73 |
-
arti.side = char.side
|
74 |
-
artis.push(arti)
|
75 |
-
})
|
76 |
-
})
|
77 |
-
|
78 |
-
if (artis.length === 0) {
|
79 |
-
e.reply('请先获取角色面板数据后再查看圣遗物列表...')
|
80 |
-
await profileHelp(e)
|
81 |
-
return true
|
82 |
-
}
|
83 |
-
artis = lodash.sortBy(artis, '_mark')
|
84 |
-
artis = artis.reverse()
|
85 |
-
let number = Cfg.get('artisNumber', 28)
|
86 |
-
artis = artis.slice(0, `${number}`)
|
87 |
-
let artisKeyTitle = ProfileArtis.getArtisKeyTitle()
|
88 |
-
|
89 |
-
// 渲染图像
|
90 |
-
return await Common.render('character/artis-list', {
|
91 |
-
save_id: uid,
|
92 |
-
uid,
|
93 |
-
artis,
|
94 |
-
artisKeyTitle
|
95 |
-
}, { e, scale: 1.4 })
|
96 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileChange.js
DELETED
@@ -1,299 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* 面板数据替换相关逻辑
|
3 |
-
*/
|
4 |
-
import lodash from 'lodash'
|
5 |
-
import { Data } from '#miao'
|
6 |
-
import { Character, ArtifactSet, ProfileData, Weapon, Player } from '#miao.models'
|
7 |
-
|
8 |
-
// 默认武器
|
9 |
-
let defWeapon = {
|
10 |
-
bow: '西风猎弓',
|
11 |
-
catalyst: '西风秘典',
|
12 |
-
claymore: '西风大剑',
|
13 |
-
polearm: '西风长枪',
|
14 |
-
sword: '西风剑'
|
15 |
-
}
|
16 |
-
|
17 |
-
const ProfileChange = {
|
18 |
-
/**
|
19 |
-
* 匹配消息
|
20 |
-
* @param msg
|
21 |
-
* @returns {{}}
|
22 |
-
*/
|
23 |
-
matchMsg (msg) {
|
24 |
-
if (!/(变|改|换)/.test(msg)) {
|
25 |
-
return false
|
26 |
-
}
|
27 |
-
msg = msg.toLowerCase().replace(/uid ?:? ?/, '').replace('', '')
|
28 |
-
let regRet = /^#*(\d{9})?(.+?)(详细|详情|面板|面版|圣遗物|伤害[1-7]?)?\s*(\d{9})?[变换改](.+)/.exec(msg)
|
29 |
-
if (!regRet || !regRet[2]) {
|
30 |
-
return false
|
31 |
-
}
|
32 |
-
let ret = {}
|
33 |
-
let change = {}
|
34 |
-
let char = Character.get(lodash.trim(regRet[2]).replace('星铁', ''))
|
35 |
-
if (!char) {
|
36 |
-
return false
|
37 |
-
}
|
38 |
-
const game = char.game
|
39 |
-
const isGs = game === 'gs'
|
40 |
-
const keyMap = isGs ? {
|
41 |
-
artis: '圣遗物',
|
42 |
-
arti1: '花,生之花',
|
43 |
-
arti2: '毛,羽,羽毛,死之羽',
|
44 |
-
arti3: '沙,沙漏,表,时之沙',
|
45 |
-
arti4: '杯,杯子,空之杯',
|
46 |
-
arti5: '头,冠,理之冠,礼冠,帽子,帽',
|
47 |
-
weapon: '武器'
|
48 |
-
} : {
|
49 |
-
artis: '圣遗物,遗器',
|
50 |
-
arti1: '头,帽子,头部',
|
51 |
-
arti2: '手,手套,手部',
|
52 |
-
arti3: '衣,衣服,甲,躯干,',
|
53 |
-
arti4: '鞋,靴,鞋子,靴子,脚,脚部',
|
54 |
-
arti5: '球,位面球',
|
55 |
-
arti6: '绳,线,链接绳,连接绳',
|
56 |
-
weapon: '武器,光锥'
|
57 |
-
}
|
58 |
-
let keyTitleMap = {}
|
59 |
-
lodash.forEach(keyMap, (val, key) => {
|
60 |
-
lodash.forEach(val.split(','), (v) => {
|
61 |
-
keyTitleMap[v] = key
|
62 |
-
})
|
63 |
-
})
|
64 |
-
const keyReg = new RegExp(`^(\\d{9})?\\s*(.+?)\\s*(\\d{9})?\\s*((?:${lodash.keys(keyTitleMap).join('|')}|\\+)+)$`)
|
65 |
-
|
66 |
-
ret.char = char.id
|
67 |
-
ret.mode = regRet[3] === '换' ? '面板' : regRet[3]
|
68 |
-
ret.uid = regRet[1] || regRet[4] || ''
|
69 |
-
ret.game = char.game
|
70 |
-
msg = regRet[5]
|
71 |
-
|
72 |
-
// 更换匹配
|
73 |
-
msg = msg.replace(/[变改]/g, '换')
|
74 |
-
lodash.forEach(msg.split('换'), (txt) => {
|
75 |
-
txt = lodash.trim(txt)
|
76 |
-
if (!txt) {
|
77 |
-
return true
|
78 |
-
}
|
79 |
-
// 匹配圣遗物
|
80 |
-
let keyRet = keyReg.exec(txt)
|
81 |
-
if (keyRet && keyRet[4]) {
|
82 |
-
let char = Character.get(lodash.trim(keyRet[2]))
|
83 |
-
if (char) {
|
84 |
-
if (char.game !== game) {
|
85 |
-
return true
|
86 |
-
}
|
87 |
-
lodash.forEach(keyRet[4].split('+'), (key) => {
|
88 |
-
key = lodash.trim(key)
|
89 |
-
let type = keyTitleMap[key]
|
90 |
-
change[type] = {
|
91 |
-
char: char.id || '',
|
92 |
-
uid: keyRet[1] || keyRet[3] || '',
|
93 |
-
type
|
94 |
-
}
|
95 |
-
})
|
96 |
-
} else if (keyRet[4].length > 2) {
|
97 |
-
return true
|
98 |
-
}
|
99 |
-
}
|
100 |
-
|
101 |
-
// 匹配圣遗物套装
|
102 |
-
let asMap = ArtifactSet.getAliasMap(game)
|
103 |
-
let asKey = lodash.keys(asMap).sort((a, b) => b.length - a.length).join('|')
|
104 |
-
let asReg = new RegExp(`^(${asKey})套?[2,4]?\\+?(${asKey})?套?[2,4]?\\+?(${asKey})?套?[2,4]?$`)
|
105 |
-
let asRet = asReg.exec(txt)
|
106 |
-
if (asRet && asRet[1] && asMap[asRet[1]]) {
|
107 |
-
if (game === 'gs') {
|
108 |
-
change.artisSet = [asMap[asRet[1]], asMap?.[asRet[2]] || asMap[asRet[1]]]
|
109 |
-
} else if (game === 'sr') {
|
110 |
-
for (let idx = 1; idx <= 3; idx++) {
|
111 |
-
let as = ArtifactSet.get(asMap?.[asRet[idx]])
|
112 |
-
if (as) { // 球&绳
|
113 |
-
change.artisSet = change.artisSet || []
|
114 |
-
let ca = change.artisSet
|
115 |
-
ca[as.sets?.[1] ? (ca[0] ? 1 : 0) : 2] = as.name
|
116 |
-
}
|
117 |
-
}
|
118 |
-
let ca = change.artisSet
|
119 |
-
if (ca && ca[0] && !ca[1]) {
|
120 |
-
ca[1] = ca[0]
|
121 |
-
}
|
122 |
-
}
|
123 |
-
return true
|
124 |
-
}
|
125 |
-
|
126 |
-
// 匹配武器
|
127 |
-
let wRet = /^(?:等?级?([1-9][0-9])?级?)?\s*(?:([1-5一二三四五满])?精炼?([1-5一二三四五])?)?\s*(?:等?级?([1-9][0-9])?级?)?\s*(.*)$/.exec(txt)
|
128 |
-
if (wRet && wRet[5]) {
|
129 |
-
let weaponName = lodash.trim(wRet[5])
|
130 |
-
let weapon = Weapon.get(weaponName, game, ret.char.game)
|
131 |
-
if (weapon || weaponName === '武器' || Weapon.isWeaponSet(weaponName)) {
|
132 |
-
let affix = wRet[2] || wRet[3]
|
133 |
-
affix = { 一: 1, 二: 2, 三: 3, 四: 4, 五: 5, 满: 5 }[affix] || affix * 1
|
134 |
-
let tmp = {
|
135 |
-
weapon: (Weapon.isWeaponSet(weaponName) ? weaponName : weapon?.name) || '',
|
136 |
-
affix: affix || '',
|
137 |
-
level: wRet[1] * 1 || wRet[4] * 1 || ''
|
138 |
-
}
|
139 |
-
if (lodash.values(tmp).join('')) {
|
140 |
-
change.weapon = tmp
|
141 |
-
}
|
142 |
-
return true
|
143 |
-
}
|
144 |
-
}
|
145 |
-
let char = change.char || {}
|
146 |
-
// 命座匹配
|
147 |
-
let consRet = /([0-6零一二三四五六满])(命|魂|星魂)/.exec(txt)
|
148 |
-
if (consRet && consRet[1]) {
|
149 |
-
let cons = consRet[1]
|
150 |
-
char.cons = Math.max(0, Math.min(6, lodash.isNaN(cons * 1) ? '零一二��四五六满'.split('').indexOf(cons) : cons * 1))
|
151 |
-
txt = txt.replace(consRet[0], '')
|
152 |
-
}
|
153 |
-
|
154 |
-
// 天赋匹配
|
155 |
-
let talentRet = (isGs ? /(?:天赋|技能|行迹)((?:[1][0-5]|[1-9])[ ,]?)((?:[1][0-5]|[1-9])[ ,]?)([1][0-5]|[1-9])/ :
|
156 |
-
/(?:天赋|技能|行迹)((?:[1][0-5]|[1-9])[ ,]?)((?:[1][0-5]|[1-9])[ ,]?)((?:[1][0-5]|[1-9])[ ,]?)([1][0-5]|[1-9])/).exec(txt)
|
157 |
-
if (talentRet) {
|
158 |
-
char.talent = {}
|
159 |
-
lodash.forEach((isGs ? 'aeq' : 'aetq').split(''), (key, idx) => {
|
160 |
-
char.talent[key] = talentRet[idx + 1] * 1 || 1
|
161 |
-
})
|
162 |
-
txt = txt.replace(talentRet[0], '')
|
163 |
-
}
|
164 |
-
|
165 |
-
let lvRet = /等级([1-9][0-9]?)|([1-9][0-9]?)级/.exec(txt)
|
166 |
-
if (lvRet && (lvRet[1] || lvRet[2])) {
|
167 |
-
char.level = (lvRet[1] || lvRet[2]) * 1
|
168 |
-
txt = txt.replace(lvRet[0], '')
|
169 |
-
}
|
170 |
-
txt = lodash.trim(txt)
|
171 |
-
if (txt) {
|
172 |
-
let chars = Character.get(txt)
|
173 |
-
if (chars && (chars.game === game)) {
|
174 |
-
char.char = chars.id
|
175 |
-
}
|
176 |
-
}
|
177 |
-
if (!lodash.isEmpty(char)) {
|
178 |
-
change.char = char
|
179 |
-
}
|
180 |
-
})
|
181 |
-
ret.change = lodash.isEmpty(change) ? false : change
|
182 |
-
return ret
|
183 |
-
},
|
184 |
-
|
185 |
-
/**
|
186 |
-
* 获取面板数据
|
187 |
-
* @param uid
|
188 |
-
* @param charid
|
189 |
-
* @param ds
|
190 |
-
* @param game
|
191 |
-
* @returns {ProfileData|boolean}
|
192 |
-
*/
|
193 |
-
getProfile (uid, charid, ds, game = 'gs') {
|
194 |
-
if (!charid) {
|
195 |
-
return false
|
196 |
-
}
|
197 |
-
|
198 |
-
const isGs = game === 'gs'
|
199 |
-
|
200 |
-
let player = Player.create(uid, game)
|
201 |
-
|
202 |
-
let source = player.getProfile(charid)
|
203 |
-
let dc = ds.char || {}
|
204 |
-
if (!source || !source.hasData) {
|
205 |
-
source = {}
|
206 |
-
}
|
207 |
-
|
208 |
-
let char = Character.get(dc?.char || source.id || charid)
|
209 |
-
if (!char) {
|
210 |
-
return false
|
211 |
-
}
|
212 |
-
let level = dc.level || source.level || 90
|
213 |
-
let promote = level === source.level ? source.promote : undefined
|
214 |
-
|
215 |
-
let profiles = {}
|
216 |
-
if (source && source.id) {
|
217 |
-
profiles[`${player.uid}:${source.id}`] = source
|
218 |
-
}
|
219 |
-
// 获取source
|
220 |
-
let getSource = function (cfg) {
|
221 |
-
if (!cfg || !cfg.char) {
|
222 |
-
return source
|
223 |
-
}
|
224 |
-
let cuid = cfg.uid || uid
|
225 |
-
let id = cfg.char || source.id
|
226 |
-
let key = cuid + ':' + id
|
227 |
-
if (!profiles[key]) {
|
228 |
-
let cPlayer = Player.create(cuid, game)
|
229 |
-
profiles[key] = cPlayer.getProfile(id) || {}
|
230 |
-
}
|
231 |
-
return profiles[key]?.id ? profiles[key] : source
|
232 |
-
}
|
233 |
-
// 初始化profile
|
234 |
-
let ret = new ProfileData({
|
235 |
-
uid,
|
236 |
-
id: char.id,
|
237 |
-
level,
|
238 |
-
cons: Data.def(dc.cons, source.cons, 0),
|
239 |
-
fetter: source.fetter || 10,
|
240 |
-
elem: char.elem,
|
241 |
-
dataSource: 'change',
|
242 |
-
_source: 'change',
|
243 |
-
promote,
|
244 |
-
trees: lodash.extend([], source.trees)
|
245 |
-
}, char.game, false)
|
246 |
-
|
247 |
-
// 设置武器
|
248 |
-
let wCfg = ds.weapon || {}
|
249 |
-
let wSource = getSource(wCfg).weapon || {}
|
250 |
-
let weapon = Weapon.get(wCfg?.weapon || wSource?.name || defWeapon[char.weaponType], char.game, char.weaponType)
|
251 |
-
if (char.isGs) {
|
252 |
-
if (!weapon || weapon.type !== char.weaponType) {
|
253 |
-
weapon = Weapon.get(defWeapon[char.weaponType], char.game)
|
254 |
-
}
|
255 |
-
}
|
256 |
-
|
257 |
-
let wDs = {
|
258 |
-
name: weapon.name,
|
259 |
-
star: weapon.star,
|
260 |
-
level: Math.min(weapon.maxLv || 90, wCfg.level || wSource.level || 90)
|
261 |
-
}
|
262 |
-
if (wSource.level === wDs.level) {
|
263 |
-
wDs.promote = wSource.promote
|
264 |
-
}
|
265 |
-
wDs.affix = Math.min(weapon.maxAffix || 5, wCfg.affix || ((wDs.star === 5 && wSource.star !== 5) ? 1 : (wSource.affix || 5)))
|
266 |
-
ret.setWeapon(wDs)
|
267 |
-
|
268 |
-
// 设置天赋
|
269 |
-
if (ds?.char?.talent) {
|
270 |
-
ret.setTalent(ds?.char?.talent, 'level')
|
271 |
-
} else {
|
272 |
-
ret.setTalent(source?.originalTalent || (isGs ? { a: 9, e: 9, q: 9 } : { a: 6, e: 8, t: 8, q: 8 }), 'original')
|
273 |
-
}
|
274 |
-
|
275 |
-
// 设置圣遗物
|
276 |
-
let artis = getSource(ds.artis)?.artis?.artis || {}
|
277 |
-
for (let idx = 1; idx <= (isGs ? 5 : 6); idx++) {
|
278 |
-
if (ds['arti' + idx]) {
|
279 |
-
let source = getSource(ds['arti' + idx])
|
280 |
-
if (source && source.artis && source.artis[idx]) {
|
281 |
-
artis[idx] = source.artis[idx]
|
282 |
-
}
|
283 |
-
}
|
284 |
-
let artisIdx = (isGs ? '00111' : '001122')[idx - 1]
|
285 |
-
if (artis[idx] && ds.artisSet && ds.artisSet[artisIdx]) {
|
286 |
-
let as = ArtifactSet.get(ds.artisSet[artisIdx], game)
|
287 |
-
if (as) {
|
288 |
-
artis[idx].id = as.getArti(idx)?.getIdByStar(artis[idx].star || 5)
|
289 |
-
artis[idx]._name = artis[idx].name = as.getArtiName(idx)
|
290 |
-
artis[idx]._set = artis[idx].set = as.name
|
291 |
-
}
|
292 |
-
}
|
293 |
-
}
|
294 |
-
ret.setArtis(artis)
|
295 |
-
ret.calcAttr()
|
296 |
-
return ret
|
297 |
-
}
|
298 |
-
}
|
299 |
-
export default ProfileChange
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileCommon.js
DELETED
@@ -1,77 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* 面板公共方法及处理
|
3 |
-
* */
|
4 |
-
import { Version } from '#miao'
|
5 |
-
import { Character, MysApi, Player } from '#miao.models'
|
6 |
-
|
7 |
-
/*
|
8 |
-
* 获取面板查询的 目标uid
|
9 |
-
* */
|
10 |
-
const _getTargetUid = async function (e) {
|
11 |
-
let uidReg = /[1-9][0-9]{8}/
|
12 |
-
|
13 |
-
if (e.uid && uidReg.test(e.uid)) {
|
14 |
-
return e.uid
|
15 |
-
}
|
16 |
-
|
17 |
-
let uidRet = uidReg.exec(e.msg)
|
18 |
-
if (uidRet) {
|
19 |
-
return uidRet[0]
|
20 |
-
}
|
21 |
-
let uid = false
|
22 |
-
|
23 |
-
try {
|
24 |
-
let user = await MysApi.initUser(e)
|
25 |
-
|
26 |
-
if (!user || !user.uid) {
|
27 |
-
return false
|
28 |
-
}
|
29 |
-
uid = user.uid
|
30 |
-
if ((!uid || !uidReg.test(uid)) && !e._replyNeedUid) {
|
31 |
-
e.reply('请先发送【#绑定+你的UID】来绑定查询目标')
|
32 |
-
e._replyNeedUid = true
|
33 |
-
return false
|
34 |
-
}
|
35 |
-
} catch (err) {
|
36 |
-
console.log(err)
|
37 |
-
}
|
38 |
-
return uid || false
|
39 |
-
}
|
40 |
-
|
41 |
-
export async function getTargetUid (e) {
|
42 |
-
let uid = await _getTargetUid(e)
|
43 |
-
if (uid) {
|
44 |
-
e.uid = uid
|
45 |
-
}
|
46 |
-
return uid
|
47 |
-
}
|
48 |
-
|
49 |
-
export async function getProfileRefresh (e, avatar) {
|
50 |
-
let char = Character.get(avatar)
|
51 |
-
if (!char) {
|
52 |
-
return false
|
53 |
-
}
|
54 |
-
|
55 |
-
let player = Player.create(e)
|
56 |
-
let profile = player.getProfile(char.id)
|
57 |
-
if (!profile || !profile.hasData) {
|
58 |
-
logger.mark(`本地无UID:${player.uid}的${char.name}面板数据,尝试自动请求...`)
|
59 |
-
await player.refresh({ profile: true })
|
60 |
-
profile = player.getProfile(char.id)
|
61 |
-
}
|
62 |
-
if (!profile || !profile.hasData) {
|
63 |
-
if (!e._isReplyed) {
|
64 |
-
e.reply(`请确认${char.name}已展示在【游戏内】的角色展柜中,并打开了“显示角色详情”。然后请使用 #更新面板\n命令来获取${char.name}的面板详情`)
|
65 |
-
}
|
66 |
-
return false
|
67 |
-
}
|
68 |
-
return profile
|
69 |
-
}
|
70 |
-
|
71 |
-
/*
|
72 |
-
* 面板帮助
|
73 |
-
* */
|
74 |
-
export async function profileHelp (e) {
|
75 |
-
e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/character/imgs/help.jpg`))
|
76 |
-
return true
|
77 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileDetail.js
DELETED
@@ -1,299 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import { getTargetUid, getProfileRefresh } from './ProfileCommon.js'
|
3 |
-
import ProfileList from './ProfileList.js'
|
4 |
-
import { Cfg, Common, Data, Format } from '#miao'
|
5 |
-
import { MysApi, ProfileRank, ProfileArtis, Character, Weapon } from '#miao.models'
|
6 |
-
import ProfileChange from './ProfileChange.js'
|
7 |
-
import { profileArtis } from './ProfileArtis.js'
|
8 |
-
import { ProfileWeapon } from './ProfileWeapon.js'
|
9 |
-
|
10 |
-
let { diyCfg } = await Data.importCfg('profile')
|
11 |
-
|
12 |
-
// 查看当前角色
|
13 |
-
let ProfileDetail = {
|
14 |
-
async detail (e) {
|
15 |
-
let msg = e.original_msg || e.msg
|
16 |
-
if (!msg) {
|
17 |
-
return false
|
18 |
-
}
|
19 |
-
if (!/详细|详情|面板|面版|圣遗物|伤害|武器|换/.test(msg)) {
|
20 |
-
return false
|
21 |
-
}
|
22 |
-
let mode = 'profile'
|
23 |
-
let profileChange = false
|
24 |
-
let changeMsg = msg
|
25 |
-
let pc = ProfileChange.matchMsg(msg)
|
26 |
-
|
27 |
-
if (pc && pc.char && pc.change) {
|
28 |
-
if (!Cfg.get('profileChange')) {
|
29 |
-
e.reply('面板替换功能已禁用...')
|
30 |
-
return true
|
31 |
-
}
|
32 |
-
e.game = pc.game
|
33 |
-
e.isSr = e.game === 'sr'
|
34 |
-
e.uid = ''
|
35 |
-
e.msg = '#喵喵面板变换'
|
36 |
-
e.uid = pc.uid || await getTargetUid(e)
|
37 |
-
profileChange = ProfileChange.getProfile(e.uid, pc.char, pc.change, pc.game)
|
38 |
-
if (profileChange && profileChange.char) {
|
39 |
-
msg = `#${profileChange.char?.name}${pc.mode || '面板'}`
|
40 |
-
e._profile = profileChange
|
41 |
-
e._profileMsg = changeMsg
|
42 |
-
}
|
43 |
-
}
|
44 |
-
let uidRet = /[0-9]{9}/.exec(msg)
|
45 |
-
if (uidRet) {
|
46 |
-
e.uid = uidRet[0]
|
47 |
-
msg = msg.replace(uidRet[0], '')
|
48 |
-
}
|
49 |
-
|
50 |
-
let name = msg.replace(/#|老婆|老公|星铁|原神/g, '').trim()
|
51 |
-
msg = msg.replace('面版', '面板')
|
52 |
-
let dmgRet = /(?:伤害|武器)(\d*)$/.exec(name)
|
53 |
-
let dmgIdx = 0, idxIsInput = false
|
54 |
-
if (/(最强|最高|最高分|最牛|第一)/.test(msg)) {
|
55 |
-
mode = /(分|圣遗物|评分|ACE)/.test(msg) ? 'rank-mark' : 'rank-dmg'
|
56 |
-
name = name.replace(/(最强|最高分|第一|最高|最牛|圣遗物|评分|群)/g, '')
|
57 |
-
}
|
58 |
-
if (/(详情|详细|面板|面版)\s*$/.test(msg) && !/更新|录入|输入/.test(msg)) {
|
59 |
-
mode = 'profile'
|
60 |
-
name = name.replace(/(详情|详细|面板)/, '').trim()
|
61 |
-
} else if (dmgRet) {
|
62 |
-
// mode = /武器/.test(msg) ? 'weapon' : 'dmg'
|
63 |
-
mode = 'dmg'
|
64 |
-
name = name.replace(/(伤害|武器)+\d*/, '').trim()
|
65 |
-
if (dmgRet[1]) {
|
66 |
-
dmgIdx = dmgRet[1] * 1
|
67 |
-
// 标识是用户指定的序号
|
68 |
-
idxIsInput = true
|
69 |
-
}
|
70 |
-
} else if (/(详情|详细|面板)更新$/.test(msg) || (/更新/.test(msg) && /(详情|详细|面板)$/.test(msg))) {
|
71 |
-
mode = 'refresh'
|
72 |
-
name = name.replace(/详情|详细|面板|更新/g, '').trim()
|
73 |
-
} else if (/圣遗物/.test(msg)) {
|
74 |
-
mode = 'artis'
|
75 |
-
name = name.replace('圣遗物', '').trim()
|
76 |
-
}
|
77 |
-
if (!Common.cfg('avatarProfile')) {
|
78 |
-
return false // 面板开关关闭
|
79 |
-
}
|
80 |
-
let char = Character.get(name.trim())
|
81 |
-
if (!char) {
|
82 |
-
return false
|
83 |
-
}
|
84 |
-
if (/星铁/.test(msg) || char.isSr) {
|
85 |
-
e.isSr = true
|
86 |
-
}
|
87 |
-
|
88 |
-
let uid = e.uid || await getTargetUid(e)
|
89 |
-
if (!uid) {
|
90 |
-
return true
|
91 |
-
}
|
92 |
-
e.uid = uid
|
93 |
-
e.avatar = char.id
|
94 |
-
|
95 |
-
if (char.isCustom) {
|
96 |
-
e.reply('自定义角色暂不支持此功能')
|
97 |
-
return true
|
98 |
-
}
|
99 |
-
if (!char.isRelease) {
|
100 |
-
// 预设面板支持未实装角色
|
101 |
-
if (!profileChange && Number(e.uid) > 100000006) {
|
102 |
-
e.reply('角色尚未实装')
|
103 |
-
return true
|
104 |
-
}
|
105 |
-
// 但仅在未实装开启时展示
|
106 |
-
if (Cfg.get('notReleasedData') === false) {
|
107 |
-
e.reply('未实装角色面板已禁用...')
|
108 |
-
return true
|
109 |
-
}
|
110 |
-
}
|
111 |
-
|
112 |
-
if (mode === 'profile' || mode === 'dmg' || mode === 'weapon') {
|
113 |
-
return ProfileDetail.render(e, char, mode, { dmgIdx, idxIsInput })
|
114 |
-
} else if (mode === 'refresh') {
|
115 |
-
await ProfileList.refresh(e)
|
116 |
-
return true
|
117 |
-
} else if (mode === 'artis') {
|
118 |
-
return profileArtis(e)
|
119 |
-
}
|
120 |
-
return true
|
121 |
-
},
|
122 |
-
|
123 |
-
async render (e, char, mode = 'profile', params = {}) {
|
124 |
-
let selfUser = await MysApi.initUser(e)
|
125 |
-
|
126 |
-
if (!selfUser) {
|
127 |
-
e.reply('尚未绑定UID')
|
128 |
-
return true
|
129 |
-
}
|
130 |
-
|
131 |
-
let { uid } = e
|
132 |
-
|
133 |
-
if (char.isCustom) {
|
134 |
-
e.reply(`暂不支持自定义角色${char.name}的面板信息查看`)
|
135 |
-
return true
|
136 |
-
}
|
137 |
-
|
138 |
-
let profile = e._profile || await getProfileRefresh(e, char.id)
|
139 |
-
if (!profile) {
|
140 |
-
return true
|
141 |
-
}
|
142 |
-
char = profile.char || char
|
143 |
-
let a = profile.attr
|
144 |
-
let base = profile.base
|
145 |
-
let attr = {}
|
146 |
-
let game = char.game
|
147 |
-
let isGs = game === 'gs'
|
148 |
-
let isSr = !isGs
|
149 |
-
|
150 |
-
lodash.forEach((isGs ? 'hp,def,atk,mastery' : 'hp,def,atk,speed').split(','), (key) => {
|
151 |
-
let fn = (n) => Format.comma(n, key === 'hp' ? 0 : 1)
|
152 |
-
attr[key] = fn(a[key])
|
153 |
-
attr[`${key}Base`] = fn(base[key])
|
154 |
-
attr[`${key}Plus`] = fn(a[key] - base[key])
|
155 |
-
})
|
156 |
-
lodash.forEach((isGs ? 'cpct,cdmg,recharge,dmg' : 'cpct,cdmg,recharge,dmg,effPct,effDef,heal,stance').split(','), (key) => {
|
157 |
-
let fn = Format.pct
|
158 |
-
let key2 = key
|
159 |
-
if (key === 'dmg') {
|
160 |
-
if (isGs) {
|
161 |
-
if (a.phy > a.dmg) {
|
162 |
-
key2 = 'phy'
|
163 |
-
}
|
164 |
-
}
|
165 |
-
}
|
166 |
-
attr[key] = fn(a[key2])
|
167 |
-
attr[`${key}Base`] = fn(base[key2])
|
168 |
-
attr[`${key}Plus`] = fn(a[key2] - base[key2])
|
169 |
-
})
|
170 |
-
|
171 |
-
let weapon = Weapon.get(profile?.weapon?.name, game)
|
172 |
-
let w = profile.weapon
|
173 |
-
let wCfg = {}
|
174 |
-
if (mode === 'weapon') {
|
175 |
-
wCfg = weapon.calcAttr(w.level, w.promote)
|
176 |
-
wCfg.weapons = await ProfileWeapon.calc(profile)
|
177 |
-
}
|
178 |
-
|
179 |
-
let enemyLv = isGs ? (await selfUser.getCfg('char.enemyLv', 91)) : profile.level
|
180 |
-
let dmgCalc = await ProfileDetail.getProfileDmgCalc({ profile, enemyLv, mode, params })
|
181 |
-
|
182 |
-
let rank = false
|
183 |
-
if (e.group_id && !e._profile) {
|
184 |
-
rank = await ProfileRank.create({ group: e.group_id, uid, qq: e.user_id })
|
185 |
-
await rank.getRank(profile, true)
|
186 |
-
}
|
187 |
-
|
188 |
-
let artisDetail = profile.getArtisMark()
|
189 |
-
let artisKeyTitle = ProfileArtis.getArtisKeyTitle(game)
|
190 |
-
let data = profile.getData('name,abbr,cons,level,talent,dataSource,updateTime,imgs,costumeSplash')
|
191 |
-
if (isSr) {
|
192 |
-
let treeData = []
|
193 |
-
let treeMap = {}
|
194 |
-
// 属性
|
195 |
-
lodash.forEach('0113355778'.split(''), (pos, idx) => {
|
196 |
-
treeData[pos] = treeData[pos] || []
|
197 |
-
let tmp = { type: 'tree', img: `/meta-sr/public/icons/tree-cpct.webp` }
|
198 |
-
treeData[pos].push(tmp)
|
199 |
-
treeMap[idx + 201 + ''] = tmp
|
200 |
-
})
|
201 |
-
// 能力
|
202 |
-
lodash.forEach([2, 4, 6], (pos, idx) => {
|
203 |
-
let tmp = { type: 'talent', img: data.imgs[`tree${idx + 1}`] }
|
204 |
-
treeData[pos] = tmp
|
205 |
-
treeMap[idx + 101 + ''] = tmp
|
206 |
-
})
|
207 |
-
lodash.forEach(profile.trees, (id) => {
|
208 |
-
let ret = /([12][01][0-9])$/.exec(id + '')
|
209 |
-
if (ret && ret[1]) {
|
210 |
-
let treeId = ret[1]
|
211 |
-
if (treeMap?.[treeId]) {
|
212 |
-
treeMap[treeId].value = 1
|
213 |
-
}
|
214 |
-
if (treeId[0] === '2') {
|
215 |
-
treeMap[treeId].img = `/meta-sr/public/icons/tree-${char.detail?.tree?.[id]?.key}.webp`
|
216 |
-
}
|
217 |
-
}
|
218 |
-
})
|
219 |
-
data.treeData = treeData
|
220 |
-
}
|
221 |
-
data.weapon = profile.getWeaponDetail()
|
222 |
-
let renderData = {
|
223 |
-
save_id: uid,
|
224 |
-
uid,
|
225 |
-
game,
|
226 |
-
data,
|
227 |
-
attr,
|
228 |
-
elem: char.elem,
|
229 |
-
dmgCalc,
|
230 |
-
artisDetail,
|
231 |
-
artisKeyTitle,
|
232 |
-
bodyClass: `char-${char.name}`,
|
233 |
-
mode,
|
234 |
-
wCfg,
|
235 |
-
changeProfile: e._profileMsg
|
236 |
-
}
|
237 |
-
// 渲染图像
|
238 |
-
let msgRes = await Common.render('character/profile-detail', renderData, { e, scale: 1.6, retMsgId: true })
|
239 |
-
if (msgRes) {
|
240 |
-
// 如果消息发送成功,就将message_id和图片路径存起来,3小时过期
|
241 |
-
const message_id = [e.message_id]
|
242 |
-
if (Array.isArray(msgRes.message_id)) {
|
243 |
-
message_id.push(...msgRes.message_id)
|
244 |
-
} else {
|
245 |
-
message_id.push(msgRes.message_id)
|
246 |
-
}
|
247 |
-
for (const i of message_id) {
|
248 |
-
await redis.set(`miao:original-picture:${i}`, JSON.stringify({
|
249 |
-
type: 'profile',
|
250 |
-
img: renderData?.data?.costumeSplash
|
251 |
-
}), { EX: 3600 * 3 })
|
252 |
-
}
|
253 |
-
}
|
254 |
-
return true
|
255 |
-
},
|
256 |
-
|
257 |
-
async getProfileDmgCalc ({ profile, enemyLv, mode, params }) {
|
258 |
-
let dmgMsg = []
|
259 |
-
let dmgData = []
|
260 |
-
let dmgCalc = await profile.calcDmg({
|
261 |
-
enemyLv,
|
262 |
-
mode,
|
263 |
-
...params
|
264 |
-
})
|
265 |
-
if (dmgCalc && dmgCalc.ret) {
|
266 |
-
lodash.forEach(dmgCalc.ret, (ds) => {
|
267 |
-
if (ds.type !== 'text') {
|
268 |
-
ds.dmg = Format.comma(ds.dmg, 0)
|
269 |
-
ds.avg = Format.comma(ds.avg, 0)
|
270 |
-
}
|
271 |
-
dmgData.push(ds)
|
272 |
-
})
|
273 |
-
lodash.forEach(dmgCalc.msg, (msg) => {
|
274 |
-
msg.replace(':', ':')
|
275 |
-
dmgMsg.push(msg.split(':'))
|
276 |
-
})
|
277 |
-
|
278 |
-
dmgCalc.dmgMsg = dmgMsg
|
279 |
-
dmgCalc.dmgData = dmgData
|
280 |
-
}
|
281 |
-
|
282 |
-
if (mode === 'dmg' && dmgCalc.dmgRet) {
|
283 |
-
let basic = dmgCalc?.dmgCfg?.basicRet
|
284 |
-
lodash.forEach(dmgCalc.dmgRet, (row) => {
|
285 |
-
lodash.forEach(row, (ds) => {
|
286 |
-
ds.val = (ds.avg > basic.avg ? '+' : '') + Format.comma(ds.avg - basic.avg)
|
287 |
-
ds.dmg = Format.comma(ds.dmg, 0)
|
288 |
-
ds.avg = Format.comma(ds.avg, 0)
|
289 |
-
})
|
290 |
-
})
|
291 |
-
basic.dmg = Format.comma(basic.dmg)
|
292 |
-
basic.avg = Format.comma(basic.avg)
|
293 |
-
}
|
294 |
-
|
295 |
-
return dmgCalc
|
296 |
-
}
|
297 |
-
}
|
298 |
-
|
299 |
-
export default ProfileDetail
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileList.js
DELETED
@@ -1,184 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import { getTargetUid } from './ProfileCommon.js'
|
3 |
-
import { Common, Data } from '#miao'
|
4 |
-
import { ProfileRank, Player, Character } from '#miao.models'
|
5 |
-
|
6 |
-
const ProfileList = {
|
7 |
-
/**
|
8 |
-
* 刷新面板
|
9 |
-
* @param e
|
10 |
-
* @returns {Promise<boolean|*>}
|
11 |
-
*/
|
12 |
-
async refresh (e) {
|
13 |
-
let uid = await getTargetUid(e)
|
14 |
-
if (!uid) {
|
15 |
-
e._replyNeedUid || e.reply('请先发送【#绑定+你的UID】来绑定查询目标')
|
16 |
-
return true
|
17 |
-
}
|
18 |
-
|
19 |
-
// 数据更新
|
20 |
-
let player = Player.create(e)
|
21 |
-
await player.refreshProfile(2)
|
22 |
-
|
23 |
-
if (!player?._update?.length) {
|
24 |
-
e._isReplyed || e.reply('获取角色面板数据失败,请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
25 |
-
e._isReplyed = true
|
26 |
-
} else {
|
27 |
-
let ret = {}
|
28 |
-
lodash.forEach(player._update, (id) => {
|
29 |
-
let char = Character.get(id)
|
30 |
-
if (char) {
|
31 |
-
ret[char.name] = true
|
32 |
-
}
|
33 |
-
})
|
34 |
-
if (lodash.isEmpty(ret)) {
|
35 |
-
e._isReplyed || e.reply('获取角色面板数据失败,未能请求到角色数据。请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
36 |
-
e._isReplyed = true
|
37 |
-
} else {
|
38 |
-
e.newChar = ret
|
39 |
-
return await ProfileList.render(e)
|
40 |
-
}
|
41 |
-
}
|
42 |
-
return true
|
43 |
-
},
|
44 |
-
|
45 |
-
/**
|
46 |
-
* 渲染面板
|
47 |
-
* @param e
|
48 |
-
* @returns {Promise<boolean|*>}
|
49 |
-
*/
|
50 |
-
|
51 |
-
async render (e) {
|
52 |
-
let uid = await getTargetUid(e)
|
53 |
-
if (!uid) {
|
54 |
-
e._replyNeedUid || e.reply('请先发送【#绑定+你的UID】来绑定查询目标')
|
55 |
-
return true
|
56 |
-
}
|
57 |
-
|
58 |
-
let isSelfUid = false
|
59 |
-
if (e.runtime) {
|
60 |
-
let uids = e.runtime?.user?.ckUids || []
|
61 |
-
isSelfUid = uids.join(',').split(',').includes(uid + '')
|
62 |
-
}
|
63 |
-
let rank = false
|
64 |
-
|
65 |
-
let hasNew = false
|
66 |
-
let newCount = 0
|
67 |
-
|
68 |
-
let chars = []
|
69 |
-
let msg = ''
|
70 |
-
let newChar = {}
|
71 |
-
if (e.newChar) {
|
72 |
-
msg = '获取角色面板数据成功'
|
73 |
-
newChar = e.newChar
|
74 |
-
}
|
75 |
-
const cfg = await Data.importCfg('cfg')
|
76 |
-
// 获取面板数据
|
77 |
-
let player = Player.create(e)
|
78 |
-
let servName = Player.getProfileServName(uid, player.game)
|
79 |
-
if (!player.hasProfile) {
|
80 |
-
await player.refresh({ profile: true })
|
81 |
-
}
|
82 |
-
if (!player.hasProfile) {
|
83 |
-
e.reply(`本地暂无uid${uid}[${player.game}]的面板数据...`)
|
84 |
-
return true
|
85 |
-
}
|
86 |
-
let profiles = player.getProfiles()
|
87 |
-
|
88 |
-
// 检测标志位
|
89 |
-
let qq = (e.at && !e.atBot) ? e.at : e.user_id
|
90 |
-
await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: isSelfUid ? 'ck' : 'bind' })
|
91 |
-
|
92 |
-
let groupId = e.group_id
|
93 |
-
if (groupId) {
|
94 |
-
rank = await ProfileRank.create({ groupId, uid, qq: e.user_id })
|
95 |
-
}
|
96 |
-
const rankCfg = await ProfileRank.getGroupCfg(groupId)
|
97 |
-
const groupRank = rank && (cfg?.diyCfg?.groupRank || false) && rankCfg.status !== 1
|
98 |
-
for (let id in profiles) {
|
99 |
-
let profile = profiles[id]
|
100 |
-
let char = profile.char
|
101 |
-
let tmp = char.getData('id,face,name,abbr,element,star')
|
102 |
-
let imgs = char.getImgs(profile.costume)
|
103 |
-
tmp.face = imgs.qFace || imgs.face
|
104 |
-
tmp.level = profile.level || 1
|
105 |
-
tmp.cons = profile.cons
|
106 |
-
tmp.isNew = 0
|
107 |
-
if (newChar[char.name]) {
|
108 |
-
tmp.isNew = 1
|
109 |
-
newCount++
|
110 |
-
}
|
111 |
-
if (rank) {
|
112 |
-
tmp.groupRank = await rank.getRank(profile, !!tmp.isNew)
|
113 |
-
}
|
114 |
-
chars.push(tmp)
|
115 |
-
}
|
116 |
-
|
117 |
-
if (newCount > 0) {
|
118 |
-
hasNew = newCount <= 8
|
119 |
-
}
|
120 |
-
|
121 |
-
chars = lodash.sortBy(chars, ['isNew', 'star', 'level', 'id'])
|
122 |
-
chars = chars.reverse()
|
123 |
-
|
124 |
-
player.save()
|
125 |
-
// 渲染图像
|
126 |
-
return await Common.render('character/profile-list', {
|
127 |
-
save_id: uid,
|
128 |
-
uid,
|
129 |
-
chars,
|
130 |
-
servName,
|
131 |
-
hasNew,
|
132 |
-
msg,
|
133 |
-
groupRank,
|
134 |
-
updateTime: player.getUpdateTime(),
|
135 |
-
allowRank: rank && rank.allowRank,
|
136 |
-
rankCfg
|
137 |
-
}, { e, scale: 1.6 })
|
138 |
-
},
|
139 |
-
/**
|
140 |
-
* 删除面板数据
|
141 |
-
* @param e
|
142 |
-
* @returns {Promise<boolean>}
|
143 |
-
*/
|
144 |
-
async del (e) {
|
145 |
-
let ret = /^#(删除全部面板|删除面板|删除面板数据)\s*(\d{9})?$/.exec(e.msg)
|
146 |
-
let uid = await getTargetUid(e)
|
147 |
-
if (!uid) {
|
148 |
-
return true
|
149 |
-
}
|
150 |
-
let targetUid = ret[2]
|
151 |
-
|
152 |
-
let user = e?.runtime?.user || {}
|
153 |
-
if (!user.hasCk && !e.isMaster) {
|
154 |
-
e.reply('为确保数据安全,目前仅允许绑定CK用户删除自己UID的面板数据,请联系Bot主人删除...')
|
155 |
-
return true
|
156 |
-
}
|
157 |
-
|
158 |
-
if (!targetUid) {
|
159 |
-
e.reply(`你确认要删除面板数据吗? 请回复 #删除面板${uid} 以删除面板数据`)
|
160 |
-
return true
|
161 |
-
}
|
162 |
-
|
163 |
-
let ckUids = (user?.ckUids || []).join(',').split(',')
|
164 |
-
if (!ckUids.includes(targetUid) && !e.isMaster) {
|
165 |
-
e.reply(`仅允许删除自己的UID数据[${ckUids.join(',')}]`)
|
166 |
-
return true
|
167 |
-
}
|
168 |
-
|
169 |
-
Player.delByUid(targetUid)
|
170 |
-
e.reply(`UID${targetUid}的本地数据已删除,排名数据已清除...`)
|
171 |
-
return true
|
172 |
-
},
|
173 |
-
|
174 |
-
async reload (e) {
|
175 |
-
let uid = await getTargetUid(e)
|
176 |
-
if (!uid) {
|
177 |
-
return true
|
178 |
-
}
|
179 |
-
let player = Player.create(e)
|
180 |
-
player.reload()
|
181 |
-
return ProfileList.render(e)
|
182 |
-
}
|
183 |
-
}
|
184 |
-
export default ProfileList
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileRank.js
DELETED
@@ -1,280 +0,0 @@
|
|
1 |
-
import ProfileDetail from './ProfileDetail.js'
|
2 |
-
import { Data, Common, Format, Cfg } from '#miao'
|
3 |
-
import { Character, ProfileRank, ProfileDmg, Player } from '#miao.models'
|
4 |
-
import lodash from 'lodash'
|
5 |
-
|
6 |
-
export async function groupRank (e) {
|
7 |
-
const groupRank = Common.cfg('groupRank')
|
8 |
-
let msg = e.original_msg || e.msg
|
9 |
-
let type = ''
|
10 |
-
if (/(排名|排行|列表)/.test(msg)) {
|
11 |
-
type = 'list'
|
12 |
-
} else if (/(最强|最高|最多|最高分|最牛|第一)/.test(msg)) {
|
13 |
-
type = 'detail'
|
14 |
-
} else if (/极限/.test(msg)) {
|
15 |
-
type = 'super'
|
16 |
-
}
|
17 |
-
let groupId = e.group_id
|
18 |
-
if (!type || (!groupId && type !== 'super')) {
|
19 |
-
return false
|
20 |
-
}
|
21 |
-
let mode = /(分|圣遗物|评分|ACE)/.test(msg) ? 'mark' : 'dmg'
|
22 |
-
mode = /(词条)/.test(msg) ? 'valid' : mode
|
23 |
-
mode = /(双爆)/.test(msg) ? 'crit' : mode
|
24 |
-
let name = msg.replace(/(#|星铁|最强|最高分|第一|词条|双爆|极限|最高|最多|最牛|圣遗物|评分|群内|群|排名|排行|面板|面版|详情|榜)/g, '')
|
25 |
-
let char = Character.get(name)
|
26 |
-
if (!char) {
|
27 |
-
// 名字不存在或不为列表模式,则返回false
|
28 |
-
if (name || type !== 'list') {
|
29 |
-
return false
|
30 |
-
}
|
31 |
-
}
|
32 |
-
if (/星铁/.test(msg) || char.isSr) {
|
33 |
-
e.isSr = true
|
34 |
-
}
|
35 |
-
// 对鲸泽佬的极限角色文件增加支持
|
36 |
-
if (type === 'super') {
|
37 |
-
let player = Player.create(100000000)
|
38 |
-
if (player.getProfile(char.id)) {
|
39 |
-
e.uid = 100000000
|
40 |
-
if (Cfg.get('notReleasedData') === false) {
|
41 |
-
e.reply('未实装角色面板已禁用...')
|
42 |
-
return true
|
43 |
-
}
|
44 |
-
return await ProfileDetail.render(e, char)
|
45 |
-
} else {
|
46 |
-
return true
|
47 |
-
}
|
48 |
-
}
|
49 |
-
// 正常群排名
|
50 |
-
let groupCfg = await ProfileRank.getGroupCfg(groupId)
|
51 |
-
if (!groupRank) {
|
52 |
-
e.reply('群面板排名功能已禁用,Bot主人可通过【#喵喵设置】启用...')
|
53 |
-
return true
|
54 |
-
}
|
55 |
-
if (groupCfg.status === 1) {
|
56 |
-
e.reply('本群已关闭群排名,群管理员或Bot主人可通过【#启用排名】启用...')
|
57 |
-
return true
|
58 |
-
}
|
59 |
-
if (type === 'detail') {
|
60 |
-
let uid = await ProfileRank.getGroupMaxUid(groupId, char.id, mode)
|
61 |
-
if (uid) {
|
62 |
-
e.uid = uid
|
63 |
-
return await ProfileDetail.render(e, char)
|
64 |
-
} else {
|
65 |
-
if (mode === 'dmg' && !ProfileDmg.dmgRulePath(char.name, char.game)) {
|
66 |
-
e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`)
|
67 |
-
} else {
|
68 |
-
e.reply('暂无排名:请通过【#面板】查看角色面板以更新排名信息...')
|
69 |
-
}
|
70 |
-
}
|
71 |
-
} else if (type === 'list') {
|
72 |
-
if (mode === 'dmg' && char && !ProfileDmg.dmgRulePath(char.name, char.game)) {
|
73 |
-
e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`)
|
74 |
-
} else {
|
75 |
-
let uids = []
|
76 |
-
if (char) {
|
77 |
-
uids = await ProfileRank.getGroupUidList(groupId, char ? char.id : '', mode)
|
78 |
-
} else {
|
79 |
-
uids = await ProfileRank.getGroupMaxUidList(groupId, mode)
|
80 |
-
}
|
81 |
-
if (uids.length > 0) {
|
82 |
-
return renderCharRankList({ e, uids, char, mode, groupId })
|
83 |
-
} else {
|
84 |
-
if (e.isSr){
|
85 |
-
e.reply('暂无排名:请通过【*面板】查看角色面板以更新排名信息...')
|
86 |
-
} else {
|
87 |
-
e.reply('暂无排名:请通过【#面板】查看角色面板以更新排名信息...')
|
88 |
-
}
|
89 |
-
}
|
90 |
-
}
|
91 |
-
return true
|
92 |
-
}
|
93 |
-
}
|
94 |
-
|
95 |
-
export async function resetRank (e) {
|
96 |
-
let groupId = e.group_id
|
97 |
-
if (!groupId) {
|
98 |
-
return true
|
99 |
-
}
|
100 |
-
if (!e.isMaster) {
|
101 |
-
e.reply('只有管理员可重置排名')
|
102 |
-
return true
|
103 |
-
}
|
104 |
-
let msg = e.original_msg || e.msg
|
105 |
-
let name = msg.replace(/(#|重置|重设|排名|排行|群|群内|面板|详情|面版)/g, '').trim()
|
106 |
-
let charId = ''
|
107 |
-
let charName = '全部角色'
|
108 |
-
if (name) {
|
109 |
-
let char = Character.get(name)
|
110 |
-
if (!char) {
|
111 |
-
e.reply(`重置排名失败,角色:${name}不存在`)
|
112 |
-
return true
|
113 |
-
}
|
114 |
-
charId = char.id
|
115 |
-
charName = char.name
|
116 |
-
}
|
117 |
-
await ProfileRank.resetRank(groupId, charId)
|
118 |
-
e.reply(`本群${charName}排名已重置...`)
|
119 |
-
}
|
120 |
-
|
121 |
-
/**
|
122 |
-
* 刷新群排名信息
|
123 |
-
* @param e
|
124 |
-
* @returns {Promise<boolean>}
|
125 |
-
*/
|
126 |
-
export async function refreshRank (e) {
|
127 |
-
let groupId = e.group_id || ''
|
128 |
-
if (!groupId) {
|
129 |
-
return true
|
130 |
-
}
|
131 |
-
if (!e.isMaster && !this.e.member?.is_admin) {
|
132 |
-
e.reply('只有主人及群管理员可刷新排名...')
|
133 |
-
return true
|
134 |
-
}
|
135 |
-
e.reply('面板数据刷新中,等待时间可能较长,请耐心等待...')
|
136 |
-
let game = e.isSr ? 'sr' : 'gs'
|
137 |
-
await ProfileRank.resetRank(groupId)
|
138 |
-
let uidMap = await ProfileRank.getUserUidMap(e, game)
|
139 |
-
let count = 0
|
140 |
-
for (let uid in uidMap) {
|
141 |
-
let { qq, type } = uidMap[uid]
|
142 |
-
let player = new Player(uid, game)
|
143 |
-
let profiles = player.getProfiles()
|
144 |
-
// 刷新rankLimit
|
145 |
-
await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: type })
|
146 |
-
let rank = await ProfileRank.create({ groupId, uid, qq })
|
147 |
-
for (let id in profiles) {
|
148 |
-
let profile = profiles[id]
|
149 |
-
if (!profile.hasData) {
|
150 |
-
continue
|
151 |
-
}
|
152 |
-
await rank.getRank(profile, true)
|
153 |
-
}
|
154 |
-
if (rank.allowRank) {
|
155 |
-
count++
|
156 |
-
}
|
157 |
-
}
|
158 |
-
e.reply(`本群排名已刷新,共刷新${count}个UID数据...`)
|
159 |
-
}
|
160 |
-
|
161 |
-
export async function manageRank (e) {
|
162 |
-
let groupId = e.group_id
|
163 |
-
if (!groupId) {
|
164 |
-
return true
|
165 |
-
}
|
166 |
-
let isClose = /(关闭|禁用)/.test(e.msg)
|
167 |
-
if (!e.isMaster && !this.e.member?.is_admin) {
|
168 |
-
e.reply(`只有主人及群管理员可${isClose ? '禁用' : '启用'}排名...`)
|
169 |
-
return true
|
170 |
-
}
|
171 |
-
await ProfileRank.setGroupStatus(groupId, isClose ? 1 : 0)
|
172 |
-
if (isClose) {
|
173 |
-
e.reply('当前群排名功能已禁用...')
|
174 |
-
} else {
|
175 |
-
e.reply('当前群排名功能已启用...\n如数据有问题可通过【#刷新排名】命令来刷新当前群内排名')
|
176 |
-
}
|
177 |
-
}
|
178 |
-
|
179 |
-
async function renderCharRankList ({ e, uids, char, mode, groupId }) {
|
180 |
-
let list = []
|
181 |
-
for (let ds of uids) {
|
182 |
-
let uid = ds.uid || ds.value
|
183 |
-
let player = Player.create(uid, e.isSr ? 'sr' : 'gs')
|
184 |
-
let avatar = player.getAvatar(ds.charId || char.id)
|
185 |
-
if (!avatar) {
|
186 |
-
continue
|
187 |
-
}
|
188 |
-
let profile = avatar.getProfile()
|
189 |
-
|
190 |
-
if (profile) {
|
191 |
-
let profileRank = await ProfileRank.create({ groupId, uid })
|
192 |
-
let data = await profileRank.getRank(profile, true)
|
193 |
-
let mark = data?.mark?.data
|
194 |
-
let tmp = {
|
195 |
-
uid,
|
196 |
-
isMax: !char,
|
197 |
-
...avatar.getData('id,star,name,sName,level,fetter,cons,weapon,elem,talent,artisSet,imgs'),
|
198 |
-
artisMark: Data.getData(mark, 'mark,markClass,valid,crit')
|
199 |
-
}
|
200 |
-
let dmg = data?.dmg?.data
|
201 |
-
if (dmg && dmg.avg) {
|
202 |
-
let title = dmg.title
|
203 |
-
// 稍微缩短下title
|
204 |
-
if (title.length > 10) {
|
205 |
-
title = title.replace(/[ ·]*/g, '')
|
206 |
-
}
|
207 |
-
title = title.length > 10 ? title.replace(/伤害$/, '') : title
|
208 |
-
tmp.dmg = {
|
209 |
-
title: title,
|
210 |
-
avg: Format.comma(dmg.avg, 1)
|
211 |
-
}
|
212 |
-
}
|
213 |
-
if (uid) {
|
214 |
-
let userInfo = await ProfileRank.getUidInfo(uid)
|
215 |
-
try {
|
216 |
-
if (userInfo?.qq && e?.group?.pickMember) {
|
217 |
-
let member = e.group.pickMember(userInfo.qq)
|
218 |
-
if (member?.getAvatarUrl) {
|
219 |
-
let img = await member.getAvatarUrl()
|
220 |
-
if (img) {
|
221 |
-
tmp.qqFace = img
|
222 |
-
}
|
223 |
-
}
|
224 |
-
}
|
225 |
-
} catch (e) {
|
226 |
-
// console.log(e)
|
227 |
-
}
|
228 |
-
}
|
229 |
-
|
230 |
-
if (mode === 'crit') {
|
231 |
-
tmp._mark = mark?._crit * 6.6044 || 0
|
232 |
-
} else if (mode === 'valid') {
|
233 |
-
tmp._mark = mark?._valid || 0
|
234 |
-
} else {
|
235 |
-
tmp._mark = mark?._mark || 0
|
236 |
-
}
|
237 |
-
tmp._formatmark = Format.comma(tmp._mark, 1)
|
238 |
-
tmp._dmg = dmg?.avg || 0
|
239 |
-
tmp._star = 5 - tmp.star
|
240 |
-
list.push(tmp)
|
241 |
-
}
|
242 |
-
}
|
243 |
-
let title
|
244 |
-
if (char) {
|
245 |
-
let modeTitleMap = {}
|
246 |
-
if (e.isSr) {
|
247 |
-
modeTitleMap = {
|
248 |
-
dmg: '',
|
249 |
-
mark: '遗器评分',
|
250 |
-
crit: '双爆副词条',
|
251 |
-
valid: '加权有效词条'
|
252 |
-
}
|
253 |
-
} else {
|
254 |
-
modeTitleMap = {
|
255 |
-
dmg: '',
|
256 |
-
mark: '圣遗物评分',
|
257 |
-
crit: '双爆副词条',
|
258 |
-
valid: '加权有效词条'
|
259 |
-
}
|
260 |
-
}
|
261 |
-
title = `${e.isSr ? '*' : '#'}${char.name}${modeTitleMap[mode]}排行`
|
262 |
-
list = lodash.sortBy(list, mode === 'dmg' ? '_dmg' : '_mark').reverse()
|
263 |
-
} else {
|
264 |
-
title = `${e.isSr ? '*' : '#'}${mode === 'mark' ? '最高分' : '最强'}排行`
|
265 |
-
list = lodash.sortBy(list, ['uid', '_star', 'id'])
|
266 |
-
}
|
267 |
-
|
268 |
-
const rankCfg = await ProfileRank.getGroupCfg(groupId)
|
269 |
-
// 渲染图像
|
270 |
-
return await Common.render('character/rank-profile-list', {
|
271 |
-
save_id: char.id,
|
272 |
-
game: e.isSr ? 'sr' : 'gs',
|
273 |
-
list,
|
274 |
-
title,
|
275 |
-
elem: char.elem,
|
276 |
-
bodyClass: `char-${char.name}`,
|
277 |
-
rankCfg,
|
278 |
-
mode
|
279 |
-
}, { e, scale: 1.4 })
|
280 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileStat.js
DELETED
@@ -1,73 +0,0 @@
|
|
1 |
-
import { Common } from '#miao'
|
2 |
-
import { MysApi, Player, Character } from '#miao.models'
|
3 |
-
|
4 |
-
const ProfileStat = {
|
5 |
-
async stat (e) {
|
6 |
-
return ProfileStat.render(e, false)
|
7 |
-
},
|
8 |
-
|
9 |
-
async avatarList (e) {
|
10 |
-
return ProfileStat.render(e, true)
|
11 |
-
},
|
12 |
-
async render (e, isAvatarList = false) {
|
13 |
-
// 缓存时间,单位小时
|
14 |
-
let msg = e.msg.replace('#', '').trim()
|
15 |
-
if (msg === '角色统计' || msg === '武器统计') {
|
16 |
-
// 暂时避让一下抽卡分析的关键词
|
17 |
-
return false
|
18 |
-
}
|
19 |
-
|
20 |
-
let mys = await MysApi.init(e)
|
21 |
-
if (!mys || !mys.uid) return false
|
22 |
-
|
23 |
-
const uid = mys.uid
|
24 |
-
|
25 |
-
let player = Player.create(e)
|
26 |
-
|
27 |
-
let avatarRet = await player.refreshAndGetAvatarData({
|
28 |
-
index: 2,
|
29 |
-
detail: 1,
|
30 |
-
talent: isAvatarList ? 0 : 1,
|
31 |
-
rank: true,
|
32 |
-
retType: 'array',
|
33 |
-
sort: true
|
34 |
-
})
|
35 |
-
|
36 |
-
if (avatarRet.length === 0) {
|
37 |
-
e._isReplyed || e.reply(`查询失败,暂未获得#${uid}角色数据,请绑定CK或 #更新面板`)
|
38 |
-
return true
|
39 |
-
}
|
40 |
-
|
41 |
-
let faceChar = Character.get(player.face || avatarRet[0]?.id)
|
42 |
-
let imgs = faceChar.imgs
|
43 |
-
let face = {
|
44 |
-
banner: imgs?.banner,
|
45 |
-
face: imgs?.face,
|
46 |
-
qFace: imgs?.qFace,
|
47 |
-
name: player.name || `#${uid}`,
|
48 |
-
sign: player.sign,
|
49 |
-
level: player.level
|
50 |
-
}
|
51 |
-
|
52 |
-
let info = player.getInfo()
|
53 |
-
info.stats = info.stats || {}
|
54 |
-
info.statMap = {
|
55 |
-
achievement: '成就',
|
56 |
-
wayPoint: '锚点',
|
57 |
-
avatar: '角色',
|
58 |
-
avatar5: '五星角色',
|
59 |
-
goldCount: '金卡总数'
|
60 |
-
}
|
61 |
-
|
62 |
-
return await Common.render(isAvatarList ? 'character/avatar-list' : 'character/profile-stat', {
|
63 |
-
save_id: uid,
|
64 |
-
uid,
|
65 |
-
info,
|
66 |
-
updateTime: player.getUpdateTime(),
|
67 |
-
isSelfCookie: e.isSelfCookie,
|
68 |
-
face,
|
69 |
-
avatars: avatarRet
|
70 |
-
}, { e, scale: 1.4 })
|
71 |
-
}
|
72 |
-
}
|
73 |
-
export default ProfileStat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileUtils.js
DELETED
@@ -1,78 +0,0 @@
|
|
1 |
-
import { Cfg } from '#miao'
|
2 |
-
import { MysApi } from '#miao.models'
|
3 |
-
|
4 |
-
/** 获取角色卡片的原图 */
|
5 |
-
export async function getOriginalPicture (e) {
|
6 |
-
let source
|
7 |
-
if (e.reply_id) {
|
8 |
-
source = { message_id: e.reply_id }
|
9 |
-
} else {
|
10 |
-
if (!e.hasReply && !e.source) {
|
11 |
-
return false
|
12 |
-
}
|
13 |
-
// 引用的消息不是自己的消息
|
14 |
-
if (e.source.user_id !== e.self_id) {
|
15 |
-
return false
|
16 |
-
}
|
17 |
-
// 引用的消息不是纯图片
|
18 |
-
if (!/^\[图片]$/.test(e.source.message)) {
|
19 |
-
return false
|
20 |
-
}
|
21 |
-
// 获取原消息
|
22 |
-
if (e.group?.getChatHistory) {
|
23 |
-
source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
|
24 |
-
} else if (e.friend?.getChatHistory) {
|
25 |
-
source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
|
26 |
-
}
|
27 |
-
}
|
28 |
-
let originalPic = Cfg.get('originalPic') * 1
|
29 |
-
if (source) {
|
30 |
-
let imgPath = await redis.get(`miao:original-picture:${source.message_id}`)
|
31 |
-
if (imgPath) {
|
32 |
-
try {
|
33 |
-
if (imgPath[0] === '{') {
|
34 |
-
imgPath = JSON.parse(imgPath)
|
35 |
-
} else {
|
36 |
-
imgPath = { img: imgPath, type: '' }
|
37 |
-
}
|
38 |
-
} catch (e) {
|
39 |
-
}
|
40 |
-
if (!e.isMaster) {
|
41 |
-
if (imgPath.type === 'character' && [2, 0].includes(originalPic)) {
|
42 |
-
e.reply('已禁止获取角色原图...')
|
43 |
-
return true
|
44 |
-
}
|
45 |
-
if (imgPath.type === 'profile' && [1, 0].includes(originalPic)) {
|
46 |
-
e.reply('已禁止获取面板原图...')
|
47 |
-
return true
|
48 |
-
}
|
49 |
-
}
|
50 |
-
if (imgPath && imgPath.img) {
|
51 |
-
e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/${decodeURIComponent(imgPath.img)}`), false, { recallMsg: 30 })
|
52 |
-
}
|
53 |
-
return true
|
54 |
-
}
|
55 |
-
// 对at错图像的增加嘲讽...
|
56 |
-
e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/common/face/what.jpg`))
|
57 |
-
return false
|
58 |
-
}
|
59 |
-
e.reply('消息太过久远了,俺也忘了原图是啥了,下次早点来吧~')
|
60 |
-
return false
|
61 |
-
}
|
62 |
-
|
63 |
-
/* #敌人等级 */
|
64 |
-
export async function enemyLv (e) {
|
65 |
-
let selfUser = await MysApi.initUser(e)
|
66 |
-
if (!selfUser || !e.msg) {
|
67 |
-
return true
|
68 |
-
}
|
69 |
-
let ret = /(敌人|怪物)等级\s*(\d{1,3})\s*$/.exec(e.msg)
|
70 |
-
if (ret && ret[2]) {
|
71 |
-
let lv = ret[2] * 1
|
72 |
-
await selfUser.setCfg('char.enemyLv', lv)
|
73 |
-
lv = await selfUser.getCfg('char.enemyLv', 91)
|
74 |
-
e.reply(`敌人等级已经设置为${lv}`)
|
75 |
-
return true
|
76 |
-
}
|
77 |
-
return true
|
78 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/profile/ProfileWeapon.js
DELETED
@@ -1,36 +0,0 @@
|
|
1 |
-
import { ProfileData, Weapon } from '#miao.models'
|
2 |
-
|
3 |
-
export const ProfileWeapon = {
|
4 |
-
async calc (profile, game = 'gs') {
|
5 |
-
let ret = []
|
6 |
-
await Weapon.forEach(async (w) => {
|
7 |
-
let weaponRet = w.getData('name,star,abbr,icon')
|
8 |
-
weaponRet.dmgs = []
|
9 |
-
for (let affix of [1, 5]) {
|
10 |
-
if (affix === 5 && w.maxAffix !== 5) {
|
11 |
-
continue
|
12 |
-
}
|
13 |
-
let tempProfile = new ProfileData({
|
14 |
-
...profile.getData('uid,id,level,cons,fetter,elem,promote,talent,artis'),
|
15 |
-
dataSource: 'change'
|
16 |
-
}, game, false)
|
17 |
-
|
18 |
-
tempProfile.setWeapon({
|
19 |
-
name: w.name,
|
20 |
-
star: w.star,
|
21 |
-
level: w.maxLv,
|
22 |
-
promote: w.maxPromote,
|
23 |
-
affix
|
24 |
-
})
|
25 |
-
tempProfile.calcAttr()
|
26 |
-
weaponRet.dmgs.push({
|
27 |
-
affix,
|
28 |
-
...await tempProfile.calcDmg({ mode: 'single' })
|
29 |
-
})
|
30 |
-
}
|
31 |
-
ret.push(weaponRet)
|
32 |
-
}, profile?.weapon?.type)
|
33 |
-
return ret
|
34 |
-
}
|
35 |
-
|
36 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/stat.js
DELETED
@@ -1,37 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* 胡桃数据库的统计
|
3 |
-
*
|
4 |
-
* */
|
5 |
-
import { ConsStat, AbyssPct } from './stat/AbyssStat.js'
|
6 |
-
import { AbyssTeam } from './stat/AbyssTeam.js'
|
7 |
-
import { AbyssSummary } from './stat/AbyssSummary.js'
|
8 |
-
import { App } from '#miao'
|
9 |
-
|
10 |
-
let app = App.init({
|
11 |
-
id: 'stat',
|
12 |
-
name: '深渊统计'
|
13 |
-
})
|
14 |
-
|
15 |
-
app.reg({
|
16 |
-
consStat: {
|
17 |
-
rule: /^#(喵喵)?角色(持有|持有率|命座|命之座|.命)(分布|统计|持有|持有率)?$/,
|
18 |
-
fn: ConsStat,
|
19 |
-
desc: '【#统计】 #角色持有率 #角色5命统计'
|
20 |
-
},
|
21 |
-
abyssPct: {
|
22 |
-
rule: /^#(喵喵)?深渊(第?.{1,2}层)?(角色)?(出场|使用)(率|统计)*$/,
|
23 |
-
fn: AbyssPct,
|
24 |
-
desc: '【#统计】 #深渊出场率 #深渊12层出场率'
|
25 |
-
},
|
26 |
-
abyssTeam: {
|
27 |
-
rule: /^#深渊(组队|配队)$/,
|
28 |
-
fn: AbyssTeam,
|
29 |
-
describe: '【#角色】 #深渊组队'
|
30 |
-
},
|
31 |
-
abyssSummary: {
|
32 |
-
rule: /^#*(喵喵|上传|本期)*(深渊|深境|深境螺旋)[ |0-9]*(数据)?$/,
|
33 |
-
fn: AbyssSummary,
|
34 |
-
desc: '上传深渊'
|
35 |
-
}
|
36 |
-
})
|
37 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/stat/AbyssStat.js
DELETED
@@ -1,164 +0,0 @@
|
|
1 |
-
import HutaoApi from './HutaoApi.js'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import { Common } from '#miao'
|
4 |
-
import { Character } from '#miao.models'
|
5 |
-
|
6 |
-
export async function ConsStat (e) {
|
7 |
-
let consData = await HutaoApi.getCons()
|
8 |
-
let overview = await HutaoApi.getOverview()
|
9 |
-
|
10 |
-
if (!consData) {
|
11 |
-
e.reply('角色持有数据获取失败,请稍后重试~')
|
12 |
-
return true
|
13 |
-
}
|
14 |
-
|
15 |
-
let msg = e.msg
|
16 |
-
|
17 |
-
let mode = /持有/.test(msg) ? 'char' : 'cons'
|
18 |
-
|
19 |
-
let conNum = -1
|
20 |
-
if (mode === 'cons') {
|
21 |
-
lodash.forEach([/0|零/, /1|一/, /2|二/, /3|三/, /4|四/, /5|五/, /6|六|满/], (reg, idx) => {
|
22 |
-
if (reg.test(msg)) {
|
23 |
-
conNum = idx
|
24 |
-
return false
|
25 |
-
}
|
26 |
-
})
|
27 |
-
}
|
28 |
-
|
29 |
-
if (!consData && !consData.data) {
|
30 |
-
return true
|
31 |
-
}
|
32 |
-
|
33 |
-
let data = consData.data
|
34 |
-
|
35 |
-
let Lumine = lodash.filter(data, (ds) => ds.avatar === 10000007)[0] || {}
|
36 |
-
let Aether = lodash.filter(data, (ds) => ds.avatar === 10000005)[0] || {}
|
37 |
-
|
38 |
-
Lumine.holdingRate = (1 - Aether.holdingRate) || Lumine.holdingRate
|
39 |
-
|
40 |
-
let ret = []
|
41 |
-
|
42 |
-
lodash.forEach(data, (ds) => {
|
43 |
-
let char = Character.get(ds.avatar)
|
44 |
-
|
45 |
-
let data = {
|
46 |
-
name: char.name || ds.avatar,
|
47 |
-
abbr: char.abbr,
|
48 |
-
star: char.star || 3,
|
49 |
-
side: char.side,
|
50 |
-
hold: ds.holdingRate
|
51 |
-
}
|
52 |
-
|
53 |
-
if (mode === 'char') {
|
54 |
-
data.cons = lodash.map(ds.rate, (c) => {
|
55 |
-
c.value = c.value * ds.holdingRate
|
56 |
-
return c
|
57 |
-
})
|
58 |
-
} else {
|
59 |
-
data.cons = ds.rate
|
60 |
-
}
|
61 |
-
data.cons = lodash.sortBy(data.cons, ['id'])
|
62 |
-
|
63 |
-
ret.push(data)
|
64 |
-
})
|
65 |
-
|
66 |
-
if (conNum > -1) {
|
67 |
-
ret = lodash.sortBy(ret, [`cons[${conNum}].value`])
|
68 |
-
ret.reverse()
|
69 |
-
} else {
|
70 |
-
ret = lodash.sortBy(ret, ['hold'])
|
71 |
-
}
|
72 |
-
// 渲染图像
|
73 |
-
return await Common.render('stat/character', {
|
74 |
-
chars: ret,
|
75 |
-
mode,
|
76 |
-
conNum,
|
77 |
-
totalCount: overview?.data?.totalPlayerCount || 0,
|
78 |
-
lastUpdate: consData.lastUpdate,
|
79 |
-
pct: function (num) {
|
80 |
-
return (num * 100).toFixed(2)
|
81 |
-
}
|
82 |
-
}, { e, scale: 1.5 })
|
83 |
-
}
|
84 |
-
|
85 |
-
export async function AbyssPct (e) {
|
86 |
-
let mode = /使用/.test(e.msg) ? 'use' : 'pct'
|
87 |
-
let modeName
|
88 |
-
let abyssData
|
89 |
-
let modeMulti = 1
|
90 |
-
|
91 |
-
if (mode === 'use') {
|
92 |
-
modeName = '使用率'
|
93 |
-
abyssData = await HutaoApi.getAbyssUse()
|
94 |
-
} else {
|
95 |
-
modeName = '出场率'
|
96 |
-
abyssData = await HutaoApi.getAbyssPct()
|
97 |
-
modeMulti = 8
|
98 |
-
}
|
99 |
-
let overview = await HutaoApi.getOverview()
|
100 |
-
|
101 |
-
if (!abyssData) {
|
102 |
-
e.reply(`深渊${modeName}数据获取失败,请稍后重试~`)
|
103 |
-
return true
|
104 |
-
}
|
105 |
-
|
106 |
-
let ret = []
|
107 |
-
let chooseFloor = -1
|
108 |
-
let msg = e.msg
|
109 |
-
|
110 |
-
const floorName = {
|
111 |
-
12: '十二层',
|
112 |
-
11: '十一层',
|
113 |
-
10: '十层',
|
114 |
-
9: '九层'
|
115 |
-
}
|
116 |
-
|
117 |
-
// 匹配深渊楼层信息
|
118 |
-
lodash.forEach(floorName, (cn, num) => {
|
119 |
-
let reg = new RegExp(`${cn}|${num}`)
|
120 |
-
if (reg.test(msg)) {
|
121 |
-
chooseFloor = num
|
122 |
-
return false
|
123 |
-
}
|
124 |
-
})
|
125 |
-
|
126 |
-
let data = abyssData.data
|
127 |
-
data = lodash.sortBy(data, 'floor')
|
128 |
-
data = data.reverse()
|
129 |
-
|
130 |
-
lodash.forEach(data, (floorData) => {
|
131 |
-
let avatars = []
|
132 |
-
lodash.forEach(floorData.avatarUsage, (ds) => {
|
133 |
-
let char = Character.get(ds.id)
|
134 |
-
if (char) {
|
135 |
-
avatars.push({
|
136 |
-
name: char.name,
|
137 |
-
star: char.star,
|
138 |
-
value: ds.value * modeMulti,
|
139 |
-
face: char.face
|
140 |
-
})
|
141 |
-
}
|
142 |
-
})
|
143 |
-
avatars = lodash.sortBy(avatars, 'value', ['asc'])
|
144 |
-
avatars.reverse()
|
145 |
-
if (chooseFloor === -1) {
|
146 |
-
avatars = avatars.slice(0, 14)
|
147 |
-
}
|
148 |
-
|
149 |
-
ret.push({
|
150 |
-
floor: floorData.floor,
|
151 |
-
avatars
|
152 |
-
})
|
153 |
-
})
|
154 |
-
|
155 |
-
return await Common.render('stat/abyss-pct', {
|
156 |
-
abyss: ret,
|
157 |
-
floorName,
|
158 |
-
chooseFloor,
|
159 |
-
mode,
|
160 |
-
modeName,
|
161 |
-
totalCount: overview?.data?.collectedPlayerCount || 0,
|
162 |
-
lastUpdate: abyssData.lastUpdate
|
163 |
-
}, { e, scale: 1.5 })
|
164 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/stat/AbyssSummary.js
DELETED
@@ -1,137 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import HutaoApi from './HutaoApi.js'
|
3 |
-
import { Cfg, Common, Data } from '#miao'
|
4 |
-
import { Abyss, Character, MysApi, Player } from '#miao.models'
|
5 |
-
|
6 |
-
export async function AbyssSummary (e) {
|
7 |
-
let isMatch = /^#(喵喵|上传)深渊(数据)?$/.test(e.original_msg || e.msg || '')
|
8 |
-
if (!Cfg.get('uploadAbyssData', false) && !isMatch) {
|
9 |
-
return false
|
10 |
-
}
|
11 |
-
let mys = await MysApi.init(e, 'all')
|
12 |
-
if (!mys || !mys.uid) {
|
13 |
-
if (isMatch) {
|
14 |
-
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
15 |
-
}
|
16 |
-
return false
|
17 |
-
}
|
18 |
-
let ret = {}
|
19 |
-
let uid = mys.uid
|
20 |
-
let player = Player.create(e)
|
21 |
-
let resDetail, resAbyss
|
22 |
-
try {
|
23 |
-
resAbyss = await mys.getSpiralAbyss(1)
|
24 |
-
let lvs = Data.getVal(resAbyss, 'floors.0.levels.0')
|
25 |
-
// 检查是否查询到了深渊信息
|
26 |
-
if (!lvs || !lvs.battles) {
|
27 |
-
e.reply('暂未获得本期深渊挑战数据...')
|
28 |
-
return true
|
29 |
-
} else if (lvs && lvs.battles && lvs.battles.length === 0) {
|
30 |
-
if (!mys.isSelfCookie) {
|
31 |
-
if (isMatch) {
|
32 |
-
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
33 |
-
}
|
34 |
-
return false
|
35 |
-
}
|
36 |
-
}
|
37 |
-
resDetail = await mys.getCharacter()
|
38 |
-
if (!resDetail || !resAbyss || !resDetail.avatars || resDetail.avatars.length <= 3) {
|
39 |
-
e.reply('角色信息获取失败')
|
40 |
-
return true
|
41 |
-
}
|
42 |
-
delete resDetail._res
|
43 |
-
delete resAbyss._res
|
44 |
-
ret = await HutaoApi.uploadData({
|
45 |
-
uid,
|
46 |
-
resDetail,
|
47 |
-
resAbyss
|
48 |
-
})
|
49 |
-
} catch (err) {
|
50 |
-
// console.log(err);
|
51 |
-
}
|
52 |
-
// 更新player信息
|
53 |
-
player.setMysCharData(resDetail)
|
54 |
-
|
55 |
-
if (ret && ret.retcode === 0) {
|
56 |
-
let stat = []
|
57 |
-
if (ret.data) {
|
58 |
-
if (resAbyss.floors.length === 0) {
|
59 |
-
e.reply('暂未获得本期深渊挑战数据...')
|
60 |
-
return true
|
61 |
-
}
|
62 |
-
let abyss = new Abyss(resAbyss)
|
63 |
-
let abyssData = abyss.getData()
|
64 |
-
let avatarIds = abyss.getAvatars()
|
65 |
-
let overview = ret.info || (await HutaoApi.getOverview())?.data || {}
|
66 |
-
let addMsg = function (title, ds) {
|
67 |
-
let tmp = {}
|
68 |
-
if (!ds) {
|
69 |
-
return false
|
70 |
-
}
|
71 |
-
if (!ds.avatarId && !ds.id) {
|
72 |
-
return false
|
73 |
-
}
|
74 |
-
let char = Character.get(ds.avatarId || ds.id)
|
75 |
-
tmp.title = title
|
76 |
-
tmp.id = char.id
|
77 |
-
tmp.value = `${(ds.value / 10000).toFixed(1)} W`
|
78 |
-
let msg = []
|
79 |
-
tmp.msg = msg
|
80 |
-
let pct = (percent, name) => {
|
81 |
-
if (percent < 0.2) {
|
82 |
-
msg.push({
|
83 |
-
title: '少于',
|
84 |
-
value: (Math.max(0.1, 100 - percent * 100)).toFixed(1),
|
85 |
-
name: name
|
86 |
-
})
|
87 |
-
} else {
|
88 |
-
msg.push({
|
89 |
-
title: '超过',
|
90 |
-
value: (Math.min(99.9, percent * 100)).toFixed(1),
|
91 |
-
name: name
|
92 |
-
})
|
93 |
-
}
|
94 |
-
}
|
95 |
-
if (ds.percent) {
|
96 |
-
pct(ds.percent, char.abbr)
|
97 |
-
pct(ds.percentTotal, '总记录')
|
98 |
-
} else {
|
99 |
-
msg.push({
|
100 |
-
txt: '暂无统计信息'
|
101 |
-
})
|
102 |
-
}
|
103 |
-
stat.push(tmp)
|
104 |
-
}
|
105 |
-
addMsg('最强一击', ret.data?.damage || abyssData?.stat?.dmg || {})
|
106 |
-
addMsg('最高承伤', ret.data?.takeDamage || abyssData?.stat.takeDmg || {})
|
107 |
-
let abyssStat = abyssData?.stat || {}
|
108 |
-
lodash.forEach({ defeat: '最多击破', e: '元素战技', q: '元素爆发' }, (title, key) => {
|
109 |
-
if (abyssStat[key]) {
|
110 |
-
stat.push({
|
111 |
-
title,
|
112 |
-
id: abyssStat[key]?.id || 0,
|
113 |
-
value: `${abyssStat[key]?.value}次`
|
114 |
-
})
|
115 |
-
} else {
|
116 |
-
stat.push({})
|
117 |
-
}
|
118 |
-
})
|
119 |
-
await player.refreshTalent(avatarIds)
|
120 |
-
let avatarData = player.getAvatarData(avatarIds)
|
121 |
-
return await Common.render('stat/abyss-summary', {
|
122 |
-
abyss: abyssData,
|
123 |
-
avatars: avatarData,
|
124 |
-
stat,
|
125 |
-
save_id: uid,
|
126 |
-
totalCount: overview?.collectedPlayerCount || 0,
|
127 |
-
uid
|
128 |
-
}, { e, scale: 1.2 })
|
129 |
-
} else {
|
130 |
-
e.reply('暂未获得本期深渊挑战数据...')
|
131 |
-
return true
|
132 |
-
}
|
133 |
-
} else {
|
134 |
-
e.reply(`${ret.message || '上传失败'},请稍后重试...`)
|
135 |
-
}
|
136 |
-
return true
|
137 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/stat/AbyssTeam.js
DELETED
@@ -1,190 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import HutaoApi from './HutaoApi.js'
|
3 |
-
import { Common } from '#miao'
|
4 |
-
import { Character, MysApi, Player } from '#miao.models'
|
5 |
-
|
6 |
-
export async function AbyssTeam (e) {
|
7 |
-
let mys = await MysApi.init(e, 'all')
|
8 |
-
if (!mys || !mys.uid) {
|
9 |
-
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
10 |
-
return false
|
11 |
-
}
|
12 |
-
let player = Player.create(e)
|
13 |
-
await player.refreshMysDetail(2)
|
14 |
-
await player.refreshTalent()
|
15 |
-
|
16 |
-
let abyssData = await HutaoApi.getAbyssTeam()
|
17 |
-
if (!abyssData || !abyssData.data) {
|
18 |
-
e.reply('深渊组队数据获取失败,请稍后重试~')
|
19 |
-
return true
|
20 |
-
}
|
21 |
-
abyssData = abyssData.data
|
22 |
-
let avatarData = player.getAvatarData()
|
23 |
-
let avatarRet = {}
|
24 |
-
let data = {}
|
25 |
-
let noAvatar = {}
|
26 |
-
lodash.forEach(avatarData, (avatar) => {
|
27 |
-
let t = avatar.originalTalent || {}
|
28 |
-
avatarRet[avatar.id] = Math.min(avatar.level, (avatar.weapon?.level || 1)) * 100 + Math.max(t?.a || 1, t?.e || 1, t?.q || 1) * 1000
|
29 |
-
})
|
30 |
-
|
31 |
-
let getTeamCfg = (str) => {
|
32 |
-
let teams = str.split(',')
|
33 |
-
teams.sort()
|
34 |
-
let teamMark = 0
|
35 |
-
lodash.forEach(teams, (a) => {
|
36 |
-
if (!avatarRet[a]) {
|
37 |
-
teamMark = -1
|
38 |
-
noAvatar[a] = true
|
39 |
-
}
|
40 |
-
if (teamMark !== -1) {
|
41 |
-
teamMark += avatarRet[a] * 1
|
42 |
-
}
|
43 |
-
})
|
44 |
-
if (teamMark === -1) {
|
45 |
-
teamMark = 1
|
46 |
-
}
|
47 |
-
return {
|
48 |
-
key: teams.join(','),
|
49 |
-
mark: teamMark
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
let hasSame = function (team1, team2) {
|
54 |
-
for (let idx = 0; idx < team1.length; idx++) {
|
55 |
-
if (team2.includes(team1[idx])) {
|
56 |
-
return true
|
57 |
-
}
|
58 |
-
}
|
59 |
-
return false
|
60 |
-
}
|
61 |
-
|
62 |
-
lodash.forEach(abyssData, (ds) => {
|
63 |
-
let floor = ds.floor
|
64 |
-
if (!data[floor]) {
|
65 |
-
data[floor] = {
|
66 |
-
up: {},
|
67 |
-
down: {},
|
68 |
-
teams: []
|
69 |
-
}
|
70 |
-
}
|
71 |
-
lodash.forEach(['up', 'down'], (halfKey) => {
|
72 |
-
lodash.forEach(ds[halfKey], (ds) => {
|
73 |
-
let teamCfg = getTeamCfg(ds.item)
|
74 |
-
if (teamCfg) {
|
75 |
-
if (!data[floor][halfKey][teamCfg.key]) {
|
76 |
-
data[floor][halfKey][teamCfg.key] = {
|
77 |
-
count: 0,
|
78 |
-
mark: 0,
|
79 |
-
hasTeam: teamCfg.mark > 1
|
80 |
-
}
|
81 |
-
}
|
82 |
-
data[floor][halfKey][teamCfg.key].count += ds.rate
|
83 |
-
data[floor][halfKey][teamCfg.key].mark += ds.rate * teamCfg.mark
|
84 |
-
}
|
85 |
-
})
|
86 |
-
})
|
87 |
-
|
88 |
-
let temp = []
|
89 |
-
lodash.forEach(['up', 'down'], (halfKey) => {
|
90 |
-
lodash.forEach(data[floor][halfKey], (ds, team) => {
|
91 |
-
temp.push({
|
92 |
-
team,
|
93 |
-
teamArr: team.split(','),
|
94 |
-
half: halfKey,
|
95 |
-
count: ds.count,
|
96 |
-
mark: ds.mark,
|
97 |
-
mark2: 1,
|
98 |
-
hasTeam: ds.hasTeam
|
99 |
-
})
|
100 |
-
})
|
101 |
-
temp = lodash.sortBy(temp, 'mark')
|
102 |
-
data[floor].teams = temp.reverse()
|
103 |
-
})
|
104 |
-
})
|
105 |
-
|
106 |
-
let ret = {}
|
107 |
-
|
108 |
-
lodash.forEach(data, (floorData, floor) => {
|
109 |
-
ret[floor] = {}
|
110 |
-
let ds = ret[floor]
|
111 |
-
lodash.forEach(floorData.teams, (t1) => {
|
112 |
-
if (t1.mark2 <= 0) {
|
113 |
-
return true
|
114 |
-
}
|
115 |
-
lodash.forEach(floorData.teams, (t2) => {
|
116 |
-
if (t1.mark2 <= 0) {
|
117 |
-
return true
|
118 |
-
}
|
119 |
-
if (t1.half === t2.half || t2.mark2 <= 0) {
|
120 |
-
return true
|
121 |
-
}
|
122 |
-
|
123 |
-
let teamKey = t1.half === 'up' ? (t1.team + '+' + t2.team) : (t2.team + '+' + t1.team)
|
124 |
-
if (ds[teamKey]) {
|
125 |
-
return true
|
126 |
-
}
|
127 |
-
if (hasSame(t1.teamArr, t2.teamArr)) {
|
128 |
-
return true
|
129 |
-
}
|
130 |
-
|
131 |
-
ds[teamKey] = {
|
132 |
-
up: t1.half === 'up' ? t1 : t2,
|
133 |
-
down: t1.half === 'up' ? t2 : t1,
|
134 |
-
count: Math.min(t1.count, t2.count),
|
135 |
-
mark: t1.hasTeam && t2.hasTeam ? t1.mark + t2.mark : t1.count + t2.count // 如果不存在组队则进行评分惩罚
|
136 |
-
}
|
137 |
-
t1.mark2--
|
138 |
-
t2.mark2--
|
139 |
-
return false
|
140 |
-
})
|
141 |
-
if (lodash.keys(ds).length >= 20) {
|
142 |
-
return false
|
143 |
-
}
|
144 |
-
})
|
145 |
-
})
|
146 |
-
|
147 |
-
lodash.forEach(ret, (ds, floor) => {
|
148 |
-
ds = lodash.sortBy(lodash.values(ds), 'mark')
|
149 |
-
ds = ds.reverse()
|
150 |
-
ds = ds.slice(0, 4)
|
151 |
-
|
152 |
-
lodash.forEach(ds, (team) => {
|
153 |
-
team.up.teamArr = Character.sortIds(team.up.teamArr)
|
154 |
-
team.down.teamArr = Character.sortIds(team.down.teamArr)
|
155 |
-
})
|
156 |
-
|
157 |
-
ret[floor] = ds
|
158 |
-
})
|
159 |
-
|
160 |
-
let avatarMap = {}
|
161 |
-
|
162 |
-
lodash.forEach(avatarData, (ds) => {
|
163 |
-
let char = Character.get(ds.id)
|
164 |
-
avatarMap[ds.id] = {
|
165 |
-
id: ds.id,
|
166 |
-
name: ds.name,
|
167 |
-
star: ds.star,
|
168 |
-
level: ds.level,
|
169 |
-
cons: ds.cons,
|
170 |
-
face: char.face
|
171 |
-
}
|
172 |
-
})
|
173 |
-
|
174 |
-
lodash.forEach(noAvatar, (d, id) => {
|
175 |
-
let char = Character.get(id)
|
176 |
-
avatarMap[id] = {
|
177 |
-
id,
|
178 |
-
name: char.name,
|
179 |
-
face: char.face,
|
180 |
-
star: char.star,
|
181 |
-
level: 0,
|
182 |
-
cons: 0
|
183 |
-
}
|
184 |
-
})
|
185 |
-
|
186 |
-
return await Common.render('stat/abyss-team', {
|
187 |
-
teams: ret,
|
188 |
-
avatars: avatarMap
|
189 |
-
}, { e, scale: 1.5 })
|
190 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/stat/HutaoApi.js
DELETED
@@ -1,73 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* 胡桃API Miao-Plugin 封装
|
3 |
-
* https://github.com/DGP-Studio/DGP.Genshin.HutaoAPI
|
4 |
-
*
|
5 |
-
* */
|
6 |
-
|
7 |
-
import fetch from 'node-fetch'
|
8 |
-
import { Data } from '#miao'
|
9 |
-
|
10 |
-
const host = 'http://miao.games/api/hutao'
|
11 |
-
|
12 |
-
function getApi (api) {
|
13 |
-
return `${host}?api=${api}`
|
14 |
-
}
|
15 |
-
|
16 |
-
let HutaoApi = {
|
17 |
-
async req (url, param = {}, EX = 3600) {
|
18 |
-
let cacheData = await Data.getCacheJSON(`miao:hutao:${url}`)
|
19 |
-
if (cacheData && cacheData.data && param.method !== 'POST') {
|
20 |
-
return cacheData
|
21 |
-
}
|
22 |
-
let response = await fetch(getApi(`${url}`), {
|
23 |
-
...param,
|
24 |
-
method: param.method || 'GET'
|
25 |
-
})
|
26 |
-
let retData = await response.json()
|
27 |
-
if (retData && retData.data && param.method !== 'POST') {
|
28 |
-
let d = new Date()
|
29 |
-
retData.lastUpdate = `${d.toLocaleDateString()} ${d.toTimeString().substr(0, 5)}`
|
30 |
-
await Data.setCacheJSON(`miao:hutao:${url}`, retData, EX)
|
31 |
-
}
|
32 |
-
return retData
|
33 |
-
},
|
34 |
-
|
35 |
-
// 角色持有及命座分布
|
36 |
-
async getCons () {
|
37 |
-
return await HutaoApi.req('/Statistics/Constellation')
|
38 |
-
},
|
39 |
-
|
40 |
-
async getAbyssPct () {
|
41 |
-
return await HutaoApi.req('/Statistics/AvatarParticipation')
|
42 |
-
},
|
43 |
-
|
44 |
-
async getAbyssUse () {
|
45 |
-
return await HutaoApi.req('/Statistics2/AvatarParticipation')
|
46 |
-
},
|
47 |
-
|
48 |
-
async getAbyssTeam () {
|
49 |
-
return await HutaoApi.req('/Statistics/Team/Combination')
|
50 |
-
},
|
51 |
-
|
52 |
-
async getOverview () {
|
53 |
-
return await HutaoApi.req('/Statistics/Overview')
|
54 |
-
},
|
55 |
-
|
56 |
-
async getUsage () {
|
57 |
-
return await HutaoApi.req('/Statistics/Avatar/AvatarCollocation')
|
58 |
-
},
|
59 |
-
|
60 |
-
async uploadData (data = {}) {
|
61 |
-
let body = JSON.stringify(data)
|
62 |
-
return await HutaoApi.req('/Record/UploadData', {
|
63 |
-
method: 'POST',
|
64 |
-
headers: {
|
65 |
-
'User-Agent': 'Yunzai-Bot/Miao-Plugin',
|
66 |
-
'Content-Type': 'text/json; charset=utf-8'
|
67 |
-
},
|
68 |
-
body
|
69 |
-
})
|
70 |
-
}
|
71 |
-
}
|
72 |
-
|
73 |
-
export default HutaoApi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki.js
DELETED
@@ -1,29 +0,0 @@
|
|
1 |
-
import { App } from '#miao'
|
2 |
-
import Calendar from './wiki/Calendar.js'
|
3 |
-
import CharWiki from './wiki/CharWiki.js'
|
4 |
-
import CalendarSr from './wiki/CalendarSr.js'
|
5 |
-
|
6 |
-
let app = App.init({
|
7 |
-
id: 'wiki',
|
8 |
-
name: '角色资料'
|
9 |
-
})
|
10 |
-
app.reg({
|
11 |
-
wiki: {
|
12 |
-
rule: '^#喵喵WIKI$',
|
13 |
-
check: CharWiki.check,
|
14 |
-
fn: CharWiki.wiki,
|
15 |
-
desc: '【#资料】 #神里天赋 #夜兰命座'
|
16 |
-
},
|
17 |
-
calendar: {
|
18 |
-
rule: /^(#|喵喵)+(日历|日历列表)$/,
|
19 |
-
fn: Calendar.render,
|
20 |
-
desc: '【#日历】 原神活动日历'
|
21 |
-
},
|
22 |
-
calendarSr: {
|
23 |
-
rule: /^#(星铁)+(日历|日历列表)$/,
|
24 |
-
fn: CalendarSr.render,
|
25 |
-
desc: '【#星铁日历】 星铁活动日历'
|
26 |
-
}
|
27 |
-
})
|
28 |
-
|
29 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki/Calendar.js
DELETED
@@ -1,414 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import fetch from 'node-fetch'
|
3 |
-
import moment from 'moment'
|
4 |
-
import { Common, Data, Cfg } from '#miao'
|
5 |
-
import { Character, Material } from '#miao.models'
|
6 |
-
|
7 |
-
const ignoreIds = [495, // 有奖问卷调查开启!
|
8 |
-
1263, // 米游社《原神》专属工具一览
|
9 |
-
423, // 《原神》玩家社区一览
|
10 |
-
422, // 《原神》防沉迷系统说明
|
11 |
-
762 // 《原神》公平运营声明
|
12 |
-
]
|
13 |
-
|
14 |
-
const ignoreReg = /(内容专题页|版本更新说明|调研|防沉迷|米游社|专项意见|更新修复与优化|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示)/
|
15 |
-
const fulltimeReg = /(魔神任务)/
|
16 |
-
|
17 |
-
let Cal = {
|
18 |
-
async reqCalData () {
|
19 |
-
let listApi = 'https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnList?game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000'
|
20 |
-
|
21 |
-
let request = await fetch(listApi)
|
22 |
-
let listData = await request.json()
|
23 |
-
|
24 |
-
let timeMap
|
25 |
-
let timeMapCache = await redis.get('miao:calendar:detail')
|
26 |
-
if (timeMapCache) {
|
27 |
-
timeMap = JSON.parse(timeMapCache) || {}
|
28 |
-
} else {
|
29 |
-
let detailApi = 'https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnContent?game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000'
|
30 |
-
let request2 = await fetch(detailApi)
|
31 |
-
let detailData = await request2.json()
|
32 |
-
timeMap = {}
|
33 |
-
if (detailData && detailData.data && detailData.data.list) {
|
34 |
-
let versionTime = {
|
35 |
-
2.7: '2022-05-31 11:00:00',
|
36 |
-
2.8: '2022-07-13 11:00:00',
|
37 |
-
3.0: '2022-08-24 11:00:00',
|
38 |
-
3.1: '2022-09-28 11:00:00',
|
39 |
-
3.2: '2022-11-02 11:00:00',
|
40 |
-
3.3: '2022-12-07 11:00:00'
|
41 |
-
}
|
42 |
-
lodash.forEach(detailData.data.list, (ds) => {
|
43 |
-
let vRet = /(\d\.\d)版本更新通知/.exec(ds.title)
|
44 |
-
if (vRet && vRet[1]) {
|
45 |
-
let content = /(?:更新时间)\s*〓([^〓]+)(?:〓|$)/.exec(ds.content)
|
46 |
-
if (content && content[1]) {
|
47 |
-
let tRet = /([0-9\\/\\: ]){9,}/.exec(content[1])
|
48 |
-
if (tRet && tRet[0]) {
|
49 |
-
versionTime[vRet[1]] = versionTime[vRet[1]] || tRet[0].replace('06:00', '11:00')
|
50 |
-
}
|
51 |
-
}
|
52 |
-
}
|
53 |
-
})
|
54 |
-
lodash.forEach(detailData.data.list, (ds) => {
|
55 |
-
let { ann_id: annId, content, title } = ds
|
56 |
-
if (ignoreReg.test(title)) {
|
57 |
-
return true
|
58 |
-
}
|
59 |
-
content = content.replace(/(<|<)[\w "%:;=\-\\/\\(\\),\\.]+(>|>)/g, '')
|
60 |
-
content = /(?:活动时间|祈愿介绍|任务开放时间|冒险....包|折扣时间)\s*〓([^〓]+)(〓|$)/.exec(content)
|
61 |
-
if (!content || !content[1]) {
|
62 |
-
return true
|
63 |
-
}
|
64 |
-
content = content[1]
|
65 |
-
let annTime = []
|
66 |
-
|
67 |
-
// 第一种简单格式
|
68 |
-
let timeRet = /(?:活动时间)?(?:〓|\s)*([0-9\\/\\: ~]{6,})/.exec(content)
|
69 |
-
if (timeRet && timeRet[1]) {
|
70 |
-
annTime = timeRet[1].split('~')
|
71 |
-
} else if (/\d\.\d版本更新后/.test(content)) {
|
72 |
-
let vRet = /(\d\.\d)版本更新后/.exec(content)
|
73 |
-
let vTime = ''
|
74 |
-
if (vRet && vRet[1] && versionTime[vRet[1]]) {
|
75 |
-
vTime = versionTime[vRet[1]]
|
76 |
-
}
|
77 |
-
if (!vTime) {
|
78 |
-
return true
|
79 |
-
}
|
80 |
-
if (/永久开放/.test(content)) {
|
81 |
-
annTime = [vTime, '2099/01/01 00:00:00']
|
82 |
-
} else {
|
83 |
-
timeRet = /([0-9\\/\\: ]){9,}/.exec(content)
|
84 |
-
if (timeRet && timeRet[0]) {
|
85 |
-
annTime = [vTime, timeRet[0]]
|
86 |
-
}
|
87 |
-
}
|
88 |
-
}
|
89 |
-
if (annTime.length === 2) {
|
90 |
-
timeMap[annId] = {
|
91 |
-
start: annTime[0].trim().replace(/\//g, '-'),
|
92 |
-
end: annTime[1].trim().replace(/\//g, '-')
|
93 |
-
}
|
94 |
-
}
|
95 |
-
})
|
96 |
-
}
|
97 |
-
let miaoApi = 'http://miao.games/api/calendar'
|
98 |
-
try {
|
99 |
-
request2 = await fetch(miaoApi)
|
100 |
-
let data = await request2.json()
|
101 |
-
if (data && data.status === 0 && data.data) {
|
102 |
-
lodash.forEach(data.data, (ds, id) => {
|
103 |
-
timeMap[id] = ds
|
104 |
-
})
|
105 |
-
}
|
106 |
-
} catch (e) {
|
107 |
-
}
|
108 |
-
await Data.setCacheJSON('miao:calendar:detail', timeMap, 60 * 10)
|
109 |
-
}
|
110 |
-
return { listData, timeMap }
|
111 |
-
},
|
112 |
-
|
113 |
-
getDateList () {
|
114 |
-
let today = moment()
|
115 |
-
let temp = today.add(-7, 'days')
|
116 |
-
let dateList = []
|
117 |
-
let month = 0
|
118 |
-
let date = []
|
119 |
-
let week = []
|
120 |
-
|
121 |
-
let startDate, endDate
|
122 |
-
|
123 |
-
for (let idx = 0; idx < 13; idx++) {
|
124 |
-
temp = today.add(1, 'days')
|
125 |
-
let m = temp.month() + 1
|
126 |
-
let d = temp.date()
|
127 |
-
if (month === 0) {
|
128 |
-
startDate = temp.format('YYYY-MM-DD')
|
129 |
-
month = m
|
130 |
-
}
|
131 |
-
if (month !== m && date.length > 0) {
|
132 |
-
dateList.push({
|
133 |
-
month,
|
134 |
-
date,
|
135 |
-
week
|
136 |
-
})
|
137 |
-
date = []
|
138 |
-
week = []
|
139 |
-
month = m
|
140 |
-
}
|
141 |
-
date.push(d)
|
142 |
-
week.push(temp.weekday())
|
143 |
-
if (idx === 12) {
|
144 |
-
dateList.push({
|
145 |
-
month,
|
146 |
-
date,
|
147 |
-
week
|
148 |
-
})
|
149 |
-
endDate = temp.format('YYYY-MM-DD')
|
150 |
-
}
|
151 |
-
}
|
152 |
-
|
153 |
-
let startTime = moment(startDate + ' 00:00:00')
|
154 |
-
let endTime = moment(endDate + ' 23:59:59')
|
155 |
-
|
156 |
-
let totalRange = endTime - startTime
|
157 |
-
return {
|
158 |
-
dateList,
|
159 |
-
startTime,
|
160 |
-
endTime,
|
161 |
-
totalRange,
|
162 |
-
nowLeft: (moment() - startTime) / totalRange * 100
|
163 |
-
}
|
164 |
-
},
|
165 |
-
|
166 |
-
// 深渊日历信息
|
167 |
-
getAbyssCal (s1, e1) {
|
168 |
-
let now = moment()
|
169 |
-
let check = []
|
170 |
-
let f = 'YYYY-MM'
|
171 |
-
let last = now.add(-1, 'M').format(f)
|
172 |
-
let lastM = now.format('MMMM')
|
173 |
-
let curr = now.add(1, 'M').format(f)
|
174 |
-
let currM = now.format('MMMM')
|
175 |
-
let next = now.add(1, 'M').format(f)
|
176 |
-
let nextM = now.format('MMMM')
|
177 |
-
|
178 |
-
check.push([moment(`${last}-16 04:00:00`), moment(`${curr}-01 03:59:59`), lastM + '下半'])
|
179 |
-
check.push([moment(`${curr}-01 04:00:00`), moment(`${curr}-16 03:59:59`), currM + '上半'])
|
180 |
-
check.push([moment(`${curr}-16 04:00:00`), moment(`${next}-01 03:59:59`), currM + '下半'])
|
181 |
-
check.push([moment(`${next}-01 04:00:00`), moment(`${next}-16 03:59:59`), nextM + '上半'])
|
182 |
-
|
183 |
-
let ret = []
|
184 |
-
lodash.forEach(check, (ds) => {
|
185 |
-
let [s2, e2] = ds
|
186 |
-
if ((s2 <= s1 && s1 <= e2) || (s2 <= e1 && e1 <= e2)) {
|
187 |
-
ret.push(ds)
|
188 |
-
}
|
189 |
-
})
|
190 |
-
return ret
|
191 |
-
},
|
192 |
-
|
193 |
-
/**
|
194 |
-
* 获取角色数据
|
195 |
-
* @param dateList
|
196 |
-
* @returns {{charBirth: {}, charNum: number, charTalent: (*|{})}}
|
197 |
-
*/
|
198 |
-
getCharData (dateList) {
|
199 |
-
let charBirth = {}
|
200 |
-
let charTalent = {}
|
201 |
-
// 初始化生日数据
|
202 |
-
lodash.forEach(dateList, (m) => {
|
203 |
-
lodash.forEach(m.date, (d) => {
|
204 |
-
charBirth[`${m.month}-${d}`] = []
|
205 |
-
})
|
206 |
-
})
|
207 |
-
// 初始化天赋数据
|
208 |
-
let now = moment(new Date())
|
209 |
-
if (now.hour() < 4) {
|
210 |
-
now = now.add(-1, 'days')
|
211 |
-
}
|
212 |
-
let week = now.weekday()
|
213 |
-
Material.forEach('talent', (material) => {
|
214 |
-
let data = material.getData('name,abbr,city,icon,week,cid')
|
215 |
-
data.chars = []
|
216 |
-
charTalent[material.name] = data
|
217 |
-
}, (ds) => ds.star === 4 && (week === 6 || ds.week === week % 3 + 1))
|
218 |
-
// 遍历角色数据
|
219 |
-
Character.forEach((char) => {
|
220 |
-
if (charBirth[char.birth] && (char.isRelease || char.birth !== '1-1')) {
|
221 |
-
charBirth[char.birth].push(char.getData('id,name:sName,star,face'))
|
222 |
-
}
|
223 |
-
let t = char.materials?.talent
|
224 |
-
if (t && charTalent[t] && !char.isTraveler) {
|
225 |
-
let data = char.getData('id,name:sName,star,face')
|
226 |
-
data.weekly = char.getMaterials('weekly')?.icon
|
227 |
-
charTalent[t].chars.push(data)
|
228 |
-
}
|
229 |
-
}, Cfg.get('notReleasedData') ? 'official' : 'release')
|
230 |
-
let charNum = 0
|
231 |
-
lodash.forEach(charBirth, (charList) => {
|
232 |
-
charNum = Math.max(charNum, charList.length)
|
233 |
-
})
|
234 |
-
charTalent = lodash.values(charTalent)
|
235 |
-
charTalent = lodash.sortBy(charTalent, 'cid')
|
236 |
-
lodash.forEach(charTalent, (ds) => {
|
237 |
-
ds.chars = lodash.sortBy(ds.chars, ['star', 'id']).reverse()
|
238 |
-
})
|
239 |
-
return { charBirth, charNum, charTalent }
|
240 |
-
},
|
241 |
-
|
242 |
-
/**
|
243 |
-
* 获取日历列表
|
244 |
-
* @param ds
|
245 |
-
* @param target
|
246 |
-
* @param startTime
|
247 |
-
* @param endTime
|
248 |
-
* @param totalRange
|
249 |
-
* @param now
|
250 |
-
* @param timeMap
|
251 |
-
* @param isAct
|
252 |
-
* @returns {boolean}
|
253 |
-
*/
|
254 |
-
getList (ds, target, { startTime, endTime, totalRange, now, timeMap = {} }, isAct = false) {
|
255 |
-
let type = isAct ? 'activity' : 'normal'
|
256 |
-
let id = ds.ann_id
|
257 |
-
let title = ds.title
|
258 |
-
let banner = isAct ? ds.banner : ''
|
259 |
-
let extra = { sort: isAct ? 5 : 10 }
|
260 |
-
let detail = timeMap[id] || {}
|
261 |
-
|
262 |
-
if (ignoreIds.includes(id) || ignoreReg.test(title) || detail.display === false) {
|
263 |
-
return false
|
264 |
-
}
|
265 |
-
|
266 |
-
if (/神铸赋形/.test(title)) {
|
267 |
-
type = 'weapon'
|
268 |
-
title = title.replace(/(单手剑|双手剑|长柄武器|弓|法器|·)/g, '')
|
269 |
-
extra.sort = 2
|
270 |
-
} else if (/祈愿/.test(title)) {
|
271 |
-
type = 'character'
|
272 |
-
let regRet = /·(.*)\(/.exec(title)
|
273 |
-
if (regRet[1]) {
|
274 |
-
let char = Character.get(regRet[1])
|
275 |
-
extra.banner2 = char.getImgs()?.card
|
276 |
-
extra.face = char.face
|
277 |
-
extra.character = regRet[1]
|
278 |
-
extra.elem = char.elem
|
279 |
-
extra.sort = 1
|
280 |
-
}
|
281 |
-
} else if (/纪行/.test(title)) {
|
282 |
-
type = 'pass'
|
283 |
-
}
|
284 |
-
|
285 |
-
let getDate = (d1, d2) => moment(d1 && d1.length > 6 ? d1 : d2)
|
286 |
-
let sDate = getDate(detail.start, ds.start_time)
|
287 |
-
let eDate = getDate(detail.end, ds.end_time)
|
288 |
-
let sTime = moment.max(sDate, startTime)
|
289 |
-
let eTime = moment.min(eDate, endTime)
|
290 |
-
|
291 |
-
let sRange = sTime - startTime
|
292 |
-
let eRange = eTime - startTime
|
293 |
-
|
294 |
-
let left = sRange / totalRange * 100
|
295 |
-
let width = eRange / totalRange * 100 - left
|
296 |
-
|
297 |
-
let label = ''
|
298 |
-
if (fulltimeReg.test(title) || eDate - sDate > 365 * 24 * 3600 * 1000) {
|
299 |
-
if (sDate < now) {
|
300 |
-
label = sDate.format('MM-DD HH:mm') + ' 后永久有效'
|
301 |
-
} else {
|
302 |
-
label = '永久有效'
|
303 |
-
}
|
304 |
-
} else if (now > sDate && eDate > now) {
|
305 |
-
label = eDate.format('MM-DD HH:mm') + ' (' + moment.duration(eDate - now).humanize() + '后结束)'
|
306 |
-
if (width > (isAct ? 38 : 55)) {
|
307 |
-
label = sDate.format('MM-DD HH:mm') + ' ~ ' + label
|
308 |
-
}
|
309 |
-
} else if (sDate > now) {
|
310 |
-
label = sDate.format('MM-DD HH:mm') + ' (' + moment.duration(sDate - now).humanize() + '后开始)'
|
311 |
-
} else if (isAct) {
|
312 |
-
label = sDate.format('MM-DD HH:mm') + ' ~ ' + eDate.format('MM-DD HH:mm')
|
313 |
-
}
|
314 |
-
if (sDate <= endTime && eDate >= startTime) {
|
315 |
-
target.push({
|
316 |
-
...extra,
|
317 |
-
id,
|
318 |
-
title,
|
319 |
-
type,
|
320 |
-
mergeStatus: ['activity', 'normal'].includes(type) ? 1 : 0,
|
321 |
-
banner,
|
322 |
-
icon: ds.tag_icon,
|
323 |
-
left,
|
324 |
-
width,
|
325 |
-
label,
|
326 |
-
duration: eTime - sTime,
|
327 |
-
start: sDate.format('MM-DD HH:mm'),
|
328 |
-
end: eDate.format('MM-DD HH:mm')
|
329 |
-
})
|
330 |
-
}
|
331 |
-
},
|
332 |
-
|
333 |
-
async get () {
|
334 |
-
moment.locale('zh-cn')
|
335 |
-
let now = moment()
|
336 |
-
|
337 |
-
let { listData, timeMap } = await Cal.reqCalData()
|
338 |
-
|
339 |
-
let dl = Cal.getDateList()
|
340 |
-
|
341 |
-
let list = []
|
342 |
-
let abyss = []
|
343 |
-
|
344 |
-
lodash.forEach(listData.data.list[1].list, (ds) => Cal.getList(ds, list, { ...dl, now, timeMap }, true))
|
345 |
-
lodash.forEach(listData.data.list[0].list, (ds) => Cal.getList(ds, list, { ...dl, now, timeMap }, false))
|
346 |
-
|
347 |
-
let abyssCal = Cal.getAbyssCal(dl.startTime, dl.endTime)
|
348 |
-
lodash.forEach(abyssCal, (t) => {
|
349 |
-
Cal.getList({
|
350 |
-
title: `「深境螺旋」· ${t[2]}`,
|
351 |
-
start_time: t[0].format('YYYY-MM-DD HH:mm'),
|
352 |
-
end_time: t[1].format('YYYY-MM-DD HH:mm')
|
353 |
-
}, abyss, { ...dl, now }, true)
|
354 |
-
})
|
355 |
-
|
356 |
-
list = lodash.sortBy(list, ['sort', 'start', 'duration'])
|
357 |
-
|
358 |
-
let charCount = 0
|
359 |
-
let charOld = 0
|
360 |
-
let weaponCount = 0
|
361 |
-
let ret = []
|
362 |
-
lodash.forEach(list, (li) => {
|
363 |
-
if (li.type === 'character') {
|
364 |
-
charCount++
|
365 |
-
li.left === 0 && charOld++
|
366 |
-
li.idx = charCount
|
367 |
-
}
|
368 |
-
if (li.type === 'weapon') {
|
369 |
-
weaponCount++
|
370 |
-
li.idx = weaponCount
|
371 |
-
}
|
372 |
-
if (li.mergeStatus === 1) {
|
373 |
-
lodash.forEach(list, (li2) => {
|
374 |
-
if (li2.mergeStatus === 1 && li.left + li.width <= li2.left) {
|
375 |
-
li.mergeStatus = 2
|
376 |
-
li2.mergeStatus = 2
|
377 |
-
ret.push([li, li2])
|
378 |
-
return false
|
379 |
-
}
|
380 |
-
})
|
381 |
-
}
|
382 |
-
if (li.mergeStatus !== 2) {
|
383 |
-
li.mergeStatus = 2
|
384 |
-
ret.push([li])
|
385 |
-
}
|
386 |
-
})
|
387 |
-
|
388 |
-
return {
|
389 |
-
game: 'gs',
|
390 |
-
...dl,
|
391 |
-
...Cal.getCharData(dl.dateList),
|
392 |
-
list: ret,
|
393 |
-
abyss,
|
394 |
-
charMode: `char-${charCount}-${charOld}`,
|
395 |
-
nowTime: now.format('YYYY-MM-DD HH:mm'),
|
396 |
-
nowDate: now.date()
|
397 |
-
}
|
398 |
-
},
|
399 |
-
|
400 |
-
async render (e) {
|
401 |
-
let calData = await Cal.get()
|
402 |
-
let mode = 'calendar'
|
403 |
-
if (/(日历列表|活动)$/.test(e.msg)) {
|
404 |
-
mode = 'list'
|
405 |
-
}
|
406 |
-
|
407 |
-
return await Common.render('wiki/calendar', {
|
408 |
-
...calData,
|
409 |
-
displayMode: mode
|
410 |
-
}, { e, scale: 1.1 })
|
411 |
-
}
|
412 |
-
}
|
413 |
-
|
414 |
-
export default Cal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki/CalendarSr.js
DELETED
@@ -1,303 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import fetch from 'node-fetch'
|
3 |
-
import moment from 'moment'
|
4 |
-
import Calendar from './Calendar.js'
|
5 |
-
import { Common, Data } from '#miao'
|
6 |
-
import { Character } from '#miao.models'
|
7 |
-
|
8 |
-
const ignoreIds = [
|
9 |
-
257, // 保密测试参与意愿调研
|
10 |
-
194, // 有奖问卷
|
11 |
-
203, // 《崩坏:星穹铁道》社媒聚合页上线
|
12 |
-
183, // 官方社群一览
|
13 |
-
187, // 《崩坏:星穹铁道》防沉迷系统公告
|
14 |
-
185, // 《崩坏:星穹铁道》公平运营声明
|
15 |
-
171 // 《崩坏:星穹铁道》社区专属工具一览
|
16 |
-
]
|
17 |
-
|
18 |
-
const ignoreReg = /(更新概览|游戏优化|优化说明|内容专题页|版本更新说明|循星归程|调研|防沉迷|米游社|专项意见|更新修复与优化|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示|角色PV|版本PV|动画短片|bilibili|激励计划|调整说明|攻略征集)/
|
19 |
-
|
20 |
-
let CalSr = {
|
21 |
-
async reqCalData () {
|
22 |
-
let listApi = 'https://hkrpg-api.mihoyo.com/common/hkrpg_cn/announcement/api/getAnnList?game=hkrpg&game_biz=hkrpg_cn&lang=zh-cn&auth_appid=announcement&authkey_ver=1&bundle_id=hkrpg_cn&channel_id=1&level=65&platform=pc®ion=prod_gf_cn&sdk_presentation_style=fullscreen&sdk_screen_transparent=true&sign_type=2&uid=100000000'
|
23 |
-
|
24 |
-
let request = await fetch(listApi)
|
25 |
-
let listData = await request.json()
|
26 |
-
|
27 |
-
let timeMap
|
28 |
-
let timeMapCache = await redis.get('miao:calendarSr:detail')
|
29 |
-
if (timeMapCache) {
|
30 |
-
timeMap = JSON.parse(timeMapCache) || {}
|
31 |
-
} else {
|
32 |
-
let detailApi = 'https://hkrpg-api-static.mihoyo.com/common/hkrpg_cn/announcement/api/getAnnContent?game=hkrpg&game_biz=hkrpg_cn&lang=zh-cn&bundle_id=hkrpg_cn&platform=pc®ion=prod_gf_cn&level=65&channel_id=1'
|
33 |
-
let request2 = await fetch(detailApi)
|
34 |
-
let detailData = await request2.json()
|
35 |
-
timeMap = {}
|
36 |
-
if (detailData && detailData.data && detailData.data.list) {
|
37 |
-
let versionTime = {
|
38 |
-
1.1: '2022-06-07 11:00:00'
|
39 |
-
}
|
40 |
-
lodash.forEach(detailData.data.list, (ds) => {
|
41 |
-
let vRet = /(\d\.\d)版本\S*更新(概览|说明)/.exec(ds.title)
|
42 |
-
if (vRet && vRet[1]) {
|
43 |
-
let content = /■(?:更新时间)\s*([^■]+)(?:■|$)/.exec(ds.content)
|
44 |
-
if (content && content[1]) {
|
45 |
-
let tRet = /([0-9\\/\\: ]){9,}/.exec(content[1])
|
46 |
-
if (tRet && tRet[0]) {
|
47 |
-
versionTime[vRet[1]] = versionTime[vRet[1]] || tRet[0].replace('06:00', '11:00')
|
48 |
-
}
|
49 |
-
}
|
50 |
-
}
|
51 |
-
})
|
52 |
-
let ret = function (ds) {
|
53 |
-
let { ann_id: annId, content, title } = ds
|
54 |
-
if (ignoreReg.test(title)) {
|
55 |
-
return true
|
56 |
-
}
|
57 |
-
content = content.replaceAll('\u003ch1 style=\"\"\u003e', '※')
|
58 |
-
content = content.replaceAll('\u003c/h1\u003e', '※')
|
59 |
-
content = content.replace(/(<|<)[\w "%:;=\-\\/\\(\\),\\.]+(>|>)/g, '')
|
60 |
-
content = /(?:活动时间|活动跃迁|开放时间|开启时间|折扣时间|上架时间)\s*※([^※]+)(※|$)/.exec(content)
|
61 |
-
if (!content || !content[1]) {
|
62 |
-
return true
|
63 |
-
}
|
64 |
-
content = content[1]
|
65 |
-
let annTime = []
|
66 |
-
|
67 |
-
// 第一种简单格式
|
68 |
-
let timeRet = /(?:活动时间)?(?:※|\s)*([0-9\\/\\: -]{6,})/.exec(content)
|
69 |
-
if (/\d\.\d版本更新后/.test(content)) {
|
70 |
-
let vRet = /(\d\.\d)版本更新后/.exec(content)
|
71 |
-
let vTime = ''
|
72 |
-
if (vRet && vRet[1] && versionTime[vRet[1]]) {
|
73 |
-
vTime = versionTime[vRet[1]]
|
74 |
-
}
|
75 |
-
if (!vTime) {
|
76 |
-
return true
|
77 |
-
}
|
78 |
-
if (/永久开放/.test(content)) {
|
79 |
-
annTime = [vTime, '2099/01/01 00:00:00']
|
80 |
-
} else {
|
81 |
-
timeRet = /([0-9\\/\\: ]){9,}/.exec(content)
|
82 |
-
if (timeRet && timeRet[0]) {
|
83 |
-
annTime = [vTime, timeRet[0]]
|
84 |
-
}
|
85 |
-
}
|
86 |
-
} else if (timeRet && timeRet[1]) {
|
87 |
-
annTime = timeRet[1].split('-')
|
88 |
-
}
|
89 |
-
|
90 |
-
if (annTime.length === 2) {
|
91 |
-
timeMap[annId] = {
|
92 |
-
start: annTime[0].trim().replace(/\//g, '-'),
|
93 |
-
end: annTime[1].trim().replace(/\//g, '-')
|
94 |
-
}
|
95 |
-
}
|
96 |
-
}
|
97 |
-
lodash.forEach(detailData.data.list, (ds) => ret(ds))
|
98 |
-
lodash.forEach(detailData.data.pic_list, (ds) => ret(ds))
|
99 |
-
}
|
100 |
-
await Data.setCacheJSON('miao:calendarSr:detail', timeMap, 60 * 10)
|
101 |
-
}
|
102 |
-
return { listData, timeMap }
|
103 |
-
},
|
104 |
-
|
105 |
-
// 深渊日历信息
|
106 |
-
getAbyssCal (s1, e1, versionStartTime) {
|
107 |
-
let check = []
|
108 |
-
let f = 'YYYY-MM-DD HH:mm:ss'
|
109 |
-
|
110 |
-
let abyss1Start = moment(versionStartTime, 'YYYY-MM-DD HH:mm:ss').add(5, 'days').subtract(3, 'hours').format(f)
|
111 |
-
let abyss1End = moment(abyss1Start).add(14, 'days').format(f)
|
112 |
-
let abyss2Start = abyss1End
|
113 |
-
let abyss2End = moment(abyss2Start).add(14, 'days').format(f)
|
114 |
-
let abyss3Start = abyss2End
|
115 |
-
let abyss3End = moment(abyss3Start).add(14, 'days').format(f)
|
116 |
-
let abyss4Start = abyss3End
|
117 |
-
let abyss4End = moment(abyss4Start).add(14, 'days').format(f)
|
118 |
-
let abyss0End = abyss1Start
|
119 |
-
let abyss0Start = moment(abyss0End).subtract(14, 'days').format(f)
|
120 |
-
|
121 |
-
check.push([moment(abyss0Start), moment(abyss0End)])
|
122 |
-
check.push([moment(abyss1Start), moment(abyss1End)])
|
123 |
-
check.push([moment(abyss2Start), moment(abyss2End)])
|
124 |
-
check.push([moment(abyss3Start), moment(abyss3End)])
|
125 |
-
check.push([moment(abyss4Start), moment(abyss4End)])
|
126 |
-
|
127 |
-
let ret = []
|
128 |
-
lodash.forEach(check, (ds) => {
|
129 |
-
let [s2, e2] = ds
|
130 |
-
if ((s2 <= s1 && s1 <= e2) || (s2 <= e1 && e1 <= e2)) {
|
131 |
-
ret.push(ds)
|
132 |
-
}
|
133 |
-
})
|
134 |
-
return ret
|
135 |
-
},
|
136 |
-
|
137 |
-
getList (ds, target, { startTime, endTime, totalRange, now, timeMap = {} }) {
|
138 |
-
let type = 'activity'
|
139 |
-
let id = ds.ann_id
|
140 |
-
let title = ds.title
|
141 |
-
let subTitle = ds.subtitle
|
142 |
-
let banner = ds.banner
|
143 |
-
let extra = { sort: 5 }
|
144 |
-
let detail = timeMap[id] || {}
|
145 |
-
|
146 |
-
if (ignoreIds.includes(id) || ignoreReg.test(title)) {
|
147 |
-
return true
|
148 |
-
}
|
149 |
-
|
150 |
-
if (/流光定影/.test(title)) {
|
151 |
-
type = 'weapon'
|
152 |
-
title = title.replace(/(限定5星光锥)/g, '')
|
153 |
-
extra.sort = 2
|
154 |
-
} else if (/跃迁/.test(subTitle)) {
|
155 |
-
type = 'character'
|
156 |
-
let regRet = /角色「(.*)((|\()/.exec(title)
|
157 |
-
if (regRet[1]) {
|
158 |
-
let char = Character.get(regRet[1])
|
159 |
-
extra.banner2 = char.getImgs()?.card
|
160 |
-
extra.face = char.face
|
161 |
-
extra.character = regRet[1]
|
162 |
-
extra.elem = char.elem
|
163 |
-
extra.sort = 1
|
164 |
-
}
|
165 |
-
} else if (/无名勋礼/.test(title)) {
|
166 |
-
type = 'pass'
|
167 |
-
}
|
168 |
-
|
169 |
-
let getDate = (d1, d2) => moment(d1 && d1.length > 6 ? d1 : d2)
|
170 |
-
let sDate = getDate(detail.start, ds.start_time)
|
171 |
-
let eDate = getDate(detail.end, ds.end_time)
|
172 |
-
let sTime = moment.max(sDate, startTime)
|
173 |
-
let eTime = moment.min(eDate, endTime)
|
174 |
-
|
175 |
-
let sRange = sTime - startTime
|
176 |
-
let eRange = eTime - startTime
|
177 |
-
|
178 |
-
let left = sRange / totalRange * 100
|
179 |
-
let width = eRange / totalRange * 100 - left
|
180 |
-
|
181 |
-
let label = ''
|
182 |
-
if (eDate - sDate > 365 * 24 * 3600 * 1000) {
|
183 |
-
if (sDate < now) {
|
184 |
-
label = sDate.format('MM-DD HH:mm') + ' 后永久有效'
|
185 |
-
} else {
|
186 |
-
label = '永久有效'
|
187 |
-
}
|
188 |
-
} else if (now > sDate && eDate > now) {
|
189 |
-
label = eDate.format('MM-DD HH:mm') + ' (' + moment.duration(eDate - now).humanize() + '后结束)'
|
190 |
-
if (width > 38) {
|
191 |
-
label = sDate.format('MM-DD HH:mm') + ' ~ ' + label
|
192 |
-
}
|
193 |
-
} else if (sDate > now) {
|
194 |
-
label = sDate.format('MM-DD HH:mm') + ' (' + moment.duration(sDate - now).humanize() + '后开始)'
|
195 |
-
} else {
|
196 |
-
label = sDate.format('MM-DD HH:mm') + ' ~ ' + eDate.format('MM-DD HH:mm')
|
197 |
-
}
|
198 |
-
if (sDate <= endTime && eDate >= startTime) {
|
199 |
-
target.push({
|
200 |
-
...extra,
|
201 |
-
id,
|
202 |
-
title,
|
203 |
-
type,
|
204 |
-
mergeStatus: ['activity'].includes(type) ? 1 : 0,
|
205 |
-
banner,
|
206 |
-
icon: ds.tag_icon,
|
207 |
-
left,
|
208 |
-
width,
|
209 |
-
label,
|
210 |
-
duration: eTime - sTime,
|
211 |
-
start: sDate.format('MM-DD HH:mm'),
|
212 |
-
end: eDate.format('MM-DD HH:mm')
|
213 |
-
})
|
214 |
-
}
|
215 |
-
},
|
216 |
-
|
217 |
-
async get () {
|
218 |
-
moment.locale('zh-cn')
|
219 |
-
let now = moment()
|
220 |
-
|
221 |
-
let { listData, timeMap } = await CalSr.reqCalData()
|
222 |
-
let dateList = Calendar.getDateList()
|
223 |
-
|
224 |
-
let resultList = []
|
225 |
-
let abyss = []
|
226 |
-
|
227 |
-
lodash.forEach(listData.data.list[0].list, (ds) => CalSr.getList(ds, resultList, { ...dateList, now, timeMap }))
|
228 |
-
lodash.forEach(listData.data.pic_list[0].type_list[0].list, (ds) => CalSr.getList(ds, resultList, { ...dateList, now, timeMap }))
|
229 |
-
|
230 |
-
let versionStartTime
|
231 |
-
lodash.forEach(listData.data.list[0].list, (ds) => {
|
232 |
-
if (/版本更新(概览|说明)/.test(ds.title)) {
|
233 |
-
versionStartTime = ds.start_time
|
234 |
-
}
|
235 |
-
})
|
236 |
-
|
237 |
-
let abyssCal = CalSr.getAbyssCal(dateList.startTime, dateList.endTime, versionStartTime)
|
238 |
-
lodash.forEach(abyssCal, (t) => {
|
239 |
-
CalSr.getList({
|
240 |
-
title: '「混沌回忆」',
|
241 |
-
start_time: t[0].format('YYYY-MM-DD HH:mm'),
|
242 |
-
end_time: t[1].format('YYYY-MM-DD HH:mm')
|
243 |
-
}, abyss, { ...dateList, now })
|
244 |
-
})
|
245 |
-
|
246 |
-
resultList = lodash.sortBy(resultList, ['sort', 'start', 'duration'])
|
247 |
-
|
248 |
-
let charCount = 0
|
249 |
-
let charOld = 0
|
250 |
-
let weaponCount = 0
|
251 |
-
let ret = []
|
252 |
-
lodash.forEach(resultList, (li) => {
|
253 |
-
if (li.type === 'character') {
|
254 |
-
charCount++
|
255 |
-
li.left === 0 && charOld++
|
256 |
-
li.idx = charCount
|
257 |
-
}
|
258 |
-
if (li.type === 'weapon') {
|
259 |
-
weaponCount++
|
260 |
-
li.idx = weaponCount
|
261 |
-
}
|
262 |
-
if (li.mergeStatus === 1) {
|
263 |
-
lodash.forEach(resultList, (li2) => {
|
264 |
-
if (li2.mergeStatus === 1 && li.left + li.width <= li2.left) {
|
265 |
-
li.mergeStatus = 2
|
266 |
-
li2.mergeStatus = 2
|
267 |
-
ret.push([li, li2])
|
268 |
-
return false
|
269 |
-
}
|
270 |
-
})
|
271 |
-
}
|
272 |
-
if (li.mergeStatus !== 2) {
|
273 |
-
li.mergeStatus = 2
|
274 |
-
ret.push([li])
|
275 |
-
}
|
276 |
-
})
|
277 |
-
|
278 |
-
return {
|
279 |
-
game: 'sr',
|
280 |
-
...dateList,
|
281 |
-
list: ret,
|
282 |
-
abyss,
|
283 |
-
charMode: `char-${charCount}-${charOld}`,
|
284 |
-
nowTime: now.format('YYYY-MM-DD HH:mm'),
|
285 |
-
nowDate: now.date()
|
286 |
-
}
|
287 |
-
},
|
288 |
-
|
289 |
-
async render (e) {
|
290 |
-
let calData = await CalSr.get()
|
291 |
-
let mode = 'calendar'
|
292 |
-
if (/(日历列表|活动)$/.test(e.msg)) {
|
293 |
-
mode = 'list'
|
294 |
-
}
|
295 |
-
|
296 |
-
return await Common.render('wiki/calendar', {
|
297 |
-
...calData,
|
298 |
-
displayMode: mode
|
299 |
-
}, { e, scale: 1.1 })
|
300 |
-
}
|
301 |
-
}
|
302 |
-
|
303 |
-
export default CalSr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki/CharMaterial.js
DELETED
@@ -1,18 +0,0 @@
|
|
1 |
-
import { Common } from '#miao'
|
2 |
-
|
3 |
-
const CharMaterial = {
|
4 |
-
async render ({ e, char }) {
|
5 |
-
let data = char.getData()
|
6 |
-
return await Common.render('wiki/character-material', {
|
7 |
-
// saveId: `info-${char.id}`,
|
8 |
-
data,
|
9 |
-
attr: char.getAttrList(),
|
10 |
-
detail: char.getDetail(),
|
11 |
-
imgs: char.getImgs(),
|
12 |
-
materials: char.getMaterials(),
|
13 |
-
elem: char.elem
|
14 |
-
}, { e, scale: 1.4 })
|
15 |
-
}
|
16 |
-
}
|
17 |
-
|
18 |
-
export default CharMaterial
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki/CharTalent.js
DELETED
@@ -1,114 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import { Common, Format } from '#miao'
|
3 |
-
|
4 |
-
const CharTalent = {
|
5 |
-
async render (e, mode, char) {
|
6 |
-
let lvs = []
|
7 |
-
for (let i = 1; i <= 15; i++) {
|
8 |
-
lvs.push('Lv' + i)
|
9 |
-
}
|
10 |
-
let detail = lodash.extend({}, char.getDetail())
|
11 |
-
if (char.game === 'sr') {
|
12 |
-
lodash.forEach(['cons', 'talent', 'treeData'], (key) => {
|
13 |
-
lodash.forEach(detail[key], (ds, idx) => {
|
14 |
-
if (ds.desc) {
|
15 |
-
if (key === 'talent' && ds.desc.split) {
|
16 |
-
let desc = CharTalent.getDesc(ds.desc, ds.tables, idx === 'a' || idx === 'a2' ? 5 : 8)
|
17 |
-
ds.desc = desc.desc
|
18 |
-
ds.tables = desc.tables
|
19 |
-
} else if (ds.desc.split) {
|
20 |
-
ds.desc = ds.desc.split('<br>')
|
21 |
-
}
|
22 |
-
}
|
23 |
-
})
|
24 |
-
})
|
25 |
-
}
|
26 |
-
return await Common.render('wiki/character-talent', {
|
27 |
-
saveId: `${mode}-${char.id}`,
|
28 |
-
...char.getData(),
|
29 |
-
game: char.game,
|
30 |
-
detail: char.getDetail(),
|
31 |
-
imgs: char.getImgs(),
|
32 |
-
mode,
|
33 |
-
lvs,
|
34 |
-
line: CharTalent.getLineData(char)
|
35 |
-
}, { e, scale: 1.1 })
|
36 |
-
},
|
37 |
-
getLineData (char) {
|
38 |
-
let ret = []
|
39 |
-
if (char.isSr) {
|
40 |
-
lodash.forEach({ hp: '基础生命', atk: '基础攻击', def: '基础防御', speed: '速度' }, (label, key) => {
|
41 |
-
ret.push({
|
42 |
-
num: Format.comma(char.getDetail().baseAttr[key], 1),
|
43 |
-
label
|
44 |
-
})
|
45 |
-
})
|
46 |
-
return ret
|
47 |
-
}
|
48 |
-
const attrMap = {
|
49 |
-
atkPct: '大攻击',
|
50 |
-
hpPct: '大生命',
|
51 |
-
defPct: '大防御',
|
52 |
-
cpct: '暴击',
|
53 |
-
cdmg: '爆伤',
|
54 |
-
recharge: '充能',
|
55 |
-
mastery: '精通',
|
56 |
-
heal: '治疗',
|
57 |
-
dmg: char.elemName + '伤',
|
58 |
-
phy: '物伤'
|
59 |
-
}
|
60 |
-
lodash.forEach({ hp: '基础生命', atk: '基础攻击', def: '基础防御' }, (label, key) => {
|
61 |
-
ret.push({
|
62 |
-
num: Format.comma(char.baseAttr[key], 1),
|
63 |
-
label
|
64 |
-
})
|
65 |
-
})
|
66 |
-
let ga = char.growAttr
|
67 |
-
ret.push({
|
68 |
-
num: ga.key === 'mastery' ? Format.comma(ga.value, 1) : ga.value,
|
69 |
-
label: `成长·${attrMap[ga.key]}`
|
70 |
-
})
|
71 |
-
return ret
|
72 |
-
},
|
73 |
-
// 获取精炼描述
|
74 |
-
getDesc (desc, tables, lv = 5) {
|
75 |
-
let reg = /\$(\d)\[[i|f1]\](\%?)/g
|
76 |
-
let ret
|
77 |
-
|
78 |
-
let idxFormat = {}
|
79 |
-
while ((ret = reg.exec(desc)) !== null) {
|
80 |
-
let idx = ret[1]
|
81 |
-
let pct = ret[2]
|
82 |
-
let value = tables?.[idx]?.values[lv - 1]
|
83 |
-
if (value) {
|
84 |
-
if (pct === '%') {
|
85 |
-
idxFormat[idx] = 'percent'
|
86 |
-
value = Format.percent(value)
|
87 |
-
} else {
|
88 |
-
idxFormat[idx] = 'comma'
|
89 |
-
value = Format.comma(value)
|
90 |
-
}
|
91 |
-
value = value + ` (lv${lv})`
|
92 |
-
desc = desc.replaceAll(ret[0], value)
|
93 |
-
}
|
94 |
-
}
|
95 |
-
let tableRet = []
|
96 |
-
lodash.forEach(tables, (ds, idx) => {
|
97 |
-
let values = []
|
98 |
-
lodash.forEach(ds.values, (v) => {
|
99 |
-
values.push(Format[idxFormat[idx] || 'comma'](v))
|
100 |
-
})
|
101 |
-
tableRet.push({
|
102 |
-
name: ds.name,
|
103 |
-
isSame: ds.isSame,
|
104 |
-
values
|
105 |
-
})
|
106 |
-
})
|
107 |
-
return {
|
108 |
-
desc: desc.split('<br>'),
|
109 |
-
tables: tableRet
|
110 |
-
}
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
export default CharTalent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki/CharWiki.js
DELETED
@@ -1,105 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import CharTalent from './CharTalent.js'
|
3 |
-
import CharWikiData from './CharWikiData.js'
|
4 |
-
import CharMaterial from './CharMaterial.js'
|
5 |
-
import { Cfg, Common } from '#miao'
|
6 |
-
import { Character } from '#miao.models'
|
7 |
-
|
8 |
-
const wikiReg = /^(?:#|喵喵)?(.*)(天赋|技能|命座|命之座|资料|图鉴|照片|写真|图片|图像)$/
|
9 |
-
|
10 |
-
const CharWiki = {
|
11 |
-
check (e) {
|
12 |
-
let msg = e.original_msg || e.msg
|
13 |
-
if (!e.msg) {
|
14 |
-
return false
|
15 |
-
}
|
16 |
-
let ret = wikiReg.exec(msg)
|
17 |
-
if (!ret || !ret[1] || !ret[2]) {
|
18 |
-
return false
|
19 |
-
}
|
20 |
-
let mode = 'talent'
|
21 |
-
if (/命/.test(ret[2])) {
|
22 |
-
mode = 'cons'
|
23 |
-
} else if (/(图鉴|资料)/.test(ret[2])) {
|
24 |
-
mode = 'wiki'
|
25 |
-
if (!Common.cfg('charWiki')) {
|
26 |
-
return false
|
27 |
-
}
|
28 |
-
} else if (/图|画|写真|照片/.test(ret[2])) {
|
29 |
-
mode = 'pic'
|
30 |
-
if (!Common.cfg('charPic')) {
|
31 |
-
return false
|
32 |
-
}
|
33 |
-
} else if (/(材料|养成|成长)/.test(ret[2])) {
|
34 |
-
mode = 'material'
|
35 |
-
}
|
36 |
-
if (['cons', 'talent'].includes(mode) && !Common.cfg('charWikiTalent')) {
|
37 |
-
return false
|
38 |
-
}
|
39 |
-
let char = Character.get(ret[1])
|
40 |
-
if (!char || (char.isCustom && mode !== 'pic')) {
|
41 |
-
return false
|
42 |
-
}
|
43 |
-
e.wikiMode = mode
|
44 |
-
e.msg = '#喵喵WIKI'
|
45 |
-
e.char = char
|
46 |
-
return true
|
47 |
-
},
|
48 |
-
|
49 |
-
async wiki (e) {
|
50 |
-
let mode = e.wikiMode
|
51 |
-
let char = e.char
|
52 |
-
|
53 |
-
if (mode === 'pic') {
|
54 |
-
let img = char.getCardImg(Cfg.get('charPicSe', false), false)
|
55 |
-
if (img && img.img) {
|
56 |
-
e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/${img.img}`))
|
57 |
-
} else {
|
58 |
-
e.reply('暂无图片')
|
59 |
-
}
|
60 |
-
return true
|
61 |
-
}
|
62 |
-
if (char.isCustom) {
|
63 |
-
if (mode === 'wiki') {
|
64 |
-
return false
|
65 |
-
}
|
66 |
-
e.reply('暂不支持自定义角色')
|
67 |
-
return true
|
68 |
-
}
|
69 |
-
if (!char.isRelease && Cfg.get('notReleasedData') === false) {
|
70 |
-
e.reply('未实装角色资料已禁用...')
|
71 |
-
return true
|
72 |
-
}
|
73 |
-
|
74 |
-
if (mode === 'wiki') {
|
75 |
-
if (char.source === 'amber') {
|
76 |
-
e.reply('暂不支持该角色图鉴展示')
|
77 |
-
return true
|
78 |
-
}
|
79 |
-
return await CharWiki.render({ e, char })
|
80 |
-
} else if (mode === 'material') {
|
81 |
-
return CharMaterial.render({ e, char })
|
82 |
-
}
|
83 |
-
return await CharTalent.render(e, mode, char)
|
84 |
-
},
|
85 |
-
|
86 |
-
async render ({ e, char }) {
|
87 |
-
let data = char.getData()
|
88 |
-
lodash.extend(data, char.getData('weaponTypeName,elemName'))
|
89 |
-
// 命座持有
|
90 |
-
let holding = await CharWikiData.getHolding(char.id)
|
91 |
-
let usage = await CharWikiData.getUsage(char.id)
|
92 |
-
return await Common.render('wiki/character-wiki', {
|
93 |
-
data,
|
94 |
-
attr: char.getAttrList(),
|
95 |
-
detail: char.getDetail(),
|
96 |
-
imgs: char.getImgs(),
|
97 |
-
holding,
|
98 |
-
usage,
|
99 |
-
materials: char.getMaterials(),
|
100 |
-
elem: char.elem
|
101 |
-
}, { e, scale: 1.4 })
|
102 |
-
}
|
103 |
-
}
|
104 |
-
|
105 |
-
export default CharWiki
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/apps/wiki/CharWikiData.js
DELETED
@@ -1,108 +0,0 @@
|
|
1 |
-
import HutaoApi from '../stat/HutaoApi.js'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import { Format } from '#miao'
|
4 |
-
import { ArtifactSet, Weapon } from '#miao.models'
|
5 |
-
|
6 |
-
let CharWikiData = {
|
7 |
-
/**
|
8 |
-
* 角色命座持有
|
9 |
-
* @param id
|
10 |
-
* @returns {Promise<{}>}
|
11 |
-
*/
|
12 |
-
async getHolding (id) {
|
13 |
-
let consData = (await HutaoApi.getCons()).data || {}
|
14 |
-
consData = lodash.find(consData, (ds) => ds.avatar === id)
|
15 |
-
let holding = {}
|
16 |
-
if (consData) {
|
17 |
-
let { holdingRate, rate } = consData
|
18 |
-
rate = lodash.sortBy(rate, 'id')
|
19 |
-
holding.num = Format.percent(holdingRate)
|
20 |
-
holding.cons = []
|
21 |
-
lodash.forEach(rate, (ds) => {
|
22 |
-
holding.cons.push({
|
23 |
-
cons: ds.id,
|
24 |
-
num: Format.percent(ds.value)
|
25 |
-
})
|
26 |
-
})
|
27 |
-
}
|
28 |
-
return holding
|
29 |
-
},
|
30 |
-
|
31 |
-
/**
|
32 |
-
* 角色武器、圣遗物使用
|
33 |
-
* @param id
|
34 |
-
* @returns {Promise<{}|{artis: *[], weapons: *[]}>}
|
35 |
-
*/
|
36 |
-
async getUsage (id) {
|
37 |
-
let ud = (await HutaoApi.getUsage()).data || {}
|
38 |
-
if (!ud[id]) {
|
39 |
-
return {}
|
40 |
-
}
|
41 |
-
ud = ud[id]
|
42 |
-
return {
|
43 |
-
weapons: CharWikiData.getWeaponsData(ud.weapons),
|
44 |
-
artis: CharWikiData.getArtisData(ud.artis)
|
45 |
-
}
|
46 |
-
},
|
47 |
-
|
48 |
-
/**
|
49 |
-
* 武器使用
|
50 |
-
* @param data
|
51 |
-
* @returns {*[]}
|
52 |
-
*/
|
53 |
-
getWeaponsData (data = []) {
|
54 |
-
let weapons = []
|
55 |
-
|
56 |
-
lodash.forEach(data, (ds) => {
|
57 |
-
let weapon = Weapon.get(ds.item) || {}
|
58 |
-
weapons.push({
|
59 |
-
...weapon.getData('name,abbr,img,star'),
|
60 |
-
value: ds.rate
|
61 |
-
})
|
62 |
-
})
|
63 |
-
|
64 |
-
weapons = lodash.sortBy(weapons, 'value')
|
65 |
-
weapons = weapons.reverse()
|
66 |
-
lodash.forEach(weapons, (ds) => {
|
67 |
-
ds.value = Format.percent(ds.value, 1)
|
68 |
-
})
|
69 |
-
return weapons
|
70 |
-
},
|
71 |
-
|
72 |
-
/**
|
73 |
-
* 圣遗物使用
|
74 |
-
* @param data
|
75 |
-
* @returns {*[]}
|
76 |
-
*/
|
77 |
-
getArtisData (data = []) {
|
78 |
-
let artis = []
|
79 |
-
|
80 |
-
lodash.forEach(data, (ds) => {
|
81 |
-
let imgs = []
|
82 |
-
let abbrs = []
|
83 |
-
let ss = ds.item.split(',')
|
84 |
-
lodash.forEach(ss, (t) => {
|
85 |
-
t = t.split(':')
|
86 |
-
let artiSet = ArtifactSet.get(t[0])
|
87 |
-
if (artiSet) {
|
88 |
-
imgs.push(artiSet.img)
|
89 |
-
abbrs.push(artiSet.abbr + (ss.length === 1 ? t[1] : ''))
|
90 |
-
}
|
91 |
-
})
|
92 |
-
|
93 |
-
artis.push({
|
94 |
-
imgs,
|
95 |
-
title: abbrs.join('+'),
|
96 |
-
value: ds.rate
|
97 |
-
})
|
98 |
-
})
|
99 |
-
|
100 |
-
artis = lodash.sortBy(artis, 'value')
|
101 |
-
artis = artis.reverse()
|
102 |
-
artis.forEach((ds) => {
|
103 |
-
ds.value = Format.percent(ds.value)
|
104 |
-
})
|
105 |
-
return artis
|
106 |
-
}
|
107 |
-
}
|
108 |
-
export default CharWikiData
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/App.js
DELETED
@@ -1,133 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import Plugin from './common/Plugin.js'
|
3 |
-
import { Version, MiaoError } from '#miao'
|
4 |
-
|
5 |
-
class App {
|
6 |
-
constructor (cfg) {
|
7 |
-
this.id = cfg.id
|
8 |
-
this.cfg = cfg
|
9 |
-
this.apps = {}
|
10 |
-
}
|
11 |
-
|
12 |
-
reg (key, fn, cfg = {}) {
|
13 |
-
if (lodash.isPlainObject(key)) {
|
14 |
-
lodash.forEach(key, (cfg, k) => {
|
15 |
-
this.reg(k, cfg.fn, cfg)
|
16 |
-
})
|
17 |
-
} else {
|
18 |
-
this.apps[key] = {
|
19 |
-
fn,
|
20 |
-
...cfg
|
21 |
-
}
|
22 |
-
}
|
23 |
-
}
|
24 |
-
|
25 |
-
// 获取v3执行方法
|
26 |
-
v3App () {
|
27 |
-
let cfg = this.cfg || {}
|
28 |
-
let rules = []
|
29 |
-
let check = []
|
30 |
-
let event = cfg.event
|
31 |
-
let cls = class extends Plugin {
|
32 |
-
constructor () {
|
33 |
-
super({
|
34 |
-
name: `喵喵:${cfg.name || cfg.id}`,
|
35 |
-
dsc: cfg.desc || cfg.name || '喵喵插件',
|
36 |
-
event: event === 'poke' ? 'notice.*.poke' : 'message',
|
37 |
-
priority: cfg.priority || 50,
|
38 |
-
rule: rules
|
39 |
-
})
|
40 |
-
}
|
41 |
-
|
42 |
-
accept (e) {
|
43 |
-
e.original_msg = e.original_msg || e.msg
|
44 |
-
for (let idx = 0; idx < check.length; idx++) {
|
45 |
-
if (check[idx](e, e.original_msg) === true) {
|
46 |
-
return true
|
47 |
-
}
|
48 |
-
}
|
49 |
-
}
|
50 |
-
}
|
51 |
-
|
52 |
-
for (let key in this.apps) {
|
53 |
-
let app = this.apps[key]
|
54 |
-
key = lodash.camelCase(key)
|
55 |
-
let rule = app.rule || app.reg || 'noCheck'
|
56 |
-
if (event !== 'poke') {
|
57 |
-
if (typeof (rule) === 'string') {
|
58 |
-
if (rule === 'noCheck') {
|
59 |
-
rule = '.*'
|
60 |
-
}
|
61 |
-
} else {
|
62 |
-
rule = lodash.trim(rule.toString(), '/')
|
63 |
-
}
|
64 |
-
} else {
|
65 |
-
rule = '.*'
|
66 |
-
}
|
67 |
-
|
68 |
-
rules.push({
|
69 |
-
reg: rule,
|
70 |
-
fnc: key
|
71 |
-
})
|
72 |
-
|
73 |
-
if (app.check) {
|
74 |
-
check.push(app.check)
|
75 |
-
}
|
76 |
-
|
77 |
-
cls.prototype[key] = async function (e) {
|
78 |
-
e = this.e || e
|
79 |
-
const self_id = e.self_id || e.bot?.uin || Bot.uin
|
80 |
-
if (event === 'poke') {
|
81 |
-
if (e.notice_type === 'group') {
|
82 |
-
if (e.target_id !== self_id && !e.isPoke) {
|
83 |
-
return false
|
84 |
-
}
|
85 |
-
// group状态下,戳一戳的发起人是operator
|
86 |
-
if (e.user_id === self_id) {
|
87 |
-
e.user_id = e.operator_id
|
88 |
-
}
|
89 |
-
}
|
90 |
-
e.isPoke = true
|
91 |
-
// 随便指定一个不太常见的msg以触发msg的正则
|
92 |
-
e.msg = '#poke#'
|
93 |
-
}
|
94 |
-
e.original_msg = e.original_msg || e.msg
|
95 |
-
try {
|
96 |
-
return await app.fn.call(this, e)
|
97 |
-
} catch (err) {
|
98 |
-
if (err?.message && (err instanceof MiaoError)) {
|
99 |
-
// 处理 MiaoError
|
100 |
-
return e.reply(err.message)
|
101 |
-
} else {
|
102 |
-
// 其他错误抛出
|
103 |
-
throw err
|
104 |
-
}
|
105 |
-
}
|
106 |
-
}
|
107 |
-
|
108 |
-
if (app.yzRule && app.yzCheck) {
|
109 |
-
let yzKey = `Yz${key}`
|
110 |
-
let yzRule = lodash.trim(app.yzRule.toString(), '/')
|
111 |
-
rules.push({
|
112 |
-
reg: yzRule,
|
113 |
-
fnc: yzKey
|
114 |
-
})
|
115 |
-
cls.prototype[yzKey] = async function (e) {
|
116 |
-
if (!Version.isMiao && !app.yzCheck()) {
|
117 |
-
return false
|
118 |
-
}
|
119 |
-
e = this.e || e
|
120 |
-
e.original_msg = e.original_msg || e.msg
|
121 |
-
return await app.fn.call(this, e)
|
122 |
-
}
|
123 |
-
}
|
124 |
-
}
|
125 |
-
return cls
|
126 |
-
}
|
127 |
-
}
|
128 |
-
|
129 |
-
App.init = function (cfg) {
|
130 |
-
return new App(cfg)
|
131 |
-
}
|
132 |
-
|
133 |
-
export default App
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/Cfg.js
DELETED
@@ -1,56 +0,0 @@
|
|
1 |
-
import fs from 'fs'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import cfgData from './cfg/CfgData.js'
|
4 |
-
import { Version } from '#miao'
|
5 |
-
|
6 |
-
const _path = process.cwd()
|
7 |
-
const _cfgPath = `${_path}/plugins/miao-plugin/components/`
|
8 |
-
let cfg = {}
|
9 |
-
let miaoCfg = {}
|
10 |
-
|
11 |
-
|
12 |
-
try {
|
13 |
-
cfg = await cfgData.getCfg()
|
14 |
-
cfgData.saveCfg(cfg)
|
15 |
-
lodash.forEach(cfgData.getCfgSchemaMap(), (cm) => {
|
16 |
-
if (cm.miao) {
|
17 |
-
miaoCfg[cm.cfgKey] = true
|
18 |
-
}
|
19 |
-
})
|
20 |
-
} catch (e) {
|
21 |
-
// do nth
|
22 |
-
}
|
23 |
-
|
24 |
-
let Cfg = {
|
25 |
-
get (rote) {
|
26 |
-
if (Version.isMiao && miaoCfg[rote]) {
|
27 |
-
return true
|
28 |
-
}
|
29 |
-
return lodash.get(cfg, rote)
|
30 |
-
},
|
31 |
-
set (rote, val) {
|
32 |
-
cfg[rote] = val
|
33 |
-
cfgData.saveCfg(cfg)
|
34 |
-
},
|
35 |
-
del (rote) {
|
36 |
-
lodash.set(cfg, rote, undefined)
|
37 |
-
fs.writeFileSync(_cfgPath + 'cfg.json', JSON.stringify(cfg, null, '\t'))
|
38 |
-
},
|
39 |
-
getCfg () {
|
40 |
-
return cfg
|
41 |
-
},
|
42 |
-
getCfgSchema () {
|
43 |
-
return cfgData.getCfgSchema()
|
44 |
-
},
|
45 |
-
getCfgSchemaMap () {
|
46 |
-
return cfgData.getCfgSchemaMap()
|
47 |
-
},
|
48 |
-
scale (pct = 1) {
|
49 |
-
let scale = Cfg.get('renderScale', 100)
|
50 |
-
scale = Math.min(2, Math.max(0.5, scale / 100))
|
51 |
-
pct = pct * scale
|
52 |
-
return `style=transform:scale(${pct})`
|
53 |
-
}
|
54 |
-
}
|
55 |
-
|
56 |
-
export default Cfg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/Common.js
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
import Cfg from './Cfg.js'
|
2 |
-
import Render from './common/Render.js'
|
3 |
-
|
4 |
-
const Common = {
|
5 |
-
render: Render.render,
|
6 |
-
cfg: Cfg.get,
|
7 |
-
sleep (ms) {
|
8 |
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
9 |
-
},
|
10 |
-
|
11 |
-
async downFile () {
|
12 |
-
console.log('down file')
|
13 |
-
}
|
14 |
-
|
15 |
-
}
|
16 |
-
|
17 |
-
export default Common
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/Data.js
DELETED
@@ -1,292 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import fs from 'fs'
|
3 |
-
|
4 |
-
const _path = process.cwd()
|
5 |
-
const getRoot = (root = '') => {
|
6 |
-
if (!root) {
|
7 |
-
root = `${_path}/`
|
8 |
-
} else if (root === 'root' || root === 'yunzai') {
|
9 |
-
root = `${_path}/`
|
10 |
-
} else if (root === 'miao') {
|
11 |
-
root = `${_path}/plugins/miao-plugin/`
|
12 |
-
} else {
|
13 |
-
root = `${_path}/plugins/${root}/`
|
14 |
-
}
|
15 |
-
return root
|
16 |
-
}
|
17 |
-
|
18 |
-
let Data = {
|
19 |
-
|
20 |
-
getRoot,
|
21 |
-
|
22 |
-
/*
|
23 |
-
* 根据指定的path依次检查与创建目录
|
24 |
-
* */
|
25 |
-
createDir (path = '', root = '', includeFile = false) {
|
26 |
-
root = getRoot(root)
|
27 |
-
let pathList = path.split('/')
|
28 |
-
let nowPath = root
|
29 |
-
pathList.forEach((name, idx) => {
|
30 |
-
name = name.trim()
|
31 |
-
if (!includeFile && idx <= pathList.length - 1) {
|
32 |
-
nowPath += name + '/'
|
33 |
-
if (name) {
|
34 |
-
if (!fs.existsSync(nowPath)) {
|
35 |
-
fs.mkdirSync(nowPath)
|
36 |
-
}
|
37 |
-
}
|
38 |
-
}
|
39 |
-
})
|
40 |
-
},
|
41 |
-
|
42 |
-
/*
|
43 |
-
* 读取json
|
44 |
-
* */
|
45 |
-
readJSON (file = '', root = '') {
|
46 |
-
root = getRoot(root)
|
47 |
-
if (fs.existsSync(`${root}/${file}`)) {
|
48 |
-
try {
|
49 |
-
return JSON.parse(fs.readFileSync(`${root}/${file}`, 'utf8'))
|
50 |
-
} catch (e) {
|
51 |
-
console.log(e)
|
52 |
-
}
|
53 |
-
}
|
54 |
-
return {}
|
55 |
-
},
|
56 |
-
|
57 |
-
/*
|
58 |
-
* 写JSON
|
59 |
-
* */
|
60 |
-
writeJSON (cfg, data, root = '', space = 2) {
|
61 |
-
if (arguments.length > 1) {
|
62 |
-
return Data.writeJSON({
|
63 |
-
name: cfg,
|
64 |
-
data,
|
65 |
-
space,
|
66 |
-
root
|
67 |
-
})
|
68 |
-
}
|
69 |
-
// 检查并创建目录
|
70 |
-
let name = cfg.path ? (cfg.path + '/' + cfg.name) : cfg.name
|
71 |
-
Data.createDir(name, cfg.root, true)
|
72 |
-
root = getRoot(cfg.root)
|
73 |
-
data = cfg.data
|
74 |
-
delete data._res
|
75 |
-
data = JSON.stringify(data, null, cfg.space || 2)
|
76 |
-
if (cfg.rn) {
|
77 |
-
data = data.replaceAll('\n', '\r\n')
|
78 |
-
}
|
79 |
-
return fs.writeFileSync(`${root}/${name}`, data)
|
80 |
-
},
|
81 |
-
|
82 |
-
delFile (file, root = '') {
|
83 |
-
root = getRoot(root)
|
84 |
-
try {
|
85 |
-
if (fs.existsSync(`${root}/${file}`)) {
|
86 |
-
fs.unlinkSync(`${root}/${file}`)
|
87 |
-
}
|
88 |
-
return true
|
89 |
-
} catch (error) {
|
90 |
-
logger.error(`文件删除失败:${error}`)
|
91 |
-
}
|
92 |
-
return false
|
93 |
-
},
|
94 |
-
|
95 |
-
async getCacheJSON (key) {
|
96 |
-
try {
|
97 |
-
let txt = await redis.get(key)
|
98 |
-
if (txt) {
|
99 |
-
return JSON.parse(txt)
|
100 |
-
}
|
101 |
-
} catch (e) {
|
102 |
-
console.log(e)
|
103 |
-
}
|
104 |
-
return {}
|
105 |
-
},
|
106 |
-
|
107 |
-
async setCacheJSON (key, data, EX = 3600 * 24 * 90) {
|
108 |
-
await redis.set(key, JSON.stringify(data), { EX })
|
109 |
-
},
|
110 |
-
|
111 |
-
async redisGet (key, def = {}) {
|
112 |
-
try {
|
113 |
-
let txt = await redis.get(key)
|
114 |
-
if (txt) {
|
115 |
-
return JSON.parse(txt)
|
116 |
-
}
|
117 |
-
} catch (e) {
|
118 |
-
console.log(e)
|
119 |
-
}
|
120 |
-
return def
|
121 |
-
},
|
122 |
-
|
123 |
-
async redisSet (key, data, EX = 3600 * 24 * 90) {
|
124 |
-
await redis.set(key, JSON.stringify(data), { EX })
|
125 |
-
},
|
126 |
-
|
127 |
-
async importModule (file, root = '') {
|
128 |
-
root = getRoot(root)
|
129 |
-
if (!/\.js$/.test(file)) {
|
130 |
-
file = file + '.js'
|
131 |
-
}
|
132 |
-
if (fs.existsSync(`${root}/${file}`)) {
|
133 |
-
try {
|
134 |
-
let data = await import(`file://${root}/${file}?t=${new Date() * 1}`)
|
135 |
-
return data || {}
|
136 |
-
} catch (e) {
|
137 |
-
console.log(e)
|
138 |
-
}
|
139 |
-
}
|
140 |
-
return {}
|
141 |
-
},
|
142 |
-
|
143 |
-
async importDefault (file, root) {
|
144 |
-
let ret = await Data.importModule(file, root)
|
145 |
-
return ret.default || {}
|
146 |
-
},
|
147 |
-
|
148 |
-
async importCfg (key) {
|
149 |
-
let sysCfg = await Data.importModule(`config/system/${key}_system.js`, 'miao')
|
150 |
-
let diyCfg = await Data.importModule(`config/${key}.js`, 'miao')
|
151 |
-
if (diyCfg.isSys) {
|
152 |
-
console.error(`miao-plugin: config/${key}.js无效,已忽略`)
|
153 |
-
console.error(`如需配置请复制config/${key}_default.js为config/${key}.js,请勿复制config/system下的系统文件`)
|
154 |
-
diyCfg = {}
|
155 |
-
}
|
156 |
-
return {
|
157 |
-
sysCfg,
|
158 |
-
diyCfg
|
159 |
-
}
|
160 |
-
},
|
161 |
-
|
162 |
-
/*
|
163 |
-
* 返回一个从 target 中选中的属性的对象
|
164 |
-
*
|
165 |
-
* keyList : 获取字段列表,逗号分割字符串
|
166 |
-
* key1, key2, toKey1:fromKey1, toKey2:fromObj.key
|
167 |
-
*
|
168 |
-
* defaultData: 当某个字段为空时会选取defaultData的对应内容
|
169 |
-
* toKeyPrefix:返回数据的字段前缀,默认为空。defaultData中的键值无需包含toKeyPrefix
|
170 |
-
*
|
171 |
-
* */
|
172 |
-
|
173 |
-
getData (target, keyList = '', cfg = {}) {
|
174 |
-
target = target || {}
|
175 |
-
let defaultData = cfg.defaultData || {}
|
176 |
-
let ret = {}
|
177 |
-
// 分割逗号
|
178 |
-
if (typeof (keyList) === 'string') {
|
179 |
-
keyList = keyList.split(',')
|
180 |
-
}
|
181 |
-
|
182 |
-
lodash.forEach(keyList, (keyCfg) => {
|
183 |
-
// 处理通过:指定 toKey & fromKey
|
184 |
-
let _keyCfg = keyCfg.split(':')
|
185 |
-
let keyTo = _keyCfg[0].trim()
|
186 |
-
let keyFrom = (_keyCfg[1] || _keyCfg[0]).trim()
|
187 |
-
let keyRet = keyTo
|
188 |
-
if (cfg.lowerFirstKey) {
|
189 |
-
keyRet = lodash.lowerFirst(keyRet)
|
190 |
-
}
|
191 |
-
if (cfg.keyPrefix) {
|
192 |
-
keyRet = cfg.keyPrefix + keyRet
|
193 |
-
}
|
194 |
-
// 通过Data.getVal获取数据
|
195 |
-
ret[keyRet] = Data.getVal(target, keyFrom, defaultData[keyTo], cfg)
|
196 |
-
})
|
197 |
-
return ret
|
198 |
-
},
|
199 |
-
|
200 |
-
getVal (target, keyFrom, defaultValue) {
|
201 |
-
return lodash.get(target, keyFrom, defaultValue)
|
202 |
-
},
|
203 |
-
|
204 |
-
// 异步池,聚合请求
|
205 |
-
async asyncPool (poolLimit, array, iteratorFn) {
|
206 |
-
const ret = [] // 存储所有的异步任务
|
207 |
-
const executing = [] // 存储正在执行的异步任务
|
208 |
-
for (const item of array) {
|
209 |
-
// 调用iteratorFn函数创建异步任务
|
210 |
-
const p = Promise.resolve().then(() => iteratorFn(item, array))
|
211 |
-
// 保存新的异步任务
|
212 |
-
ret.push(p)
|
213 |
-
|
214 |
-
// 当poolLimit值小于或等于总任务个数时,进行并发控制
|
215 |
-
if (poolLimit <= array.length) {
|
216 |
-
// 当任务完成后,从正在执行的任务数组中移除已完成的任务
|
217 |
-
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
|
218 |
-
executing.push(e) // 保存正在执行的异步任务
|
219 |
-
if (executing.length >= poolLimit) {
|
220 |
-
// 等待较快的任务执行完成
|
221 |
-
await Promise.race(executing)
|
222 |
-
}
|
223 |
-
}
|
224 |
-
}
|
225 |
-
return Promise.all(ret)
|
226 |
-
},
|
227 |
-
|
228 |
-
// sleep
|
229 |
-
sleep (ms) {
|
230 |
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
231 |
-
},
|
232 |
-
|
233 |
-
// 获取默认值
|
234 |
-
def () {
|
235 |
-
for (let idx in arguments) {
|
236 |
-
if (!lodash.isUndefined(arguments[idx])) {
|
237 |
-
return arguments[idx]
|
238 |
-
}
|
239 |
-
}
|
240 |
-
},
|
241 |
-
|
242 |
-
async forEach (data, fn) {
|
243 |
-
if (lodash.isArray(data)) {
|
244 |
-
for (let idx = 0; idx < data.length; idx++) {
|
245 |
-
let ret = fn(data[idx], idx)
|
246 |
-
if (ret instanceof Promise) {
|
247 |
-
ret = await ret
|
248 |
-
}
|
249 |
-
if (ret === false) {
|
250 |
-
break
|
251 |
-
}
|
252 |
-
}
|
253 |
-
} else if (lodash.isPlainObject(data)) {
|
254 |
-
for (const idx in data) {
|
255 |
-
let ret = fn(data[idx], idx)
|
256 |
-
if (ret instanceof Promise) {
|
257 |
-
ret = await ret
|
258 |
-
}
|
259 |
-
if (ret === false) {
|
260 |
-
break
|
261 |
-
}
|
262 |
-
}
|
263 |
-
}
|
264 |
-
},
|
265 |
-
|
266 |
-
// 循环字符串回调
|
267 |
-
eachStr: (arr, fn) => {
|
268 |
-
if (lodash.isString(arr)) {
|
269 |
-
arr = arr.replace(/\s*(;|;|、|,)\s*/, ',')
|
270 |
-
arr = arr.split(',')
|
271 |
-
} else if (lodash.isNumber(arr)) {
|
272 |
-
arr = [arr.toString()]
|
273 |
-
}
|
274 |
-
lodash.forEach(arr, (str, idx) => {
|
275 |
-
if (!lodash.isUndefined(str)) {
|
276 |
-
fn(str.trim ? str.trim() : str, idx)
|
277 |
-
}
|
278 |
-
})
|
279 |
-
},
|
280 |
-
|
281 |
-
regRet (reg, txt, idx) {
|
282 |
-
if (reg && txt) {
|
283 |
-
let ret = reg.exec(txt)
|
284 |
-
if (ret && ret[idx]) {
|
285 |
-
return ret[idx]
|
286 |
-
}
|
287 |
-
}
|
288 |
-
return false
|
289 |
-
}
|
290 |
-
}
|
291 |
-
|
292 |
-
export default Data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/Format.js
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
import lodash from 'lodash'
|
2 |
-
import Elem from './common/Elem.js'
|
3 |
-
import { Cfg } from '#miao'
|
4 |
-
|
5 |
-
let Format = {
|
6 |
-
...Elem,
|
7 |
-
int: function (d) {
|
8 |
-
return parseInt(d)
|
9 |
-
},
|
10 |
-
comma: function (num, fix = 0) {
|
11 |
-
num = parseFloat((num * 1).toFixed(fix))
|
12 |
-
let [integer, decimal] = String.prototype.split.call(num, '.')
|
13 |
-
let re = new RegExp(`\\d(?=(\\d{${Cfg.get('commaGroup', 3)}})+$)`, 'g')
|
14 |
-
integer = integer.replace(re, '$&,') // 正则先行断言 = /\d(?=(\d{3})+$)/g
|
15 |
-
return `${integer}${fix > 0 ? '.' + (decimal || lodash.repeat('0', fix)) : ''}`
|
16 |
-
},
|
17 |
-
pct: function (num, fix = 1) {
|
18 |
-
return (num * 1).toFixed(fix) + '%'
|
19 |
-
},
|
20 |
-
percent: function (num, fix = 1) {
|
21 |
-
return Format.pct(num * 100, fix)
|
22 |
-
}
|
23 |
-
}
|
24 |
-
|
25 |
-
export default Format
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/MiaoError.js
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
export default class MiaoError extends Error {
|
2 |
-
|
3 |
-
constructor(message) {
|
4 |
-
// 允许返回特殊消息,需传递数组,例如 [segment.image()]
|
5 |
-
if (Array.isArray(message)) {
|
6 |
-
super()
|
7 |
-
this._message = message
|
8 |
-
} else {
|
9 |
-
super(message);
|
10 |
-
}
|
11 |
-
}
|
12 |
-
|
13 |
-
get message() {
|
14 |
-
return this._message ? this._message : super.message;
|
15 |
-
}
|
16 |
-
|
17 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/Version.js
DELETED
@@ -1,109 +0,0 @@
|
|
1 |
-
import fs from 'fs'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import { Data } from '#miao'
|
4 |
-
|
5 |
-
let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
6 |
-
|
7 |
-
const getLine = function (line) {
|
8 |
-
line = line.replace(/(^\s*\*|\r)/g, '')
|
9 |
-
line = line.replace(/\s*`([^`]+`)/g, '<span class="cmd">$1')
|
10 |
-
line = line.replace(/`\s*/g, '</span>')
|
11 |
-
line = line.replace(/\s*\*\*([^\*]+\*\*)/g, '<span class="strong">$1')
|
12 |
-
line = line.replace(/\*\*\s*/g, '</span>')
|
13 |
-
line = line.replace(/ⁿᵉʷ/g, '<span class="new"></span>')
|
14 |
-
return line
|
15 |
-
}
|
16 |
-
|
17 |
-
const readLogFile = function (root, versionCount = 4) {
|
18 |
-
root = Data.getRoot(root)
|
19 |
-
let logPath = `${root}/CHANGELOG.md`
|
20 |
-
let logs = {}
|
21 |
-
let changelogs = []
|
22 |
-
let currentVersion
|
23 |
-
|
24 |
-
try {
|
25 |
-
if (fs.existsSync(logPath)) {
|
26 |
-
logs = fs.readFileSync(logPath, 'utf8') || ''
|
27 |
-
logs = logs.split('\n')
|
28 |
-
|
29 |
-
let temp = {}
|
30 |
-
let lastLine = {}
|
31 |
-
lodash.forEach(logs, (line) => {
|
32 |
-
if (versionCount <= -1) {
|
33 |
-
return false
|
34 |
-
}
|
35 |
-
let versionRet = /^#\s*([0-9a-zA-Z\\.~\s]+?)\s*$/.exec(line)
|
36 |
-
if (versionRet && versionRet[1]) {
|
37 |
-
let v = versionRet[1].trim()
|
38 |
-
if (!currentVersion) {
|
39 |
-
currentVersion = v
|
40 |
-
} else {
|
41 |
-
changelogs.push(temp)
|
42 |
-
if (/0\s*$/.test(v) && versionCount > 0) {
|
43 |
-
versionCount = 0
|
44 |
-
} else {
|
45 |
-
versionCount--
|
46 |
-
}
|
47 |
-
}
|
48 |
-
|
49 |
-
temp = {
|
50 |
-
version: v,
|
51 |
-
logs: []
|
52 |
-
}
|
53 |
-
} else {
|
54 |
-
if (!line.trim()) {
|
55 |
-
return
|
56 |
-
}
|
57 |
-
if (/^\*/.test(line)) {
|
58 |
-
lastLine = {
|
59 |
-
title: getLine(line),
|
60 |
-
logs: []
|
61 |
-
}
|
62 |
-
temp.logs.push(lastLine)
|
63 |
-
} else if (/^\s{2,}\*/.test(line)) {
|
64 |
-
lastLine.logs.push(getLine(line))
|
65 |
-
}
|
66 |
-
}
|
67 |
-
})
|
68 |
-
}
|
69 |
-
} catch (e) {
|
70 |
-
// do nth
|
71 |
-
}
|
72 |
-
return { changelogs, currentVersion }
|
73 |
-
}
|
74 |
-
|
75 |
-
const { changelogs, currentVersion } = readLogFile('miao')
|
76 |
-
|
77 |
-
|
78 |
-
const yunzaiVersion = packageJson.version
|
79 |
-
const isV3 = yunzaiVersion[0] === '3'
|
80 |
-
let isMiao = false
|
81 |
-
let name = "Yunzai-Bot"
|
82 |
-
if (packageJson.name === 'miao-yunzai') {
|
83 |
-
isMiao = true
|
84 |
-
name = "Miao-Yunzai"
|
85 |
-
} else if (packageJson.name === 'trss-yunzai') {
|
86 |
-
isMiao = true
|
87 |
-
name = "TRSS-Yunzai"
|
88 |
-
}
|
89 |
-
|
90 |
-
let Version = {
|
91 |
-
isV3,
|
92 |
-
isMiao,
|
93 |
-
name,
|
94 |
-
get version () {
|
95 |
-
return currentVersion
|
96 |
-
},
|
97 |
-
get yunzai () {
|
98 |
-
return yunzaiVersion
|
99 |
-
},
|
100 |
-
get changelogs () {
|
101 |
-
return changelogs
|
102 |
-
},
|
103 |
-
runtime () {
|
104 |
-
console.log(`未能找到e.runtime,请升级至最新版${isV3 ? 'V3' : 'V2'}-Yunzai以使用miao-plugin`)
|
105 |
-
},
|
106 |
-
readLogFile
|
107 |
-
}
|
108 |
-
|
109 |
-
export default Version
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/cfg/CfgData.js
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
import { cfgSchema } from '../../config/system/cfg_system.js'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
import { Data } from '../index.js'
|
4 |
-
import fs from 'node:fs'
|
5 |
-
|
6 |
-
let cfgData = {
|
7 |
-
saveCfg (cfg) {
|
8 |
-
let ret = []
|
9 |
-
lodash.forEach(cfgSchema, (cfgGroup) => {
|
10 |
-
ret.push(`/** ************ 【${cfgGroup.title}】 ************* */`)
|
11 |
-
lodash.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => {
|
12 |
-
ret.push(`// ${cfgItem.desc || cfgItem.title}`)
|
13 |
-
let val = Data.def(cfg[cfgKey], cfgItem.def)
|
14 |
-
if (cfgItem.input) {
|
15 |
-
val = cfgItem.input(val)
|
16 |
-
}
|
17 |
-
ret.push(`export const ${cfgKey} = ${val.toString()}`, '')
|
18 |
-
})
|
19 |
-
})
|
20 |
-
fs.writeFileSync(`${process.cwd()}/plugins/miao-plugin/config/cfg.js`, ret.join('\n'), 'utf8')
|
21 |
-
},
|
22 |
-
|
23 |
-
async getCfg () {
|
24 |
-
let ret = lodash.toPlainObject(await Data.importModule('/config/cfg.js', 'miao'))
|
25 |
-
lodash.forEach(cfgSchema, (cfgGroup) => {
|
26 |
-
lodash.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => {
|
27 |
-
ret[cfgKey] = Data.def(ret[cfgKey], cfgItem.def)
|
28 |
-
})
|
29 |
-
})
|
30 |
-
return ret
|
31 |
-
},
|
32 |
-
|
33 |
-
getCfgSchemaMap () {
|
34 |
-
let ret = {}
|
35 |
-
lodash.forEach(cfgSchema, (cfgGroup) => {
|
36 |
-
lodash.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => {
|
37 |
-
ret[cfgItem.key] = cfgItem
|
38 |
-
cfgItem.cfgKey = cfgKey
|
39 |
-
})
|
40 |
-
})
|
41 |
-
return ret
|
42 |
-
},
|
43 |
-
getCfgSchema () {
|
44 |
-
return cfgSchema
|
45 |
-
}
|
46 |
-
}
|
47 |
-
export default cfgData
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/common/Elem.js
DELETED
@@ -1,86 +0,0 @@
|
|
1 |
-
import { Data } from '../index.js'
|
2 |
-
import lodash from 'lodash'
|
3 |
-
|
4 |
-
const elemAlias = {
|
5 |
-
anemo: '风,蒙德',
|
6 |
-
geo: '岩,璃月',
|
7 |
-
electro: '雷,电,雷电,稻妻',
|
8 |
-
dendro: '草,须弥',
|
9 |
-
pyro: '火,纳塔',
|
10 |
-
hydro: '水,枫丹',
|
11 |
-
cryo: '冰,至冬'
|
12 |
-
}
|
13 |
-
|
14 |
-
const elemAliasSR = {
|
15 |
-
fire: '火',
|
16 |
-
ice: '冰',
|
17 |
-
wind: '风',
|
18 |
-
elec: '雷',
|
19 |
-
phy: '物理',
|
20 |
-
quantum: '量子',
|
21 |
-
imaginary: '虚数'
|
22 |
-
}
|
23 |
-
|
24 |
-
// 元素属性映射, 名称=>elem
|
25 |
-
let elemMap = {}
|
26 |
-
let elemMapSR = {}
|
27 |
-
|
28 |
-
// 标准元素名
|
29 |
-
let elemTitleMap = {}
|
30 |
-
let elemTitleMapSR = elemAliasSR
|
31 |
-
|
32 |
-
lodash.forEach(elemAlias, (txt, key) => {
|
33 |
-
elemMap[key] = key
|
34 |
-
elemTitleMap[key] = txt[0]
|
35 |
-
Data.eachStr(txt, (t) => (elemMap[t] = key))
|
36 |
-
})
|
37 |
-
lodash.forEach(elemAliasSR, (txt, key) => {
|
38 |
-
elemMapSR[key] = key
|
39 |
-
elemMapSR[txt] = key
|
40 |
-
})
|
41 |
-
|
42 |
-
const Elem = {
|
43 |
-
// 根据名称获取元素key
|
44 |
-
elem (elem = '', defElem = '', game = 'gs') {
|
45 |
-
elem = elem.toLowerCase()
|
46 |
-
return (game === 'gs' ? elemMap : elemMapSR)[elem] || defElem
|
47 |
-
},
|
48 |
-
|
49 |
-
// 根据key获取元素名
|
50 |
-
elemName (elem = '', defName = '') {
|
51 |
-
return elemTitleMap[Elem.elem(elem)] || defName
|
52 |
-
},
|
53 |
-
|
54 |
-
// 从字符串中匹配元素
|
55 |
-
matchElem (name = '', defElem = '', withName = false) {
|
56 |
-
const elemReg = new RegExp(`^(${lodash.keys(elemMap).join('|')})`)
|
57 |
-
let elemRet = elemReg.exec(name)
|
58 |
-
let elem = (elemRet && elemRet[1]) ? Elem.elem(elemRet[1]) : defElem
|
59 |
-
if (elem) {
|
60 |
-
if (withName) {
|
61 |
-
return {
|
62 |
-
elem,
|
63 |
-
name: name.replace(elemReg, '')
|
64 |
-
}
|
65 |
-
}
|
66 |
-
return elem
|
67 |
-
}
|
68 |
-
return ''
|
69 |
-
},
|
70 |
-
|
71 |
-
eachElem (fn, game = 'gs') {
|
72 |
-
lodash.forEach(game === 'gs' ? elemTitleMap : elemTitleMapSR, (title, key) => {
|
73 |
-
fn(key, title)
|
74 |
-
})
|
75 |
-
},
|
76 |
-
|
77 |
-
isElem (elem = '', game = 'gs') {
|
78 |
-
return !!(game === 'gs' ? elemMap : elemMapSR)[elem]
|
79 |
-
},
|
80 |
-
|
81 |
-
sameElem (key1, key2, game = 'gs') {
|
82 |
-
let map = (game === 'gs' ? elemMap : elemMapSR)
|
83 |
-
return map[key1] === map[key2]
|
84 |
-
}
|
85 |
-
}
|
86 |
-
export default Elem
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/common/Plugin.js
DELETED
@@ -1,103 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* V3版Yunzai plugin
|
3 |
-
* */
|
4 |
-
let stateArr = {}
|
5 |
-
|
6 |
-
export default class plugin {
|
7 |
-
/**
|
8 |
-
* @param name 插件名称
|
9 |
-
* @param dsc 插件描述
|
10 |
-
* @param event 执行事件,默认message
|
11 |
-
* @param priority 优先级,数字越小优先级越高
|
12 |
-
* @param rule.reg 命令正则
|
13 |
-
* @param rule.fnc 命令执行方法
|
14 |
-
* @param rule.event 执行事件,默认message
|
15 |
-
* @param rule.log false时不显示执行日志
|
16 |
-
* @param rule.permission 权限 master,owner,admin,all
|
17 |
-
* @param task.name 定时任务名称
|
18 |
-
* @param task.cron 定时任务cron表达式
|
19 |
-
* @param task.fnc 定时任务方法名
|
20 |
-
* @param task.log false时不显示执行日志
|
21 |
-
*/
|
22 |
-
constructor (data) {
|
23 |
-
/** 插件名称 */
|
24 |
-
this.name = data.name
|
25 |
-
/** 插件描述 */
|
26 |
-
this.dsc = data.dsc
|
27 |
-
/** 监听事件,默认message https://oicqjs.github.io/oicq/#events */
|
28 |
-
this.event = data.event || 'message'
|
29 |
-
/** 优先级 */
|
30 |
-
this.priority = data.priority || 5000
|
31 |
-
/** 定时任务,可以是数组 */
|
32 |
-
this.task = {
|
33 |
-
/** 任务名 */
|
34 |
-
name: '',
|
35 |
-
/** 任务方法名 */
|
36 |
-
fnc: data.task?.fnc || '',
|
37 |
-
/** 任务cron表达式 */
|
38 |
-
cron: data.task?.cron || ''
|
39 |
-
}
|
40 |
-
|
41 |
-
/** 命令规则 */
|
42 |
-
this.rule = data.rule || []
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @param msg 发送的消息
|
47 |
-
* @param quote 是否引用回复
|
48 |
-
* @param data.recallMsg 群聊是否撤回消息,0-120秒,0不撤回
|
49 |
-
* @param data.at 是否at用户
|
50 |
-
*/
|
51 |
-
reply (msg = '', quote = false, data = {}) {
|
52 |
-
if (!this.e.reply || !msg) return false
|
53 |
-
return this.e.reply(msg, quote, data)
|
54 |
-
}
|
55 |
-
|
56 |
-
conKey (isGroup = false) {
|
57 |
-
if (isGroup) {
|
58 |
-
return `${this.name}.${this.e.group_id}`
|
59 |
-
} else {
|
60 |
-
return `${this.name}.${this.userId || this.e.user_id}`
|
61 |
-
}
|
62 |
-
}
|
63 |
-
|
64 |
-
/**
|
65 |
-
* @param type 执行方法
|
66 |
-
* @param isGroup 是否群聊
|
67 |
-
* @param time 操作时间,默认120秒
|
68 |
-
*/
|
69 |
-
setContext (type, isGroup = false, time = 120) {
|
70 |
-
let key = this.conKey(isGroup)
|
71 |
-
if (!stateArr[key]) stateArr[key] = {}
|
72 |
-
stateArr[key][type] = this.e
|
73 |
-
if (time) {
|
74 |
-
/** 操作时间 */
|
75 |
-
setTimeout(() => {
|
76 |
-
if (stateArr[key][type]) {
|
77 |
-
delete stateArr[key][type]
|
78 |
-
this.e.reply('操作超时已取消', true)
|
79 |
-
}
|
80 |
-
}, time * 1000)
|
81 |
-
}
|
82 |
-
}
|
83 |
-
|
84 |
-
getContext () {
|
85 |
-
let key = this.conKey()
|
86 |
-
return stateArr[key]
|
87 |
-
}
|
88 |
-
|
89 |
-
getContextGroup () {
|
90 |
-
let key = this.conKey(true)
|
91 |
-
return stateArr[key]
|
92 |
-
}
|
93 |
-
|
94 |
-
/**
|
95 |
-
* @param type 执行方法
|
96 |
-
* @param isGroup 是否群聊
|
97 |
-
*/
|
98 |
-
finish (type, isGroup = false) {
|
99 |
-
if (stateArr[this.conKey(isGroup)] && stateArr[this.conKey(isGroup)][type]) {
|
100 |
-
delete stateArr[this.conKey(isGroup)][type]
|
101 |
-
}
|
102 |
-
}
|
103 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Yunzai/plugins/miao-plugin/components/common/Render.js
DELETED
@@ -1,42 +0,0 @@
|
|
1 |
-
import { Version, Cfg } from '#miao'
|
2 |
-
|
3 |
-
const Render = {
|
4 |
-
async render (path, params, cfg) {
|
5 |
-
let { e } = cfg
|
6 |
-
if (!e.runtime) {
|
7 |
-
console.log('未找到e.runtime,请升级至最新版Yunzai')
|
8 |
-
}
|
9 |
-
return e.runtime.render('miao-plugin', path, params, {
|
10 |
-
retType: cfg.retMsgId ? 'msgId' : 'default',
|
11 |
-
beforeRender ({ data }) {
|
12 |
-
let pluginName = ''
|
13 |
-
if (data.pluginName !== false) {
|
14 |
-
pluginName = ` & ${data.pluginName || 'Miao-Plugin'}`
|
15 |
-
if (data.pluginVersion !== false) {
|
16 |
-
pluginName += `<span class="version">${data.pluginVersion || Version.version}`
|
17 |
-
}
|
18 |
-
}
|
19 |
-
let resPath = data.pluResPath
|
20 |
-
const layoutPath = process.cwd() + '/plugins/miao-plugin/resources/common/layout/'
|
21 |
-
return {
|
22 |
-
...data,
|
23 |
-
_res_path: resPath,
|
24 |
-
_miao_path: resPath,
|
25 |
-
_layout_path: layoutPath,
|
26 |
-
_tpl_path: process.cwd() + '/plugins/miao-plugin/resources/common/tpl/',
|
27 |
-
defaultLayout: layoutPath + 'default.html',
|
28 |
-
elemLayout: layoutPath + 'elem.html',
|
29 |
-
sys: {
|
30 |
-
scale: Cfg.scale(cfg.scale || 1)
|
31 |
-
},
|
32 |
-
copyright: `Created By ${Version.name}<span class="version">${Version.yunzai}</span>${pluginName}</span>`,
|
33 |
-
pageGotoParams: {
|
34 |
-
waitUntil: 'networkidle2'
|
35 |
-
}
|
36 |
-
}
|
37 |
-
}
|
38 |
-
})
|
39 |
-
}
|
40 |
-
}
|
41 |
-
|
42 |
-
export default Render
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|