@sophiacyl/dsh-plugin-waves 0.0.0-stage → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DSH-GO-VERIFICATION.md +57 -0
- package/ICON.png +0 -0
- package/LICENSE +674 -0
- package/README.md +251 -2
- package/cordis.patch.yml +8 -0
- package/install.ps1 +0 -0
- package/install.sh +209 -0
- package/lib/client.js +1511 -0
- package/lib/host/aliashint.js +70 -0
- package/lib/host/attachments.js +25 -0
- package/lib/host/command.js +34 -0
- package/lib/host/consts.js +16 -0
- package/lib/host/dataguide.js +35 -0
- package/lib/host/imagebridge.js +41 -0
- package/lib/host/native-result.js +91 -0
- package/lib/host/native.js +191 -0
- package/lib/host/proxy.js +59 -0
- package/lib/host/results.js +67 -0
- package/lib/host/service.js +263 -0
- package/lib/host/tool.js +185 -0
- package/lib/host/troubleshoot.js +31 -0
- package/lib/host/worldbook.js +80 -0
- package/lib/index.js +74 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +136 -4
- package/service/ICON.png +0 -0
- package/service/ai/AI_DATA.md +221 -0
- package/service/knowledge/additional/manual.jsonl +5 -0
- package/service/knowledge/wiki/baike.jsonl +1231 -0
- package/service/knowledge/wiki/chengjiu.jsonl +36 -0
- package/service/knowledge/wiki/gonglve.jsonl +383 -0
- package/service/knowledge/wiki/huodong.jsonl +427 -0
- package/service/knowledge/wiki/renwu.jsonl +412 -0
- package/service/knowledge/wiki/tujian.jsonl +2889 -0
- package/service/knowledge/wiki/zixun.jsonl +47 -0
- package/service/plugins/__init__.py +0 -0
- package/service/pyproject.toml +40 -0
- package/service/rover/__init__.py +0 -0
- package/service/rover/ai_core/__init__.py +0 -0
- package/service/rover/ai_core/models.py +50 -0
- package/service/rover/ai_core/rag/__init__.py +5 -0
- package/service/rover/ai_core/rag/knowledge.py +23 -0
- package/service/rover/ai_core/register.py +86 -0
- package/service/rover/ai_core/resource.py +6 -0
- package/service/rover/ai_core/skills/__init__.py +0 -0
- package/service/rover/ai_core/skills/operations.py +8 -0
- package/service/rover/api.py +720 -0
- package/service/rover/api_render.py +161 -0
- package/service/rover/app_life.py +154 -0
- package/service/rover/aps.py +47 -0
- package/service/rover/avatar.py +85 -0
- package/service/rover/bot.py +133 -0
- package/service/rover/builtin.py +152 -0
- package/service/rover/cards/__init__.py +26 -0
- package/service/rover/cards/_shared.py +129 -0
- package/service/rover/cards/char_list.py +258 -0
- package/service/rover/cards/char_panel.py +1353 -0
- package/service/rover/cards/echo_list.py +206 -0
- package/service/rover/cards/matrix_roles.py +25 -0
- package/service/rover/cards/rank_boards.py +714 -0
- package/service/rover/cards/rank_total.py +664 -0
- package/service/rover/compat.py +215 -0
- package/service/rover/config.py +163 -0
- package/service/rover/custom_panel.py +220 -0
- package/service/rover/data_store.py +31 -0
- package/service/rover/gss.py +19 -0
- package/service/rover/handler.py +191 -0
- package/service/rover/help/__init__.py +0 -0
- package/service/rover/help/draw_new_plugin_help.py +332 -0
- package/service/rover/help/model.py +16 -0
- package/service/rover/help/utils.py +7 -0
- package/service/rover/hooks.py +420 -0
- package/service/rover/html_actions.py +236 -0
- package/service/rover/i18n.py +19 -0
- package/service/rover/knowledge.py +235 -0
- package/service/rover/logger.py +102 -0
- package/service/rover/main.py +33 -0
- package/service/rover/media.py +222 -0
- package/service/rover/message_models.py +23 -0
- package/service/rover/models.py +92 -0
- package/service/rover/native_media.py +64 -0
- package/service/rover/ocr.py +79 -0
- package/service/rover/pool.py +43 -0
- package/service/rover/restart.py +36 -0
- package/service/rover/segment.py +143 -0
- package/service/rover/server.py +131 -0
- package/service/rover/status/__init__.py +0 -0
- package/service/rover/status/models.py +10 -0
- package/service/rover/status/plugin_status.py +17 -0
- package/service/rover/subscribe.py +148 -0
- package/service/rover/sv.py +403 -0
- package/service/rover/templates/char_list.html +182 -0
- package/service/rover/templates/char_panel.html +465 -0
- package/service/rover/templates/echo_list.html +221 -0
- package/service/rover/templates/rank_all_total.html +193 -0
- package/service/rover/templates/rank_board.html +107 -0
- package/service/rover/templates/rank_level_total.html +57 -0
- package/service/rover/templates/rank_matrix_total.html +66 -0
- package/service/rover/templates/rank_phantom_total.html +180 -0
- package/service/rover/templates/rank_slash_total.html +38 -0
- package/service/rover/trigger.py +98 -0
- package/service/rover/utils/__init__.py +0 -0
- package/service/rover/utils/boardcast/__init__.py +0 -0
- package/service/rover/utils/boardcast/models.py +15 -0
- package/service/rover/utils/cookie_manager/__init__.py +0 -0
- package/service/rover/utils/cookie_manager/qrlogin.py +24 -0
- package/service/rover/utils/database/__init__.py +0 -0
- package/service/rover/utils/database/base_models.py +1771 -0
- package/service/rover/utils/database/models.py +80 -0
- package/service/rover/utils/database/startup.py +60 -0
- package/service/rover/utils/default_bg/bg.jpg +0 -0
- package/service/rover/utils/download_resource/__init__.py +0 -0
- package/service/rover/utils/download_resource/download_core.py +164 -0
- package/service/rover/utils/download_resource/download_file.py +46 -0
- package/service/rover/utils/fonts/__init__.py +0 -0
- package/service/rover/utils/fonts/fonts.py +33 -0
- package/service/rover/utils/image/__init__.py +0 -0
- package/service/rover/utils/image/convert.py +51 -0
- package/service/rover/utils/image/image_tools.py +30 -0
- package/service/rover/utils/image/utils.py +70 -0
- package/service/rover/utils/plugins_config/__init__.py +0 -0
- package/service/rover/utils/plugins_config/gs_config.py +506 -0
- package/service/rover/utils/plugins_config/models.py +182 -0
- package/service/rover/web_app.py +3 -0
- package/service/rover/webconsole/__init__.py +0 -0
- package/service/rover/webconsole/mount_app.py +26 -0
- package/service/tools/migrate.py +351 -0
- package/service/tools/regression.py +87 -0
- package/service/tools/smoke.py +63 -0
- package/service/tools/update_plugins.py +212 -0
- package/service/tools/verify_actions.py +104 -0
- package/service/tools/verify_card.py +82 -0
- package/service/tools/wwdata.py +665 -0
- package/tests/compat.test.js +181 -0
- package/tests/imagebridge.test.js +58 -0
- package/tests/media.test.js +68 -0
- package/tests/native.test.js +127 -0
- package/tests/runtime.test.js +69 -0
- package/tests/service.test.js +48 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>{{ header.title_name }}</title>
|
|
6
|
+
<style>
|
|
7
|
+
@import url('{{ font_css_url }}');
|
|
8
|
+
|
|
9
|
+
* { box-sizing: border-box; }
|
|
10
|
+
body { margin: 0; background: #0f1115; }
|
|
11
|
+
|
|
12
|
+
.container {
|
|
13
|
+
position: relative;
|
|
14
|
+
width: {{ card_w }}px;
|
|
15
|
+
padding-bottom: 40px;
|
|
16
|
+
background-image: url('{{ bg }}');
|
|
17
|
+
background-size: cover;
|
|
18
|
+
background-position: center;
|
|
19
|
+
font-family: 'Source Han Sans CN', 'Noto Sans CJK JP', 'Noto Sans CJK KR', sans-serif;
|
|
20
|
+
font-weight: 700;
|
|
21
|
+
color: #fff;
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* 文本按 PIL 锚点定位: lm 左中 / mm 中中 / rm 右中 */
|
|
26
|
+
.t { position: absolute; white-space: nowrap; line-height: 1; transform: translateY(-50%); }
|
|
27
|
+
.t.mm { transform: translate(-50%, -50%); }
|
|
28
|
+
|
|
29
|
+
/* ---------------- 头部: 标题底图 + 立绘, 底部渐隐 ---------------- */
|
|
30
|
+
.header { position: relative; width: 100%; height: {{ header_h }}px; }
|
|
31
|
+
.header .art {
|
|
32
|
+
position: absolute; inset: 0; overflow: hidden;
|
|
33
|
+
-webkit-mask-image: {{ header.mask }}; mask-image: {{ header.mask }};
|
|
34
|
+
}
|
|
35
|
+
.header .art img { position: absolute; }
|
|
36
|
+
.header .title-bg { left: {{ header.title_dx }}px; top: 0; width: 1050px; height: 500px; }
|
|
37
|
+
.header .logo { left: 50px; top: 65px; width: 200px; height: 80px; }
|
|
38
|
+
.header .time { left: 170px; top: 205px; font-size: 20px; color: {{ grey }}; }
|
|
39
|
+
.header .title { left: 240px; top: 265px; font-size: 30px; color: #000; }
|
|
40
|
+
.header .ver {
|
|
41
|
+
position: absolute; top: 255px; width: 100px; height: 30px;
|
|
42
|
+
border-radius: 6px; background: rgba(0, 79, 152, .9);
|
|
43
|
+
font-size: 24px; line-height: 30px; text-align: center;
|
|
44
|
+
}
|
|
45
|
+
.header .stat-v { top: 335px; font-size: 44px; }
|
|
46
|
+
.header .stat-l { top: 375px; font-size: 20px; color: {{ gold }}; }
|
|
47
|
+
|
|
48
|
+
/* ---------------- 上榜条件 ---------------- */
|
|
49
|
+
.cond { position: relative; width: 100%; height: {{ cond.height }}px; }
|
|
50
|
+
.cond .panel {
|
|
51
|
+
position: absolute; left: 20px; top: 20px;
|
|
52
|
+
width: {{ card_w - 40 }}px; height: {{ cond.height - 35 }}px;
|
|
53
|
+
border-radius: 8px; background: rgba(36, 36, 41, .9);
|
|
54
|
+
}
|
|
55
|
+
.cond .accent {
|
|
56
|
+
position: absolute; left: 20px; top: 20px;
|
|
57
|
+
width: {{ card_w - 40 }}px; height: 7px; background: rgb(203, 161, 95);
|
|
58
|
+
}
|
|
59
|
+
.cond .label { left: 40px; top: 60px; font-size: 24px; color: {{ grey }}; }
|
|
60
|
+
.cond .line { left: 185px; font-size: 20px; color: {{ gold }}; }
|
|
61
|
+
.cond .notes { right: 40px; top: {{ cond.height - 30 }}px; font-size: 16px; color: {{ gold }}; }
|
|
62
|
+
|
|
63
|
+
/* ---------------- 排行行 ---------------- */
|
|
64
|
+
.row {
|
|
65
|
+
position: relative; width: {{ card_w }}px; height: {{ geo.item_h }}px;
|
|
66
|
+
background-image: url('{{ bar }}'); background-size: 100% 100%;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
}
|
|
69
|
+
.row .glow { position: absolute; left: {{ geo.user_x - 20 }}px; right: 70px; top: 10px; bottom: 10px; border-radius: 14px; }
|
|
70
|
+
.row.t1 .glow { background: linear-gradient(90deg, rgba(255, 196, 60, .18), rgba(255, 196, 60, 0) 42%); }
|
|
71
|
+
.row.t2 .glow { background: linear-gradient(90deg, rgba(208, 216, 226, .16), rgba(208, 216, 226, 0) 42%); }
|
|
72
|
+
.row.t3 .glow { background: linear-gradient(90deg, rgba(214, 150, 92, .16), rgba(214, 150, 92, 0) 42%); }
|
|
73
|
+
|
|
74
|
+
.row .medal { position: absolute; left: {{ geo.rank_x }}px; top: {{ geo.medal_y }}px; width: {{ geo.medal_size }}px; height: {{ geo.medal_size }}px; }
|
|
75
|
+
.row .box {
|
|
76
|
+
position: absolute; top: {{ geo.box_y }}px; height: {{ geo.box_h }}px;
|
|
77
|
+
border-radius: 8px; background: rgba(54, 54, 54, .9); text-align: center;
|
|
78
|
+
line-height: {{ geo.box_h }}px;
|
|
79
|
+
}
|
|
80
|
+
.row .avatar { position: absolute; }
|
|
81
|
+
.row .name {
|
|
82
|
+
left: {{ geo.user_x }}px; top: {{ geo.name_y }}px; font-size: 22px;
|
|
83
|
+
max-width: {{ geo.name_max }}px; overflow: hidden; text-overflow: ellipsis;
|
|
84
|
+
}
|
|
85
|
+
.row .uid { left: {{ geo.user_x }}px; top: {{ geo.uid_y }}px; font-size: 18px; }
|
|
86
|
+
.row .badge { position: absolute; left: {{ geo.badge_x }}px; top: {{ geo.badge_y }}px; width: 208px; height: 39px; }
|
|
87
|
+
.row .badge .plate { position: absolute; left: 4px; top: 5px; width: 201px; height: 31px; border-radius: 6px; background: rgba(54, 54, 54, .6); }
|
|
88
|
+
.row .badge .bg { position: absolute; left: 104px; top: 19px; transform: translate(-50%, -50%); }
|
|
89
|
+
.row .badge .txt { position: absolute; left: 104px; top: 20px; transform: translate(-50%, -50%); font-size: 18px; white-space: nowrap; }
|
|
90
|
+
|
|
91
|
+
.row .thumb { position: absolute; left: {{ geo.thumb_x }}px; top: {{ geo.icon_y }}px; width: {{ geo.icon_size }}px; height: {{ geo.icon_size }}px; }
|
|
92
|
+
.row .fetter { position: absolute; left: {{ geo.thumb_x + geo.fetter_dx }}px; top: {{ geo.fetter_y }}px; width: {{ geo.fetter_size }}px; height: {{ geo.fetter_size }}px; }
|
|
93
|
+
.row .pip { position: absolute; top: {{ geo.pip_y }}px; width: {{ geo.pip_size }}px; height: {{ geo.pip_size }}px; }
|
|
94
|
+
|
|
95
|
+
.row .hl { position: absolute; height: 26px; border-radius: 6px; background: rgba(234, 183, 4, .18); }
|
|
96
|
+
.row .pname { max-width: {{ geo.name_col_max }}px; overflow: hidden; text-overflow: ellipsis; }
|
|
97
|
+
.row .pval, .row .pscore { font-size: 16px; }
|
|
98
|
+
|
|
99
|
+
.row .emblem { position: absolute; left: {{ geo.emblem_x }}px; top: {{ geo.emblem_y }}px; width: {{ geo.emblem_size }}px; height: {{ geo.emblem_size }}px; }
|
|
100
|
+
.row .score-v { left: {{ geo.score_x }}px; top: {{ geo.score_y }}px; font-size: 40px; }
|
|
101
|
+
.row .score-l { left: {{ geo.score_label_x }}px; top: {{ geo.score_label_y }}px; font-size: 16px; color: {{ gold }}; }
|
|
102
|
+
.hot { position: absolute; border-radius: 10px; }
|
|
103
|
+
|
|
104
|
+
.icon-img { background-size: 100% 100%; background-repeat: no-repeat; }
|
|
105
|
+
{% for a in assets %}.{{ a.cls }} { background-image: url('{{ a.uri }}'); }
|
|
106
|
+
{% endfor %}
|
|
107
|
+
</style>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<div class="container">
|
|
111
|
+
<div class="header">
|
|
112
|
+
<div class="art">
|
|
113
|
+
<img class="title-bg" src="{{ header.title_bg }}">
|
|
114
|
+
<img class="logo" src="{{ header.logo }}">
|
|
115
|
+
<div class="t time">{{ header.time }}</div>
|
|
116
|
+
<div class="t title">{{ header.title_name }}</div>
|
|
117
|
+
<div class="ver" style="left: {{ header.version_x }}px">{{ header.version }}</div>
|
|
118
|
+
{% for s in header.stats %}
|
|
119
|
+
<div class="t mm stat-v" style="left: {{ s.x }}px">{{ s.value }}</div>
|
|
120
|
+
<div class="t mm stat-l" style="left: {{ s.x }}px">{{ s.label }}</div>
|
|
121
|
+
{% endfor %}
|
|
122
|
+
{% if header.pile %}
|
|
123
|
+
<img class="pile" src="{{ header.pile.uri }}"
|
|
124
|
+
style="left: {{ header.pile.x }}px; top: {{ header.pile.y }}px; width: {{ header.pile.w }}px; height: {{ header.pile.h }}px">
|
|
125
|
+
{% endif %}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div class="cond">
|
|
130
|
+
<div class="panel"></div>
|
|
131
|
+
<div class="accent"></div>
|
|
132
|
+
<div class="t label">上榜条件</div>
|
|
133
|
+
<div class="t line" style="top: 50px">{{ cond.line1 }}</div>
|
|
134
|
+
<div class="t line" style="top: 85px">{{ cond.line2 }}</div>
|
|
135
|
+
<div class="t notes">{{ cond.notes }}</div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
{% for row in rows %}
|
|
139
|
+
<div class="row{% if row.rank <= 3 %} t{{ row.rank }}{% endif %}">
|
|
140
|
+
<div class="glow"></div>
|
|
141
|
+
{% if row.medal %}
|
|
142
|
+
<div class="medal icon-img {{ row.medal }}"></div>
|
|
143
|
+
{% else %}
|
|
144
|
+
<div class="box" style="left: {{ geo.box_cx - row.box.w // 2 }}px; width: {{ row.box.w }}px; font-size: {{ row.box.size }}px">{{ row.box.text }}</div>
|
|
145
|
+
{% endif %}
|
|
146
|
+
{% if row.avatar %}
|
|
147
|
+
<img class="avatar" src="{{ row.avatar.uri }}"
|
|
148
|
+
style="left: {{ row.avatar.x }}px; top: {{ row.avatar.y }}px; width: {{ row.avatar.w }}px; height: {{ row.avatar.h }}px">
|
|
149
|
+
{% endif %}
|
|
150
|
+
<div class="t name">{{ row.name }}</div>
|
|
151
|
+
<div class="t uid" style="color: {{ row.uid_color }}">{{ row.uid }}</div>
|
|
152
|
+
{% if row.badge %}
|
|
153
|
+
<div class="badge">
|
|
154
|
+
{% if row.badge.cls %}
|
|
155
|
+
<div class="bg icon-img {{ row.badge.cls }}" style="width: {{ row.badge.w }}px; height: {{ row.badge.h }}px"></div>
|
|
156
|
+
{% else %}<div class="plate"></div>{% endif %}
|
|
157
|
+
<div class="txt">{{ row.badge.name }}</div>
|
|
158
|
+
</div>
|
|
159
|
+
{% endif %}
|
|
160
|
+
{% if row.icon %}<div class="thumb icon-img {{ row.icon }}"></div>{% endif %}
|
|
161
|
+
{% if row.fetter %}<div class="fetter icon-img {{ row.fetter }}"></div>{% endif %}
|
|
162
|
+
{% for x in row.pips %}<img class="pip" src="{{ pip }}" style="left: {{ x }}px">{% endfor %}
|
|
163
|
+
|
|
164
|
+
{% for p in row.props %}
|
|
165
|
+
{% if p.highlight %}<div class="hl" style="left: {{ p.highlight.left }}px; top: {{ p.y - 13 }}px; width: {{ p.highlight.w }}px"></div>{% endif %}
|
|
166
|
+
<div class="t pname" style="left: {{ p.name_x }}px; top: {{ p.y }}px; font-size: {{ p.name_size }}px; color: {{ p.name_color }}">{{ p.name }}</div>
|
|
167
|
+
<div class="t pval" style="right: {{ p.value_right }}px; top: {{ p.y }}px; color: {{ p.value_color }}">{{ p.value }}</div>
|
|
168
|
+
<div class="t pscore" style="right: {{ p.score_right }}px; top: {{ p.y }}px; color: {{ p.score_color }}">{{ p.score }}</div>
|
|
169
|
+
{% endfor %}
|
|
170
|
+
|
|
171
|
+
{% if row.emblem %}<div class="emblem icon-img {{ row.emblem }}"></div>{% endif %}
|
|
172
|
+
<div class="t mm score-v">{{ row.score }}</div>
|
|
173
|
+
<div class="t mm score-l">单声骸分数</div>
|
|
174
|
+
<div class="hot" style="left: {{ geo.emblem_x }}px; top: {{ geo.emblem_y }}px; width: {{ geo.width - geo.emblem_x - 30 }}px; height: {{ geo.emblem_size }}px" data-ww-cmd="{{ cmd_damage }}"></div>
|
|
175
|
+
<div class="hot" style="left: {{ geo.thumb_x }}px; top: {{ geo.icon_y }}px; width: {{ geo.icon_size }}px; height: {{ geo.icon_size }}px" data-ww-cmd="{{ cmd_score }}"></div>
|
|
176
|
+
</div>
|
|
177
|
+
{% endfor %}
|
|
178
|
+
</div>
|
|
179
|
+
</body>
|
|
180
|
+
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{% extends "rank_board.html" %}
|
|
2
|
+
|
|
3
|
+
{% block style %}
|
|
4
|
+
/* ---------------- 行内: 限定金数 / 两个半场 / 总分 ---------------- */
|
|
5
|
+
.row .gold { left: 210px; top: 40px; font-size: 18px; }
|
|
6
|
+
.row .score { left: 1140px; top: 55px; font-size: 44px; }
|
|
7
|
+
|
|
8
|
+
/* 挂了命令的格子会被交互桥改成 position:relative, 这里按更高优先级钉回绝对定位 */
|
|
9
|
+
.row .ch { position: absolute; top: 20px; width: 45px; height: 45px; overflow: hidden; }
|
|
10
|
+
.row .ch .pic { position: absolute; inset: 0; background-size: 100% 100%; }
|
|
11
|
+
.row .ch .chain { position: absolute; left: 30px; top: 30px; width: 20px; height: 20px; }
|
|
12
|
+
.row .ch .chain span { position: absolute; left: 8px; top: 8px; transform: translate(-50%, -50%); font-size: 12px; }
|
|
13
|
+
|
|
14
|
+
.row .buff { top: 15px; width: 50px; height: 50px; }
|
|
15
|
+
.row .buff .plate { position: absolute; inset: 0; border-radius: 5px; background: rgba(0, 0, 0, .8); }
|
|
16
|
+
.row .buff .strip { position: absolute; left: 0; top: 45px; width: 50px; height: 5px; }
|
|
17
|
+
.row .buff .pic { position: absolute; inset: 0; background-size: 100% 100%; }
|
|
18
|
+
.row .half-score { top: 80px; font-size: 20px; }
|
|
19
|
+
{% endblock %}
|
|
20
|
+
|
|
21
|
+
{% block row %}
|
|
22
|
+
<div class="t gold">{{ row.gold }}</div>
|
|
23
|
+
<div class="t mm score" style="color: {{ row.score_color }}">{{ row.score }}</div>
|
|
24
|
+
{% for half in row.halves %}
|
|
25
|
+
{% for c in half.chars %}
|
|
26
|
+
<div class="ch icon-img" style="left: {{ c.x }}px"{% if c.cmd %} data-ww-cmd="{{ c.cmd }}"{% endif %}>
|
|
27
|
+
<div class="pic {{ c.cls }}"></div>
|
|
28
|
+
{% if c.chain != -1 %}<div class="chain" style="background: {{ c.chain_color }}"><span>{{ c.chain }}</span></div>{% endif %}
|
|
29
|
+
</div>
|
|
30
|
+
{% endfor %}
|
|
31
|
+
<div class="buff icon-img" style="left: {{ half.buff_x }}px">
|
|
32
|
+
<div class="plate"></div>
|
|
33
|
+
<div class="strip" style="background: {{ half.buff_color }}"></div>
|
|
34
|
+
{% if half.buff %}<div class="pic {{ half.buff }}"></div>{% endif %}
|
|
35
|
+
</div>
|
|
36
|
+
<div class="t mm half-score" style="left: {{ half.score_x }}px; color: {{ half.score_color }}">{{ half.score }}</div>
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endblock %}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Any, Awaitable, Callable, Literal
|
|
3
|
+
|
|
4
|
+
from rover.models import Event
|
|
5
|
+
|
|
6
|
+
TriggerType = Literal[
|
|
7
|
+
"prefix",
|
|
8
|
+
"suffix",
|
|
9
|
+
"keyword",
|
|
10
|
+
"fullmatch",
|
|
11
|
+
"command",
|
|
12
|
+
"file",
|
|
13
|
+
"regex",
|
|
14
|
+
"message",
|
|
15
|
+
"meta",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Trigger:
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
type: TriggerType,
|
|
23
|
+
keyword: str,
|
|
24
|
+
func: Callable,
|
|
25
|
+
prefix: str = "",
|
|
26
|
+
block: bool = False,
|
|
27
|
+
to_me: bool = False,
|
|
28
|
+
):
|
|
29
|
+
self.type = type
|
|
30
|
+
self.prefix = prefix
|
|
31
|
+
self.keyword = keyword
|
|
32
|
+
self.func: Callable[[Any, Event], Awaitable[Any]] = func
|
|
33
|
+
self.block = block
|
|
34
|
+
self.to_me = to_me
|
|
35
|
+
|
|
36
|
+
def check_command(self, ev: Event) -> bool:
|
|
37
|
+
msg = ev.raw_text
|
|
38
|
+
if self.to_me and not ev.is_tome:
|
|
39
|
+
return False
|
|
40
|
+
if self.type == "file":
|
|
41
|
+
return self._check_file(self.keyword, ev)
|
|
42
|
+
if self.type == "meta":
|
|
43
|
+
return self._check_meta(self.keyword, ev)
|
|
44
|
+
return getattr(self, f"_check_{self.type}")(self.keyword, msg)
|
|
45
|
+
|
|
46
|
+
def _check_prefix(self, prefix: str, msg: str) -> bool:
|
|
47
|
+
return msg.startswith(self.prefix + prefix) and not self._check_fullmatch(prefix, msg)
|
|
48
|
+
|
|
49
|
+
def _check_command(self, command: str, msg: str) -> bool:
|
|
50
|
+
return msg.startswith(self.prefix + command)
|
|
51
|
+
|
|
52
|
+
def _check_suffix(self, suffix: str, msg: str) -> bool:
|
|
53
|
+
return (
|
|
54
|
+
msg.startswith(self.prefix)
|
|
55
|
+
and msg.endswith(suffix)
|
|
56
|
+
and not self._check_fullmatch(suffix, msg)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def _check_keyword(self, keyword: str, msg: str) -> bool:
|
|
60
|
+
return keyword in msg and msg.startswith(self.prefix)
|
|
61
|
+
|
|
62
|
+
def _check_fullmatch(self, keyword: str, msg: str) -> bool:
|
|
63
|
+
return msg == f"{self.prefix}{keyword}" and msg.startswith(self.prefix)
|
|
64
|
+
|
|
65
|
+
def _check_file(self, file_type: str, ev: Event) -> bool:
|
|
66
|
+
if ev.file and ev.file_name:
|
|
67
|
+
return ev.file_name.split(".")[-1] == file_type
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def _check_meta(self, event_name: str, ev: Event) -> bool:
|
|
71
|
+
return ev.meta_event_type == event_name
|
|
72
|
+
|
|
73
|
+
def _check_regex(self, pattern: str, msg: str) -> bool:
|
|
74
|
+
if msg.startswith(self.prefix):
|
|
75
|
+
_msg = msg.replace(self.prefix, "", 1)
|
|
76
|
+
return bool(re.findall(pattern, _msg))
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
def _check_message(self, keyword: str, msg: str) -> bool:
|
|
80
|
+
return True
|
|
81
|
+
|
|
82
|
+
async def get_command(self, msg: Event) -> Event:
|
|
83
|
+
if self.type != "regex":
|
|
84
|
+
msg.command = self.keyword
|
|
85
|
+
msg.text = msg.raw_text.replace(self.keyword, "", 1)
|
|
86
|
+
if self.prefix:
|
|
87
|
+
msg.text = msg.text.replace(self.prefix, "", 1)
|
|
88
|
+
else:
|
|
89
|
+
if self.prefix:
|
|
90
|
+
msg.text = msg.text.replace(self.prefix, "", 1)
|
|
91
|
+
command_group = re.search(self.keyword, msg.text)
|
|
92
|
+
if command_group:
|
|
93
|
+
msg.regex_dict = command_group.groupdict()
|
|
94
|
+
msg.regex_group = command_group.groups()
|
|
95
|
+
msg.command = "|".join([i if i is not None else "" for i in list(msg.regex_group)])
|
|
96
|
+
text_list = re.split(self.keyword, msg.raw_text)
|
|
97
|
+
msg.text = "|".join([i if i is not None else "" for i in text_list])
|
|
98
|
+
return msg
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""广播消息结构。"""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, TypedDict
|
|
4
|
+
|
|
5
|
+
from rover.models import Message
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BoardCastMsg(TypedDict):
|
|
9
|
+
bot_id: str
|
|
10
|
+
messages: List[Message]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BoardCastMsgDict(TypedDict):
|
|
14
|
+
private_msg_dict: Dict[str, List[BoardCastMsg]]
|
|
15
|
+
group_msg_dict: Dict[str, BoardCastMsg]
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""扫码登录二维码。"""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def get_qrcode_base64(url: str, path: Path, bot_id: str) -> bytes:
|
|
8
|
+
# qrcode(+约2.7MB, 连带 PIL) 仅扫码登录时用到, 按需导入避免常驻启动内存。
|
|
9
|
+
import qrcode
|
|
10
|
+
from qrcode.constants import ERROR_CORRECT_L
|
|
11
|
+
|
|
12
|
+
qr = qrcode.QRCode( # type: ignore
|
|
13
|
+
version=1,
|
|
14
|
+
error_correction=ERROR_CORRECT_L,
|
|
15
|
+
box_size=10,
|
|
16
|
+
border=4,
|
|
17
|
+
)
|
|
18
|
+
qr.add_data(url)
|
|
19
|
+
qr.make(fit=True)
|
|
20
|
+
img = qr.make_image(fill_color=(255, 134, 36), back_color="white")
|
|
21
|
+
|
|
22
|
+
img_byte = io.BytesIO()
|
|
23
|
+
img.save(img_byte, format="PNG") # type: ignore
|
|
24
|
+
return img_byte.getvalue()
|
|
File without changes
|