koishi-plugin-apple-rank 0.0.2 → 0.0.4
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 +81 -31
- package/package.json +4 -1
package/lib/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(src_exports, {
|
|
|
25
25
|
name: () => name
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(src_exports);
|
|
28
|
+
var import_jimp = require("jimp");
|
|
28
29
|
var import_koishi = require("koishi");
|
|
29
30
|
var name = "apple-rank";
|
|
30
31
|
var Config = import_koishi.Schema.object({
|
|
@@ -80,7 +81,7 @@ function formatRankItem(item) {
|
|
|
80
81
|
__name(formatRankItem, "formatRankItem");
|
|
81
82
|
function formatRankItemWithIcon(item) {
|
|
82
83
|
const text = formatRankItem(item);
|
|
83
|
-
return item.icon ?
|
|
84
|
+
return item.icon ? [import_koishi.h.image(item.icon), text].join("") : text;
|
|
84
85
|
}
|
|
85
86
|
__name(formatRankItemWithIcon, "formatRankItemWithIcon");
|
|
86
87
|
function formatUpdatedAt(updated) {
|
|
@@ -90,6 +91,14 @@ function formatUpdatedAt(updated) {
|
|
|
90
91
|
return `更新时间:${date.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai", hour12: false })}`;
|
|
91
92
|
}
|
|
92
93
|
__name(formatUpdatedAt, "formatUpdatedAt");
|
|
94
|
+
function formatNote() {
|
|
95
|
+
return "说明:Apple 公开榜单,只代表 iOS 排名,不代表全平台流水";
|
|
96
|
+
}
|
|
97
|
+
__name(formatNote, "formatNote");
|
|
98
|
+
function joinBlocks(blocks) {
|
|
99
|
+
return blocks.filter(Boolean).join("\n\n");
|
|
100
|
+
}
|
|
101
|
+
__name(joinBlocks, "joinBlocks");
|
|
93
102
|
function parseFeedType(type = "grossing") {
|
|
94
103
|
if (["grossing", "畅销", "畅销榜", "流水"].includes(type)) return "topgrossingapplications";
|
|
95
104
|
if (["free", "免费", "免费榜"].includes(type)) return "topfreeapplications";
|
|
@@ -106,6 +115,7 @@ function apply(ctx, config) {
|
|
|
106
115
|
let cachedFeed = "";
|
|
107
116
|
let cachedRankFeed = { ranks: [], actualLimit: 0 };
|
|
108
117
|
const recentReplies = /* @__PURE__ */ new Map();
|
|
118
|
+
const grayscaleIconCache = /* @__PURE__ */ new Map();
|
|
109
119
|
async function fetchRanks(feedType = "topgrossingapplications") {
|
|
110
120
|
const now = Date.now();
|
|
111
121
|
if (cachedFeed === feedType && cachedRankFeed.ranks.length && now - cachedAt < config.cacheTtl * 1e3) {
|
|
@@ -136,6 +146,21 @@ function apply(ctx, config) {
|
|
|
136
146
|
return true;
|
|
137
147
|
}
|
|
138
148
|
__name(shouldReplyOnce, "shouldReplyOnce");
|
|
149
|
+
async function toGrayscaleIcon(url) {
|
|
150
|
+
if (!url) return void 0;
|
|
151
|
+
const cached = grayscaleIconCache.get(url);
|
|
152
|
+
if (cached) return cached;
|
|
153
|
+
try {
|
|
154
|
+
const image = await import_jimp.Jimp.read(url);
|
|
155
|
+
image.greyscale();
|
|
156
|
+
const base64 = await image.getBase64("image/png");
|
|
157
|
+
grayscaleIconCache.set(url, base64);
|
|
158
|
+
return base64;
|
|
159
|
+
} catch {
|
|
160
|
+
return url;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
__name(toGrayscaleIcon, "toGrayscaleIcon");
|
|
139
164
|
async function searchApp(keyword) {
|
|
140
165
|
const url = "https://itunes.apple.com/search";
|
|
141
166
|
const response = parseJson(await ctx.http.get(url, {
|
|
@@ -187,7 +212,14 @@ function apply(ctx, config) {
|
|
|
187
212
|
const feed = await fetchRanks(feedType);
|
|
188
213
|
const actualLimit = feed.actualLimit || feed.ranks.length;
|
|
189
214
|
const lines = feed.ranks.slice(0, Math.min(limit, actualLimit)).map(formatRankItemWithIcon);
|
|
190
|
-
return
|
|
215
|
+
return joinBlocks([
|
|
216
|
+
`App Store ${config.country.toUpperCase()} ${feedLabels[feedType]} Top ${actualLimit}`,
|
|
217
|
+
[
|
|
218
|
+
formatUpdatedAt(feed.updated),
|
|
219
|
+
formatNote()
|
|
220
|
+
].join("\n"),
|
|
221
|
+
lines.join("\n")
|
|
222
|
+
]);
|
|
191
223
|
});
|
|
192
224
|
ctx.command("ios排名 <game:text>", "查询游戏在 iOS 畅销榜的排名").option("type", "-t <type:string> 榜单类型:畅销/免费/付费", { fallback: "畅销" }).action(async ({ options, session }, game) => {
|
|
193
225
|
if (session && !shouldReplyOnce(`${session.sid}:ios排名:${options.type}:${game}`)) return;
|
|
@@ -197,21 +229,29 @@ function apply(ctx, config) {
|
|
|
197
229
|
const { appId, item, detail, updated, actualLimit } = await findRank(game, feedType);
|
|
198
230
|
if (!appId) return `没找到「${game}」对应的 App Store 应用`;
|
|
199
231
|
if (!item) {
|
|
200
|
-
return [
|
|
232
|
+
return joinBlocks([
|
|
201
233
|
detail?.artworkUrl100 ? import_koishi.h.image(detail.artworkUrl100) : "",
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
234
|
+
`${detail?.trackName || game}`,
|
|
235
|
+
`未进入 App Store ${config.country.toUpperCase()} ${feedLabels[feedType]} Top ${actualLimit}`,
|
|
236
|
+
[
|
|
237
|
+
formatUpdatedAt(updated),
|
|
238
|
+
detail?.artistName ? `开发者:${detail.artistName}` : "",
|
|
239
|
+
detail?.primaryGenreName ? `分类:${detail.genres?.join(" / ") || detail.primaryGenreName}` : "",
|
|
240
|
+
formatNote()
|
|
241
|
+
].filter(Boolean).join("\n")
|
|
242
|
+
]);
|
|
206
243
|
}
|
|
207
|
-
return [
|
|
244
|
+
return joinBlocks([
|
|
208
245
|
item.icon ? import_koishi.h.image(item.icon) : "",
|
|
209
|
-
`${item.name}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
246
|
+
`${item.name}`,
|
|
247
|
+
[
|
|
248
|
+
`排名:App Store ${config.country.toUpperCase()} ${feedLabels[feedType]} 第 ${item.rank} 名`,
|
|
249
|
+
formatUpdatedAt(updated),
|
|
250
|
+
`开发者:${item.artist}`,
|
|
251
|
+
`分类:${item.category || "未知"}`,
|
|
252
|
+
formatNote()
|
|
253
|
+
].join("\n")
|
|
254
|
+
]);
|
|
215
255
|
});
|
|
216
256
|
ctx.command("ios对比 <games:text>", "对比多个游戏的 iOS 畅销榜排名").action(async ({ session }, games) => {
|
|
217
257
|
if (session && !shouldReplyOnce(`${session.sid}:ios对比:${games}`)) return;
|
|
@@ -220,28 +260,35 @@ function apply(ctx, config) {
|
|
|
220
260
|
const feed = await fetchRanks();
|
|
221
261
|
const actualLimit = feed.actualLimit || feed.ranks.length;
|
|
222
262
|
const details = await Promise.all(names.map(resolveAppDetail));
|
|
263
|
+
const grayIcons = await Promise.all(details.map((detail) => toGrayscaleIcon(detail?.artworkUrl100)));
|
|
223
264
|
const results = names.map((game, index) => {
|
|
224
265
|
const detail = details[index];
|
|
266
|
+
const grayIcon = grayIcons[index];
|
|
225
267
|
const appId = detail?.trackId.toString() || config.aliases[game] || (/^\d+$/.test(game) ? game : void 0);
|
|
226
268
|
if (!appId) return `${game}:未找到应用`;
|
|
227
269
|
const item = feed.ranks.find((item2) => item2.appId === appId);
|
|
228
270
|
if (!item) {
|
|
229
|
-
return [
|
|
230
|
-
|
|
231
|
-
`${detail?.trackName || game}
|
|
232
|
-
|
|
271
|
+
return joinBlocks([
|
|
272
|
+
grayIcon ? import_koishi.h.image(grayIcon) : "",
|
|
273
|
+
`${detail?.trackName || game}`,
|
|
274
|
+
`未进入畅销榜 Top ${actualLimit}`
|
|
275
|
+
]);
|
|
233
276
|
}
|
|
234
|
-
return [
|
|
277
|
+
return joinBlocks([
|
|
235
278
|
item.icon ? import_koishi.h.image(item.icon) : "",
|
|
236
|
-
`${item.name}
|
|
237
|
-
|
|
279
|
+
`${item.name}`,
|
|
280
|
+
`排名:第 ${item.rank} 名`
|
|
281
|
+
]);
|
|
238
282
|
});
|
|
239
|
-
return [
|
|
283
|
+
return joinBlocks([
|
|
240
284
|
`App Store ${config.country.toUpperCase()} 畅销榜对比`,
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
285
|
+
[
|
|
286
|
+
formatUpdatedAt(feed.updated),
|
|
287
|
+
`榜单条数:${actualLimit}`,
|
|
288
|
+
formatNote()
|
|
289
|
+
].join("\n"),
|
|
290
|
+
results.join("\n\n")
|
|
291
|
+
]);
|
|
245
292
|
});
|
|
246
293
|
ctx.command("ios搜索 <keyword:text>", "搜索 App Store 应用").action(async ({ session }, keyword) => {
|
|
247
294
|
if (session && !shouldReplyOnce(`${session.sid}:ios搜索:${keyword}`)) return;
|
|
@@ -251,12 +298,15 @@ function apply(ctx, config) {
|
|
|
251
298
|
return results.map((result, index) => {
|
|
252
299
|
const genres = result.genres?.join(" / ") || result.primaryGenreName;
|
|
253
300
|
const icon = result.artworkUrl100 ? `${import_koishi.h.image(result.artworkUrl100)}` : "";
|
|
254
|
-
return [
|
|
301
|
+
return joinBlocks([
|
|
255
302
|
icon,
|
|
256
|
-
`${index + 1}. ${result.trackName}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
303
|
+
`${index + 1}. ${result.trackName}`,
|
|
304
|
+
[
|
|
305
|
+
`App ID:${result.trackId}`,
|
|
306
|
+
`开发者:${result.artistName}`,
|
|
307
|
+
`分类:${genres}`
|
|
308
|
+
].join("\n")
|
|
309
|
+
]);
|
|
260
310
|
}).join("\n\n");
|
|
261
311
|
});
|
|
262
312
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-apple-rank",
|
|
3
3
|
"description": "给二游痴看流水用的,数据来自苹果的rss",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"koishi",
|
|
15
15
|
"plugin"
|
|
16
16
|
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"jimp": "^1.6.0"
|
|
19
|
+
},
|
|
17
20
|
"peerDependencies": {
|
|
18
21
|
"koishi": "^4.18.7"
|
|
19
22
|
}
|