koishi-plugin-my-pig-group-friends 1.0.0 → 1.1.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/README.md +62 -0
- package/lib/config.d.ts +2 -0
- package/lib/index.js +564 -491
- package/package.json +9 -4
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# koishi-plugin-my-pig-group-friends
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/koishi-plugin-my-pig-group-friends)
|
|
4
|
+
|
|
5
|
+
猪醒 - 虚拟旅行打卡插件,让你的猪猪群友环游世界。
|
|
6
|
+
|
|
7
|
+
## 功能特点
|
|
8
|
+
|
|
9
|
+
- **虚拟旅行打卡**:随机(或通过 LLM)生成全球旅行地点,生成精美毛玻璃效果足迹卡片
|
|
10
|
+
- **作息异常检测(实验性)**:自动检测用户每日首条消息,根据当地日出时间判断作息是否异常并触发旅行
|
|
11
|
+
- **高质量背景**:集成 Unsplash API 获取目的地真实风景图
|
|
12
|
+
- **AI 生图支持**:支持通过 media-luna 插件生成小猪在当地旅行的 AI 插画
|
|
13
|
+
- **存储集成**:深度集成 chatluna-storage-service 进行图片管理
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install koishi-plugin-my-pig-group-friends
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 依赖
|
|
22
|
+
|
|
23
|
+
### 必需
|
|
24
|
+
- `database` - 存储用户状态和旅行日志
|
|
25
|
+
- `cron` - 定时清理和报表生成
|
|
26
|
+
- `puppeteer` - 生成精美卡片
|
|
27
|
+
|
|
28
|
+
### 可选
|
|
29
|
+
- `chatluna` - 用于 LLM 动态生成旅行地点
|
|
30
|
+
- `chatluna_storage` - 用于高效管理和分发生成的图片卡片
|
|
31
|
+
- `media-luna` - 用于 AI 绘图功能
|
|
32
|
+
|
|
33
|
+
## 使用方法
|
|
34
|
+
|
|
35
|
+
### 指令
|
|
36
|
+
|
|
37
|
+
- `pig [user]` - 触发一次虚拟旅行。如果不指定用户,则对自己生效。
|
|
38
|
+
- `猪醒 [user]` - `pig` 指令的别名。
|
|
39
|
+
|
|
40
|
+
## 配置项
|
|
41
|
+
|
|
42
|
+
### 基础设置
|
|
43
|
+
- `outputMode`: 输出模式(image/text)。
|
|
44
|
+
- `travelMessageTemplate`: 旅行消息模板。
|
|
45
|
+
|
|
46
|
+
### 地点与图片
|
|
47
|
+
- `llmLocationEnabled`: 是否启用 LLM 动态生成地点。
|
|
48
|
+
- `llmLocationModel`: 生成地点的 LLM 模型(推荐使用轻量快速模型)。
|
|
49
|
+
- `unsplashAccessKey`: Unsplash API 访问密钥。
|
|
50
|
+
|
|
51
|
+
### AI 生图(可选)
|
|
52
|
+
- `aigcEnabled`: 是否启用 AI 绘图。
|
|
53
|
+
- `aigcChannel`: media-luna 绘图渠道。
|
|
54
|
+
- `aigcPrompt`: 绘图提示词模板。
|
|
55
|
+
|
|
56
|
+
### 自动检测(实验性)
|
|
57
|
+
- `experimentalAutoDetect`: 是否启用自动作息异常检测。
|
|
58
|
+
- `abnormalThreshold`: 异常判定阈值(小时)。
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
package/lib/config.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export interface Config {
|
|
|
16
16
|
llmLocationModel: string;
|
|
17
17
|
unsplashAccessKey: string;
|
|
18
18
|
logRetentionDays: number;
|
|
19
|
+
experimentalAutoDetect: boolean;
|
|
19
20
|
debug: boolean;
|
|
21
|
+
emojiFont: 'Noto Color Emoji' | 'Twemoji' | 'System';
|
|
20
22
|
}
|
|
21
23
|
export declare const Config: Schema<Config>;
|
package/lib/index.js
CHANGED
|
@@ -55,7 +55,7 @@ __name(applyDatabase, "applyDatabase");
|
|
|
55
55
|
// src/services/sunrise.ts
|
|
56
56
|
async function getSunriseInfo(ctx, lat, lng, date = "today") {
|
|
57
57
|
const url = `https://api.sunrise-sunset.org/json?lat=${lat}&lng=${lng}&formatted=0&date=${date}`;
|
|
58
|
-
const data = await ctx.http.get(url);
|
|
58
|
+
const data = await ctx.http.get(url, { timeout: 8e3 });
|
|
59
59
|
if (data.status !== "OK") {
|
|
60
60
|
throw new Error("Failed to fetch sunrise info");
|
|
61
61
|
}
|
|
@@ -69,419 +69,16 @@ __name(getSunriseInfo, "getSunriseInfo");
|
|
|
69
69
|
// src/services/card.ts
|
|
70
70
|
var import_promises = require("fs/promises");
|
|
71
71
|
var import_url = require("url");
|
|
72
|
-
|
|
73
|
-
// src/constants.ts
|
|
74
|
-
var LOCATIONS = [
|
|
75
|
-
// 亚洲 (UTC+5 ~ UTC+9)
|
|
76
|
-
{
|
|
77
|
-
country: "Japan",
|
|
78
|
-
countryZh: "日本",
|
|
79
|
-
city: "Kyoto",
|
|
80
|
-
landmark: "Fushimi Inari Shrine",
|
|
81
|
-
landmarkZh: "伏见稻荷大社",
|
|
82
|
-
timezone: "Asia/Tokyo",
|
|
83
|
-
landscapeUrl: "https://images.unsplash.com/photo-1478436127897-769e1b3f0f36"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
country: "Japan",
|
|
87
|
-
countryZh: "日本",
|
|
88
|
-
city: "Osaka",
|
|
89
|
-
landmark: "Dotonbori",
|
|
90
|
-
landmarkZh: "道顿堀",
|
|
91
|
-
timezone: "Asia/Tokyo",
|
|
92
|
-
landscapeUrl: "https://images.unsplash.com/photo-1590559899731-a382839e5549"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
country: "South Korea",
|
|
96
|
-
countryZh: "韩国",
|
|
97
|
-
city: "Seoul",
|
|
98
|
-
landmark: "Gyeongbokgung Palace",
|
|
99
|
-
landmarkZh: "景福宫",
|
|
100
|
-
timezone: "Asia/Seoul",
|
|
101
|
-
landscapeUrl: "https://images.unsplash.com/photo-1534274988757-a28bf1a57c17"
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
country: "China",
|
|
105
|
-
countryZh: "中国",
|
|
106
|
-
city: "Shanghai",
|
|
107
|
-
landmark: "The Bund",
|
|
108
|
-
landmarkZh: "外滩",
|
|
109
|
-
timezone: "Asia/Shanghai",
|
|
110
|
-
landscapeUrl: "https://images.unsplash.com/photo-1537531383496-f4749b918caa"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
country: "China",
|
|
114
|
-
countryZh: "中国",
|
|
115
|
-
city: "Guilin",
|
|
116
|
-
landmark: "Li River",
|
|
117
|
-
landmarkZh: "漓江",
|
|
118
|
-
timezone: "Asia/Shanghai",
|
|
119
|
-
landscapeUrl: "https://images.unsplash.com/photo-1529921879218-f99546d03a50"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
country: "Thailand",
|
|
123
|
-
countryZh: "泰国",
|
|
124
|
-
city: "Bangkok",
|
|
125
|
-
landmark: "Grand Palace",
|
|
126
|
-
landmarkZh: "大皇宫",
|
|
127
|
-
timezone: "Asia/Bangkok",
|
|
128
|
-
landscapeUrl: "https://images.unsplash.com/photo-1563492065599-3520f775eeed"
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
country: "Vietnam",
|
|
132
|
-
countryZh: "越南",
|
|
133
|
-
city: "Ha Long Bay",
|
|
134
|
-
landmark: "Ha Long Bay",
|
|
135
|
-
landmarkZh: "下龙湾",
|
|
136
|
-
timezone: "Asia/Ho_Chi_Minh",
|
|
137
|
-
landscapeUrl: "https://images.unsplash.com/photo-1528127269322-539801943592"
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
country: "India",
|
|
141
|
-
countryZh: "印度",
|
|
142
|
-
city: "Agra",
|
|
143
|
-
landmark: "Taj Mahal",
|
|
144
|
-
landmarkZh: "泰姬陵",
|
|
145
|
-
timezone: "Asia/Kolkata",
|
|
146
|
-
landscapeUrl: "https://images.unsplash.com/photo-1564507592333-c60657eea523"
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
country: "Singapore",
|
|
150
|
-
countryZh: "新加坡",
|
|
151
|
-
city: "Singapore",
|
|
152
|
-
landmark: "Marina Bay Sands",
|
|
153
|
-
landmarkZh: "滨海湾金沙",
|
|
154
|
-
timezone: "Asia/Singapore",
|
|
155
|
-
landscapeUrl: "https://images.unsplash.com/photo-1525625293386-3f8f99389edd"
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
country: "Indonesia",
|
|
159
|
-
countryZh: "印度尼西亚",
|
|
160
|
-
city: "Bali",
|
|
161
|
-
landmark: "Tanah Lot Temple",
|
|
162
|
-
landmarkZh: "海神庙",
|
|
163
|
-
timezone: "Asia/Jakarta",
|
|
164
|
-
landscapeUrl: "https://images.unsplash.com/photo-1537996194471-e657df975ab4"
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
country: "Nepal",
|
|
168
|
-
countryZh: "尼泊尔",
|
|
169
|
-
city: "Kathmandu",
|
|
170
|
-
landmark: "Himalaya Mountains",
|
|
171
|
-
landmarkZh: "喜马拉雅山",
|
|
172
|
-
timezone: "Asia/Kathmandu",
|
|
173
|
-
landscapeUrl: "https://images.unsplash.com/photo-1544735716-392fe2489ffa"
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
country: "UAE",
|
|
177
|
-
countryZh: "阿联酋",
|
|
178
|
-
city: "Dubai",
|
|
179
|
-
landmark: "Burj Khalifa",
|
|
180
|
-
landmarkZh: "哈利法塔",
|
|
181
|
-
timezone: "Asia/Dubai",
|
|
182
|
-
landscapeUrl: "https://images.unsplash.com/photo-1512453979798-5ea266f8880c"
|
|
183
|
-
},
|
|
184
|
-
// 欧洲 (UTC+0 ~ UTC+3)
|
|
185
|
-
{
|
|
186
|
-
country: "UK",
|
|
187
|
-
countryZh: "英国",
|
|
188
|
-
city: "London",
|
|
189
|
-
landmark: "Big Ben",
|
|
190
|
-
landmarkZh: "大本钟",
|
|
191
|
-
timezone: "Europe/London",
|
|
192
|
-
landscapeUrl: "https://images.unsplash.com/photo-1513635269975-59663e0ac1ad"
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
country: "France",
|
|
196
|
-
countryZh: "法国",
|
|
197
|
-
city: "Provence",
|
|
198
|
-
landmark: "Lavender Fields",
|
|
199
|
-
landmarkZh: "薰衣草田",
|
|
200
|
-
timezone: "Europe/Paris",
|
|
201
|
-
landscapeUrl: "https://images.unsplash.com/photo-1499002238440-d264edd596ec"
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
country: "Italy",
|
|
205
|
-
countryZh: "意大利",
|
|
206
|
-
city: "Venice",
|
|
207
|
-
landmark: "Grand Canal",
|
|
208
|
-
landmarkZh: "大运河",
|
|
209
|
-
timezone: "Europe/Rome",
|
|
210
|
-
landscapeUrl: "https://images.unsplash.com/photo-1514890547357-a9ee288728e0"
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
country: "Italy",
|
|
214
|
-
countryZh: "意大利",
|
|
215
|
-
city: "Rome",
|
|
216
|
-
landmark: "Colosseum",
|
|
217
|
-
landmarkZh: "罗马斗兽场",
|
|
218
|
-
timezone: "Europe/Rome",
|
|
219
|
-
landscapeUrl: "https://images.unsplash.com/photo-1552832230-c0197dd311b5"
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
country: "Spain",
|
|
223
|
-
countryZh: "西班牙",
|
|
224
|
-
city: "Barcelona",
|
|
225
|
-
landmark: "Sagrada Familia",
|
|
226
|
-
landmarkZh: "圣家堂",
|
|
227
|
-
timezone: "Europe/Madrid",
|
|
228
|
-
landscapeUrl: "https://images.unsplash.com/photo-1583422409516-2895a77efded"
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
country: "Greece",
|
|
232
|
-
countryZh: "希腊",
|
|
233
|
-
city: "Santorini",
|
|
234
|
-
landmark: "Oia Village",
|
|
235
|
-
landmarkZh: "伊亚小镇",
|
|
236
|
-
timezone: "Europe/Athens",
|
|
237
|
-
landscapeUrl: "https://images.unsplash.com/photo-1613395877344-13d4a8e0d49e"
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
country: "Netherlands",
|
|
241
|
-
countryZh: "荷兰",
|
|
242
|
-
city: "Amsterdam",
|
|
243
|
-
landmark: "Canal Ring",
|
|
244
|
-
landmarkZh: "运河环",
|
|
245
|
-
timezone: "Europe/Amsterdam",
|
|
246
|
-
landscapeUrl: "https://images.unsplash.com/photo-1534351590666-13e3e96b5017"
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
country: "Switzerland",
|
|
250
|
-
countryZh: "瑞士",
|
|
251
|
-
city: "Interlaken",
|
|
252
|
-
landmark: "Swiss Alps",
|
|
253
|
-
landmarkZh: "阿尔卑斯山",
|
|
254
|
-
timezone: "Europe/Zurich",
|
|
255
|
-
landscapeUrl: "https://images.unsplash.com/photo-1531366936337-7c912a4589a7"
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
country: "Norway",
|
|
259
|
-
countryZh: "挪威",
|
|
260
|
-
city: "Tromsø",
|
|
261
|
-
landmark: "Northern Lights",
|
|
262
|
-
landmarkZh: "北极光",
|
|
263
|
-
timezone: "Europe/Oslo",
|
|
264
|
-
landscapeUrl: "https://images.unsplash.com/photo-1483347756197-71ef80e95f73"
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
country: "Iceland",
|
|
268
|
-
countryZh: "冰岛",
|
|
269
|
-
city: "Reykjavik",
|
|
270
|
-
landmark: "Blue Lagoon",
|
|
271
|
-
landmarkZh: "蓝湖温泉",
|
|
272
|
-
timezone: "Atlantic/Reykjavik",
|
|
273
|
-
landscapeUrl: "https://images.unsplash.com/photo-1504829857797-ddff29c27927"
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
country: "Turkey",
|
|
277
|
-
countryZh: "土耳其",
|
|
278
|
-
city: "Cappadocia",
|
|
279
|
-
landmark: "Hot Air Balloons",
|
|
280
|
-
landmarkZh: "热气球",
|
|
281
|
-
timezone: "Europe/Istanbul",
|
|
282
|
-
landscapeUrl: "https://images.unsplash.com/photo-1641128324972-af3212f0f6bd"
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
country: "Russia",
|
|
286
|
-
countryZh: "俄罗斯",
|
|
287
|
-
city: "Moscow",
|
|
288
|
-
landmark: "Red Square",
|
|
289
|
-
landmarkZh: "红场",
|
|
290
|
-
timezone: "Europe/Moscow",
|
|
291
|
-
landscapeUrl: "https://images.unsplash.com/photo-1513326738677-b964603b136d"
|
|
292
|
-
},
|
|
293
|
-
// 非洲 (UTC+0 ~ UTC+3)
|
|
294
|
-
{
|
|
295
|
-
country: "Egypt",
|
|
296
|
-
countryZh: "埃及",
|
|
297
|
-
city: "Giza",
|
|
298
|
-
landmark: "Pyramids of Giza",
|
|
299
|
-
landmarkZh: "吉萨金字塔",
|
|
300
|
-
timezone: "Africa/Cairo",
|
|
301
|
-
landscapeUrl: "https://images.unsplash.com/photo-1503177119275-0aa32b3a9368"
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
country: "Morocco",
|
|
305
|
-
countryZh: "摩洛哥",
|
|
306
|
-
city: "Marrakech",
|
|
307
|
-
landmark: "Jardin Majorelle",
|
|
308
|
-
landmarkZh: "马约尔花园",
|
|
309
|
-
timezone: "Africa/Casablanca",
|
|
310
|
-
landscapeUrl: "https://images.unsplash.com/photo-1489749798305-4fea3ae63d43"
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
country: "South Africa",
|
|
314
|
-
countryZh: "南非",
|
|
315
|
-
city: "Cape Town",
|
|
316
|
-
landmark: "Table Mountain",
|
|
317
|
-
landmarkZh: "桌山",
|
|
318
|
-
timezone: "Africa/Johannesburg",
|
|
319
|
-
landscapeUrl: "https://images.unsplash.com/photo-1580060839134-75a5edca2e99"
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
country: "Kenya",
|
|
323
|
-
countryZh: "肯尼亚",
|
|
324
|
-
city: "Masai Mara",
|
|
325
|
-
landmark: "Safari Savanna",
|
|
326
|
-
landmarkZh: "马赛马拉草原",
|
|
327
|
-
timezone: "Africa/Nairobi",
|
|
328
|
-
landscapeUrl: "https://images.unsplash.com/photo-1547970810-dc1eac37d174"
|
|
329
|
-
},
|
|
330
|
-
// 北美洲 (UTC-5 ~ UTC-8)
|
|
331
|
-
{
|
|
332
|
-
country: "USA",
|
|
333
|
-
countryZh: "美国",
|
|
334
|
-
city: "New York",
|
|
335
|
-
landmark: "Times Square",
|
|
336
|
-
landmarkZh: "时代广场",
|
|
337
|
-
timezone: "America/New_York",
|
|
338
|
-
landscapeUrl: "https://images.unsplash.com/photo-1534430480872-3498386e7856"
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
country: "USA",
|
|
342
|
-
countryZh: "美国",
|
|
343
|
-
city: "San Francisco",
|
|
344
|
-
landmark: "Golden Gate Bridge",
|
|
345
|
-
landmarkZh: "金门大桥",
|
|
346
|
-
timezone: "America/Los_Angeles",
|
|
347
|
-
landscapeUrl: "https://images.unsplash.com/photo-1449034446853-66c86144b0ad"
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
country: "USA",
|
|
351
|
-
countryZh: "美国",
|
|
352
|
-
city: "Las Vegas",
|
|
353
|
-
landmark: "The Strip",
|
|
354
|
-
landmarkZh: "拉斯维加斯大道",
|
|
355
|
-
timezone: "America/Los_Angeles",
|
|
356
|
-
landscapeUrl: "https://images.unsplash.com/photo-1605833556294-ea5c7a74f57d"
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
country: "USA",
|
|
360
|
-
countryZh: "美国",
|
|
361
|
-
city: "Arizona",
|
|
362
|
-
landmark: "Grand Canyon",
|
|
363
|
-
landmarkZh: "大峡谷",
|
|
364
|
-
timezone: "America/Phoenix",
|
|
365
|
-
landscapeUrl: "https://images.unsplash.com/photo-1474044159687-1ee9f3a51722"
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
country: "Canada",
|
|
369
|
-
countryZh: "加拿大",
|
|
370
|
-
city: "Banff",
|
|
371
|
-
landmark: "Lake Louise",
|
|
372
|
-
landmarkZh: "路易斯湖",
|
|
373
|
-
timezone: "America/Edmonton",
|
|
374
|
-
landscapeUrl: "https://images.unsplash.com/photo-1502085671122-2d218cd434e6"
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
country: "Canada",
|
|
378
|
-
countryZh: "加拿大",
|
|
379
|
-
city: "Niagara Falls",
|
|
380
|
-
landmark: "Niagara Falls",
|
|
381
|
-
landmarkZh: "尼亚加拉瀑布",
|
|
382
|
-
timezone: "America/Toronto",
|
|
383
|
-
landscapeUrl: "https://images.unsplash.com/photo-1489447068241-b3490214e879"
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
country: "Mexico",
|
|
387
|
-
countryZh: "墨西哥",
|
|
388
|
-
city: "Cancun",
|
|
389
|
-
landmark: "Chichen Itza",
|
|
390
|
-
landmarkZh: "奇琴伊察",
|
|
391
|
-
timezone: "America/Cancun",
|
|
392
|
-
landscapeUrl: "https://images.unsplash.com/photo-1518638150340-f706e86654de"
|
|
393
|
-
},
|
|
394
|
-
// 南美洲 (UTC-3 ~ UTC-5)
|
|
395
|
-
{
|
|
396
|
-
country: "Brazil",
|
|
397
|
-
countryZh: "巴西",
|
|
398
|
-
city: "Rio de Janeiro",
|
|
399
|
-
landmark: "Christ the Redeemer",
|
|
400
|
-
landmarkZh: "基督救世主像",
|
|
401
|
-
timezone: "America/Sao_Paulo",
|
|
402
|
-
landscapeUrl: "https://images.unsplash.com/photo-1483729558449-99ef09a8c325"
|
|
403
|
-
},
|
|
404
|
-
{
|
|
405
|
-
country: "Peru",
|
|
406
|
-
countryZh: "秘鲁",
|
|
407
|
-
city: "Cusco",
|
|
408
|
-
landmark: "Machu Picchu",
|
|
409
|
-
landmarkZh: "马丘比丘",
|
|
410
|
-
timezone: "America/Lima",
|
|
411
|
-
landscapeUrl: "https://images.unsplash.com/photo-1526392060635-9d6019884377"
|
|
412
|
-
},
|
|
413
|
-
{
|
|
414
|
-
country: "Argentina",
|
|
415
|
-
countryZh: "阿根廷",
|
|
416
|
-
city: "Patagonia",
|
|
417
|
-
landmark: "Perito Moreno Glacier",
|
|
418
|
-
landmarkZh: "莫雷诺冰川",
|
|
419
|
-
timezone: "America/Argentina/Buenos_Aires",
|
|
420
|
-
landscapeUrl: "https://images.unsplash.com/photo-1551279880-03041531948f"
|
|
421
|
-
},
|
|
422
|
-
{
|
|
423
|
-
country: "Chile",
|
|
424
|
-
countryZh: "智利",
|
|
425
|
-
city: "Atacama",
|
|
426
|
-
landmark: "Atacama Desert",
|
|
427
|
-
landmarkZh: "阿塔卡马沙漠",
|
|
428
|
-
timezone: "America/Santiago",
|
|
429
|
-
landscapeUrl: "https://images.unsplash.com/photo-1489392191049-fc10c97e64b6"
|
|
430
|
-
},
|
|
431
|
-
// 大洋洲 (UTC+10 ~ UTC+12)
|
|
432
|
-
{
|
|
433
|
-
country: "Australia",
|
|
434
|
-
countryZh: "澳大利亚",
|
|
435
|
-
city: "Sydney",
|
|
436
|
-
landmark: "Sydney Opera House",
|
|
437
|
-
landmarkZh: "悉尼歌剧院",
|
|
438
|
-
timezone: "Australia/Sydney",
|
|
439
|
-
landscapeUrl: "https://images.unsplash.com/photo-1506973035872-a4ec16b8e8d9"
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
country: "Australia",
|
|
443
|
-
countryZh: "澳大利亚",
|
|
444
|
-
city: "Queensland",
|
|
445
|
-
landmark: "Great Barrier Reef",
|
|
446
|
-
landmarkZh: "大堡礁",
|
|
447
|
-
timezone: "Australia/Brisbane",
|
|
448
|
-
landscapeUrl: "https://images.unsplash.com/photo-1559128010-7c1ad6e1b6a5"
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
country: "New Zealand",
|
|
452
|
-
countryZh: "新西兰",
|
|
453
|
-
city: "Queenstown",
|
|
454
|
-
landmark: "Milford Sound",
|
|
455
|
-
landmarkZh: "米尔福德峡湾",
|
|
456
|
-
timezone: "Pacific/Auckland",
|
|
457
|
-
landscapeUrl: "https://images.unsplash.com/photo-1507699622108-4be3abd695ad"
|
|
458
|
-
},
|
|
459
|
-
{
|
|
460
|
-
country: "New Zealand",
|
|
461
|
-
countryZh: "新西兰",
|
|
462
|
-
city: "Matamata",
|
|
463
|
-
landmark: "Hobbiton",
|
|
464
|
-
landmarkZh: "霍比屯",
|
|
465
|
-
timezone: "Pacific/Auckland",
|
|
466
|
-
landscapeUrl: "https://images.unsplash.com/photo-1507097634215-e82e6b552cae"
|
|
467
|
-
},
|
|
468
|
-
{
|
|
469
|
-
country: "Fiji",
|
|
470
|
-
countryZh: "斐济",
|
|
471
|
-
city: "Nadi",
|
|
472
|
-
landmark: "Fiji Islands",
|
|
473
|
-
landmarkZh: "斐济群岛",
|
|
474
|
-
timezone: "Pacific/Fiji",
|
|
475
|
-
landscapeUrl: "https://images.unsplash.com/photo-1589179899031-d86b7e3fcd61"
|
|
476
|
-
}
|
|
477
|
-
];
|
|
478
|
-
|
|
479
|
-
// src/services/card.ts
|
|
480
72
|
async function generateFootprintCard(ctx, config, data, userInfo, platform, backgroundUrl) {
|
|
481
73
|
const username = userInfo.username || userInfo.userId;
|
|
482
74
|
let avatarUrl = userInfo.avatarUrl || "";
|
|
483
75
|
if (!avatarUrl) {
|
|
484
|
-
|
|
76
|
+
if (platform === "onebot") {
|
|
77
|
+
avatarUrl = `https://q.qlogo.cn/headimg_dl?dst_uin=${userInfo.userId}&spec=640`;
|
|
78
|
+
} else {
|
|
79
|
+
const initial = username.charAt(0) || "U";
|
|
80
|
+
avatarUrl = `https://ui-avatars.com/api/?name=${encodeURIComponent(initial)}&background=007AFF&color=fff&size=200&bold=true`;
|
|
81
|
+
}
|
|
485
82
|
}
|
|
486
83
|
let bgImage = backgroundUrl || data.location.landscapeUrl;
|
|
487
84
|
if (config.debug) ctx.logger("pig").debug(`Initial background URL: ${bgImage || "none"}`);
|
|
@@ -529,7 +126,8 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
529
126
|
if (config.debug) ctx.logger("pig").debug(`Server-side fetching background: ${normalized}`);
|
|
530
127
|
const response = await ctx.http(normalized, {
|
|
531
128
|
responseType: "arraybuffer",
|
|
532
|
-
timeout:
|
|
129
|
+
timeout: 8e3,
|
|
130
|
+
// Reduced from 15s to 8s for better responsiveness
|
|
533
131
|
headers: {
|
|
534
132
|
"User-Agent": "Mozilla/5.0",
|
|
535
133
|
"Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8"
|
|
@@ -571,20 +169,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
571
169
|
ctx.logger("pig").debug(`Successfully converted background to base64 (length=${fetched.length})`);
|
|
572
170
|
}
|
|
573
171
|
} else {
|
|
574
|
-
if (config.debug) ctx.logger("pig").warn("Background fetch failed,
|
|
575
|
-
const fallbackLoc = LOCATIONS.find(
|
|
576
|
-
(l) => l.country === data.location.country || l.timezone === data.location.timezone
|
|
577
|
-
);
|
|
578
|
-
if (fallbackLoc && fallbackLoc.landscapeUrl !== bgImage) {
|
|
579
|
-
if (config.debug) ctx.logger("pig").info(`Found fallback static location: ${fallbackLoc.landmark} (${fallbackLoc.landscapeUrl})`);
|
|
580
|
-
const fallback = await fetchToDataUrl(fallbackLoc.landscapeUrl);
|
|
581
|
-
if (fallback) {
|
|
582
|
-
bgImage = fallback;
|
|
583
|
-
if (config.debug) ctx.logger("pig").info("Successfully used fallback static image");
|
|
584
|
-
} else if (config.debug) {
|
|
585
|
-
ctx.logger("pig").warn("Fallback static image also failed");
|
|
586
|
-
}
|
|
587
|
-
}
|
|
172
|
+
if (config.debug) ctx.logger("pig").warn("Background fetch failed, proceeding with URL directly (no fallback fetch)");
|
|
588
173
|
}
|
|
589
174
|
if (config.debug) {
|
|
590
175
|
ctx.logger("pig").debug(`Final background value: ${bgImage ? bgImage.startsWith("data:") ? `data-url(${bgImage.length})` : bgImage : "none"}`);
|
|
@@ -592,14 +177,14 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
592
177
|
}
|
|
593
178
|
const now = /* @__PURE__ */ new Date();
|
|
594
179
|
const dateStr = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`;
|
|
180
|
+
const emojiFont = config.emojiFont === "System" ? "" : `"${config.emojiFont}", `;
|
|
595
181
|
const html = `
|
|
596
182
|
<!DOCTYPE html>
|
|
597
183
|
<html>
|
|
598
184
|
<head>
|
|
599
185
|
<meta charset="UTF-8">
|
|
600
186
|
<style>
|
|
601
|
-
|
|
602
|
-
|
|
187
|
+
/* System fonts only - no external font loading for Docker compatibility */
|
|
603
188
|
* {
|
|
604
189
|
margin: 0;
|
|
605
190
|
padding: 0;
|
|
@@ -610,7 +195,8 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
610
195
|
width: 1080px;
|
|
611
196
|
height: 1920px;
|
|
612
197
|
overflow: hidden;
|
|
613
|
-
|
|
198
|
+
/* Prioritize system fonts with wide Unicode coverage for emoji and CJK support */
|
|
199
|
+
font-family: ${emojiFont}"Noto Sans CJK SC", "Noto Sans SC", "Source Han Sans SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "Droid Sans Fallback", "PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
|
|
614
200
|
background: #f0f0f2;
|
|
615
201
|
--bg-image: url('${bgImage}');
|
|
616
202
|
}
|
|
@@ -689,11 +275,11 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
689
275
|
content: "";
|
|
690
276
|
position: absolute;
|
|
691
277
|
inset: 0;
|
|
692
|
-
/*
|
|
278
|
+
/* Use scroll instead of fixed to avoid Puppeteer rendering issues */
|
|
693
279
|
background-image: var(--bg-image);
|
|
694
|
-
background-attachment:
|
|
280
|
+
background-attachment: scroll;
|
|
695
281
|
background-size: cover;
|
|
696
|
-
background-position: center;
|
|
282
|
+
background-position: center bottom;
|
|
697
283
|
|
|
698
284
|
/* 模糊处理,模拟毛玻璃内部的散射 */
|
|
699
285
|
filter: blur(25px) brightness(1.1);
|
|
@@ -935,11 +521,17 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
935
521
|
for (let i = 0; i < allElements.length; i++) {
|
|
936
522
|
const bg = window.getComputedStyle(allElements[i]).backgroundImage;
|
|
937
523
|
if (bg && bg !== 'none' && bg.includes('url(')) {
|
|
938
|
-
const urlMatch = bg.match(/url(["']?(.+?)["']?)/);
|
|
939
|
-
if (urlMatch) {
|
|
940
|
-
|
|
524
|
+
const urlMatch = bg.match(/url(s*?["']?(.+?)["']?s*?)/);
|
|
525
|
+
if (urlMatch && urlMatch[1]) {
|
|
526
|
+
const url = urlMatch[1];
|
|
527
|
+
// Skip data URLs as they don't need pre-loading and can be fragile in Image constructor
|
|
528
|
+
if (url.startsWith('data:')) {
|
|
529
|
+
console.log('Skipping data-url pre-load');
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
console.log('Found background image: ' + url);
|
|
941
533
|
const img = new Image();
|
|
942
|
-
img.src =
|
|
534
|
+
img.src = url;
|
|
943
535
|
bgImages.push(img);
|
|
944
536
|
}
|
|
945
537
|
}
|
|
@@ -970,16 +562,17 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
970
562
|
]);
|
|
971
563
|
|
|
972
564
|
console.log('All images and fonts loaded');
|
|
973
|
-
// Extra safety delay for rendering
|
|
974
|
-
await new Promise(r => setTimeout(r,
|
|
565
|
+
// Extra safety delay for rendering (reduced from 400ms)
|
|
566
|
+
await new Promise(r => setTimeout(r, 200));
|
|
975
567
|
}
|
|
976
568
|
window.renderReady = waitForImages();
|
|
977
569
|
</script>
|
|
978
570
|
</body>
|
|
979
571
|
</html>
|
|
980
572
|
`;
|
|
573
|
+
let page = null;
|
|
981
574
|
try {
|
|
982
|
-
|
|
575
|
+
page = await ctx.puppeteer.page();
|
|
983
576
|
if (config.debug) {
|
|
984
577
|
page.on("console", (msg) => ctx.logger("pig").debug(`[Browser] ${msg.text()}`));
|
|
985
578
|
page.on("requestfailed", (request) => {
|
|
@@ -987,30 +580,445 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
987
580
|
});
|
|
988
581
|
}
|
|
989
582
|
await page.setViewport({ width: 1080, height: 1920, deviceScaleFactor: 1 });
|
|
990
|
-
await page.setContent(html, { waitUntil: "
|
|
583
|
+
await page.setContent(html, { waitUntil: "domcontentloaded" });
|
|
991
584
|
await page.evaluate(() => window["renderReady"]);
|
|
992
585
|
const buffer = await page.screenshot({ type: "png", fullPage: true });
|
|
993
|
-
await page.close();
|
|
994
586
|
const filename = `pig_${userInfo.userId}_${now.getTime()}.png`;
|
|
995
587
|
ctx.logger("pig").info(`足迹卡片已生成: ${filename}`);
|
|
996
588
|
return { buffer, filename };
|
|
997
589
|
} catch (e) {
|
|
998
590
|
ctx.logger("pig").error("Failed to generate card", e);
|
|
999
591
|
throw e;
|
|
592
|
+
} finally {
|
|
593
|
+
if (page) {
|
|
594
|
+
try {
|
|
595
|
+
await page.close();
|
|
596
|
+
} catch (closeError) {
|
|
597
|
+
if (config.debug) {
|
|
598
|
+
ctx.logger("pig").warn(`Failed to close puppeteer page: ${closeError}`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
__name(generateFootprintCard, "generateFootprintCard");
|
|
605
|
+
function escapeHtml(text) {
|
|
606
|
+
const map = {
|
|
607
|
+
"&": "&",
|
|
608
|
+
"<": "<",
|
|
609
|
+
">": ">",
|
|
610
|
+
'"': """,
|
|
611
|
+
"'": "'"
|
|
612
|
+
};
|
|
613
|
+
return text.replace(/[&<>"']/g, (m) => map[m]);
|
|
614
|
+
}
|
|
615
|
+
__name(escapeHtml, "escapeHtml");
|
|
616
|
+
|
|
617
|
+
// src/constants.ts
|
|
618
|
+
var LOCATIONS = [
|
|
619
|
+
// 亚洲 (UTC+5 ~ UTC+9)
|
|
620
|
+
{
|
|
621
|
+
country: "Japan",
|
|
622
|
+
countryZh: "日本",
|
|
623
|
+
city: "Kyoto",
|
|
624
|
+
landmark: "Fushimi Inari Shrine",
|
|
625
|
+
landmarkZh: "伏见稻荷大社",
|
|
626
|
+
timezone: "Asia/Tokyo",
|
|
627
|
+
landscapeUrl: "https://images.unsplash.com/photo-1478436127897-769e1b3f0f36"
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
country: "Japan",
|
|
631
|
+
countryZh: "日本",
|
|
632
|
+
city: "Osaka",
|
|
633
|
+
landmark: "Dotonbori",
|
|
634
|
+
landmarkZh: "道顿堀",
|
|
635
|
+
timezone: "Asia/Tokyo",
|
|
636
|
+
landscapeUrl: "https://images.unsplash.com/photo-1590559899731-a382839e5549"
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
country: "South Korea",
|
|
640
|
+
countryZh: "韩国",
|
|
641
|
+
city: "Seoul",
|
|
642
|
+
landmark: "Gyeongbokgung Palace",
|
|
643
|
+
landmarkZh: "景福宫",
|
|
644
|
+
timezone: "Asia/Seoul",
|
|
645
|
+
landscapeUrl: "https://images.unsplash.com/photo-1534274988757-a28bf1a57c17"
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
country: "China",
|
|
649
|
+
countryZh: "中国",
|
|
650
|
+
city: "Shanghai",
|
|
651
|
+
landmark: "The Bund",
|
|
652
|
+
landmarkZh: "外滩",
|
|
653
|
+
timezone: "Asia/Shanghai",
|
|
654
|
+
landscapeUrl: "https://images.unsplash.com/photo-1537531383496-f4749b918caa"
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
country: "China",
|
|
658
|
+
countryZh: "中国",
|
|
659
|
+
city: "Guilin",
|
|
660
|
+
landmark: "Li River",
|
|
661
|
+
landmarkZh: "漓江",
|
|
662
|
+
timezone: "Asia/Shanghai",
|
|
663
|
+
landscapeUrl: "https://images.unsplash.com/photo-1529921879218-f99546d03a50"
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
country: "Thailand",
|
|
667
|
+
countryZh: "泰国",
|
|
668
|
+
city: "Bangkok",
|
|
669
|
+
landmark: "Grand Palace",
|
|
670
|
+
landmarkZh: "大皇宫",
|
|
671
|
+
timezone: "Asia/Bangkok",
|
|
672
|
+
landscapeUrl: "https://images.unsplash.com/photo-1563492065599-3520f775eeed"
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
country: "Vietnam",
|
|
676
|
+
countryZh: "越南",
|
|
677
|
+
city: "Ha Long Bay",
|
|
678
|
+
landmark: "Ha Long Bay",
|
|
679
|
+
landmarkZh: "下龙湾",
|
|
680
|
+
timezone: "Asia/Ho_Chi_Minh",
|
|
681
|
+
landscapeUrl: "https://images.unsplash.com/photo-1528127269322-539801943592"
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
country: "India",
|
|
685
|
+
countryZh: "印度",
|
|
686
|
+
city: "Agra",
|
|
687
|
+
landmark: "Taj Mahal",
|
|
688
|
+
landmarkZh: "泰姬陵",
|
|
689
|
+
timezone: "Asia/Kolkata",
|
|
690
|
+
landscapeUrl: "https://images.unsplash.com/photo-1564507592333-c60657eea523"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
country: "Singapore",
|
|
694
|
+
countryZh: "新加坡",
|
|
695
|
+
city: "Singapore",
|
|
696
|
+
landmark: "Marina Bay Sands",
|
|
697
|
+
landmarkZh: "滨海湾金沙",
|
|
698
|
+
timezone: "Asia/Singapore",
|
|
699
|
+
landscapeUrl: "https://images.unsplash.com/photo-1525625293386-3f8f99389edd"
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
country: "Indonesia",
|
|
703
|
+
countryZh: "印度尼西亚",
|
|
704
|
+
city: "Bali",
|
|
705
|
+
landmark: "Tanah Lot Temple",
|
|
706
|
+
landmarkZh: "海神庙",
|
|
707
|
+
timezone: "Asia/Jakarta",
|
|
708
|
+
landscapeUrl: "https://images.unsplash.com/photo-1537996194471-e657df975ab4"
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
country: "Nepal",
|
|
712
|
+
countryZh: "尼泊尔",
|
|
713
|
+
city: "Kathmandu",
|
|
714
|
+
landmark: "Himalaya Mountains",
|
|
715
|
+
landmarkZh: "喜马拉雅山",
|
|
716
|
+
timezone: "Asia/Kathmandu",
|
|
717
|
+
landscapeUrl: "https://images.unsplash.com/photo-1544735716-392fe2489ffa"
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
country: "UAE",
|
|
721
|
+
countryZh: "阿联酋",
|
|
722
|
+
city: "Dubai",
|
|
723
|
+
landmark: "Burj Khalifa",
|
|
724
|
+
landmarkZh: "哈利法塔",
|
|
725
|
+
timezone: "Asia/Dubai",
|
|
726
|
+
landscapeUrl: "https://images.unsplash.com/photo-1512453979798-5ea266f8880c"
|
|
727
|
+
},
|
|
728
|
+
// 欧洲 (UTC+0 ~ UTC+3)
|
|
729
|
+
{
|
|
730
|
+
country: "UK",
|
|
731
|
+
countryZh: "英国",
|
|
732
|
+
city: "London",
|
|
733
|
+
landmark: "Big Ben",
|
|
734
|
+
landmarkZh: "大本钟",
|
|
735
|
+
timezone: "Europe/London",
|
|
736
|
+
landscapeUrl: "https://images.unsplash.com/photo-1513635269975-59663e0ac1ad"
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
country: "France",
|
|
740
|
+
countryZh: "法国",
|
|
741
|
+
city: "Provence",
|
|
742
|
+
landmark: "Lavender Fields",
|
|
743
|
+
landmarkZh: "薰衣草田",
|
|
744
|
+
timezone: "Europe/Paris",
|
|
745
|
+
landscapeUrl: "https://images.unsplash.com/photo-1499002238440-d264edd596ec"
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
country: "Italy",
|
|
749
|
+
countryZh: "意大利",
|
|
750
|
+
city: "Venice",
|
|
751
|
+
landmark: "Grand Canal",
|
|
752
|
+
landmarkZh: "大运河",
|
|
753
|
+
timezone: "Europe/Rome",
|
|
754
|
+
landscapeUrl: "https://images.unsplash.com/photo-1514890547357-a9ee288728e0"
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
country: "Italy",
|
|
758
|
+
countryZh: "意大利",
|
|
759
|
+
city: "Rome",
|
|
760
|
+
landmark: "Colosseum",
|
|
761
|
+
landmarkZh: "罗马斗兽场",
|
|
762
|
+
timezone: "Europe/Rome",
|
|
763
|
+
landscapeUrl: "https://images.unsplash.com/photo-1552832230-c0197dd311b5"
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
country: "Spain",
|
|
767
|
+
countryZh: "西班牙",
|
|
768
|
+
city: "Barcelona",
|
|
769
|
+
landmark: "Sagrada Familia",
|
|
770
|
+
landmarkZh: "圣家堂",
|
|
771
|
+
timezone: "Europe/Madrid",
|
|
772
|
+
landscapeUrl: "https://images.unsplash.com/photo-1583422409516-2895a77efded"
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
country: "Greece",
|
|
776
|
+
countryZh: "希腊",
|
|
777
|
+
city: "Santorini",
|
|
778
|
+
landmark: "Oia Village",
|
|
779
|
+
landmarkZh: "伊亚小镇",
|
|
780
|
+
timezone: "Europe/Athens",
|
|
781
|
+
landscapeUrl: "https://images.unsplash.com/photo-1613395877344-13d4a8e0d49e"
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
country: "Netherlands",
|
|
785
|
+
countryZh: "荷兰",
|
|
786
|
+
city: "Amsterdam",
|
|
787
|
+
landmark: "Canal Ring",
|
|
788
|
+
landmarkZh: "运河环",
|
|
789
|
+
timezone: "Europe/Amsterdam",
|
|
790
|
+
landscapeUrl: "https://images.unsplash.com/photo-1534351590666-13e3e96b5017"
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
country: "Switzerland",
|
|
794
|
+
countryZh: "瑞士",
|
|
795
|
+
city: "Interlaken",
|
|
796
|
+
landmark: "Swiss Alps",
|
|
797
|
+
landmarkZh: "阿尔卑斯山",
|
|
798
|
+
timezone: "Europe/Zurich",
|
|
799
|
+
landscapeUrl: "https://images.unsplash.com/photo-1531366936337-7c912a4589a7"
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
country: "Norway",
|
|
803
|
+
countryZh: "挪威",
|
|
804
|
+
city: "Tromsø",
|
|
805
|
+
landmark: "Northern Lights",
|
|
806
|
+
landmarkZh: "北极光",
|
|
807
|
+
timezone: "Europe/Oslo",
|
|
808
|
+
landscapeUrl: "https://images.unsplash.com/photo-1483347756197-71ef80e95f73"
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
country: "Iceland",
|
|
812
|
+
countryZh: "冰岛",
|
|
813
|
+
city: "Reykjavik",
|
|
814
|
+
landmark: "Blue Lagoon",
|
|
815
|
+
landmarkZh: "蓝湖温泉",
|
|
816
|
+
timezone: "Atlantic/Reykjavik",
|
|
817
|
+
landscapeUrl: "https://images.unsplash.com/photo-1504829857797-ddff29c27927"
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
country: "Turkey",
|
|
821
|
+
countryZh: "土耳其",
|
|
822
|
+
city: "Cappadocia",
|
|
823
|
+
landmark: "Hot Air Balloons",
|
|
824
|
+
landmarkZh: "热气球",
|
|
825
|
+
timezone: "Europe/Istanbul",
|
|
826
|
+
landscapeUrl: "https://images.unsplash.com/photo-1641128324972-af3212f0f6bd"
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
country: "Russia",
|
|
830
|
+
countryZh: "俄罗斯",
|
|
831
|
+
city: "Moscow",
|
|
832
|
+
landmark: "Red Square",
|
|
833
|
+
landmarkZh: "红场",
|
|
834
|
+
timezone: "Europe/Moscow",
|
|
835
|
+
landscapeUrl: "https://images.unsplash.com/photo-1513326738677-b964603b136d"
|
|
836
|
+
},
|
|
837
|
+
// 非洲 (UTC+0 ~ UTC+3)
|
|
838
|
+
{
|
|
839
|
+
country: "Egypt",
|
|
840
|
+
countryZh: "埃及",
|
|
841
|
+
city: "Giza",
|
|
842
|
+
landmark: "Pyramids of Giza",
|
|
843
|
+
landmarkZh: "吉萨金字塔",
|
|
844
|
+
timezone: "Africa/Cairo",
|
|
845
|
+
landscapeUrl: "https://images.unsplash.com/photo-1503177119275-0aa32b3a9368"
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
country: "Morocco",
|
|
849
|
+
countryZh: "摩洛哥",
|
|
850
|
+
city: "Marrakech",
|
|
851
|
+
landmark: "Jardin Majorelle",
|
|
852
|
+
landmarkZh: "马约尔花园",
|
|
853
|
+
timezone: "Africa/Casablanca",
|
|
854
|
+
landscapeUrl: "https://images.unsplash.com/photo-1489749798305-4fea3ae63d43"
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
country: "South Africa",
|
|
858
|
+
countryZh: "南非",
|
|
859
|
+
city: "Cape Town",
|
|
860
|
+
landmark: "Table Mountain",
|
|
861
|
+
landmarkZh: "桌山",
|
|
862
|
+
timezone: "Africa/Johannesburg",
|
|
863
|
+
landscapeUrl: "https://images.unsplash.com/photo-1580060839134-75a5edca2e99"
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
country: "Kenya",
|
|
867
|
+
countryZh: "肯尼亚",
|
|
868
|
+
city: "Masai Mara",
|
|
869
|
+
landmark: "Safari Savanna",
|
|
870
|
+
landmarkZh: "马赛马拉草原",
|
|
871
|
+
timezone: "Africa/Nairobi",
|
|
872
|
+
landscapeUrl: "https://images.unsplash.com/photo-1547970810-dc1eac37d174"
|
|
873
|
+
},
|
|
874
|
+
// 北美洲 (UTC-5 ~ UTC-8)
|
|
875
|
+
{
|
|
876
|
+
country: "USA",
|
|
877
|
+
countryZh: "美国",
|
|
878
|
+
city: "New York",
|
|
879
|
+
landmark: "Times Square",
|
|
880
|
+
landmarkZh: "时代广场",
|
|
881
|
+
timezone: "America/New_York",
|
|
882
|
+
landscapeUrl: "https://images.unsplash.com/photo-1534430480872-3498386e7856"
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
country: "USA",
|
|
886
|
+
countryZh: "美国",
|
|
887
|
+
city: "San Francisco",
|
|
888
|
+
landmark: "Golden Gate Bridge",
|
|
889
|
+
landmarkZh: "金门大桥",
|
|
890
|
+
timezone: "America/Los_Angeles",
|
|
891
|
+
landscapeUrl: "https://images.unsplash.com/photo-1449034446853-66c86144b0ad"
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
country: "USA",
|
|
895
|
+
countryZh: "美国",
|
|
896
|
+
city: "Las Vegas",
|
|
897
|
+
landmark: "The Strip",
|
|
898
|
+
landmarkZh: "拉斯维加斯大道",
|
|
899
|
+
timezone: "America/Los_Angeles",
|
|
900
|
+
landscapeUrl: "https://images.unsplash.com/photo-1605833556294-ea5c7a74f57d"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
country: "USA",
|
|
904
|
+
countryZh: "美国",
|
|
905
|
+
city: "Arizona",
|
|
906
|
+
landmark: "Grand Canyon",
|
|
907
|
+
landmarkZh: "大峡谷",
|
|
908
|
+
timezone: "America/Phoenix",
|
|
909
|
+
landscapeUrl: "https://images.unsplash.com/photo-1474044159687-1ee9f3a51722"
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
country: "Canada",
|
|
913
|
+
countryZh: "加拿大",
|
|
914
|
+
city: "Banff",
|
|
915
|
+
landmark: "Lake Louise",
|
|
916
|
+
landmarkZh: "路易斯湖",
|
|
917
|
+
timezone: "America/Edmonton",
|
|
918
|
+
landscapeUrl: "https://images.unsplash.com/photo-1502085671122-2d218cd434e6"
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
country: "Canada",
|
|
922
|
+
countryZh: "加拿大",
|
|
923
|
+
city: "Niagara Falls",
|
|
924
|
+
landmark: "Niagara Falls",
|
|
925
|
+
landmarkZh: "尼亚加拉瀑布",
|
|
926
|
+
timezone: "America/Toronto",
|
|
927
|
+
landscapeUrl: "https://images.unsplash.com/photo-1489447068241-b3490214e879"
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
country: "Mexico",
|
|
931
|
+
countryZh: "墨西哥",
|
|
932
|
+
city: "Cancun",
|
|
933
|
+
landmark: "Chichen Itza",
|
|
934
|
+
landmarkZh: "奇琴伊察",
|
|
935
|
+
timezone: "America/Cancun",
|
|
936
|
+
landscapeUrl: "https://images.unsplash.com/photo-1518638150340-f706e86654de"
|
|
937
|
+
},
|
|
938
|
+
// 南美洲 (UTC-3 ~ UTC-5)
|
|
939
|
+
{
|
|
940
|
+
country: "Brazil",
|
|
941
|
+
countryZh: "巴西",
|
|
942
|
+
city: "Rio de Janeiro",
|
|
943
|
+
landmark: "Christ the Redeemer",
|
|
944
|
+
landmarkZh: "基督救世主像",
|
|
945
|
+
timezone: "America/Sao_Paulo",
|
|
946
|
+
landscapeUrl: "https://images.unsplash.com/photo-1483729558449-99ef09a8c325"
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
country: "Peru",
|
|
950
|
+
countryZh: "秘鲁",
|
|
951
|
+
city: "Cusco",
|
|
952
|
+
landmark: "Machu Picchu",
|
|
953
|
+
landmarkZh: "马丘比丘",
|
|
954
|
+
timezone: "America/Lima",
|
|
955
|
+
landscapeUrl: "https://images.unsplash.com/photo-1526392060635-9d6019884377"
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
country: "Argentina",
|
|
959
|
+
countryZh: "阿根廷",
|
|
960
|
+
city: "Patagonia",
|
|
961
|
+
landmark: "Perito Moreno Glacier",
|
|
962
|
+
landmarkZh: "莫雷诺冰川",
|
|
963
|
+
timezone: "America/Argentina/Buenos_Aires",
|
|
964
|
+
landscapeUrl: "https://images.unsplash.com/photo-1551279880-03041531948f"
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
country: "Chile",
|
|
968
|
+
countryZh: "智利",
|
|
969
|
+
city: "Atacama",
|
|
970
|
+
landmark: "Atacama Desert",
|
|
971
|
+
landmarkZh: "阿塔卡马沙漠",
|
|
972
|
+
timezone: "America/Santiago",
|
|
973
|
+
landscapeUrl: "https://images.unsplash.com/photo-1489392191049-fc10c97e64b6"
|
|
974
|
+
},
|
|
975
|
+
// 大洋洲 (UTC+10 ~ UTC+12)
|
|
976
|
+
{
|
|
977
|
+
country: "Australia",
|
|
978
|
+
countryZh: "澳大利亚",
|
|
979
|
+
city: "Sydney",
|
|
980
|
+
landmark: "Sydney Opera House",
|
|
981
|
+
landmarkZh: "悉尼歌剧院",
|
|
982
|
+
timezone: "Australia/Sydney",
|
|
983
|
+
landscapeUrl: "https://images.unsplash.com/photo-1506973035872-a4ec16b8e8d9"
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
country: "Australia",
|
|
987
|
+
countryZh: "澳大利亚",
|
|
988
|
+
city: "Queensland",
|
|
989
|
+
landmark: "Great Barrier Reef",
|
|
990
|
+
landmarkZh: "大堡礁",
|
|
991
|
+
timezone: "Australia/Brisbane",
|
|
992
|
+
landscapeUrl: "https://images.unsplash.com/photo-1559128010-7c1ad6e1b6a5"
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
country: "New Zealand",
|
|
996
|
+
countryZh: "新西兰",
|
|
997
|
+
city: "Queenstown",
|
|
998
|
+
landmark: "Milford Sound",
|
|
999
|
+
landmarkZh: "米尔福德峡湾",
|
|
1000
|
+
timezone: "Pacific/Auckland",
|
|
1001
|
+
landscapeUrl: "https://images.unsplash.com/photo-1507699622108-4be3abd695ad"
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
country: "New Zealand",
|
|
1005
|
+
countryZh: "新西兰",
|
|
1006
|
+
city: "Matamata",
|
|
1007
|
+
landmark: "Hobbiton",
|
|
1008
|
+
landmarkZh: "霍比屯",
|
|
1009
|
+
timezone: "Pacific/Auckland",
|
|
1010
|
+
landscapeUrl: "https://images.unsplash.com/photo-1507097634215-e82e6b552cae"
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
country: "Fiji",
|
|
1014
|
+
countryZh: "斐济",
|
|
1015
|
+
city: "Nadi",
|
|
1016
|
+
landmark: "Fiji Islands",
|
|
1017
|
+
landmarkZh: "斐济群岛",
|
|
1018
|
+
timezone: "Pacific/Fiji",
|
|
1019
|
+
landscapeUrl: "https://images.unsplash.com/photo-1589179899031-d86b7e3fcd61"
|
|
1000
1020
|
}
|
|
1001
|
-
|
|
1002
|
-
__name(generateFootprintCard, "generateFootprintCard");
|
|
1003
|
-
function escapeHtml(text) {
|
|
1004
|
-
const map = {
|
|
1005
|
-
"&": "&",
|
|
1006
|
-
"<": "<",
|
|
1007
|
-
">": ">",
|
|
1008
|
-
'"': """,
|
|
1009
|
-
"'": "'"
|
|
1010
|
-
};
|
|
1011
|
-
return text.replace(/[&<>"']/g, (m) => map[m]);
|
|
1012
|
-
}
|
|
1013
|
-
__name(escapeHtml, "escapeHtml");
|
|
1021
|
+
];
|
|
1014
1022
|
|
|
1015
1023
|
// src/services/location.ts
|
|
1016
1024
|
var import_messages = require("@langchain/core/messages");
|
|
@@ -1040,7 +1048,12 @@ async function searchUnsplashPhoto(ctx, accessKey, query, debug = false) {
|
|
|
1040
1048
|
}
|
|
1041
1049
|
);
|
|
1042
1050
|
if (response.results && response.results.length > 0) {
|
|
1043
|
-
|
|
1051
|
+
let photoUrl = response.results[0].urls.regular;
|
|
1052
|
+
if (photoUrl.includes("?")) {
|
|
1053
|
+
photoUrl += "&fm=webp&q=85";
|
|
1054
|
+
} else {
|
|
1055
|
+
photoUrl += "?fm=webp&q=85";
|
|
1056
|
+
}
|
|
1044
1057
|
if (debug) ctx.logger("pig").debug(`Unsplash: Found photo URL: ${photoUrl}`);
|
|
1045
1058
|
return photoUrl;
|
|
1046
1059
|
}
|
|
@@ -1287,29 +1300,43 @@ __name(triggerTravelSequence, "triggerTravelSequence");
|
|
|
1287
1300
|
|
|
1288
1301
|
// src/config.ts
|
|
1289
1302
|
var import_koishi = require("koishi");
|
|
1290
|
-
var Config = import_koishi.Schema.
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1303
|
+
var Config = import_koishi.Schema.intersect([
|
|
1304
|
+
import_koishi.Schema.object({
|
|
1305
|
+
outputMode: import_koishi.Schema.union(["text", "image"]).default("image").description("输出模式:text 纯文本,image 生成精美卡片"),
|
|
1306
|
+
emojiFont: import_koishi.Schema.union([
|
|
1307
|
+
import_koishi.Schema.const("System").description("系统默认"),
|
|
1308
|
+
import_koishi.Schema.const("Noto Color Emoji").description("Noto Color Emoji"),
|
|
1309
|
+
import_koishi.Schema.const("Twemoji").description("Twemoji (Twitter Emoji)")
|
|
1310
|
+
]).default("System").description("Emoji 字体偏好(需确保容器内已安装相应字体)"),
|
|
1311
|
+
travelMessageTemplate: import_koishi.Schema.string().default("去了 {landmark},{country}!📸").description("旅行消息模板(可用变量:{landmark} 地标名, {country} 国家名)")
|
|
1312
|
+
}).description("基础设置"),
|
|
1313
|
+
import_koishi.Schema.object({
|
|
1314
|
+
llmLocationEnabled: import_koishi.Schema.boolean().default(false).description("启用后使用 LLM 动态生成全球旅行地点,关闭则使用预设地点库"),
|
|
1315
|
+
llmLocationModel: import_koishi.Schema.dynamic("model").description("用于生成地点的模型(推荐使用快速模型如 gemini-flash)"),
|
|
1316
|
+
unsplashAccessKey: import_koishi.Schema.string().role("secret").default("").description("用于获取高质量风景背景图(从 unsplash.com/developers 免费申请)")
|
|
1317
|
+
}).description("地点与图片 🌍"),
|
|
1318
|
+
import_koishi.Schema.object({
|
|
1319
|
+
aigcEnabled: import_koishi.Schema.boolean().default(false).description("启用后使用 AI 生成小猪旅行插画(需要 media-luna 插件)"),
|
|
1320
|
+
aigcChannel: import_koishi.Schema.string().default("").description("media-luna 渠道名称"),
|
|
1321
|
+
aigcPrompt: import_koishi.Schema.string().role("textarea").default("一个可爱的卡通小猪正在 {country} 的 {landmark} 前面自拍,阳光明媚,旅游照片风格").description("AI 生图提示词模板")
|
|
1322
|
+
}).description("AI 生图(可选)🎨"),
|
|
1323
|
+
import_koishi.Schema.object({
|
|
1324
|
+
experimentalAutoDetect: import_koishi.Schema.boolean().default(false).description("自动检测用户首条消息并判断作息是否异常"),
|
|
1325
|
+
sunriseApi: import_koishi.Schema.string().default("https://api.sunrise-sunset.org/json").description("日出日落 API 地址"),
|
|
1326
|
+
defaultLat: import_koishi.Schema.number().default(30).description("默认纬度(北纬为正)"),
|
|
1327
|
+
defaultLng: import_koishi.Schema.number().default(120).description("默认经度(东经为正)"),
|
|
1328
|
+
abnormalThreshold: import_koishi.Schema.number().default(3).description("作息异常判定阈值(小时)")
|
|
1329
|
+
}).description("自动检测(实验性)🧪"),
|
|
1330
|
+
import_koishi.Schema.object({
|
|
1331
|
+
useStorageService: import_koishi.Schema.boolean().default(true).description("使用 chatluna-storage-service 缓存图片(推荐)"),
|
|
1332
|
+
storageCacheHours: import_koishi.Schema.number().default(24).description("图片缓存时间(小时)"),
|
|
1333
|
+
logRetentionDays: import_koishi.Schema.number().default(45).description("旅行记录保留天数"),
|
|
1334
|
+
logPath: import_koishi.Schema.string().default("./data/pig/logs").description("本地日志存储路径(仅在不使用存储服务时生效)")
|
|
1335
|
+
}).description("存储设置 💾"),
|
|
1336
|
+
import_koishi.Schema.object({
|
|
1337
|
+
debug: import_koishi.Schema.boolean().default(false).description("输出详细调试日志")
|
|
1338
|
+
}).description("调试")
|
|
1339
|
+
]);
|
|
1313
1340
|
|
|
1314
1341
|
// src/index.ts
|
|
1315
1342
|
var name = "my-pig-group-friends";
|
|
@@ -1339,9 +1366,17 @@ function apply(ctx, config) {
|
|
|
1339
1366
|
if (config.useStorageService && !ctx.chatluna_storage) {
|
|
1340
1367
|
ctx.logger("pig").warn("useStorageService 已启用但 chatluna_storage 服务不可用,将回退到 base64 模式");
|
|
1341
1368
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1369
|
+
const travelLocks = /* @__PURE__ */ new Map();
|
|
1370
|
+
const LOCK_DURATION_MS = 60 * 1e3;
|
|
1371
|
+
ctx.command("pig [user:user]", "虚拟旅行").alias("猪醒").action(async ({ session }, user) => {
|
|
1372
|
+
let platform;
|
|
1373
|
+
let userId;
|
|
1374
|
+
if (user) {
|
|
1375
|
+
[platform, userId] = user.split(":");
|
|
1376
|
+
} else {
|
|
1377
|
+
platform = session.platform;
|
|
1378
|
+
userId = session.userId;
|
|
1379
|
+
}
|
|
1345
1380
|
let userInfo;
|
|
1346
1381
|
if (session?.userId === userId) {
|
|
1347
1382
|
userInfo = {
|
|
@@ -1350,18 +1385,55 @@ function apply(ctx, config) {
|
|
|
1350
1385
|
avatarUrl: session.author?.avatar || ""
|
|
1351
1386
|
};
|
|
1352
1387
|
} else {
|
|
1388
|
+
let avatarUrl = "";
|
|
1389
|
+
let username = userId;
|
|
1390
|
+
try {
|
|
1391
|
+
if (platform === "onebot") {
|
|
1392
|
+
avatarUrl = `https://q.qlogo.cn/headimg_dl?dst_uin=${userId}&spec=640`;
|
|
1393
|
+
}
|
|
1394
|
+
if (session.bot) {
|
|
1395
|
+
if (session.guildId && session.bot.getGuildMember) {
|
|
1396
|
+
try {
|
|
1397
|
+
const member = await session.bot.getGuildMember(session.guildId, userId);
|
|
1398
|
+
username = member.nick || member.name || member.user?.name || username;
|
|
1399
|
+
avatarUrl = avatarUrl || member.user?.avatar || "";
|
|
1400
|
+
} catch (e) {
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (username === userId && session.bot.getUser) {
|
|
1404
|
+
try {
|
|
1405
|
+
const user2 = await session.bot.getUser(userId);
|
|
1406
|
+
username = user2.name || username;
|
|
1407
|
+
avatarUrl = avatarUrl || user2.avatar || "";
|
|
1408
|
+
} catch (e) {
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
} catch (e) {
|
|
1413
|
+
ctx.logger("pig").warn(`Failed to fetch metadata for user ${userId}: ${e}`);
|
|
1414
|
+
}
|
|
1353
1415
|
userInfo = {
|
|
1354
1416
|
userId,
|
|
1355
|
-
username
|
|
1356
|
-
avatarUrl
|
|
1417
|
+
username,
|
|
1418
|
+
avatarUrl
|
|
1357
1419
|
};
|
|
1358
1420
|
}
|
|
1359
1421
|
const result = await triggerTravelSequence(ctx, config, userInfo, platform);
|
|
1360
1422
|
return formatTravelMessage(result, userId, config);
|
|
1361
1423
|
});
|
|
1362
1424
|
ctx.middleware(async (session, next) => {
|
|
1425
|
+
if (!config.experimentalAutoDetect) return next();
|
|
1363
1426
|
if (!session.userId || !session.content) return next();
|
|
1364
|
-
const
|
|
1427
|
+
const lockKey = `${session.platform}:${session.userId}`;
|
|
1428
|
+
const now = Date.now();
|
|
1429
|
+
const lockTime = travelLocks.get(lockKey);
|
|
1430
|
+
if (lockTime && now - lockTime < LOCK_DURATION_MS) {
|
|
1431
|
+
if (config.debug) {
|
|
1432
|
+
ctx.logger("pig").debug(`用户 ${session.userId} 处于锁定期,跳过自动检测`);
|
|
1433
|
+
}
|
|
1434
|
+
return next();
|
|
1435
|
+
}
|
|
1436
|
+
const nowDate = /* @__PURE__ */ new Date();
|
|
1365
1437
|
const [userState] = await ctx.database.get("pig_user_state", {
|
|
1366
1438
|
userId: session.userId,
|
|
1367
1439
|
platform: session.platform
|
|
@@ -1371,10 +1443,17 @@ function apply(ctx, config) {
|
|
|
1371
1443
|
try {
|
|
1372
1444
|
const sunriseInfo = await getSunriseInfo(ctx, lat, lng);
|
|
1373
1445
|
const dayStart = new Date(sunriseInfo.sunrise.getTime() - 2 * 60 * 60 * 1e3);
|
|
1374
|
-
if (
|
|
1446
|
+
if (nowDate >= dayStart && (!userState?.lastWakeUp || userState.lastWakeUp < dayStart)) {
|
|
1447
|
+
await ctx.database.upsert("pig_user_state", [{
|
|
1448
|
+
userId: session.userId,
|
|
1449
|
+
platform: session.platform,
|
|
1450
|
+
lastWakeUp: nowDate,
|
|
1451
|
+
lastSunrise: sunriseInfo.sunrise
|
|
1452
|
+
}], ["platform", "userId"]);
|
|
1375
1453
|
if (userState?.lastWakeUp) {
|
|
1376
|
-
const diffHours = Math.abs((
|
|
1454
|
+
const diffHours = Math.abs((nowDate.getTime() - userState.lastWakeUp.getTime() - 24 * 60 * 60 * 1e3) / (1e3 * 60 * 60));
|
|
1377
1455
|
if (diffHours > config.abnormalThreshold) {
|
|
1456
|
+
travelLocks.set(lockKey, now);
|
|
1378
1457
|
await session.send(`检测到 ${import_koishi2.segment.at(session.userId)} 作息异常(差异: ${diffHours.toFixed(1)}小时),准备虚拟旅行...`);
|
|
1379
1458
|
const userInfo = {
|
|
1380
1459
|
userId: session.userId,
|
|
@@ -1385,12 +1464,6 @@ function apply(ctx, config) {
|
|
|
1385
1464
|
await session.send(formatTravelMessage(result, session.userId, config));
|
|
1386
1465
|
}
|
|
1387
1466
|
}
|
|
1388
|
-
await ctx.database.upsert("pig_user_state", [{
|
|
1389
|
-
userId: session.userId,
|
|
1390
|
-
platform: session.platform,
|
|
1391
|
-
lastWakeUp: now,
|
|
1392
|
-
lastSunrise: sunriseInfo.sunrise
|
|
1393
|
-
}]);
|
|
1394
1467
|
}
|
|
1395
1468
|
} catch (e) {
|
|
1396
1469
|
ctx.logger("pig").error("Failed to process wake-up detection:", e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-my-pig-group-friends",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -21,13 +21,18 @@
|
|
|
21
21
|
},
|
|
22
22
|
"koishi": {
|
|
23
23
|
"description": {
|
|
24
|
-
"zh": "
|
|
24
|
+
"zh": "猪醒 - 虚拟旅行打卡插件,让你的猪猪群友环游世界"
|
|
25
25
|
},
|
|
26
26
|
"service": {
|
|
27
27
|
"required": [
|
|
28
28
|
"database",
|
|
29
|
-
"cron"
|
|
29
|
+
"cron",
|
|
30
|
+
"puppeteer"
|
|
31
|
+
],
|
|
32
|
+
"optional": [
|
|
33
|
+
"chatluna",
|
|
34
|
+
"chatluna_storage"
|
|
30
35
|
]
|
|
31
36
|
}
|
|
32
37
|
}
|
|
33
|
-
}
|
|
38
|
+
}
|