CikeyQi commited on
Commit
e333ecb
·
1 Parent(s): 050a257

Delete Yunzai/plugins/miao-plugin

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Yunzai/plugins/miao-plugin/.gitignore +0 -20
  2. Yunzai/plugins/miao-plugin/CHANGELOG.md +0 -377
  3. Yunzai/plugins/miao-plugin/LICENSE +0 -21
  4. Yunzai/plugins/miao-plugin/README.md +0 -106
  5. Yunzai/plugins/miao-plugin/apps/admin.js +0 -204
  6. Yunzai/plugins/miao-plugin/apps/character.js +0 -36
  7. Yunzai/plugins/miao-plugin/apps/character/AvatarCard.js +0 -132
  8. Yunzai/plugins/miao-plugin/apps/character/AvatarWife.js +0 -188
  9. Yunzai/plugins/miao-plugin/apps/character/ImgUpload.js +0 -258
  10. Yunzai/plugins/miao-plugin/apps/gacha.js +0 -26
  11. Yunzai/plugins/miao-plugin/apps/gacha/Gacha.js +0 -90
  12. Yunzai/plugins/miao-plugin/apps/gacha/GachaData.js +0 -444
  13. Yunzai/plugins/miao-plugin/apps/help.js +0 -23
  14. Yunzai/plugins/miao-plugin/apps/help/Help.js +0 -77
  15. Yunzai/plugins/miao-plugin/apps/help/HelpTheme.js +0 -68
  16. Yunzai/plugins/miao-plugin/apps/index.js +0 -16
  17. Yunzai/plugins/miao-plugin/apps/poke.js +0 -17
  18. Yunzai/plugins/miao-plugin/apps/profile.js +0 -143
  19. Yunzai/plugins/miao-plugin/apps/profile/ProfileArtis.js +0 -96
  20. Yunzai/plugins/miao-plugin/apps/profile/ProfileChange.js +0 -299
  21. Yunzai/plugins/miao-plugin/apps/profile/ProfileCommon.js +0 -77
  22. Yunzai/plugins/miao-plugin/apps/profile/ProfileDetail.js +0 -299
  23. Yunzai/plugins/miao-plugin/apps/profile/ProfileList.js +0 -184
  24. Yunzai/plugins/miao-plugin/apps/profile/ProfileRank.js +0 -280
  25. Yunzai/plugins/miao-plugin/apps/profile/ProfileStat.js +0 -73
  26. Yunzai/plugins/miao-plugin/apps/profile/ProfileUtils.js +0 -78
  27. Yunzai/plugins/miao-plugin/apps/profile/ProfileWeapon.js +0 -36
  28. Yunzai/plugins/miao-plugin/apps/stat.js +0 -37
  29. Yunzai/plugins/miao-plugin/apps/stat/AbyssStat.js +0 -164
  30. Yunzai/plugins/miao-plugin/apps/stat/AbyssSummary.js +0 -137
  31. Yunzai/plugins/miao-plugin/apps/stat/AbyssTeam.js +0 -190
  32. Yunzai/plugins/miao-plugin/apps/stat/HutaoApi.js +0 -73
  33. Yunzai/plugins/miao-plugin/apps/wiki.js +0 -29
  34. Yunzai/plugins/miao-plugin/apps/wiki/Calendar.js +0 -414
  35. Yunzai/plugins/miao-plugin/apps/wiki/CalendarSr.js +0 -303
  36. Yunzai/plugins/miao-plugin/apps/wiki/CharMaterial.js +0 -18
  37. Yunzai/plugins/miao-plugin/apps/wiki/CharTalent.js +0 -114
  38. Yunzai/plugins/miao-plugin/apps/wiki/CharWiki.js +0 -105
  39. Yunzai/plugins/miao-plugin/apps/wiki/CharWikiData.js +0 -108
  40. Yunzai/plugins/miao-plugin/components/App.js +0 -133
  41. Yunzai/plugins/miao-plugin/components/Cfg.js +0 -56
  42. Yunzai/plugins/miao-plugin/components/Common.js +0 -17
  43. Yunzai/plugins/miao-plugin/components/Data.js +0 -292
  44. Yunzai/plugins/miao-plugin/components/Format.js +0 -25
  45. Yunzai/plugins/miao-plugin/components/MiaoError.js +0 -17
  46. Yunzai/plugins/miao-plugin/components/Version.js +0 -109
  47. Yunzai/plugins/miao-plugin/components/cfg/CfgData.js +0 -47
  48. Yunzai/plugins/miao-plugin/components/common/Elem.js +0 -86
  49. Yunzai/plugins/miao-plugin/components/common/Plugin.js +0 -103
  50. 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&region=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&region=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(/(<|&lt;)[\w "%:;=\-\\/\\(\\),\\.]+(>|&gt;)/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&region=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&region=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(/(<|&lt;)[\w "%:;=\-\\/\\(\\),\\.]+(>|&gt;)/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