koishi-plugin-nitter 0.0.16 → 0.0.17
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.d.ts +1 -0
- package/lib/index.js +80 -7
- package/package.json +1 -1
- package/readme.md +2 -2
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -278,7 +278,8 @@ var Config = import_koishi.Schema.intersect([
|
|
|
278
278
|
import_koishi.Schema.object({})
|
|
279
279
|
]),
|
|
280
280
|
import_koishi.Schema.object({
|
|
281
|
-
app: import_koishi.Schema.string().description("subscription配置中应用名")
|
|
281
|
+
app: import_koishi.Schema.string().description("subscription配置中应用名"),
|
|
282
|
+
ownerAccount: import_koishi.Schema.string().description("主人账号。轮询连续失败3次后会停止轮询并向该账号发送告警。可填写 userId,或 platform:userId 指定平台。")
|
|
282
283
|
}).description("订阅配置"),
|
|
283
284
|
import_koishi.Schema.object({
|
|
284
285
|
enablePollingOnStart: import_koishi.Schema.boolean().default(true).description("启动后是否立刻开始轮询"),
|
|
@@ -302,6 +303,7 @@ function apply(ctx, config) {
|
|
|
302
303
|
logging: true
|
|
303
304
|
});
|
|
304
305
|
let cronJob;
|
|
306
|
+
let pollingFailures = 0;
|
|
305
307
|
const queue = new taskQueue();
|
|
306
308
|
(async () => {
|
|
307
309
|
if (config.enableTranslate == "google") {
|
|
@@ -336,7 +338,21 @@ function apply(ctx, config) {
|
|
|
336
338
|
})();
|
|
337
339
|
ctx.command("nitter.follow", "按照subscription中的订阅配置,使用登录的推特账号关注所有需要订阅的账号", { authority: 3 }).action(async () => {
|
|
338
340
|
const whiteList = ctx.subscription.getAvailableAccounts(config.app);
|
|
339
|
-
const
|
|
341
|
+
const followingList = [];
|
|
342
|
+
let cursor = void 0;
|
|
343
|
+
while (true) {
|
|
344
|
+
const res = await retry(
|
|
345
|
+
3,
|
|
346
|
+
async () => {
|
|
347
|
+
return await twitterClient.user.following(void 0, 100, cursor);
|
|
348
|
+
},
|
|
349
|
+
(err) => ctx.logger("nitter").error(`获取已关注账号列表失败: ${err}`)
|
|
350
|
+
);
|
|
351
|
+
followingList.push(...res.list);
|
|
352
|
+
if (!res.next || res.next.split("|")[0] == "0") break;
|
|
353
|
+
cursor = res.next;
|
|
354
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
355
|
+
}
|
|
340
356
|
const followingIdList = followingList.map((user) => user.userName);
|
|
341
357
|
for (const id of whiteList) {
|
|
342
358
|
if (!followingIdList.includes(id)) {
|
|
@@ -350,7 +366,7 @@ function apply(ctx, config) {
|
|
|
350
366
|
await twitterClient.user.follow(user.id);
|
|
351
367
|
ctx.logger("nitter").info(`关注${id}成功`);
|
|
352
368
|
}, (err) => ctx.logger("nitter").error(`关注${id}失败: ${err}`));
|
|
353
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
369
|
+
await new Promise((resolve) => setTimeout(resolve, 60 * 1e3));
|
|
354
370
|
}
|
|
355
371
|
}
|
|
356
372
|
return "关注完成";
|
|
@@ -436,6 +452,7 @@ function apply(ctx, config) {
|
|
|
436
452
|
checking = Date.now();
|
|
437
453
|
try {
|
|
438
454
|
const tweetList = await getFollowedFeed();
|
|
455
|
+
pollingFailures = 0;
|
|
439
456
|
if (tweetList.length === 0) {
|
|
440
457
|
return;
|
|
441
458
|
}
|
|
@@ -451,11 +468,67 @@ function apply(ctx, config) {
|
|
|
451
468
|
ctx.logger("nitter").info(`检测到推文id:${data.id},开始推送`);
|
|
452
469
|
queue.push({ account: data.tweetBy.userName, tweetId: data.id });
|
|
453
470
|
}
|
|
471
|
+
} catch (error) {
|
|
472
|
+
pollingFailures += 1;
|
|
473
|
+
ctx.logger("nitter").warn("检查推文更新失败:%o", error);
|
|
474
|
+
if (pollingFailures >= 3) {
|
|
475
|
+
cronJob?.stop();
|
|
476
|
+
const message = `Nitter 轮询连续失败 ${pollingFailures} 次,已停止轮询。
|
|
477
|
+
${formatError(error)}`;
|
|
478
|
+
ctx.logger("nitter").warn(message);
|
|
479
|
+
await notifyOwner(message);
|
|
480
|
+
}
|
|
454
481
|
} finally {
|
|
455
482
|
checking = void 0;
|
|
456
483
|
}
|
|
457
484
|
}
|
|
458
485
|
__name(checkForUpdates, "checkForUpdates");
|
|
486
|
+
async function notifyOwner(message) {
|
|
487
|
+
const owner = parseOwnerAccount(config.ownerAccount);
|
|
488
|
+
if (!owner) return;
|
|
489
|
+
try {
|
|
490
|
+
const bot = await findOwnerBot(owner.platform);
|
|
491
|
+
if (!bot) {
|
|
492
|
+
ctx.logger("nitter").warn("未找到可用于发送 Nitter 轮询告警的 bot");
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
await bot.sendPrivateMessage(owner.userId, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { children: message }));
|
|
496
|
+
} catch (error) {
|
|
497
|
+
ctx.logger("nitter").warn("发送 Nitter 轮询告警失败:%o", error);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
__name(notifyOwner, "notifyOwner");
|
|
501
|
+
async function findOwnerBot(platform) {
|
|
502
|
+
if (platform) return ctx.bots.find((bot) => bot.platform === platform);
|
|
503
|
+
const accounts = ctx.subscription.getAvailableAccounts(config.app);
|
|
504
|
+
for (const account of accounts) {
|
|
505
|
+
const groups = await ctx.subscription.getSubscribedGroups(config.app, account);
|
|
506
|
+
for (const group of groups) {
|
|
507
|
+
const groupPlatform = group.split(":")[0];
|
|
508
|
+
const bot = ctx.bots.find((bot2) => bot2.platform === groupPlatform);
|
|
509
|
+
if (bot) return bot;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return ctx.bots[0];
|
|
513
|
+
}
|
|
514
|
+
__name(findOwnerBot, "findOwnerBot");
|
|
515
|
+
function parseOwnerAccount(input) {
|
|
516
|
+
const value = input?.trim();
|
|
517
|
+
if (!value) return null;
|
|
518
|
+
const index = value.indexOf(":");
|
|
519
|
+
if (index > 0) {
|
|
520
|
+
return {
|
|
521
|
+
platform: value.slice(0, index),
|
|
522
|
+
userId: value.slice(index + 1)
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
return { userId: value };
|
|
526
|
+
}
|
|
527
|
+
__name(parseOwnerAccount, "parseOwnerAccount");
|
|
528
|
+
function formatError(error) {
|
|
529
|
+
return error?.message || String(error);
|
|
530
|
+
}
|
|
531
|
+
__name(formatError, "formatError");
|
|
459
532
|
async function renderTweetScreenshot(tweetId) {
|
|
460
533
|
const puppeteer = ctx.puppeteer;
|
|
461
534
|
if (!puppeteer) {
|
|
@@ -523,15 +596,15 @@ function apply(ctx, config) {
|
|
|
523
596
|
const element2 = document.querySelector(".main-thread");
|
|
524
597
|
if (!element2) return;
|
|
525
598
|
Object.assign(element2.style, {
|
|
526
|
-
border: "
|
|
599
|
+
border: "3px solid transparent",
|
|
527
600
|
borderRadius: "8px",
|
|
528
|
-
|
|
601
|
+
background: "linear-gradient(#fff, #fff) padding-box, linear-gradient(135deg, #1DA1F2 0%, #35C2FF 35%, #6EE7F9 68%, #A7F3D0 100%) border-box",
|
|
602
|
+
boxShadow: "0 8px 24px rgba(29, 161, 242, 0.18)",
|
|
529
603
|
margin: "20px",
|
|
530
604
|
boxSizing: "border-box",
|
|
531
605
|
overflow: "hidden",
|
|
532
606
|
width: "100%",
|
|
533
|
-
padding: "20px 20px 10px 20px"
|
|
534
|
-
backgroundColor: "#fff"
|
|
607
|
+
padding: "20px 20px 10px 20px"
|
|
535
608
|
});
|
|
536
609
|
});
|
|
537
610
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# koishi-plugin-
|
|
1
|
+
# koishi-plugin-nitter
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/koishi-plugin-twitter)
|
|
4
4
|
|
|
5
5
|
推文订阅
|