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 CHANGED
@@ -14,6 +14,7 @@ export interface Config {
14
14
  temperature: number;
15
15
  timeout?: number;
16
16
  app: string;
17
+ ownerAccount?: string;
17
18
  enablePollingOnStart: boolean;
18
19
  enableReTweet: boolean;
19
20
  sendPic: boolean;
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 { list: followingList } = await twitterClient.user.following();
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, 30 * 1e3));
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: "1px solid #1DA1F2",
599
+ border: "3px solid transparent",
527
600
  borderRadius: "8px",
528
- boxShadow: "0px 1px 9px 12px rgba(29, 161, 242, 0.2)",
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-nitter",
3
3
  "description": "使用Rettiwt-API订阅推文,并使用nitter渲染",
4
- "version": "0.0.16",
4
+ "version": "0.0.17",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -1,5 +1,5 @@
1
- # koishi-plugin-twitter
1
+ # koishi-plugin-nitter
2
2
 
3
- [![npm](https://img.shields.io/npm/v/koishi-plugin-twitter?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-twitter)
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-nitter?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-twitter)
4
4
 
5
5
  推文订阅