@zhin.js/plugin-60s 0.0.7 → 0.0.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/package.json +6 -4
- package/plugin.yml +3 -0
- package/tools/60s-news/60s-news.tool.md +8 -0
- package/tools/60s-news/handler.ts +11 -0
- package/tools/api.ts +34 -0
- package/tools/bing-image/bing-image.tool.md +8 -0
- package/tools/bing-image/handler.ts +13 -0
- package/tools/douyin-hot/douyin-hot.tool.md +12 -0
- package/tools/douyin-hot/handler.ts +6 -0
- package/tools/duanzi/duanzi.tool.md +8 -0
- package/tools/duanzi/handler.ts +6 -0
- package/tools/exchange-rate/exchange-rate.tool.md +14 -0
- package/tools/exchange-rate/handler.ts +26 -0
- package/tools/fuel-price/fuel-price.tool.md +11 -0
- package/tools/fuel-price/handler.ts +19 -0
- package/tools/gold-price/gold-price.tool.md +8 -0
- package/tools/gold-price/handler.ts +20 -0
- package/tools/history-today/handler.ts +15 -0
- package/tools/history-today/history-today.tool.md +8 -0
- package/tools/hitokoto/handler.ts +16 -0
- package/tools/hitokoto/hitokoto.tool.md +12 -0
- package/tools/ip-query/handler.ts +15 -0
- package/tools/ip-query/ip-query.tool.md +12 -0
- package/tools/kfc/handler.ts +6 -0
- package/tools/kfc/kfc.tool.md +8 -0
- package/tools/moyu/handler.ts +28 -0
- package/tools/moyu/moyu.tool.md +8 -0
- package/tools/toutiao-hot/handler.ts +6 -0
- package/tools/toutiao-hot/toutiao-hot.tool.md +12 -0
- package/tools/translate/handler.ts +19 -0
- package/tools/translate/translate.tool.md +15 -0
- package/tools/weather/handler.ts +22 -0
- package/tools/weather/weather.tool.md +12 -0
- package/tools/weibo-hot/handler.ts +6 -0
- package/tools/weibo-hot/weibo-hot.tool.md +12 -0
- package/tools/zhihu-hot/handler.ts +6 -0
- package/tools/zhihu-hot/zhihu-hot.tool.md +12 -0
- package/LICENSE +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-60s",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "60s API aggregation plugin for Zhin.js — news, weather, hot searches, utilities and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"client",
|
|
20
20
|
"dist",
|
|
21
21
|
"skills",
|
|
22
|
+
"tools",
|
|
23
|
+
"plugin.yml",
|
|
22
24
|
"README.md"
|
|
23
25
|
],
|
|
24
26
|
"keywords": [
|
|
@@ -45,11 +47,11 @@
|
|
|
45
47
|
"license": "MIT",
|
|
46
48
|
"dependencies": {},
|
|
47
49
|
"devDependencies": {
|
|
48
|
-
"typescript": "^
|
|
49
|
-
"zhin.js": "1.0.
|
|
50
|
+
"typescript": "^6.0.0",
|
|
51
|
+
"zhin.js": "1.0.71"
|
|
50
52
|
},
|
|
51
53
|
"peerDependencies": {
|
|
52
|
-
"zhin.js": "
|
|
54
|
+
"zhin.js": "1.0.71"
|
|
53
55
|
},
|
|
54
56
|
"repository": {
|
|
55
57
|
"type": "git",
|
package/plugin.yml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function () {
|
|
4
|
+
const data = await fetchApi<any>('/60s');
|
|
5
|
+
const lines = [`📰 今日60秒新闻 (${data.date || ''})`, ''];
|
|
6
|
+
if (data.news && Array.isArray(data.news)) {
|
|
7
|
+
lines.push(...data.news.map((n: string, i: number) => `${i + 1}. ${n}`));
|
|
8
|
+
}
|
|
9
|
+
if (data.tip) lines.push('', `💡 ${data.tip}`);
|
|
10
|
+
return lines.join('\n');
|
|
11
|
+
}
|
package/tools/api.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
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 async function fetchApi<T = any>(
|
|
8
|
+
endpoint: string,
|
|
9
|
+
params?: Record<string, string>,
|
|
10
|
+
): Promise<T> {
|
|
11
|
+
const url = new URL(`${API_BASE}/v2${endpoint}`);
|
|
12
|
+
if (params) {
|
|
13
|
+
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
14
|
+
}
|
|
15
|
+
const res = await fetch(url.toString());
|
|
16
|
+
const data = (await res.json()) as any;
|
|
17
|
+
if (data.error) throw new Error(data.error);
|
|
18
|
+
if (data.code !== undefined && data.code !== 200 && data.code !== 0) {
|
|
19
|
+
throw new Error(data.message || data.msg || `API 错误: ${data.code}`);
|
|
20
|
+
}
|
|
21
|
+
return data.data ?? data;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function formatList(items: any[], limit = 10): string {
|
|
25
|
+
return items
|
|
26
|
+
.slice(0, limit)
|
|
27
|
+
.map((item, i) => {
|
|
28
|
+
const title = item.title || item.name || item.word || item;
|
|
29
|
+
const hot = item.hot_value || item.hot;
|
|
30
|
+
const hotStr = hot ? ` 🔥${hot}` : '';
|
|
31
|
+
return `${i + 1}. ${title}${hotStr}`;
|
|
32
|
+
})
|
|
33
|
+
.join('\n');
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function () {
|
|
4
|
+
const data = await fetchApi<any>('/bing');
|
|
5
|
+
const lines = ['🖼️ Bing 每日壁纸', ''];
|
|
6
|
+
if (data.title) lines.push(`📌 ${data.title}`);
|
|
7
|
+
if (data.headline) lines.push(`💡 ${data.headline}`);
|
|
8
|
+
if (data.copyright) lines.push(`📝 ${data.copyright}`);
|
|
9
|
+
if (data.description) lines.push('', data.description);
|
|
10
|
+
const imgUrl = data.cover || data.cover_4k || data.url || data.image;
|
|
11
|
+
if (imgUrl) lines.push('', imgUrl);
|
|
12
|
+
return lines.join('\n');
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exchange_rate
|
|
3
|
+
description: 查询货币汇率
|
|
4
|
+
tags: [金融, 汇率, 查询]
|
|
5
|
+
keywords: [汇率, 兑换, 外汇, exchange, rate]
|
|
6
|
+
parameters:
|
|
7
|
+
from:
|
|
8
|
+
type: string
|
|
9
|
+
description: 源货币,如 USD, EUR, JPY
|
|
10
|
+
to:
|
|
11
|
+
type: string
|
|
12
|
+
description: 目标货币,如 CNY
|
|
13
|
+
handler: ./handler.ts
|
|
14
|
+
---
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function (args: { from?: string; to?: string }) {
|
|
4
|
+
const params: Record<string, string> = {};
|
|
5
|
+
if (args.from) params.from = args.from.toUpperCase();
|
|
6
|
+
if (args.to) params.to = args.to.toUpperCase();
|
|
7
|
+
const data = await fetchApi<any>(
|
|
8
|
+
'/exchange-rate',
|
|
9
|
+
Object.keys(params).length ? params : undefined,
|
|
10
|
+
);
|
|
11
|
+
const lines = ['💱 汇率查询', ''];
|
|
12
|
+
const base = data.base_code || args.from || 'CNY';
|
|
13
|
+
lines.push(`基准货币: ${base}`);
|
|
14
|
+
if (data.updated) lines.push(`更新时间: ${data.updated}`);
|
|
15
|
+
lines.push('');
|
|
16
|
+
const rates = data.rates || (Array.isArray(data) ? data : []);
|
|
17
|
+
const targetCurrencies = args.to
|
|
18
|
+
? [args.to.toUpperCase()]
|
|
19
|
+
: ['USD', 'EUR', 'JPY', 'GBP', 'HKD', 'KRW', 'AUD', 'CAD', 'SGD', 'CHF'];
|
|
20
|
+
rates.forEach((item: any) => {
|
|
21
|
+
if (targetCurrencies.includes(item.currency) && item.currency !== base) {
|
|
22
|
+
lines.push(`${base} → ${item.currency}: ${item.rate}`);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return lines.join('\n');
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function (args: { province?: string }) {
|
|
4
|
+
const params: Record<string, string> | undefined = args.province
|
|
5
|
+
? { province: args.province }
|
|
6
|
+
: undefined;
|
|
7
|
+
const data = await fetchApi<any>('/fuel-price', params);
|
|
8
|
+
const lines = ['⛽ 今日油价', ''];
|
|
9
|
+
if (data.region) lines.push(`📍 ${data.region}`);
|
|
10
|
+
if (data.items && Array.isArray(data.items)) {
|
|
11
|
+
data.items.forEach((item: any) => {
|
|
12
|
+
lines.push(`${item.name}: ${item.price_desc || `¥${item.price}/升`}`);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
if (data.trend) {
|
|
16
|
+
lines.push('', `📊 ${data.trend.description || ''}`);
|
|
17
|
+
}
|
|
18
|
+
return lines.join('\n');
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function () {
|
|
4
|
+
const data = await fetchApi<any>('/gold-price');
|
|
5
|
+
const lines = ['💰 今日金价', ''];
|
|
6
|
+
if (data.date) lines.push(`📅 ${data.date}`);
|
|
7
|
+
const metals = data.metals || (Array.isArray(data) ? data : []);
|
|
8
|
+
if (metals.length > 0) {
|
|
9
|
+
lines.push('');
|
|
10
|
+
metals.forEach((item: any) => {
|
|
11
|
+
const name = item.name || '黄金';
|
|
12
|
+
const price = item.today_price || item.sell_price || item.price || 'N/A';
|
|
13
|
+
const unit = item.unit || '元/克';
|
|
14
|
+
if (price !== 'N/A') lines.push(`${name}: ¥${price} ${unit}`);
|
|
15
|
+
});
|
|
16
|
+
} else if (data.price) {
|
|
17
|
+
lines.push(`当前金价: ¥${data.price}/克`);
|
|
18
|
+
}
|
|
19
|
+
return lines.join('\n');
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function () {
|
|
4
|
+
const data = await fetchApi<any>('/today-in-history');
|
|
5
|
+
const dateStr = data.date || `${data.month || ''}月${data.day || ''}日`;
|
|
6
|
+
const lines = [`📅 历史上的今天 (${dateStr})`, ''];
|
|
7
|
+
const items = data.items || (Array.isArray(data) ? data : []);
|
|
8
|
+
items.slice(0, 10).forEach((item: any, i: number) => {
|
|
9
|
+
const year = item.year || '';
|
|
10
|
+
const title = item.title || item.event || item.content || item;
|
|
11
|
+
const typeIcon = item.event_type === 'birth' ? '👶' : item.event_type === 'death' ? '🕊️' : '📌';
|
|
12
|
+
lines.push(`${typeIcon} ${i + 1}. ${year ? `[${year}] ` : ''}${title}`);
|
|
13
|
+
});
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function (args: { type?: string }) {
|
|
4
|
+
const params: Record<string, string> | undefined = args.type
|
|
5
|
+
? { c: args.type }
|
|
6
|
+
: undefined;
|
|
7
|
+
const data = await fetchApi<any>('/hitokoto', params);
|
|
8
|
+
const text = data.hitokoto || data.content || (typeof data === 'string' ? data : '');
|
|
9
|
+
const lines = ['💬 一言', '', `「${text}」`];
|
|
10
|
+
if (data.from || data.source || data.from_who || data.author) {
|
|
11
|
+
const author = data.from_who || data.author || '';
|
|
12
|
+
const source = data.from || data.source || '';
|
|
13
|
+
lines.push(`——${author}${source ? `《${source}》` : ''}`);
|
|
14
|
+
}
|
|
15
|
+
return lines.join('\n');
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hitokoto
|
|
3
|
+
description: 获取一言/每日一句,随机返回一条语句
|
|
4
|
+
tags: [语录, 文学, 随机]
|
|
5
|
+
keywords: [一言, 每日一句, 语录, 名言, hitokoto]
|
|
6
|
+
preExecutable: true
|
|
7
|
+
parameters:
|
|
8
|
+
type:
|
|
9
|
+
type: string
|
|
10
|
+
description: "类型:a=动画, b=漫画, c=游戏, d=文学, e=原创, f=网络, g=其他, h=影视, i=诗词, j=网易云, k=哲学, l=抖机灵"
|
|
11
|
+
handler: ./handler.ts
|
|
12
|
+
---
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function (args: { ip?: string }) {
|
|
4
|
+
const params: Record<string, string> | undefined = args.ip
|
|
5
|
+
? { ip: args.ip }
|
|
6
|
+
: undefined;
|
|
7
|
+
const data = await fetchApi<any>('/ip', params);
|
|
8
|
+
const lines = ['🌐 IP 查询', '', `IP: ${data.ip || args.ip || '当前 IP'}`];
|
|
9
|
+
if (data.country || data.region || data.city) {
|
|
10
|
+
lines.push(`位置: ${[data.country, data.region, data.city].filter(Boolean).join(' ')}`);
|
|
11
|
+
}
|
|
12
|
+
if (data.location) lines.push(`位置: ${data.location}`);
|
|
13
|
+
if (data.isp) lines.push(`运营商: ${data.isp}`);
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function () {
|
|
4
|
+
const data = await fetchApi<any>('/moyu');
|
|
5
|
+
if (typeof data === 'string') return `🐟 摸鱼日历\n\n${data}`;
|
|
6
|
+
const lines = ['🐟 摸鱼日历', ''];
|
|
7
|
+
if (data.date?.gregorian) lines.push(`📅 ${data.date.gregorian} ${data.date.weekday || ''}`);
|
|
8
|
+
if (data.date?.lunar) {
|
|
9
|
+
const l = data.date.lunar;
|
|
10
|
+
lines.push(`🌙 农历${l.monthCN || ''}${l.dayCN || ''} ${l.yearGanZhi || ''}年`);
|
|
11
|
+
}
|
|
12
|
+
if (data.today) {
|
|
13
|
+
const t = data.today;
|
|
14
|
+
if (t.holidayName) lines.push(`🎉 ${t.holidayName}`);
|
|
15
|
+
if (t.solarTerm) lines.push(`🌿 ${t.solarTerm}`);
|
|
16
|
+
lines.push(t.isWorkday ? '💼 今天是工作日' : '🎮 今天不上班');
|
|
17
|
+
}
|
|
18
|
+
if (data.festivals && Array.isArray(data.festivals)) {
|
|
19
|
+
data.festivals.forEach((f: any) => lines.push(`🎊 ${f.name || f}`));
|
|
20
|
+
}
|
|
21
|
+
if (data.countdown && Array.isArray(data.countdown)) {
|
|
22
|
+
lines.push('');
|
|
23
|
+
data.countdown.forEach((c: any) => {
|
|
24
|
+
if (c.name && c.days !== undefined) lines.push(`⏳ 距 ${c.name} 还有 ${c.days} 天`);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return lines.join('\n');
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function (args: { text: string; to?: string }) {
|
|
4
|
+
const params: Record<string, string> = { text: args.text };
|
|
5
|
+
if (args.to) params.to = args.to;
|
|
6
|
+
const data = await fetchApi<any>('/fanyi', params);
|
|
7
|
+
const srcText = data.source?.text || args.text;
|
|
8
|
+
const srcLang = data.source?.type_desc || data.source?.type || '';
|
|
9
|
+
const tgtText = data.target?.text || data.result || data.translation || (typeof data === 'string' ? data : '');
|
|
10
|
+
const tgtLang = data.target?.type_desc || data.target?.type || '';
|
|
11
|
+
const lines = [
|
|
12
|
+
'🌐 翻译结果',
|
|
13
|
+
'',
|
|
14
|
+
`原文${srcLang ? ` (${srcLang})` : ''}: ${srcText}`,
|
|
15
|
+
`译文${tgtLang ? ` (${tgtLang})` : ''}: ${tgtText}`,
|
|
16
|
+
];
|
|
17
|
+
if (data.target?.pronounce) lines.push(`发音: ${data.target.pronounce}`);
|
|
18
|
+
return lines.join('\n');
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: translate_60s
|
|
3
|
+
description: 翻译文本
|
|
4
|
+
tags: [工具, 翻译, 语言]
|
|
5
|
+
keywords: [翻译, 英文, 中文, 日文, translate, 译]
|
|
6
|
+
parameters:
|
|
7
|
+
text:
|
|
8
|
+
type: string
|
|
9
|
+
description: 要翻译的文本
|
|
10
|
+
required: true
|
|
11
|
+
to:
|
|
12
|
+
type: string
|
|
13
|
+
description: 目标语言,如 en, zh, ja
|
|
14
|
+
handler: ./handler.ts
|
|
15
|
+
---
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { fetchApi } from '../api.js';
|
|
2
|
+
|
|
3
|
+
export default async function (args: { city: string }) {
|
|
4
|
+
const data = await fetchApi<any>('/weather', { query: args.city });
|
|
5
|
+
const w = data.weather;
|
|
6
|
+
const aq = data.air_quality;
|
|
7
|
+
const loc = data.location;
|
|
8
|
+
const cityName = loc?.city || loc?.name || args.city;
|
|
9
|
+
const lines = [
|
|
10
|
+
`🌤️ ${cityName} 天气`,
|
|
11
|
+
'',
|
|
12
|
+
`🌡️ 温度: ${w.temperature}°C`,
|
|
13
|
+
`☁️ 天气: ${w.condition}`,
|
|
14
|
+
`💧 湿度: ${w.humidity}%`,
|
|
15
|
+
`💨 风: ${w.wind_direction} ${w.wind_power}`,
|
|
16
|
+
];
|
|
17
|
+
if (aq) {
|
|
18
|
+
const quality = aq.quality || '';
|
|
19
|
+
lines.push(`🌬️ 空气: ${quality}${aq.aqi ? ` (AQI ${aq.aqi})` : ''}`);
|
|
20
|
+
}
|
|
21
|
+
return lines.join('\n');
|
|
22
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 凉菜
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|