koishi-plugin-aka-60s-api 0.2.8 → 0.2.9
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/lib/index.js +23 -11
- package/package.json +1 -1
- package/lib/index.js.backup +0 -1027
package/lib/index.js
CHANGED
|
@@ -38,25 +38,25 @@ var Config = import_koishi.Schema.intersect([
|
|
|
38
38
|
}).description("基础设置"),
|
|
39
39
|
import_koishi.Schema.object({
|
|
40
40
|
enableSchedule: import_koishi.Schema.boolean().default(false).description("启用定时发送新闻"),
|
|
41
|
-
scheduleTime: import_koishi.Schema.string().default("08:00").description("定时发送时间 (格式: HH:MM
|
|
41
|
+
scheduleTime: import_koishi.Schema.string().default("08:00").description("定时发送时间 (格式: HH:MM 或 HH:MM / Nd,如 08:00 或 08:00 / 1d,表示每天或每N天的固定时间)"),
|
|
42
42
|
useForward: import_koishi.Schema.boolean().default(false).description("是否使用合并转发(仅QQ平台效果最佳)")
|
|
43
43
|
}).description("每日新闻"),
|
|
44
44
|
import_koishi.Schema.object({
|
|
45
45
|
enableAiNewsSchedule: import_koishi.Schema.boolean().default(false).description("启用AI快报定时发送(仅当天)"),
|
|
46
|
-
aiNewsScheduleTime: import_koishi.Schema.string().default("22:00").description("AI快报定时发送时间 (格式: HH:MM
|
|
46
|
+
aiNewsScheduleTime: import_koishi.Schema.string().default("22:00").description("AI快报定时发送时间 (格式: HH:MM 或 HH:MM / Nd,如 22:00 或 22:00 / 1d)"),
|
|
47
47
|
aiUseForward: import_koishi.Schema.boolean().default(false).description("AI快报是否使用合并转发(仅QQ平台效果最佳)")
|
|
48
48
|
}).description("AI快报"),
|
|
49
49
|
import_koishi.Schema.object({
|
|
50
50
|
enableMoyuSchedule: import_koishi.Schema.boolean().default(false).description("启用摸鱼日报定时发送"),
|
|
51
|
-
moyuScheduleTime: import_koishi.Schema.string().default("10:00").description("摸鱼日报定时发送时间 (格式: HH:MM
|
|
51
|
+
moyuScheduleTime: import_koishi.Schema.string().default("10:00").description("摸鱼日报定时发送时间 (格式: HH:MM 或 HH:MM / Nd,如 10:00 或 10:00 / 1d)")
|
|
52
52
|
}).description("摸鱼日报"),
|
|
53
53
|
import_koishi.Schema.object({
|
|
54
54
|
enableGoldSchedule: import_koishi.Schema.boolean().default(false).description("启用今日金价定时发送"),
|
|
55
|
-
goldScheduleTime: import_koishi.Schema.string().default("09:00").description("今日金价定时发送时间 (格式: HH:MM
|
|
55
|
+
goldScheduleTime: import_koishi.Schema.string().default("09:00").description("今日金价定时发送时间 (格式: HH:MM 或 HH:MM / Nd,如 09:00 或 09:00 / 1d)")
|
|
56
56
|
}).description("今日金价"),
|
|
57
57
|
import_koishi.Schema.object({
|
|
58
58
|
enableFuelSchedule: import_koishi.Schema.boolean().default(false).description("启用今日油价定时发送"),
|
|
59
|
-
fuelScheduleTime: import_koishi.Schema.string().default("09:30").description("今日油价定时发送时间 (格式: HH:MM
|
|
59
|
+
fuelScheduleTime: import_koishi.Schema.string().default("09:30").description("今日油价定时发送时间 (格式: HH:MM 或 HH:MM / Nd,如 09:30 或 09:30 / 1d)"),
|
|
60
60
|
fuelDefaultRegion: import_koishi.Schema.string().default("上海").description("今日油价默认地区")
|
|
61
61
|
}).description("今日油价")
|
|
62
62
|
]);
|
|
@@ -455,7 +455,8 @@ ${newsItem.link}`).join("\n\n");
|
|
|
455
455
|
}
|
|
456
456
|
__name(sendMoyuToChannels, "sendMoyuToChannels");
|
|
457
457
|
function formatGoldText(data) {
|
|
458
|
-
const
|
|
458
|
+
const targetKeywords = ["黄金", "伦敦金", "白银", "钯金"];
|
|
459
|
+
const metals = data.metals.filter((item) => targetKeywords.some((keyword) => item.name.includes(keyword))).map((item) => {
|
|
459
460
|
return `${item.name}: ${item.today_price}${item.unit}`;
|
|
460
461
|
});
|
|
461
462
|
return [
|
|
@@ -529,17 +530,21 @@ ${newsItem.link}`).join("\n\n");
|
|
|
529
530
|
}
|
|
530
531
|
__name(sendFuelToChannels, "sendFuelToChannels");
|
|
531
532
|
function getMsUntilNextTime(timeStr) {
|
|
532
|
-
const
|
|
533
|
-
|
|
533
|
+
const trimmedTimeStr = timeStr.trim();
|
|
534
|
+
const fullPattern = /^([0-1]?\d|2[0-3]):([0-5]\d)\s*(?:\/\s*(\d+)\s*d)?$/;
|
|
535
|
+
const match = trimmedTimeStr.match(fullPattern);
|
|
536
|
+
if (!match) {
|
|
534
537
|
logError("60s API: 时间格式无效,跳过今天", { timeStr });
|
|
535
538
|
return null;
|
|
536
539
|
}
|
|
537
|
-
const
|
|
540
|
+
const hours = parseInt(match[1], 10);
|
|
541
|
+
const minutes = parseInt(match[2], 10);
|
|
542
|
+
const daysInterval = match[3] ? parseInt(match[3], 10) : 1;
|
|
538
543
|
const now = /* @__PURE__ */ new Date();
|
|
539
544
|
const target = /* @__PURE__ */ new Date();
|
|
540
545
|
target.setHours(hours, minutes, 0, 0);
|
|
541
546
|
if (target <= now) {
|
|
542
|
-
target.setDate(target.getDate() +
|
|
547
|
+
target.setDate(target.getDate() + daysInterval);
|
|
543
548
|
}
|
|
544
549
|
const msUntilNext = target.getTime() - now.getTime();
|
|
545
550
|
if (!isFinite(msUntilNext) || msUntilNext <= 0) {
|
|
@@ -550,7 +555,14 @@ ${newsItem.link}`).join("\n\n");
|
|
|
550
555
|
}
|
|
551
556
|
__name(getMsUntilNextTime, "getMsUntilNextTime");
|
|
552
557
|
function isTimePassedToday(timeStr) {
|
|
553
|
-
const
|
|
558
|
+
const trimmedTimeStr = timeStr.trim();
|
|
559
|
+
const fullPattern = /^([0-1]?\d|2[0-3]):([0-5]\d)\s*(?:\/\s*(\d+)\s*d)?$/;
|
|
560
|
+
const match = trimmedTimeStr.match(fullPattern);
|
|
561
|
+
if (!match) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
const hours = parseInt(match[1], 10);
|
|
565
|
+
const minutes = parseInt(match[2], 10);
|
|
554
566
|
const now = /* @__PURE__ */ new Date();
|
|
555
567
|
const target = /* @__PURE__ */ new Date();
|
|
556
568
|
target.setHours(hours, minutes, 0, 0);
|
package/package.json
CHANGED
package/lib/index.js.backup
DELETED
|
@@ -1,1027 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name2 in all)
|
|
8
|
-
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var src_exports = {};
|
|
22
|
-
__export(src_exports, {
|
|
23
|
-
Config: () => Config,
|
|
24
|
-
apply: () => apply,
|
|
25
|
-
inject: () => inject,
|
|
26
|
-
name: () => name
|
|
27
|
-
});
|
|
28
|
-
module.exports = __toCommonJS(src_exports);
|
|
29
|
-
var import_koishi = require("koishi");
|
|
30
|
-
var name = "aka-60s-api";
|
|
31
|
-
var inject = ["database"];
|
|
32
|
-
var Config = import_koishi.Schema.intersect([
|
|
33
|
-
import_koishi.Schema.object({
|
|
34
|
-
apiBaseUrl: import_koishi.Schema.string().default("http://172.0.0.1:4399").description("60s 服务 URL(不含 /v2 路径)"),
|
|
35
|
-
cooldownTime: import_koishi.Schema.number().default(30).min(5).max(300).description("冷却时间(秒)"),
|
|
36
|
-
enableLog: import_koishi.Schema.boolean().default(true).description("启用日志记录"),
|
|
37
|
-
scheduleWhitelist: import_koishi.Schema.array(String).default([]).description("定时发送群组白名单频道ID列表(为空=不发送)")
|
|
38
|
-
}).description("基础设置"),
|
|
39
|
-
import_koishi.Schema.object({
|
|
40
|
-
enableSchedule: import_koishi.Schema.boolean().default(false).description("启用定时发送新闻"),
|
|
41
|
-
scheduleTime: import_koishi.Schema.string().default("08:00 / 1d").description("定时发送时间 (格式: HH:MM / 1d)"),
|
|
42
|
-
useForward: import_koishi.Schema.boolean().default(false).description("是否使用合并转发(仅QQ平台效果最佳)")
|
|
43
|
-
}).description("每日新闻"),
|
|
44
|
-
import_koishi.Schema.object({
|
|
45
|
-
enableAiNewsSchedule: import_koishi.Schema.boolean().default(false).description("启用AI快报定时发送(仅当天)"),
|
|
46
|
-
aiNewsScheduleTime: import_koishi.Schema.string().default("22:00 / 1d").description("AI快报定时发送时间 (格式: HH:MM / 1d)"),
|
|
47
|
-
aiUseForward: import_koishi.Schema.boolean().default(false).description("AI快报是否使用合并转发(仅QQ平台效果最佳)")
|
|
48
|
-
}).description("AI快报"),
|
|
49
|
-
import_koishi.Schema.object({
|
|
50
|
-
enableMoyuSchedule: import_koishi.Schema.boolean().default(false).description("启用摸鱼日报定时发送"),
|
|
51
|
-
moyuScheduleTime: import_koishi.Schema.string().default("10:00 / 1d").description("摸鱼日报定时发送时间 (格式: HH:MM / 1d)")
|
|
52
|
-
}).description("摸鱼日报"),
|
|
53
|
-
import_koishi.Schema.object({
|
|
54
|
-
enableGoldSchedule: import_koishi.Schema.boolean().default(false).description("启用今日金价定时发送"),
|
|
55
|
-
goldScheduleTime: import_koishi.Schema.string().default("09:00 / 1d").description("今日金价定时发送时间 (格式: HH:MM / 1d)")
|
|
56
|
-
}).description("今日金价"),
|
|
57
|
-
import_koishi.Schema.object({
|
|
58
|
-
enableFuelSchedule: import_koishi.Schema.boolean().default(false).description("启用今日油价定时发送"),
|
|
59
|
-
fuelScheduleTime: import_koishi.Schema.string().default("09:30 / 1d").description("今日油价定时发送时间 (格式: HH:MM / 1d)"),
|
|
60
|
-
fuelDefaultRegion: import_koishi.Schema.string().default("上海").description("今日油价默认地区")
|
|
61
|
-
}).description("今日油价")
|
|
62
|
-
]);
|
|
63
|
-
function apply(ctx, config) {
|
|
64
|
-
const logger = ctx.logger("aka-60s-api");
|
|
65
|
-
const normalizedApiBaseUrl = (config.apiBaseUrl || "http://172.0.0.1:4399").replace(/\/$/, "");
|
|
66
|
-
const buildApiUrl = /* @__PURE__ */ __name((path) => `${normalizedApiBaseUrl}${path}`, "buildApiUrl");
|
|
67
|
-
const cooldowns = /* @__PURE__ */ new Map();
|
|
68
|
-
let scheduleInterval = null;
|
|
69
|
-
let aiNewsScheduleInterval = null;
|
|
70
|
-
let moyuScheduleInterval = null;
|
|
71
|
-
let goldScheduleInterval = null;
|
|
72
|
-
let fuelScheduleInterval = null;
|
|
73
|
-
async function resolveGroupScheduleChannels(whitelist, tag) {
|
|
74
|
-
try {
|
|
75
|
-
if (!whitelist.length) {
|
|
76
|
-
logInfo("60s API: 未配置定时发送白名单", { tag });
|
|
77
|
-
return [];
|
|
78
|
-
}
|
|
79
|
-
const assigned = await ctx.database.getAssignedChannels(["id", "platform", "guildId"]);
|
|
80
|
-
const groupChannels = assigned.filter((channel) => !!channel.guildId).map((channel) => `${channel.platform}:${channel.id}`);
|
|
81
|
-
if (!groupChannels.length) {
|
|
82
|
-
logInfo("60s API: 没有可发送的群组频道", { tag });
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
85
|
-
const whitelistSet = new Set(whitelist);
|
|
86
|
-
const targets = groupChannels.filter((channelId) => whitelistSet.has(channelId));
|
|
87
|
-
if (!targets.length) {
|
|
88
|
-
logInfo("60s API: 白名单未命中任何已加入群组频道", { tag });
|
|
89
|
-
}
|
|
90
|
-
return targets;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
logError("60s API: 获取群组频道失败", { tag, error });
|
|
93
|
-
return [];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
__name(resolveGroupScheduleChannels, "resolveGroupScheduleChannels");
|
|
97
|
-
function logInfo(message, data) {
|
|
98
|
-
if (config.enableLog && logger) {
|
|
99
|
-
logger.info(message, data);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
__name(logInfo, "logInfo");
|
|
103
|
-
function logError(message, error) {
|
|
104
|
-
if (config.enableLog && logger) {
|
|
105
|
-
logger.error(message, error);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
__name(logError, "logError");
|
|
109
|
-
function checkCooldown(userId) {
|
|
110
|
-
const now = Date.now();
|
|
111
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
112
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
113
|
-
if (timeLeft > 0) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
cooldowns.set(userId, now);
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
__name(checkCooldown, "checkCooldown");
|
|
120
|
-
async function get60sNewsImage() {
|
|
121
|
-
try {
|
|
122
|
-
logInfo("60s API: 开始获取新闻图片");
|
|
123
|
-
const response = await ctx.http.get(buildApiUrl("/v2/60s"), {
|
|
124
|
-
params: {
|
|
125
|
-
encoding: "image"
|
|
126
|
-
},
|
|
127
|
-
timeout: 3e4,
|
|
128
|
-
responseType: "arraybuffer"
|
|
129
|
-
});
|
|
130
|
-
const buffer = Buffer.from(response);
|
|
131
|
-
logInfo("60s API: 获取新闻图片成功", {
|
|
132
|
-
size: buffer.length
|
|
133
|
-
});
|
|
134
|
-
return buffer;
|
|
135
|
-
} catch (error) {
|
|
136
|
-
logError("60s API: 获取新闻图片失败", error);
|
|
137
|
-
throw error;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
__name(get60sNewsImage, "get60sNewsImage");
|
|
141
|
-
async function getTodayInHistory() {
|
|
142
|
-
try {
|
|
143
|
-
logInfo("60s API: 开始获取历史上的今天");
|
|
144
|
-
const response = await ctx.http.get(buildApiUrl("/v2/today-in-history"), {
|
|
145
|
-
params: {
|
|
146
|
-
encoding: "json"
|
|
147
|
-
},
|
|
148
|
-
timeout: 3e4
|
|
149
|
-
});
|
|
150
|
-
logInfo("60s API: 获取历史上的今天成功", {
|
|
151
|
-
code: response.code,
|
|
152
|
-
hasData: !!response.data,
|
|
153
|
-
itemsCount: response.data?.items?.length || 0
|
|
154
|
-
});
|
|
155
|
-
return response;
|
|
156
|
-
} catch (error) {
|
|
157
|
-
logError("60s API: 获取历史上的今天失败", error);
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
__name(getTodayInHistory, "getTodayInHistory");
|
|
162
|
-
async function getZhihuTrends() {
|
|
163
|
-
try {
|
|
164
|
-
logInfo("60s API: 开始获取知乎话题榜");
|
|
165
|
-
const response = await ctx.http.get(buildApiUrl("/v2/zhihu"), {
|
|
166
|
-
params: {
|
|
167
|
-
encoding: "json"
|
|
168
|
-
},
|
|
169
|
-
timeout: 3e4
|
|
170
|
-
});
|
|
171
|
-
logInfo("60s API: 获取知乎话题榜成功", {
|
|
172
|
-
code: response.code,
|
|
173
|
-
hasData: !!response.data,
|
|
174
|
-
topicsCount: response.data?.length || 0
|
|
175
|
-
});
|
|
176
|
-
return response;
|
|
177
|
-
} catch (error) {
|
|
178
|
-
logError("60s API: 获取知乎话题榜失败", error);
|
|
179
|
-
throw error;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
__name(getZhihuTrends, "getZhihuTrends");
|
|
183
|
-
async function getAiNews(params) {
|
|
184
|
-
try {
|
|
185
|
-
logInfo("60s API: 开始获取AI快报", params);
|
|
186
|
-
const response = await ctx.http.get(buildApiUrl("/v2/ai-news"), {
|
|
187
|
-
params: {
|
|
188
|
-
date: params.date,
|
|
189
|
-
all: params.all,
|
|
190
|
-
encoding: params.encoding || "text"
|
|
191
|
-
},
|
|
192
|
-
timeout: 3e4
|
|
193
|
-
});
|
|
194
|
-
logInfo("60s API: 获取AI快报成功");
|
|
195
|
-
return response;
|
|
196
|
-
} catch (error) {
|
|
197
|
-
logError("60s API: 获取AI快报失败", error);
|
|
198
|
-
throw error;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
__name(getAiNews, "getAiNews");
|
|
202
|
-
async function getMoyuDaily(encoding = "text") {
|
|
203
|
-
try {
|
|
204
|
-
logInfo("60s API: 开始获取摸鱼日报", { encoding });
|
|
205
|
-
const response = await ctx.http.get(buildApiUrl("/v2/moyu"), {
|
|
206
|
-
params: {
|
|
207
|
-
encoding
|
|
208
|
-
},
|
|
209
|
-
timeout: 3e4
|
|
210
|
-
});
|
|
211
|
-
logInfo("60s API: 获取摸鱼日报成功");
|
|
212
|
-
return response;
|
|
213
|
-
} catch (error) {
|
|
214
|
-
logError("60s API: 获取摸鱼日报失败", error);
|
|
215
|
-
throw error;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
__name(getMoyuDaily, "getMoyuDaily");
|
|
219
|
-
async function getGoldPrice(encoding = "text") {
|
|
220
|
-
try {
|
|
221
|
-
logInfo("60s API: 开始获取今日金价", { encoding });
|
|
222
|
-
const response = await ctx.http.get(buildApiUrl("/v2/gold-price"), {
|
|
223
|
-
params: {
|
|
224
|
-
encoding
|
|
225
|
-
},
|
|
226
|
-
timeout: 3e4
|
|
227
|
-
});
|
|
228
|
-
logInfo("60s API: 获取今日金价成功");
|
|
229
|
-
return response;
|
|
230
|
-
} catch (error) {
|
|
231
|
-
logError("60s API: 获取今日金价失败", error);
|
|
232
|
-
throw error;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
__name(getGoldPrice, "getGoldPrice");
|
|
236
|
-
async function getFuelPrice(params) {
|
|
237
|
-
try {
|
|
238
|
-
logInfo("60s API: 开始获取今日油价", params);
|
|
239
|
-
const response = await ctx.http.get(buildApiUrl("/v2/fuel-price"), {
|
|
240
|
-
params: {
|
|
241
|
-
region: params.region,
|
|
242
|
-
encoding: params.encoding || "text"
|
|
243
|
-
},
|
|
244
|
-
timeout: 3e4
|
|
245
|
-
});
|
|
246
|
-
logInfo("60s API: 获取今日油价成功");
|
|
247
|
-
return response;
|
|
248
|
-
} catch (error) {
|
|
249
|
-
logError("60s API: 获取今日油价失败", error);
|
|
250
|
-
throw error;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
__name(getFuelPrice, "getFuelPrice");
|
|
254
|
-
async function sendNewsToChannels() {
|
|
255
|
-
const targetChannels = await resolveGroupScheduleChannels(config.scheduleWhitelist, "news");
|
|
256
|
-
if (targetChannels.length === 0) return;
|
|
257
|
-
try {
|
|
258
|
-
const imageBuffer = await get60sNewsImage();
|
|
259
|
-
const imageMessage = import_koishi.h.image(imageBuffer, "image/png");
|
|
260
|
-
for (const channelId of targetChannels) {
|
|
261
|
-
try {
|
|
262
|
-
await ctx.broadcast([channelId], imageMessage);
|
|
263
|
-
logInfo("60s API: 定时发送新闻成功", { channelId });
|
|
264
|
-
} catch (error) {
|
|
265
|
-
logError("60s API: 定时发送新闻到频道失败", { channelId, error });
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
} catch (error) {
|
|
269
|
-
logError("60s API: 定时发送新闻失败", error);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
__name(sendNewsToChannels, "sendNewsToChannels");
|
|
273
|
-
function formatAiNewsText(data) {
|
|
274
|
-
const items = normalizeAiNewsData(data).flatMap((item) => item.news);
|
|
275
|
-
return items.map((newsItem, index) => `${index + 1}. ${newsItem.title}
|
|
276
|
-
${newsItem.link}`).join("\n\n");
|
|
277
|
-
}
|
|
278
|
-
__name(formatAiNewsText, "formatAiNewsText");
|
|
279
|
-
function formatAiNewsMarkdown(data) {
|
|
280
|
-
const items = normalizeAiNewsData(data).flatMap((item) => item.news);
|
|
281
|
-
return items.map((newsItem) => `- [${newsItem.title}](${newsItem.link})`).join("\n");
|
|
282
|
-
}
|
|
283
|
-
__name(formatAiNewsMarkdown, "formatAiNewsMarkdown");
|
|
284
|
-
function toTitleLinkData(data) {
|
|
285
|
-
return normalizeAiNewsData(data).map((item) => ({
|
|
286
|
-
date: item.date,
|
|
287
|
-
news: item.news.map((newsItem) => ({
|
|
288
|
-
title: newsItem.title,
|
|
289
|
-
detail: "",
|
|
290
|
-
link: newsItem.link,
|
|
291
|
-
source: "",
|
|
292
|
-
date: newsItem.date
|
|
293
|
-
}))
|
|
294
|
-
}));
|
|
295
|
-
}
|
|
296
|
-
__name(toTitleLinkData, "toTitleLinkData");
|
|
297
|
-
function formatDate(date) {
|
|
298
|
-
const year = date.getFullYear();
|
|
299
|
-
const month = `${date.getMonth() + 1}`.padStart(2, "0");
|
|
300
|
-
const day = `${date.getDate()}`.padStart(2, "0");
|
|
301
|
-
return `${year}-${month}-${day}`;
|
|
302
|
-
}
|
|
303
|
-
__name(formatDate, "formatDate");
|
|
304
|
-
function normalizeAiNewsData(data) {
|
|
305
|
-
return Array.isArray(data) ? data : [data];
|
|
306
|
-
}
|
|
307
|
-
__name(normalizeAiNewsData, "normalizeAiNewsData");
|
|
308
|
-
function getRecentAiNewsDates() {
|
|
309
|
-
const now = /* @__PURE__ */ new Date();
|
|
310
|
-
const yesterday = new Date(now);
|
|
311
|
-
yesterday.setDate(now.getDate() - 1);
|
|
312
|
-
return [formatDate(now), formatDate(yesterday)];
|
|
313
|
-
}
|
|
314
|
-
__name(getRecentAiNewsDates, "getRecentAiNewsDates");
|
|
315
|
-
async function fetchAiNewsByDates(dates) {
|
|
316
|
-
const responses = await Promise.all(
|
|
317
|
-
dates.map((date) => getAiNews({ date, encoding: "json" }))
|
|
318
|
-
);
|
|
319
|
-
const items = [];
|
|
320
|
-
responses.forEach((response, index) => {
|
|
321
|
-
if (response.code !== 200 || !response.data) {
|
|
322
|
-
logError("60s API: AI快报返回错误", { code: response.code, message: response.message, date: dates[index] });
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
items.push(...normalizeAiNewsData(response.data));
|
|
326
|
-
});
|
|
327
|
-
return items.sort((a, b) => b.date.localeCompare(a.date));
|
|
328
|
-
}
|
|
329
|
-
__name(fetchAiNewsByDates, "fetchAiNewsByDates");
|
|
330
|
-
async function sendAiNewsToChannels() {
|
|
331
|
-
const targetChannels = await resolveGroupScheduleChannels(config.scheduleWhitelist, "ai-news");
|
|
332
|
-
if (targetChannels.length === 0) return;
|
|
333
|
-
try {
|
|
334
|
-
const response = await getAiNews({ encoding: "json" });
|
|
335
|
-
if (response.code !== 200 || !response.data) {
|
|
336
|
-
logError("60s API: AI快报返回错误", { code: response.code, message: response.message });
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const message = formatAiNewsText(response.data);
|
|
340
|
-
for (const channelId of targetChannels) {
|
|
341
|
-
try {
|
|
342
|
-
const output = config.aiUseForward ? (0, import_koishi.h)("figure", {}, [message]) : message;
|
|
343
|
-
await ctx.broadcast([channelId], output);
|
|
344
|
-
logInfo("60s API: 定时发送AI快报成功", { channelId });
|
|
345
|
-
} catch (error) {
|
|
346
|
-
logError("60s API: 定时发送AI快报到频道失败", { channelId, error });
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
} catch (error) {
|
|
350
|
-
logError("60s API: 定时发送AI快报失败", error);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
__name(sendAiNewsToChannels, "sendAiNewsToChannels");
|
|
354
|
-
function formatMoyuText(data) {
|
|
355
|
-
const lunar = `${data.date.lunar.yearCN}年${data.date.lunar.monthCN}${data.date.lunar.dayCN}`;
|
|
356
|
-
const festival = data.today.lunarFestivals.length ? `节日:${data.today.lunarFestivals.join("、")}` : "节日:无";
|
|
357
|
-
const holidayName = data.today.holidayName ? `假期:${data.today.holidayName}` : "假期:无";
|
|
358
|
-
const solarTerm = data.today.solarTerm ? `节气:${data.today.solarTerm}` : "节气:无";
|
|
359
|
-
const lines = [
|
|
360
|
-
`🍱 摸鱼日报 ${data.date.gregorian} ${data.date.weekday}`,
|
|
361
|
-
`农历:${lunar}`,
|
|
362
|
-
`${holidayName} | ${solarTerm} | ${festival}`,
|
|
363
|
-
`进度:周 ${data.progress.week.percentage}% / 月 ${data.progress.month.percentage}% / 年 ${data.progress.year.percentage}%`,
|
|
364
|
-
`倒计时:周末 ${data.countdown.toWeekEnd} 天 | 周五 ${data.countdown.toFriday} 天 | 月末 ${data.countdown.toMonthEnd} 天 | 年末 ${data.countdown.toYearEnd} 天`,
|
|
365
|
-
`下个周末:${data.nextWeekend.date}(${data.nextWeekend.weekday})还剩 ${data.nextWeekend.daysUntil} 天`,
|
|
366
|
-
`下个假期:${data.nextHoliday.name} ${data.nextHoliday.date}(${data.nextHoliday.until} 天后)`,
|
|
367
|
-
`摸鱼语录:${data.moyuQuote}`
|
|
368
|
-
];
|
|
369
|
-
return lines.join("\n");
|
|
370
|
-
}
|
|
371
|
-
__name(formatMoyuText, "formatMoyuText");
|
|
372
|
-
async function sendMoyuToChannels() {
|
|
373
|
-
const targetChannels = await resolveGroupScheduleChannels(config.scheduleWhitelist, "moyu");
|
|
374
|
-
if (targetChannels.length === 0) return;
|
|
375
|
-
try {
|
|
376
|
-
const response = await getMoyuDaily("json");
|
|
377
|
-
if (response.code !== 200 || !response.data) {
|
|
378
|
-
logError("60s API: 摸鱼日报返回错误", { code: response.code, message: response.message });
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
const message = formatMoyuText(response.data);
|
|
382
|
-
for (const channelId of targetChannels) {
|
|
383
|
-
try {
|
|
384
|
-
await ctx.broadcast([channelId], message);
|
|
385
|
-
logInfo("60s API: 定时发送摸鱼日报成功", { channelId });
|
|
386
|
-
} catch (error) {
|
|
387
|
-
logError("60s API: 定时发送摸鱼日报到频道失败", { channelId, error });
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
} catch (error) {
|
|
391
|
-
logError("60s API: 定时发送摸鱼日报失败", error);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
__name(sendMoyuToChannels, "sendMoyuToChannels");
|
|
395
|
-
function formatGoldText(data) {
|
|
396
|
-
const metals = data.metals.slice(0, 5).map((item, index) => {
|
|
397
|
-
return `${index + 1}. ${item.name} ${item.today_price}${item.unit} (最高${item.high_price} / 最低${item.low_price})`;
|
|
398
|
-
});
|
|
399
|
-
const stores = data.stores.slice(0, 5).map((item, index) => {
|
|
400
|
-
return `${index + 1}. ${item.brand} ${item.product} ${item.formatted}`;
|
|
401
|
-
});
|
|
402
|
-
const banks = data.banks.slice(0, 5).map((item, index) => {
|
|
403
|
-
return `${index + 1}. ${item.bank} ${item.product} ${item.formatted}`;
|
|
404
|
-
});
|
|
405
|
-
const recycle = data.recycle.slice(0, 5).map((item, index) => {
|
|
406
|
-
return `${index + 1}. ${item.type} ${item.formatted} (${item.purity})`;
|
|
407
|
-
});
|
|
408
|
-
return [
|
|
409
|
-
`💰 今日金价 ${data.date}`,
|
|
410
|
-
`-- 金属行情 --`,
|
|
411
|
-
...metals,
|
|
412
|
-
`-- 金店报价 --`,
|
|
413
|
-
...stores,
|
|
414
|
-
`-- 银行报价 --`,
|
|
415
|
-
...banks,
|
|
416
|
-
`-- 回收报价 --`,
|
|
417
|
-
...recycle
|
|
418
|
-
].join("\n");
|
|
419
|
-
}
|
|
420
|
-
__name(formatGoldText, "formatGoldText");
|
|
421
|
-
function formatFuelText(data) {
|
|
422
|
-
const items = data.items.map((item, index) => {
|
|
423
|
-
return `${index + 1}. ${item.name} ${item.price_desc}`;
|
|
424
|
-
});
|
|
425
|
-
return [
|
|
426
|
-
`⛽ 今日油价 ${data.region}`,
|
|
427
|
-
...items,
|
|
428
|
-
`更新时间:${data.updated}`,
|
|
429
|
-
`详情:${data.link}`
|
|
430
|
-
].join("\n");
|
|
431
|
-
}
|
|
432
|
-
__name(formatFuelText, "formatFuelText");
|
|
433
|
-
async function sendGoldToChannels() {
|
|
434
|
-
const targetChannels = await resolveGroupScheduleChannels(config.scheduleWhitelist, "gold");
|
|
435
|
-
if (targetChannels.length === 0) return;
|
|
436
|
-
try {
|
|
437
|
-
const response = await getGoldPrice("json");
|
|
438
|
-
if (response.code !== 200 || !response.data) {
|
|
439
|
-
logError("60s API: 今日金价返回错误", { code: response.code, message: response.message });
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
const message = formatGoldText(response.data);
|
|
443
|
-
for (const channelId of targetChannels) {
|
|
444
|
-
try {
|
|
445
|
-
await ctx.broadcast([channelId], message);
|
|
446
|
-
logInfo("60s API: 定时发送今日金价成功", { channelId });
|
|
447
|
-
} catch (error) {
|
|
448
|
-
logError("60s API: 定时发送今日金价到频道失败", { channelId, error });
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
} catch (error) {
|
|
452
|
-
logError("60s API: 定时发送今日金价失败", error);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
__name(sendGoldToChannels, "sendGoldToChannels");
|
|
456
|
-
async function sendFuelToChannels() {
|
|
457
|
-
const targetChannels = await resolveGroupScheduleChannels(config.scheduleWhitelist, "fuel");
|
|
458
|
-
if (targetChannels.length === 0) return;
|
|
459
|
-
try {
|
|
460
|
-
const response = await getFuelPrice({ region: config.fuelDefaultRegion, encoding: "json" });
|
|
461
|
-
if (response.code !== 200 || !response.data) {
|
|
462
|
-
logError("60s API: 今日油价返回错误", { code: response.code, message: response.message });
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
const message = formatFuelText(response.data);
|
|
466
|
-
for (const channelId of targetChannels) {
|
|
467
|
-
try {
|
|
468
|
-
await ctx.broadcast([channelId], message);
|
|
469
|
-
logInfo("60s API: 定时发送今日油价成功", { channelId });
|
|
470
|
-
} catch (error) {
|
|
471
|
-
logError("60s API: 定时发送今日油价到频道失败", { channelId, error });
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
} catch (error) {
|
|
475
|
-
logError("60s API: 定时发送今日油价失败", error);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
__name(sendFuelToChannels, "sendFuelToChannels");
|
|
479
|
-
function parseScheduleTime(timeStr) {
|
|
480
|
-
if (timeStr.includes("/")) {
|
|
481
|
-
const [timePart] = timeStr.split(" / ");
|
|
482
|
-
const [hours, minutes] = timePart.split(":").map(Number);
|
|
483
|
-
const now = /* @__PURE__ */ new Date();
|
|
484
|
-
const targetTime = /* @__PURE__ */ new Date();
|
|
485
|
-
targetTime.setHours(hours, minutes, 0, 0);
|
|
486
|
-
if (targetTime <= now) {
|
|
487
|
-
targetTime.setDate(targetTime.getDate() + 1);
|
|
488
|
-
}
|
|
489
|
-
return targetTime.getTime() - now.getTime();
|
|
490
|
-
} else if (timeStr.includes("h")) {
|
|
491
|
-
const hours = parseInt(timeStr.replace("h", ""));
|
|
492
|
-
return hours * 60 * 60 * 1e3;
|
|
493
|
-
} else if (timeStr.includes("m")) {
|
|
494
|
-
const minutes = parseInt(timeStr.replace("m", ""));
|
|
495
|
-
return minutes * 60 * 1e3;
|
|
496
|
-
} else {
|
|
497
|
-
return 60 * 60 * 1e3;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
__name(parseScheduleTime, "parseScheduleTime");
|
|
501
|
-
function setupSchedule() {
|
|
502
|
-
if (!config.enableSchedule) {
|
|
503
|
-
logInfo("60s API: 定时发送功能已禁用");
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
if (scheduleInterval) {
|
|
507
|
-
clearInterval(scheduleInterval);
|
|
508
|
-
scheduleInterval = null;
|
|
509
|
-
}
|
|
510
|
-
try {
|
|
511
|
-
const interval = parseScheduleTime(config.scheduleTime);
|
|
512
|
-
scheduleInterval = setInterval(async () => {
|
|
513
|
-
await sendNewsToChannels();
|
|
514
|
-
}, interval);
|
|
515
|
-
logInfo("60s API: 定时任务设置成功", {
|
|
516
|
-
scheduleTime: config.scheduleTime,
|
|
517
|
-
interval,
|
|
518
|
-
channels: config.scheduleWhitelist
|
|
519
|
-
});
|
|
520
|
-
} catch (error) {
|
|
521
|
-
logError("60s API: 设置定时任务失败", error);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
__name(setupSchedule, "setupSchedule");
|
|
525
|
-
function setupAiNewsSchedule() {
|
|
526
|
-
if (!config.enableAiNewsSchedule) {
|
|
527
|
-
logInfo("60s API: AI快报定时发送功能已禁用");
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
if (aiNewsScheduleInterval) {
|
|
531
|
-
clearInterval(aiNewsScheduleInterval);
|
|
532
|
-
aiNewsScheduleInterval = null;
|
|
533
|
-
}
|
|
534
|
-
try {
|
|
535
|
-
const interval = parseScheduleTime(config.aiNewsScheduleTime);
|
|
536
|
-
aiNewsScheduleInterval = setInterval(async () => {
|
|
537
|
-
await sendAiNewsToChannels();
|
|
538
|
-
}, interval);
|
|
539
|
-
logInfo("60s API: AI快报定时任务设置成功", {
|
|
540
|
-
scheduleTime: config.aiNewsScheduleTime,
|
|
541
|
-
interval,
|
|
542
|
-
channels: config.scheduleWhitelist
|
|
543
|
-
});
|
|
544
|
-
} catch (error) {
|
|
545
|
-
logError("60s API: 设置AI快报定时任务失败", error);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
__name(setupAiNewsSchedule, "setupAiNewsSchedule");
|
|
549
|
-
function setupMoyuSchedule() {
|
|
550
|
-
if (!config.enableMoyuSchedule) {
|
|
551
|
-
logInfo("60s API: 摸鱼日报定时发送功能已禁用");
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
if (moyuScheduleInterval) {
|
|
555
|
-
clearInterval(moyuScheduleInterval);
|
|
556
|
-
moyuScheduleInterval = null;
|
|
557
|
-
}
|
|
558
|
-
try {
|
|
559
|
-
const interval = parseScheduleTime(config.moyuScheduleTime);
|
|
560
|
-
moyuScheduleInterval = setInterval(async () => {
|
|
561
|
-
await sendMoyuToChannels();
|
|
562
|
-
}, interval);
|
|
563
|
-
logInfo("60s API: 摸鱼日报定时任务设置成功", {
|
|
564
|
-
scheduleTime: config.moyuScheduleTime,
|
|
565
|
-
interval,
|
|
566
|
-
channels: config.scheduleWhitelist
|
|
567
|
-
});
|
|
568
|
-
} catch (error) {
|
|
569
|
-
logError("60s API: 设置摸鱼日报定时任务失败", error);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
__name(setupMoyuSchedule, "setupMoyuSchedule");
|
|
573
|
-
function setupGoldSchedule() {
|
|
574
|
-
if (!config.enableGoldSchedule) {
|
|
575
|
-
logInfo("60s API: 今日金价定时发送功能已禁用");
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (goldScheduleInterval) {
|
|
579
|
-
clearInterval(goldScheduleInterval);
|
|
580
|
-
goldScheduleInterval = null;
|
|
581
|
-
}
|
|
582
|
-
try {
|
|
583
|
-
const interval = parseScheduleTime(config.goldScheduleTime);
|
|
584
|
-
goldScheduleInterval = setInterval(async () => {
|
|
585
|
-
await sendGoldToChannels();
|
|
586
|
-
}, interval);
|
|
587
|
-
logInfo("60s API: 今日金价定时任务设置成功", {
|
|
588
|
-
scheduleTime: config.goldScheduleTime,
|
|
589
|
-
interval,
|
|
590
|
-
channels: config.scheduleWhitelist
|
|
591
|
-
});
|
|
592
|
-
} catch (error) {
|
|
593
|
-
logError("60s API: 设置今日金价定时任务失败", error);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
__name(setupGoldSchedule, "setupGoldSchedule");
|
|
597
|
-
function setupFuelSchedule() {
|
|
598
|
-
if (!config.enableFuelSchedule) {
|
|
599
|
-
logInfo("60s API: 今日油价定时发送功能已禁用");
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
if (fuelScheduleInterval) {
|
|
603
|
-
clearInterval(fuelScheduleInterval);
|
|
604
|
-
fuelScheduleInterval = null;
|
|
605
|
-
}
|
|
606
|
-
try {
|
|
607
|
-
const interval = parseScheduleTime(config.fuelScheduleTime);
|
|
608
|
-
fuelScheduleInterval = setInterval(async () => {
|
|
609
|
-
await sendFuelToChannels();
|
|
610
|
-
}, interval);
|
|
611
|
-
logInfo("60s API: 今日油价定时任务设置成功", {
|
|
612
|
-
scheduleTime: config.fuelScheduleTime,
|
|
613
|
-
interval,
|
|
614
|
-
channels: config.scheduleWhitelist
|
|
615
|
-
});
|
|
616
|
-
} catch (error) {
|
|
617
|
-
logError("60s API: 设置今日油价定时任务失败", error);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
__name(setupFuelSchedule, "setupFuelSchedule");
|
|
621
|
-
ctx.command("新闻", "获取60秒新闻图片").action(async (argv) => {
|
|
622
|
-
const userId = argv.session.userId;
|
|
623
|
-
if (!checkCooldown(userId)) {
|
|
624
|
-
const now = Date.now();
|
|
625
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
626
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
627
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
628
|
-
}
|
|
629
|
-
try {
|
|
630
|
-
logInfo("60s API: 用户请求新闻图片", { userId });
|
|
631
|
-
const imageBuffer = await get60sNewsImage();
|
|
632
|
-
const imageMessage = import_koishi.h.image(imageBuffer, "image/png");
|
|
633
|
-
await argv.session.send(imageMessage);
|
|
634
|
-
logInfo("60s API: 成功发送新闻图片", {
|
|
635
|
-
size: imageBuffer.length,
|
|
636
|
-
userId
|
|
637
|
-
});
|
|
638
|
-
} catch (error) {
|
|
639
|
-
logError("60s API: 处理新闻图片请求失败", {
|
|
640
|
-
error,
|
|
641
|
-
errorMessage: error?.message || "未知错误",
|
|
642
|
-
userId
|
|
643
|
-
});
|
|
644
|
-
return "获取新闻图片失败,请稍后重试";
|
|
645
|
-
}
|
|
646
|
-
});
|
|
647
|
-
ctx.command("历史上的今天", "获取历史上的今天").action(async (argv) => {
|
|
648
|
-
const userId = argv.session.userId;
|
|
649
|
-
if (!checkCooldown(userId)) {
|
|
650
|
-
const now = Date.now();
|
|
651
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
652
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
653
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
654
|
-
}
|
|
655
|
-
try {
|
|
656
|
-
logInfo("60s API: 用户请求历史上的今天", { userId });
|
|
657
|
-
const response = await getTodayInHistory();
|
|
658
|
-
if (response.code !== 200) {
|
|
659
|
-
logError("60s API: 返回错误", {
|
|
660
|
-
code: response.code,
|
|
661
|
-
message: response.message
|
|
662
|
-
});
|
|
663
|
-
return `获取历史上的今天失败: ${response.message || "未知错误"}`;
|
|
664
|
-
}
|
|
665
|
-
if (!response.data || !response.data.items || response.data.items.length === 0) {
|
|
666
|
-
logError("60s API: 返回数据为空");
|
|
667
|
-
return "获取历史上的今天失败: 未获取到历史事件数据";
|
|
668
|
-
}
|
|
669
|
-
const { date, items } = response.data;
|
|
670
|
-
if (config.useForward && argv.session.platform === "onebot") {
|
|
671
|
-
const forwardElements = [
|
|
672
|
-
`📅 ${date} 历史上的今天`,
|
|
673
|
-
...items.map((item, index) => {
|
|
674
|
-
const typeIcon = {
|
|
675
|
-
"birth": "👶",
|
|
676
|
-
"event": "📅",
|
|
677
|
-
"death": "💀"
|
|
678
|
-
}[item.event_type] || "📅";
|
|
679
|
-
return `${index + 1}. ${typeIcon} ${item.year}年 - ${item.title}
|
|
680
|
-
${item.description}`;
|
|
681
|
-
})
|
|
682
|
-
];
|
|
683
|
-
const forwardMessage = (0, import_koishi.h)("figure", {}, forwardElements);
|
|
684
|
-
await argv.session.send(forwardMessage);
|
|
685
|
-
} else {
|
|
686
|
-
let message = `📅 ${date} 历史上的今天
|
|
687
|
-
|
|
688
|
-
`;
|
|
689
|
-
items.forEach((item, index) => {
|
|
690
|
-
const typeIcon = {
|
|
691
|
-
"birth": "👶",
|
|
692
|
-
"event": "📅",
|
|
693
|
-
"death": "💀"
|
|
694
|
-
}[item.event_type] || "📅";
|
|
695
|
-
message += `${index + 1}. ${typeIcon} ${item.year}年 - ${item.title}
|
|
696
|
-
${item.description}
|
|
697
|
-
|
|
698
|
-
`;
|
|
699
|
-
});
|
|
700
|
-
await argv.session.send(message);
|
|
701
|
-
}
|
|
702
|
-
logInfo("60s API: 成功发送历史上的今天", {
|
|
703
|
-
date,
|
|
704
|
-
itemsCount: items.length,
|
|
705
|
-
userId
|
|
706
|
-
});
|
|
707
|
-
} catch (error) {
|
|
708
|
-
logError("60s API: 处理历史上的今天请求失败", {
|
|
709
|
-
error,
|
|
710
|
-
errorMessage: error?.message || "未知错误",
|
|
711
|
-
userId
|
|
712
|
-
});
|
|
713
|
-
return "获取历史上的今天失败,请稍后重试";
|
|
714
|
-
}
|
|
715
|
-
});
|
|
716
|
-
ctx.command("知乎话题榜", "获取知乎话题榜").action(async (argv) => {
|
|
717
|
-
const userId = argv.session.userId;
|
|
718
|
-
if (!checkCooldown(userId)) {
|
|
719
|
-
const now = Date.now();
|
|
720
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
721
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
722
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
723
|
-
}
|
|
724
|
-
try {
|
|
725
|
-
logInfo("60s API: 用户请求知乎话题榜", { userId });
|
|
726
|
-
const response = await getZhihuTrends();
|
|
727
|
-
if (response.code !== 200) {
|
|
728
|
-
logError("60s API: 返回错误", {
|
|
729
|
-
code: response.code,
|
|
730
|
-
message: response.message
|
|
731
|
-
});
|
|
732
|
-
return `获取知乎话题榜失败: ${response.message || "未知错误"}`;
|
|
733
|
-
}
|
|
734
|
-
if (!response.data || response.data.length === 0) {
|
|
735
|
-
logError("60s API: 返回数据为空");
|
|
736
|
-
return "获取知乎话题榜失败: 未获取到话题数据";
|
|
737
|
-
}
|
|
738
|
-
const topics = response.data;
|
|
739
|
-
if (config.useForward && argv.session.platform === "onebot") {
|
|
740
|
-
const forwardElements = [
|
|
741
|
-
`🔥 知乎话题榜`,
|
|
742
|
-
...topics.map((topic, index) => {
|
|
743
|
-
return `${index + 1}. ${topic.title}
|
|
744
|
-
${topic.detail}
|
|
745
|
-
🔗 ${topic.link}`;
|
|
746
|
-
})
|
|
747
|
-
];
|
|
748
|
-
const forwardMessage = (0, import_koishi.h)("figure", {}, forwardElements);
|
|
749
|
-
await argv.session.send(forwardMessage);
|
|
750
|
-
} else {
|
|
751
|
-
let message = `🔥 知乎话题榜
|
|
752
|
-
|
|
753
|
-
`;
|
|
754
|
-
const maxTopics = 10;
|
|
755
|
-
const topicsToShow = topics.slice(0, maxTopics);
|
|
756
|
-
topicsToShow.forEach((topic, index) => {
|
|
757
|
-
const shortDetail = topic.detail.length > 200 ? topic.detail.substring(0, 200) + "..." : topic.detail;
|
|
758
|
-
message += `${index + 1}. ${topic.title}
|
|
759
|
-
${shortDetail}
|
|
760
|
-
🔗 ${topic.link}
|
|
761
|
-
|
|
762
|
-
`;
|
|
763
|
-
});
|
|
764
|
-
if (topics.length > maxTopics) {
|
|
765
|
-
message += `
|
|
766
|
-
... 还有 ${topics.length - maxTopics} 个话题,完整内容请使用合并转发模式`;
|
|
767
|
-
}
|
|
768
|
-
await argv.session.send(message);
|
|
769
|
-
}
|
|
770
|
-
logInfo("60s API: 成功发送知乎话题榜", {
|
|
771
|
-
topicsCount: topics.length,
|
|
772
|
-
userId
|
|
773
|
-
});
|
|
774
|
-
} catch (error) {
|
|
775
|
-
logError("60s API: 处理知乎话题榜请求失败", {
|
|
776
|
-
error,
|
|
777
|
-
errorMessage: error?.message || "未知错误",
|
|
778
|
-
userId
|
|
779
|
-
});
|
|
780
|
-
return "获取知乎话题榜失败,请稍后重试";
|
|
781
|
-
}
|
|
782
|
-
});
|
|
783
|
-
ctx.command("AI快报 [date]", "获取AI资讯快报").option("date", "-d <date> 指定日期 (格式: YYYY-MM-DD)").option("all", "-a 获取所有日期").option("encoding", "-e <encoding> 编码方式 text/json/markdown").action(async (argv, date) => {
|
|
784
|
-
const userId = argv.session.userId;
|
|
785
|
-
if (!checkCooldown(userId)) {
|
|
786
|
-
const now = Date.now();
|
|
787
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
788
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
789
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
790
|
-
}
|
|
791
|
-
try {
|
|
792
|
-
logInfo("60s API: 用户请求AI快报", { userId });
|
|
793
|
-
const encoding = argv.options.encoding || "text";
|
|
794
|
-
const all = argv.options.all ? "1" : void 0;
|
|
795
|
-
const targetDate = argv.options.date || date;
|
|
796
|
-
if (!targetDate && !all) {
|
|
797
|
-
const dates = getRecentAiNewsDates();
|
|
798
|
-
const data = await fetchAiNewsByDates(dates);
|
|
799
|
-
if (!data.length) return "未获取到近两天的AI快报数据";
|
|
800
|
-
if (encoding === "json") {
|
|
801
|
-
await argv.session.send(JSON.stringify(toTitleLinkData(data), null, 2));
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
if (encoding === "markdown") {
|
|
805
|
-
await argv.session.send(formatAiNewsMarkdown(data));
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
const message2 = formatAiNewsText(data);
|
|
809
|
-
if (config.aiUseForward && argv.session.platform === "onebot") {
|
|
810
|
-
await argv.session.send((0, import_koishi.h)("figure", {}, [message2]));
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
await argv.session.send(message2);
|
|
814
|
-
return;
|
|
815
|
-
}
|
|
816
|
-
if (encoding === "json") {
|
|
817
|
-
const response2 = await getAiNews({ date: targetDate, all, encoding: "json" });
|
|
818
|
-
if (response2.code !== 200 || !response2.data) {
|
|
819
|
-
logError("60s API: AI快报返回错误", { code: response2.code, message: response2.message });
|
|
820
|
-
return `获取AI快报失败: ${response2.message || "未知错误"}`;
|
|
821
|
-
}
|
|
822
|
-
await argv.session.send(JSON.stringify(toTitleLinkData(response2.data), null, 2));
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
if (encoding === "markdown") {
|
|
826
|
-
const response2 = await getAiNews({ date: targetDate, all, encoding: "json" });
|
|
827
|
-
if (response2.code !== 200 || !response2.data) {
|
|
828
|
-
logError("60s API: AI快报返回错误", { code: response2.code, message: response2.message });
|
|
829
|
-
return `获取AI快报失败: ${response2.message || "未知错误"}`;
|
|
830
|
-
}
|
|
831
|
-
await argv.session.send(formatAiNewsMarkdown(response2.data));
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
const response = await getAiNews({ date: targetDate, all, encoding: "json" });
|
|
835
|
-
if (response.code !== 200 || !response.data) {
|
|
836
|
-
logError("60s API: AI快报返回错误", { code: response.code, message: response.message });
|
|
837
|
-
return `获取AI快报失败: ${response.message || "未知错误"}`;
|
|
838
|
-
}
|
|
839
|
-
const message = formatAiNewsText(response.data);
|
|
840
|
-
if (config.aiUseForward && argv.session.platform === "onebot") {
|
|
841
|
-
const forwardMessage = (0, import_koishi.h)("figure", {}, [message]);
|
|
842
|
-
await argv.session.send(forwardMessage);
|
|
843
|
-
} else {
|
|
844
|
-
await argv.session.send(message);
|
|
845
|
-
}
|
|
846
|
-
logInfo("60s API: 成功发送AI快报", {
|
|
847
|
-
userId,
|
|
848
|
-
date: targetDate || "today",
|
|
849
|
-
all: all || "0"
|
|
850
|
-
});
|
|
851
|
-
} catch (error) {
|
|
852
|
-
logError("60s API: 处理AI快报请求失败", {
|
|
853
|
-
error,
|
|
854
|
-
errorMessage: error?.message || "未知错误",
|
|
855
|
-
userId
|
|
856
|
-
});
|
|
857
|
-
return "获取AI快报失败,请稍后重试";
|
|
858
|
-
}
|
|
859
|
-
});
|
|
860
|
-
ctx.command("摸鱼", "获取摸鱼日报").option("encoding", "-e <encoding> 编码方式 text/json/markdown").action(async (argv) => {
|
|
861
|
-
const userId = argv.session.userId;
|
|
862
|
-
if (!checkCooldown(userId)) {
|
|
863
|
-
const now = Date.now();
|
|
864
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
865
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
866
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
867
|
-
}
|
|
868
|
-
try {
|
|
869
|
-
logInfo("60s API: 用户请求摸鱼日报", { userId });
|
|
870
|
-
const encoding = argv.options.encoding || "text";
|
|
871
|
-
if (encoding === "markdown") {
|
|
872
|
-
const response2 = await getMoyuDaily("markdown");
|
|
873
|
-
await argv.session.send(response2);
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
if (encoding === "json") {
|
|
877
|
-
const response2 = await getMoyuDaily("json");
|
|
878
|
-
if (response2.code !== 200 || !response2.data) {
|
|
879
|
-
logError("60s API: 摸鱼日报返回错误", { code: response2.code, message: response2.message });
|
|
880
|
-
return `获取摸鱼日报失败: ${response2.message || "未知错误"}`;
|
|
881
|
-
}
|
|
882
|
-
await argv.session.send(JSON.stringify(response2.data, null, 2));
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
const response = await getMoyuDaily("json");
|
|
886
|
-
if (response.code !== 200 || !response.data) {
|
|
887
|
-
logError("60s API: 摸鱼日报返回错误", { code: response.code, message: response.message });
|
|
888
|
-
return `获取摸鱼日报失败: ${response.message || "未知错误"}`;
|
|
889
|
-
}
|
|
890
|
-
const message = formatMoyuText(response.data);
|
|
891
|
-
await argv.session.send(message);
|
|
892
|
-
logInfo("60s API: 成功发送摸鱼日报", {
|
|
893
|
-
userId
|
|
894
|
-
});
|
|
895
|
-
} catch (error) {
|
|
896
|
-
logError("60s API: 处理摸鱼日报请求失败", {
|
|
897
|
-
error,
|
|
898
|
-
errorMessage: error?.message || "未知错误",
|
|
899
|
-
userId
|
|
900
|
-
});
|
|
901
|
-
return "获取摸鱼日报失败,请稍后重试";
|
|
902
|
-
}
|
|
903
|
-
});
|
|
904
|
-
ctx.command("金价", "获取今日金价").option("encoding", "-e <encoding> 编码方式 text/json/markdown").action(async (argv) => {
|
|
905
|
-
const userId = argv.session.userId;
|
|
906
|
-
if (!checkCooldown(userId)) {
|
|
907
|
-
const now = Date.now();
|
|
908
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
909
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
910
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
911
|
-
}
|
|
912
|
-
try {
|
|
913
|
-
logInfo("60s API: 用户请求今日金价", { userId });
|
|
914
|
-
const encoding = argv.options.encoding || "text";
|
|
915
|
-
if (encoding === "markdown") {
|
|
916
|
-
const response2 = await getGoldPrice("markdown");
|
|
917
|
-
await argv.session.send(response2);
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
if (encoding === "json") {
|
|
921
|
-
const response2 = await getGoldPrice("json");
|
|
922
|
-
if (response2.code !== 200 || !response2.data) {
|
|
923
|
-
logError("60s API: 今日金价返回错误", { code: response2.code, message: response2.message });
|
|
924
|
-
return `获取今日金价失败: ${response2.message || "未知错误"}`;
|
|
925
|
-
}
|
|
926
|
-
await argv.session.send(JSON.stringify(response2.data, null, 2));
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
const response = await getGoldPrice("json");
|
|
930
|
-
if (response.code !== 200 || !response.data) {
|
|
931
|
-
logError("60s API: 今日金价返回错误", { code: response.code, message: response.message });
|
|
932
|
-
return `获取今日金价失败: ${response.message || "未知错误"}`;
|
|
933
|
-
}
|
|
934
|
-
const message = formatGoldText(response.data);
|
|
935
|
-
await argv.session.send(message);
|
|
936
|
-
logInfo("60s API: 成功发送今日金价", { userId });
|
|
937
|
-
} catch (error) {
|
|
938
|
-
logError("60s API: 处理今日金价请求失败", {
|
|
939
|
-
error,
|
|
940
|
-
errorMessage: error?.message || "未知错误",
|
|
941
|
-
userId
|
|
942
|
-
});
|
|
943
|
-
return "获取今日金价失败,请稍后重试";
|
|
944
|
-
}
|
|
945
|
-
});
|
|
946
|
-
ctx.command("油价 [region]", "获取今日油价").option("region", "-r <region> 地区").option("encoding", "-e <encoding> 编码方式 text/json/markdown").action(async (argv, region) => {
|
|
947
|
-
const userId = argv.session.userId;
|
|
948
|
-
if (!checkCooldown(userId)) {
|
|
949
|
-
const now = Date.now();
|
|
950
|
-
const lastTime = cooldowns.get(userId) || 0;
|
|
951
|
-
const timeLeft = Math.ceil((lastTime + config.cooldownTime * 1e3 - now) / 1e3);
|
|
952
|
-
return `请等待 ${timeLeft} 秒后再试`;
|
|
953
|
-
}
|
|
954
|
-
try {
|
|
955
|
-
logInfo("60s API: 用户请求今日油价", { userId });
|
|
956
|
-
const encoding = argv.options.encoding || "text";
|
|
957
|
-
const targetRegion = argv.options.region || region || config.fuelDefaultRegion;
|
|
958
|
-
if (encoding === "markdown") {
|
|
959
|
-
const response2 = await getFuelPrice({ region: targetRegion, encoding: "markdown" });
|
|
960
|
-
await argv.session.send(response2);
|
|
961
|
-
return;
|
|
962
|
-
}
|
|
963
|
-
if (encoding === "json") {
|
|
964
|
-
const response2 = await getFuelPrice({ region: targetRegion, encoding: "json" });
|
|
965
|
-
if (response2.code !== 200 || !response2.data) {
|
|
966
|
-
logError("60s API: 今日油价返回错误", { code: response2.code, message: response2.message });
|
|
967
|
-
return `获取今日油价失败: ${response2.message || "未知错误"}`;
|
|
968
|
-
}
|
|
969
|
-
await argv.session.send(JSON.stringify(response2.data, null, 2));
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
const response = await getFuelPrice({ region: targetRegion, encoding: "json" });
|
|
973
|
-
if (response.code !== 200 || !response.data) {
|
|
974
|
-
logError("60s API: 今日油价返回错误", { code: response.code, message: response.message });
|
|
975
|
-
return `获取今日油价失败: ${response.message || "未知错误"}`;
|
|
976
|
-
}
|
|
977
|
-
const message = formatFuelText(response.data);
|
|
978
|
-
await argv.session.send(message);
|
|
979
|
-
logInfo("60s API: 成功发送今日油价", { userId, region: targetRegion });
|
|
980
|
-
} catch (error) {
|
|
981
|
-
logError("60s API: 处理今日油价请求失败", {
|
|
982
|
-
error,
|
|
983
|
-
errorMessage: error?.message || "未知错误",
|
|
984
|
-
userId
|
|
985
|
-
});
|
|
986
|
-
return "获取今日油价失败,请稍后重试";
|
|
987
|
-
}
|
|
988
|
-
});
|
|
989
|
-
ctx.on("ready", async () => {
|
|
990
|
-
await setupSchedule();
|
|
991
|
-
await setupAiNewsSchedule();
|
|
992
|
-
await setupMoyuSchedule();
|
|
993
|
-
await setupGoldSchedule();
|
|
994
|
-
await setupFuelSchedule();
|
|
995
|
-
});
|
|
996
|
-
ctx.on("dispose", () => {
|
|
997
|
-
cooldowns.clear();
|
|
998
|
-
if (scheduleInterval) {
|
|
999
|
-
clearInterval(scheduleInterval);
|
|
1000
|
-
scheduleInterval = null;
|
|
1001
|
-
}
|
|
1002
|
-
if (aiNewsScheduleInterval) {
|
|
1003
|
-
clearInterval(aiNewsScheduleInterval);
|
|
1004
|
-
aiNewsScheduleInterval = null;
|
|
1005
|
-
}
|
|
1006
|
-
if (moyuScheduleInterval) {
|
|
1007
|
-
clearInterval(moyuScheduleInterval);
|
|
1008
|
-
moyuScheduleInterval = null;
|
|
1009
|
-
}
|
|
1010
|
-
if (goldScheduleInterval) {
|
|
1011
|
-
clearInterval(goldScheduleInterval);
|
|
1012
|
-
goldScheduleInterval = null;
|
|
1013
|
-
}
|
|
1014
|
-
if (fuelScheduleInterval) {
|
|
1015
|
-
clearInterval(fuelScheduleInterval);
|
|
1016
|
-
fuelScheduleInterval = null;
|
|
1017
|
-
}
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
__name(apply, "apply");
|
|
1021
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1022
|
-
0 && (module.exports = {
|
|
1023
|
-
Config,
|
|
1024
|
-
apply,
|
|
1025
|
-
inject,
|
|
1026
|
-
name
|
|
1027
|
-
});
|