@zhin.js/plugin-60s 3.0.1 → 3.0.3
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/agent/tools/60s_news.ts +13 -0
- package/agent/tools/bing_image.ts +13 -0
- package/agent/tools/douyin_hot.ts +13 -0
- package/agent/tools/duanzi.ts +13 -0
- package/agent/tools/exchange_rate.ts +13 -0
- package/agent/tools/fuel_price.ts +13 -0
- package/agent/tools/gold_price.ts +13 -0
- package/agent/tools/history_today.ts +13 -0
- package/agent/tools/hitokoto.ts +13 -0
- package/agent/tools/ip_query.ts +13 -0
- package/agent/tools/kfc.ts +13 -0
- package/agent/tools/moyu.ts +13 -0
- package/agent/tools/toutiao_hot.ts +13 -0
- package/agent/tools/translate_60s.ts +13 -0
- package/agent/tools/weather.ts +13 -0
- package/agent/tools/weibo_hot.ts +13 -0
- package/agent/tools/zhihu_hot.ts +13 -0
- package/commands/60s.ts +7 -0
- package/commands/bing.ts +7 -0
- package/commands/douyin/[limit:number=10].ts +7 -0
- package/commands/duanzi.ts +7 -0
- package/commands/exchange.ts +10 -0
- package/commands/fanyi/[text:string].ts +7 -0
- package/commands/fuel/[province:string].ts +7 -0
- package/commands/gold.ts +7 -0
- package/commands/history.ts +7 -0
- package/commands/hitokoto/[type:string].ts +7 -0
- package/commands/ip/[ip:string].ts +7 -0
- package/commands/kfc.ts +7 -0
- package/commands/moyu.ts +7 -0
- package/commands/toutiao/[limit:number=10].ts +7 -0
- package/commands/weather/[city:string].ts +7 -0
- package/commands/weibo/[limit:number=10].ts +7 -0
- package/commands/zhihu/[limit:number=10].ts +7 -0
- package/lib/api.js +45 -0
- package/lib/api.js.map +1 -0
- package/lib/handlers/60s-news.js +12 -0
- package/lib/handlers/60s-news.js.map +1 -0
- package/lib/handlers/bing-image.js +18 -0
- package/lib/handlers/bing-image.js.map +1 -0
- package/lib/handlers/douyin-hot.js +6 -0
- package/lib/handlers/douyin-hot.js.map +1 -0
- package/lib/handlers/duanzi.js +6 -0
- package/lib/handlers/duanzi.js.map +1 -0
- package/lib/handlers/exchange-rate.js +28 -0
- package/lib/handlers/exchange-rate.js.map +1 -0
- package/lib/handlers/fuel-price.js +21 -0
- package/lib/handlers/fuel-price.js.map +1 -0
- package/lib/handlers/gold-price.js +24 -0
- package/lib/handlers/gold-price.js.map +1 -0
- package/lib/handlers/history-today.js +16 -0
- package/lib/handlers/history-today.js.map +1 -0
- package/lib/handlers/hitokoto.js +16 -0
- package/lib/handlers/hitokoto.js.map +1 -0
- package/lib/handlers/ip-query.js +17 -0
- package/lib/handlers/ip-query.js.map +1 -0
- package/lib/handlers/kfc.js +6 -0
- package/lib/handlers/kfc.js.map +1 -0
- package/lib/handlers/moyu.js +39 -0
- package/lib/handlers/moyu.js.map +1 -0
- package/lib/handlers/toutiao-hot.js +6 -0
- package/lib/handlers/toutiao-hot.js.map +1 -0
- package/lib/handlers/translate.js +26 -0
- package/lib/handlers/translate.js.map +1 -0
- package/lib/handlers/weather.js +22 -0
- package/lib/handlers/weather.js.map +1 -0
- package/lib/handlers/weibo-hot.js +6 -0
- package/lib/handlers/weibo-hot.js.map +1 -0
- package/lib/handlers/zhihu-hot.js +6 -0
- package/lib/handlers/zhihu-hot.js.map +1 -0
- package/lib/index.js +1 -34
- package/lib/index.js.map +1 -1
- package/package.json +48 -12
- package/plugin.ts +18 -0
- package/schema.json +12 -0
- package/src/api.ts +63 -0
- package/{tools/60s-news/handler.ts → src/handlers/60s-news.ts} +1 -1
- package/{tools/bing-image/handler.ts → src/handlers/bing-image.ts} +4 -4
- package/{tools/douyin-hot/handler.ts → src/handlers/douyin-hot.ts} +2 -2
- package/{tools/duanzi/handler.ts → src/handlers/duanzi.ts} +1 -1
- package/{tools/exchange-rate/handler.ts → src/handlers/exchange-rate.ts} +8 -6
- package/{tools/fuel-price/handler.ts → src/handlers/fuel-price.ts} +5 -4
- package/{tools/gold-price/handler.ts → src/handlers/gold-price.ts} +8 -7
- package/src/handlers/history-today.ts +16 -0
- package/{tools/hitokoto/handler.ts → src/handlers/hitokoto.ts} +1 -1
- package/{tools/ip-query/handler.ts → src/handlers/ip-query.ts} +1 -1
- package/{tools/kfc/handler.ts → src/handlers/kfc.ts} +1 -1
- package/src/handlers/moyu.ts +35 -0
- package/{tools/toutiao-hot/handler.ts → src/handlers/toutiao-hot.ts} +2 -2
- package/src/handlers/translate.ts +25 -0
- package/src/handlers/weather.ts +22 -0
- package/{tools/weibo-hot/handler.ts → src/handlers/weibo-hot.ts} +2 -2
- package/{tools/zhihu-hot/handler.ts → src/handlers/zhihu-hot.ts} +2 -2
- package/src/index.ts +8 -44
- package/lib/index.d.ts +0 -2
- package/lib/index.d.ts.map +0 -1
- package/plugin.yml +0 -3
- package/tools/60s-news/60s-news.tool.md +0 -8
- package/tools/api.ts +0 -34
- package/tools/bing-image/bing-image.tool.md +0 -8
- package/tools/douyin-hot/douyin-hot.tool.md +0 -12
- package/tools/duanzi/duanzi.tool.md +0 -8
- package/tools/exchange-rate/exchange-rate.tool.md +0 -14
- package/tools/fuel-price/fuel-price.tool.md +0 -11
- package/tools/gold-price/gold-price.tool.md +0 -8
- package/tools/history-today/handler.ts +0 -15
- package/tools/history-today/history-today.tool.md +0 -8
- package/tools/hitokoto/hitokoto.tool.md +0 -12
- package/tools/ip-query/ip-query.tool.md +0 -12
- package/tools/kfc/kfc.tool.md +0 -8
- package/tools/moyu/handler.ts +0 -28
- package/tools/moyu/moyu.tool.md +0 -8
- package/tools/toutiao-hot/toutiao-hot.tool.md +0 -12
- package/tools/translate/handler.ts +0 -19
- package/tools/translate/translate.tool.md +0 -15
- package/tools/weather/handler.ts +0 -22
- package/tools/weather/weather.tool.md +0 -12
- package/tools/weibo-hot/weibo-hot.tool.md +0 -12
- package/tools/zhihu-hot/zhihu-hot.tool.md +0 -12
- /package/{skills/60s/SKILL.md → agent/skills/60s.md} +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { asArray, asRecord, fetchApi } from '../api.js';
|
|
2
|
+
export default async function () {
|
|
3
|
+
const data = await fetchApi('/today-in-history');
|
|
4
|
+
const dateStr = data.date || `${data.month || ''}月${data.day || ''}日`;
|
|
5
|
+
const lines = [`📅 历史上的今天 (${dateStr})`, ''];
|
|
6
|
+
const items = asArray(data.items);
|
|
7
|
+
items.slice(0, 10).forEach((item, i) => {
|
|
8
|
+
const row = asRecord(item);
|
|
9
|
+
const year = row.year || '';
|
|
10
|
+
const title = row.title || row.event || row.content || item;
|
|
11
|
+
const typeIcon = row.event_type === 'birth' ? '👶' : row.event_type === 'death' ? '🕊️' : '📌';
|
|
12
|
+
lines.push(`${typeIcon} ${i + 1}. ${year ? `[${year}] ` : ''}${title}`);
|
|
13
|
+
});
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=history-today.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-today.js","sourceRoot":"","sources":["../../src/handlers/history-today.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,CAAC,OAAO,CAAC,KAAK;IAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC;IACtE,MAAM,KAAK,GAAG,CAAC,cAAc,OAAO,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAS,EAAE,EAAE;QAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC;QAC5D,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/F,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
export default async function (args) {
|
|
3
|
+
const params = args.type
|
|
4
|
+
? { c: args.type }
|
|
5
|
+
: undefined;
|
|
6
|
+
const data = await fetchApi('/hitokoto', params);
|
|
7
|
+
const text = data.hitokoto || data.content || (typeof data === 'string' ? data : '');
|
|
8
|
+
const lines = ['💬 一言', '', `「${text}」`];
|
|
9
|
+
if (data.from || data.source || data.from_who || data.author) {
|
|
10
|
+
const author = data.from_who || data.author || '';
|
|
11
|
+
const source = data.from || data.source || '';
|
|
12
|
+
lines.push(`——${author}${source ? `《${source}》` : ''}`);
|
|
13
|
+
}
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=hitokoto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hitokoto.js","sourceRoot":"","sources":["../../src/handlers/hitokoto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAuB;IACpD,MAAM,MAAM,GAAuC,IAAI,CAAC,IAAI;QAC1D,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE;QAClB,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrF,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
export default async function (args) {
|
|
3
|
+
const params = args.ip
|
|
4
|
+
? { ip: args.ip }
|
|
5
|
+
: undefined;
|
|
6
|
+
const data = await fetchApi('/ip', params);
|
|
7
|
+
const lines = ['🌐 IP 查询', '', `IP: ${data.ip || args.ip || '当前 IP'}`];
|
|
8
|
+
if (data.country || data.region || data.city) {
|
|
9
|
+
lines.push(`位置: ${[data.country, data.region, data.city].filter(Boolean).join(' ')}`);
|
|
10
|
+
}
|
|
11
|
+
if (data.location)
|
|
12
|
+
lines.push(`位置: ${data.location}`);
|
|
13
|
+
if (data.isp)
|
|
14
|
+
lines.push(`运营商: ${data.isp}`);
|
|
15
|
+
return lines.join('\n');
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=ip-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip-query.js","sourceRoot":"","sources":["../../src/handlers/ip-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAqB;IAClD,MAAM,MAAM,GAAuC,IAAI,CAAC,EAAE;QACxD,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACjB,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,CAAC,CAAC;IACvE,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kfc.js","sourceRoot":"","sources":["../../src/handlers/kfc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,OAAO,CAAC,KAAK;IAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,eAAe,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC1G,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { asArray, asRecord, asString, fetchApi } from '../api.js';
|
|
2
|
+
export default async function () {
|
|
3
|
+
const data = await fetchApi('/moyu');
|
|
4
|
+
if (typeof data === 'string')
|
|
5
|
+
return `🐟 摸鱼日历\n\n${data}`;
|
|
6
|
+
const lines = ['🐟 摸鱼日历', ''];
|
|
7
|
+
const date = asRecord(data.date);
|
|
8
|
+
if (date.gregorian)
|
|
9
|
+
lines.push(`📅 ${date.gregorian} ${asString(date.weekday)}`);
|
|
10
|
+
const lunar = asRecord(date.lunar);
|
|
11
|
+
if (lunar.monthCN || lunar.dayCN) {
|
|
12
|
+
lines.push(`🌙 农历${asString(lunar.monthCN)}${asString(lunar.dayCN)} ${asString(lunar.yearGanZhi)}年`);
|
|
13
|
+
}
|
|
14
|
+
const today = asRecord(data.today);
|
|
15
|
+
if (today.holidayName)
|
|
16
|
+
lines.push(`🎉 ${today.holidayName}`);
|
|
17
|
+
if (today.solarTerm)
|
|
18
|
+
lines.push(`🌿 ${today.solarTerm}`);
|
|
19
|
+
if (today.isWorkday !== undefined) {
|
|
20
|
+
lines.push(today.isWorkday ? '💼 今天是工作日' : '🎮 今天不上班');
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(data.festivals)) {
|
|
23
|
+
data.festivals.forEach((f) => {
|
|
24
|
+
lines.push(`🎊 ${typeof f === 'string' ? f : asString(asRecord(f).name ?? f)}`);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const countdown = asArray(data.countdown);
|
|
28
|
+
if (countdown.length > 0) {
|
|
29
|
+
lines.push('');
|
|
30
|
+
countdown.forEach((c) => {
|
|
31
|
+
const row = asRecord(c);
|
|
32
|
+
if (typeof row.name === 'string' && typeof row.days === 'number') {
|
|
33
|
+
lines.push(`⏳ 距 ${row.name} 还有 ${row.days} 天`);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return lines.join('\n');
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=moyu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moyu.js","sourceRoot":"","sources":["../../src/handlers/moyu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAmB,MAAM,WAAW,CAAC;AAEnF,MAAM,CAAC,OAAO,CAAC,KAAK;IAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAsB,OAAO,CAAC,CAAC;IAC1D,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,cAAc,IAAI,EAAE,CAAC;IAC1D,MAAM,KAAK,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,IAAI,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjF,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,QAAQ,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACvG,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,WAAW;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7D,IAAI,KAAK,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAU,EAAE,EAAE;YACpC,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC,CAAC,CAAC;IACL,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,SAAS,CAAC,OAAO,CAAC,CAAC,CAAU,EAAE,EAAE;YAC/B,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACjE,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;YACjD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toutiao-hot.js","sourceRoot":"","sources":["../../src/handlers/toutiao-hot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAiB,MAAM,WAAW,CAAC;AAEhE,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAwB;IACrD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAa,UAAU,CAAC,CAAC;IACpD,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { asRecord, asString, fetchApi } from '../api.js';
|
|
2
|
+
export default async function (args) {
|
|
3
|
+
const params = { text: args.text };
|
|
4
|
+
if (args.to)
|
|
5
|
+
params.to = args.to;
|
|
6
|
+
const data = await fetchApi('/fanyi', params);
|
|
7
|
+
const source = asRecord(data.source);
|
|
8
|
+
const target = asRecord(data.target);
|
|
9
|
+
const srcText = asString(source.text) || args.text;
|
|
10
|
+
const srcLang = asString(source.type_desc) || asString(source.type);
|
|
11
|
+
const tgtText = asString(target.text) ||
|
|
12
|
+
asString(data.result) ||
|
|
13
|
+
asString(data.translation) ||
|
|
14
|
+
(typeof data === 'string' ? data : '');
|
|
15
|
+
const tgtLang = asString(target.type_desc) || asString(target.type);
|
|
16
|
+
const lines = [
|
|
17
|
+
'🌐 翻译结果',
|
|
18
|
+
'',
|
|
19
|
+
`原文${srcLang ? ` (${srcLang})` : ''}: ${srcText}`,
|
|
20
|
+
`译文${tgtLang ? ` (${tgtLang})` : ''}: ${tgtText}`,
|
|
21
|
+
];
|
|
22
|
+
if (target.pronounce)
|
|
23
|
+
lines.push(`发音: ${asString(target.pronounce)}`);
|
|
24
|
+
return lines.join('\n');
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=translate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/handlers/translate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAmC;IAChE,MAAM,MAAM,GAA2B,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC3D,IAAI,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;IACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,OAAO,GACX,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC;QAC1B,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG;QACZ,SAAS;QACT,EAAE;QACF,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,EAAE;QACjD,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,EAAE;KAClD,CAAC;IACF,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { asRecord, asString, fetchApi } from '../api.js';
|
|
2
|
+
export default async function (args) {
|
|
3
|
+
const data = await fetchApi('/weather', { query: args.city });
|
|
4
|
+
const w = asRecord(data.weather);
|
|
5
|
+
const aq = asRecord(data.air_quality);
|
|
6
|
+
const loc = asRecord(data.location);
|
|
7
|
+
const cityName = asString(loc.city) || asString(loc.name) || args.city;
|
|
8
|
+
const lines = [
|
|
9
|
+
`🌤️ ${cityName} 天气`,
|
|
10
|
+
'',
|
|
11
|
+
`🌡️ 温度: ${asString(w.temperature)}°C`,
|
|
12
|
+
`☁️ 天气: ${asString(w.condition)}`,
|
|
13
|
+
`💧 湿度: ${asString(w.humidity)}%`,
|
|
14
|
+
`💨 风: ${asString(w.wind_direction)} ${asString(w.wind_power)}`,
|
|
15
|
+
];
|
|
16
|
+
if (Object.keys(aq).length > 0) {
|
|
17
|
+
const quality = asString(aq.quality);
|
|
18
|
+
lines.push(`🌬️ 空气: ${quality}${aq.aqi ? ` (AQI ${asString(aq.aqi)})` : ''}`);
|
|
19
|
+
}
|
|
20
|
+
return lines.join('\n');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=weather.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weather.js","sourceRoot":"","sources":["../../src/handlers/weather.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEzD,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAsB;IACnD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;IACvE,MAAM,KAAK,GAAG;QACZ,OAAO,QAAQ,KAAK;QACpB,EAAE;QACF,WAAW,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI;QACtC,UAAU,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;QACjC,UAAU,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG;QACjC,SAAS,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;KAChE,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,WAAW,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weibo-hot.js","sourceRoot":"","sources":["../../src/handlers/weibo-hot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAiB,MAAM,WAAW,CAAC;AAEhE,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAwB;IACrD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAa,QAAQ,CAAC,CAAC;IAClD,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zhihu-hot.js","sourceRoot":"","sources":["../../src/handlers/zhihu-hot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAiB,MAAM,WAAW,CAAC;AAEhE,MAAM,CAAC,OAAO,CAAC,KAAK,WAAW,IAAwB;IACrD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAa,QAAQ,CAAC,CAAC;IAClD,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxE,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -1,35 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* @zhin.js/plugin-60s
|
|
3
|
-
*
|
|
4
|
-
* 60s API 聚合插件 —— 基于 https://github.com/vikiboss/60s
|
|
5
|
-
*
|
|
6
|
-
* 提供多种实用 API 功能,每个功能通过 tools/*.tool.md 文件定义:
|
|
7
|
-
* - 聊天命令(/60s, /天气 北京, /微博 …)
|
|
8
|
-
* - AI 工具(Agent 可通过关键词自动匹配并调用)
|
|
9
|
-
*
|
|
10
|
-
* 功能列表:
|
|
11
|
-
* 60s新闻 · 天气 · 微博热搜 · 知乎热榜 · 抖音热搜 · 头条热搜
|
|
12
|
-
* 一言 · 摸鱼日历 · IP查询 · Bing壁纸 · 金价 · 油价
|
|
13
|
-
* 汇率 · 翻译 · 历史上的今天 · KFC文案 · 段子
|
|
14
|
-
*
|
|
15
|
-
* 所有工具定义在 tools/ 目录下,框架自动发现注册。
|
|
16
|
-
*
|
|
17
|
-
* 配置方式(zhin.config.yml):
|
|
18
|
-
* ```yaml
|
|
19
|
-
* plugins:
|
|
20
|
-
* 60s:
|
|
21
|
-
* apiBase: https://60s.viki.moe
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
import { usePlugin } from 'zhin.js';
|
|
25
|
-
const plugin = usePlugin();
|
|
26
|
-
const { logger, root } = plugin;
|
|
27
|
-
const configService = root.inject('config');
|
|
28
|
-
const appConfig = configService?.getPrimary() || {};
|
|
29
|
-
const config = {
|
|
30
|
-
apiBase: 'https://60s.viki.moe',
|
|
31
|
-
...appConfig['60s'],
|
|
32
|
-
};
|
|
33
|
-
// 将 API 地址写入环境变量,供 tool handler 使用
|
|
34
|
-
process.env.ZHIN_60S_API = config.apiBase || 'https://60s.viki.moe';
|
|
1
|
+
export { asArray, asRecord, asString, fetchApi, formatList, } from './api.js';
|
|
35
2
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,GACX,MAAM,UAAU,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-60s",
|
|
3
|
-
"version": "3.0.
|
|
4
|
-
"description": "60s API aggregation plugin for Zhin.js — news, weather, hot searches, utilities
|
|
3
|
+
"version": "3.0.3",
|
|
4
|
+
"description": "60s API aggregation plugin for Zhin.js — news, weather, hot searches, utilities (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -14,13 +14,12 @@
|
|
|
14
14
|
"./package.json": "./package.json"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
+
"plugin.ts",
|
|
18
|
+
"schema.json",
|
|
19
|
+
"commands",
|
|
17
20
|
"src",
|
|
18
21
|
"lib",
|
|
19
|
-
"
|
|
20
|
-
"dist",
|
|
21
|
-
"skills",
|
|
22
|
-
"tools",
|
|
23
|
-
"plugin.yml",
|
|
22
|
+
"agent",
|
|
24
23
|
"README.md"
|
|
25
24
|
],
|
|
26
25
|
"keywords": [
|
|
@@ -45,13 +44,28 @@
|
|
|
45
44
|
"url": "https://github.com/lc-cn"
|
|
46
45
|
},
|
|
47
46
|
"license": "MIT",
|
|
48
|
-
"dependencies": {
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@zhin.js/command": "1.0.1",
|
|
49
|
+
"@zhin.js/plugin-runtime": "1.0.1",
|
|
50
|
+
"@zhin.js/tool": "1.0.1"
|
|
51
|
+
},
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"typescript": "^6.0.3",
|
|
51
|
-
"
|
|
54
|
+
"vitest": "^4.1.10",
|
|
55
|
+
"zod": "^4.4.3",
|
|
56
|
+
"@zhin.js/agent": "1.0.4"
|
|
52
57
|
},
|
|
53
58
|
"peerDependencies": {
|
|
54
|
-
"
|
|
59
|
+
"zod": "^4.0.0",
|
|
60
|
+
"@zhin.js/agent": "1.0.4"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@zhin.js/agent": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"zod": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
55
69
|
},
|
|
56
70
|
"repository": {
|
|
57
71
|
"type": "git",
|
|
@@ -62,8 +76,30 @@
|
|
|
62
76
|
"access": "public",
|
|
63
77
|
"registry": "https://registry.npmjs.org"
|
|
64
78
|
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
81
|
+
},
|
|
82
|
+
"zhin": {
|
|
83
|
+
"protocol": 1,
|
|
84
|
+
"type": "plugin",
|
|
85
|
+
"entry": "./plugin.ts",
|
|
86
|
+
"engine": "^1.0.0",
|
|
87
|
+
"runtime": "trusted",
|
|
88
|
+
"features": [
|
|
89
|
+
{
|
|
90
|
+
"package": "@zhin.js/command",
|
|
91
|
+
"api": "^1.0.0"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"package": "@zhin.js/tool",
|
|
95
|
+
"api": "^1.0.0"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"plugins": []
|
|
99
|
+
},
|
|
65
100
|
"scripts": {
|
|
66
|
-
"build": "tsc
|
|
67
|
-
"clean": "rimraf lib"
|
|
101
|
+
"build": "tsc",
|
|
102
|
+
"clean": "rimraf lib",
|
|
103
|
+
"test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/utils/60s/tests"
|
|
68
104
|
}
|
|
69
105
|
}
|
package/plugin.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { definePlugin } from '@zhin.js/plugin-runtime';
|
|
2
|
+
|
|
3
|
+
export interface SixtySConfig {
|
|
4
|
+
readonly apiBase?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const DEFAULT_API_BASE = 'https://60s.viki.moe';
|
|
8
|
+
|
|
9
|
+
export default definePlugin<SixtySConfig>({
|
|
10
|
+
name: 'sixty-s',
|
|
11
|
+
metadata: {
|
|
12
|
+
displayName: '60s API',
|
|
13
|
+
},
|
|
14
|
+
setup(context) {
|
|
15
|
+
const apiBase = context.config.get().apiBase?.trim() || DEFAULT_API_BASE;
|
|
16
|
+
process.env.ZHIN_60S_API = apiBase;
|
|
17
|
+
},
|
|
18
|
+
});
|
package/schema.json
ADDED
package/src/api.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 60s API 共享模块 — 供 *.tool.md handler 使用
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const API_BASE = process.env.ZHIN_60S_API || 'https://60s.viki.moe';
|
|
6
|
+
|
|
7
|
+
export type ListItem = string | Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
/** Untyped 60s API JSON payload (handlers narrow fields at runtime). */
|
|
10
|
+
export type ApiPayload = Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
export async function fetchApi<T = ApiPayload>(
|
|
13
|
+
endpoint: string,
|
|
14
|
+
params?: Record<string, string>,
|
|
15
|
+
): Promise<T> {
|
|
16
|
+
const url = new URL(`${API_BASE}/v2${endpoint}`);
|
|
17
|
+
if (params) {
|
|
18
|
+
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
19
|
+
}
|
|
20
|
+
const res = await fetch(url.toString());
|
|
21
|
+
const data = (await res.json()) as {
|
|
22
|
+
error?: string;
|
|
23
|
+
code?: number;
|
|
24
|
+
message?: string;
|
|
25
|
+
msg?: string;
|
|
26
|
+
data?: T;
|
|
27
|
+
};
|
|
28
|
+
if (data.error) throw new Error(data.error);
|
|
29
|
+
if (data.code !== undefined && data.code !== 200 && data.code !== 0) {
|
|
30
|
+
throw new Error(data.message || data.msg || `API 错误: ${data.code}`);
|
|
31
|
+
}
|
|
32
|
+
return (data.data ?? data) as T;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Coerce nested API JSON objects for property access in handlers. */
|
|
36
|
+
export function asRecord(value: unknown): ApiPayload {
|
|
37
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
38
|
+
? (value as ApiPayload)
|
|
39
|
+
: {};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function asString(value: unknown): string {
|
|
43
|
+
return value == null ? '' : String(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function asArray(value: unknown): unknown[] {
|
|
47
|
+
return Array.isArray(value) ? value : [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function formatList(items: ListItem[], limit = 10): string {
|
|
51
|
+
return items
|
|
52
|
+
.slice(0, limit)
|
|
53
|
+
.map((item, i) => {
|
|
54
|
+
const obj = typeof item === 'string' ? null : item;
|
|
55
|
+
const title = obj
|
|
56
|
+
? String(obj.title ?? obj.name ?? obj.word ?? item)
|
|
57
|
+
: item;
|
|
58
|
+
const hot = obj ? obj.hot_value ?? obj.hot : undefined;
|
|
59
|
+
const hotStr = hot ? ` 🔥${hot}` : '';
|
|
60
|
+
return `${i + 1}. ${title}${hotStr}`;
|
|
61
|
+
})
|
|
62
|
+
.join('\n');
|
|
63
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function () {
|
|
4
|
-
const data = await fetchApi
|
|
4
|
+
const data = await fetchApi('/60s');
|
|
5
5
|
const lines = [`📰 今日60秒新闻 (${data.date || ''})`, ''];
|
|
6
6
|
if (data.news && Array.isArray(data.news)) {
|
|
7
7
|
lines.push(...data.news.map((n: string, i: number) => `${i + 1}. ${n}`));
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { fetchApi } from '../api.js';
|
|
1
|
+
import { asString, fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function () {
|
|
4
|
-
const data = await fetchApi
|
|
4
|
+
const data = await fetchApi('/bing');
|
|
5
5
|
const lines = ['🖼️ Bing 每日壁纸', ''];
|
|
6
6
|
if (data.title) lines.push(`📌 ${data.title}`);
|
|
7
7
|
if (data.headline) lines.push(`💡 ${data.headline}`);
|
|
8
8
|
if (data.copyright) lines.push(`📝 ${data.copyright}`);
|
|
9
|
-
if (data.description) lines.push('', data.description);
|
|
9
|
+
if (data.description) lines.push('', asString(data.description));
|
|
10
10
|
const imgUrl = data.cover || data.cover_4k || data.url || data.image;
|
|
11
|
-
if (imgUrl) lines.push('', imgUrl);
|
|
11
|
+
if (imgUrl) lines.push('', asString(imgUrl));
|
|
12
12
|
return lines.join('\n');
|
|
13
13
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { fetchApi, formatList } from '../api.js';
|
|
1
|
+
import { fetchApi, formatList, type ListItem } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function (args: { limit?: number }) {
|
|
4
|
-
const data = await fetchApi<
|
|
4
|
+
const data = await fetchApi<ListItem[]>('/douyin');
|
|
5
5
|
return ['🔥 抖音热搜', '', formatList(data, args.limit || 10)].join('\n');
|
|
6
6
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function () {
|
|
4
|
-
const data = await fetchApi
|
|
4
|
+
const data = await fetchApi('/duanzi');
|
|
5
5
|
return `😂 段子\n\n${data.duanzi || data.content || data.text || (typeof data === 'string' ? data : '')}`;
|
|
6
6
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { fetchApi } from '../api.js';
|
|
1
|
+
import { asArray, asRecord, asString, fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function (args: { from?: string; to?: string }) {
|
|
4
4
|
const params: Record<string, string> = {};
|
|
5
5
|
if (args.from) params.from = args.from.toUpperCase();
|
|
6
6
|
if (args.to) params.to = args.to.toUpperCase();
|
|
7
|
-
const data = await fetchApi
|
|
7
|
+
const data = await fetchApi(
|
|
8
8
|
'/exchange-rate',
|
|
9
9
|
Object.keys(params).length ? params : undefined,
|
|
10
10
|
);
|
|
@@ -13,13 +13,15 @@ export default async function (args: { from?: string; to?: string }) {
|
|
|
13
13
|
lines.push(`基准货币: ${base}`);
|
|
14
14
|
if (data.updated) lines.push(`更新时间: ${data.updated}`);
|
|
15
15
|
lines.push('');
|
|
16
|
-
const rates = data.rates
|
|
16
|
+
const rates = asArray(data.rates);
|
|
17
17
|
const targetCurrencies = args.to
|
|
18
18
|
? [args.to.toUpperCase()]
|
|
19
19
|
: ['USD', 'EUR', 'JPY', 'GBP', 'HKD', 'KRW', 'AUD', 'CAD', 'SGD', 'CHF'];
|
|
20
|
-
rates.forEach((item
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
rates.forEach((item) => {
|
|
21
|
+
const row = asRecord(item);
|
|
22
|
+
const currency = asString(row.currency);
|
|
23
|
+
if (targetCurrencies.includes(currency) && currency !== base) {
|
|
24
|
+
lines.push(`${base} → ${currency}: ${row.rate}`);
|
|
23
25
|
}
|
|
24
26
|
});
|
|
25
27
|
return lines.join('\n');
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { fetchApi } from '../api.js';
|
|
1
|
+
import { asRecord, asString, fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function (args: { province?: string }) {
|
|
4
4
|
const params: Record<string, string> | undefined = args.province
|
|
5
5
|
? { province: args.province }
|
|
6
6
|
: undefined;
|
|
7
|
-
const data = await fetchApi
|
|
7
|
+
const data = await fetchApi('/fuel-price', params);
|
|
8
8
|
const lines = ['⛽ 今日油价', ''];
|
|
9
9
|
if (data.region) lines.push(`📍 ${data.region}`);
|
|
10
10
|
if (data.items && Array.isArray(data.items)) {
|
|
11
|
-
data.items.forEach((item:
|
|
11
|
+
data.items.forEach((item: Record<string, unknown>) => {
|
|
12
12
|
lines.push(`${item.name}: ${item.price_desc || `¥${item.price}/升`}`);
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
if (data.trend) {
|
|
16
|
-
|
|
16
|
+
const trend = asRecord(data.trend);
|
|
17
|
+
lines.push('', `📊 ${asString(trend.description)}`);
|
|
17
18
|
}
|
|
18
19
|
return lines.join('\n');
|
|
19
20
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { fetchApi } from '../api.js';
|
|
1
|
+
import { asArray, asRecord, fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function () {
|
|
4
|
-
const data = await fetchApi
|
|
4
|
+
const data = await fetchApi('/gold-price');
|
|
5
5
|
const lines = ['💰 今日金价', ''];
|
|
6
6
|
if (data.date) lines.push(`📅 ${data.date}`);
|
|
7
|
-
const metals = data.metals
|
|
7
|
+
const metals = asArray(data.metals);
|
|
8
8
|
if (metals.length > 0) {
|
|
9
9
|
lines.push('');
|
|
10
|
-
metals.forEach((item
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
10
|
+
metals.forEach((item) => {
|
|
11
|
+
const row = asRecord(item);
|
|
12
|
+
const name = row.name || '黄金';
|
|
13
|
+
const price = row.today_price || row.sell_price || row.price || 'N/A';
|
|
14
|
+
const unit = row.unit || '元/克';
|
|
14
15
|
if (price !== 'N/A') lines.push(`${name}: ¥${price} ${unit}`);
|
|
15
16
|
});
|
|
16
17
|
} else if (data.price) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { asArray, asRecord, fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function () {
|
|
4
|
+
const data = await fetchApi('/today-in-history');
|
|
5
|
+
const dateStr = data.date || `${data.month || ''}月${data.day || ''}日`;
|
|
6
|
+
const lines = [`📅 历史上的今天 (${dateStr})`, ''];
|
|
7
|
+
const items = asArray(data.items);
|
|
8
|
+
items.slice(0, 10).forEach((item, i: number) => {
|
|
9
|
+
const row = asRecord(item);
|
|
10
|
+
const year = row.year || '';
|
|
11
|
+
const title = row.title || row.event || row.content || item;
|
|
12
|
+
const typeIcon = row.event_type === 'birth' ? '👶' : row.event_type === 'death' ? '🕊️' : '📌';
|
|
13
|
+
lines.push(`${typeIcon} ${i + 1}. ${year ? `[${year}] ` : ''}${title}`);
|
|
14
|
+
});
|
|
15
|
+
return lines.join('\n');
|
|
16
|
+
}
|
|
@@ -4,7 +4,7 @@ export default async function (args: { type?: string }) {
|
|
|
4
4
|
const params: Record<string, string> | undefined = args.type
|
|
5
5
|
? { c: args.type }
|
|
6
6
|
: undefined;
|
|
7
|
-
const data = await fetchApi
|
|
7
|
+
const data = await fetchApi('/hitokoto', params);
|
|
8
8
|
const text = data.hitokoto || data.content || (typeof data === 'string' ? data : '');
|
|
9
9
|
const lines = ['💬 一言', '', `「${text}」`];
|
|
10
10
|
if (data.from || data.source || data.from_who || data.author) {
|
|
@@ -4,7 +4,7 @@ export default async function (args: { ip?: string }) {
|
|
|
4
4
|
const params: Record<string, string> | undefined = args.ip
|
|
5
5
|
? { ip: args.ip }
|
|
6
6
|
: undefined;
|
|
7
|
-
const data = await fetchApi
|
|
7
|
+
const data = await fetchApi('/ip', params);
|
|
8
8
|
const lines = ['🌐 IP 查询', '', `IP: ${data.ip || args.ip || '当前 IP'}`];
|
|
9
9
|
if (data.country || data.region || data.city) {
|
|
10
10
|
lines.push(`位置: ${[data.country, data.region, data.city].filter(Boolean).join(' ')}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fetchApi } from '../api.js';
|
|
2
2
|
|
|
3
3
|
export default async function () {
|
|
4
|
-
const data = await fetchApi
|
|
4
|
+
const data = await fetchApi('/kfc');
|
|
5
5
|
return `🍗 疯狂星期四\n\n${data.kfc || data.content || data.text || (typeof data === 'string' ? data : '')}`;
|
|
6
6
|
}
|