koishi-plugin-vr-fever 0.0.1 → 0.0.2

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.
@@ -111,7 +111,7 @@ const registerWeiboCommand = (ctx, config, pollWeibo) => {
111
111
  if (message === "login") {
112
112
  try {
113
113
  await (0, puppeteer_cookie_1.ensurePuppeteerBrowser)(ctx);
114
- await (0, login_1.getQRcode)(ctx, argv.session);
114
+ await (0, login_1.getQRcode)(ctx, argv.session, config.isDebugMode);
115
115
  }
116
116
  catch (error) {
117
117
  (0, send_msg_1.sendMsg)((0, puppeteer_cookie_1.formatPuppeteerError)(error), argv.session);
package/lib/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export interface Config {
31
31
  adminGroupID: string;
32
32
  waitMinutes: number;
33
33
  isTextMode: boolean;
34
+ isDebugMode: boolean;
34
35
  }
35
36
  export declare const Config: Schema<Config>;
36
37
  export declare function apply(ctx: Context, config: Config): Promise<void>;
package/lib/index.js CHANGED
@@ -24,6 +24,9 @@ exports.Config = koishi_1.Schema.object({
24
24
  isTextMode: koishi_1.Schema.boolean()
25
25
  .default(false)
26
26
  .description("开启后以文本推送微博,关闭则以截图图片推送"),
27
+ isDebugMode: koishi_1.Schema.boolean()
28
+ .default(false)
29
+ .description("开启后保存调试截图(登录二维码、微博推送截图等)"),
27
30
  });
28
31
  async function apply(ctx, config) {
29
32
  ctx.model.extend("weibo_cookies", {
@@ -1,4 +1,4 @@
1
1
  import { Context, Session } from "koishi";
2
2
  /** 打开微博登录页,截图二维码并等待扫码完成 */
3
- export declare const getQRcode: (ctx: Context, session: Session) => Promise<boolean>;
3
+ export declare const getQRcode: (ctx: Context, session: Session, isDebugMode?: boolean) => Promise<boolean>;
4
4
  export declare const checkLoginStatus: (ctx: Context) => Promise<boolean | null>;
@@ -4,8 +4,9 @@ exports.checkLoginStatus = exports.getQRcode = void 0;
4
4
  const constants_1 = require("../util/constants");
5
5
  const puppeteer_cookie_1 = require("../util/puppeteer-cookie");
6
6
  const send_msg_1 = require("../util/send-msg");
7
+ const timer_1 = require("../util/timer");
7
8
  /** 打开微博登录页,截图二维码并等待扫码完成 */
8
- const getQRcode = async (ctx, session) => {
9
+ const getQRcode = async (ctx, session, isDebugMode = false) => {
9
10
  await (0, puppeteer_cookie_1.ensurePuppeteerBrowser)(ctx);
10
11
  const page = await ctx.puppeteer.page();
11
12
  if (!page) {
@@ -14,14 +15,16 @@ const getQRcode = async (ctx, session) => {
14
15
  }
15
16
  try {
16
17
  (0, send_msg_1.sendMsg)("开启网站中...", session);
17
- await (0, puppeteer_cookie_1.navigatePage)(page, constants_1.CONSTANTS.WEIBO_PASSPORT_URL);
18
+ await (0, puppeteer_cookie_1.navigatePage)(page, constants_1.CONSTANTS.WEIBO_PASSPORT_URL, (0, timer_1.getWaitMs)(0.4));
18
19
  (0, send_msg_1.sendMsg)("正在切换到扫码登录...", session);
19
- const qrResult = await (0, puppeteer_cookie_1.captureLoginQrFromPage)(page, 15000);
20
+ const qrResult = await (0, puppeteer_cookie_1.captureLoginQrFromPage)(page, (0, timer_1.getWaitMs)(0.4), isDebugMode);
20
21
  if (qrResult.debugDir) {
21
22
  (0, send_msg_1.sendMsg)(`调试截图已保存到: ${qrResult.debugDir}`, session);
22
23
  }
23
24
  if (!qrResult.detected || !qrResult.dataUrl) {
24
- (0, send_msg_1.sendMsg)("未找到二维码,请查看调试目录中的 page.png / meta.json", session);
25
+ (0, send_msg_1.sendMsg)(isDebugMode
26
+ ? "未找到二维码,请查看调试目录中的 page.png / meta.json"
27
+ : "未找到二维码,请重试", session);
25
28
  return false;
26
29
  }
27
30
  const base64 = qrResult.dataUrl.replace(/^data:image\/\w+;base64,/, "");
@@ -79,14 +79,18 @@ const createPollWeibo = (ctx, config, sendMsgOnebot) => {
79
79
  for (let i = 0; i < images.length; i++) {
80
80
  const image = images[i];
81
81
  const postCount = Math.min(constants_1.CONSTANTS.POSTS_PER_SCREENSHOT, entry.timeline.length - i * constants_1.CONSTANTS.POSTS_PER_SCREENSHOT);
82
- const saved = await (0, save_screenshot_1.saveScreenshotDebug)(image, {
83
- uid,
84
- name,
85
- chunkIndex: i,
86
- totalChunks: images.length,
87
- postCount,
88
- });
89
- ctx.logger.info(`截图已保存: ${saved.filePath} (${saved.sizeKB} KB, ${name} ${i + 1}/${images.length})`);
82
+ const saved = config.isDebugMode
83
+ ? await (0, save_screenshot_1.saveScreenshotDebug)(image, {
84
+ uid,
85
+ name,
86
+ chunkIndex: i,
87
+ totalChunks: images.length,
88
+ postCount,
89
+ })
90
+ : null;
91
+ if (saved) {
92
+ ctx.logger.info(`截图已保存: ${saved.filePath} (${saved.sizeKB} KB, ${name} ${i + 1}/${images.length})`);
93
+ }
90
94
  await (0, send_msg_1.sendImg)(image, session);
91
95
  }
92
96
  }
@@ -10,9 +10,17 @@ const getWeiboByUID = async (weiboUID, ctx, _session) => {
10
10
  if (!weiboHttp) {
11
11
  return null;
12
12
  }
13
- const profile = await weiboHttp
14
- .get(`/ajax/profile/info?uid=${weiboUID}&scene=profile`)
13
+ const profilePath = `/ajax/profile/info?uid=${weiboUID}&scene=profile`;
14
+ const fetchProfile = () => weiboHttp
15
+ .get(profilePath)
15
16
  .then((res) => res?.data || null);
17
+ let profile;
18
+ try {
19
+ profile = await fetchProfile();
20
+ }
21
+ catch {
22
+ profile = await fetchProfile();
23
+ }
16
24
  const timeline = await weiboHttp
17
25
  .get(`/ajax/statuses/mymblog?uid=${weiboUID}&page=1&feature=0`)
18
26
  .then((res) => res?.data || null);
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.REGEX = exports.CONSTANTS = void 0;
4
- const WEIBO_PASSPORT_URL = "https://passport.weibo.com/";
4
+ const WEIBO_PASSPORT_URL = "https://passport.weibo.com/sso/signin?entry=account&source=sinassopage&url=https%3A%2F%2Fmy.sina.com.cn";
5
+ // const WEIBO_PASSPORT_URL = "https://passport.weibo.com/";
5
6
  const WEB_TIMEOUT = 120000;
6
7
  const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
7
8
  const WEIBO_SAMPLE_UID = "8376019184";
@@ -21,20 +21,21 @@ export declare function waitForLogin(page: any, timeoutMs?: number): Promise<boo
21
21
  export declare function collectFullCookiesAfterLogin(page: any): Promise<AnyCookie[]>;
22
22
  export interface QrLoginOptions {
23
23
  timeoutMs?: number;
24
+ saveDebug?: boolean;
24
25
  onPageCreated?: (page: any) => void | Promise<void>;
25
26
  onQrCaptured?: (dataUrl: string | null) => void | Promise<void>;
26
27
  }
27
28
  /** 微博登录页默认可能是短信登录,需先点击 scan.png 图标所在父 span 切换到「扫码登录」 */
28
29
  export declare function clickWeiboQrLoginTab(page: any): Promise<boolean>;
29
30
  /** 导出登录页截图到 data/weibo-login-debug 便于排查白图问题 */
30
- export declare function saveLoginQrDebug(page: any, element: any | null, label: string): Promise<string>;
31
+ export declare function saveLoginQrDebug(page: any, element: any | null, label: string, saveDebug?: boolean): Promise<string | null>;
31
32
  /** 切换到扫码登录并等待二维码出现 */
32
- export declare function captureLoginQrFromPage(page: any, timeoutMs?: number): Promise<{
33
+ export declare function captureLoginQrFromPage(page: any, timeoutMs?: number, saveDebug?: boolean): Promise<{
33
34
  dataUrl: string | null;
34
35
  detected: boolean;
35
36
  debugDir?: string;
36
37
  }>;
37
- export declare function captureQrFromPage(page: any, timeoutMs?: number, debugLabel?: string): Promise<{
38
+ export declare function captureQrFromPage(page: any, timeoutMs?: number, debugLabel?: string, saveDebug?: boolean): Promise<{
38
39
  dataUrl: string | null;
39
40
  detected: boolean;
40
41
  debugDir?: string;
@@ -336,7 +336,9 @@ async function waitForQrElementReady(page) {
336
336
  });
337
337
  }
338
338
  /** 导出登录页截图到 data/weibo-login-debug 便于排查白图问题 */
339
- async function saveLoginQrDebug(page, element, label) {
339
+ async function saveLoginQrDebug(page, element, label, saveDebug = false) {
340
+ if (!saveDebug)
341
+ return null;
340
342
  await promises_1.default.mkdir(LOGIN_QR_DEBUG_DIR, { recursive: true });
341
343
  const stamp = `${label}-${Date.now()}`;
342
344
  const meta = { label, savedAt: new Date().toISOString() };
@@ -417,26 +419,26 @@ async function saveLoginQrDebug(page, element, label) {
417
419
  }
418
420
  const bufferToDataUrl = (buffer) => `data:image/png;base64,${buffer.toString("base64")}`;
419
421
  /** 切换到扫码登录并等待二维码出现 */
420
- async function captureLoginQrFromPage(page, timeoutMs = 15000) {
422
+ async function captureLoginQrFromPage(page, timeoutMs = 15000, saveDebug = false) {
421
423
  for (let i = 0; i < 3; i++) {
422
424
  await clickWeiboQrLoginTab(page);
423
425
  await wait(1000);
424
- const qrResult = await captureQrFromPage(page, 5000, `attempt-${i + 1}`);
426
+ const qrResult = await captureQrFromPage(page, 5000, `attempt-${i + 1}`, saveDebug);
425
427
  if (qrResult.detected)
426
428
  return qrResult;
427
429
  }
428
- return captureQrFromPage(page, timeoutMs, "final");
430
+ return captureQrFromPage(page, timeoutMs, "final", saveDebug);
429
431
  }
430
- async function captureQrFromPage(page, timeoutMs = 1500, debugLabel = "capture") {
432
+ async function captureQrFromPage(page, timeoutMs = 1500, debugLabel = "capture", saveDebug = false) {
431
433
  let element = null;
432
434
  try {
433
435
  element = await waitForQrElement(page, timeoutMs);
434
436
  if (!element) {
435
- const debugDir = await saveLoginQrDebug(page, null, `${debugLabel}-missing`);
436
- return { dataUrl: null, detected: false, debugDir };
437
+ const debugDir = await saveLoginQrDebug(page, null, `${debugLabel}-missing`, saveDebug);
438
+ return { dataUrl: null, detected: false, debugDir: debugDir ?? undefined };
437
439
  }
438
440
  await waitForQrElementReady(page);
439
- const debugDir = await saveLoginQrDebug(page, element, debugLabel);
441
+ const debugDir = await saveLoginQrDebug(page, element, debugLabel, saveDebug);
440
442
  const box = await element.boundingBox();
441
443
  if (box?.width && box?.height) {
442
444
  const clipBuffer = await page.screenshot({
@@ -450,20 +452,20 @@ async function captureQrFromPage(page, timeoutMs = 1500, debugLabel = "capture")
450
452
  return {
451
453
  dataUrl: bufferToDataUrl(Buffer.from(clipBuffer)),
452
454
  detected: true,
453
- debugDir,
455
+ debugDir: debugDir ?? undefined,
454
456
  };
455
457
  }
456
458
  const elementBuffer = await element.screenshot();
457
459
  return {
458
460
  dataUrl: bufferToDataUrl(Buffer.from(elementBuffer)),
459
461
  detected: true,
460
- debugDir,
462
+ debugDir: debugDir ?? undefined,
461
463
  };
462
464
  }
463
465
  catch (error) {
464
- const debugDir = await saveLoginQrDebug(page, element, `${debugLabel}-error`).catch(() => LOGIN_QR_DEBUG_DIR);
466
+ const debugDir = await saveLoginQrDebug(page, element, `${debugLabel}-error`, saveDebug).catch(() => null);
465
467
  console.error("captureQrFromPage failed:", error, "debugDir:", debugDir);
466
- return { dataUrl: null, detected: false, debugDir };
468
+ return { dataUrl: null, detected: false, debugDir: debugDir ?? undefined };
467
469
  }
468
470
  }
469
471
  async function loginWithQrViaService(ctx, opts = {}) {
@@ -477,7 +479,7 @@ async function loginWithQrViaService(ctx, opts = {}) {
477
479
  try {
478
480
  await opts.onPageCreated?.(page);
479
481
  await gotoAndWait(page, WEIBO_PASSPORT_URL, opts.timeoutMs || 120000);
480
- const qrResult = await captureLoginQrFromPage(page, opts.timeoutMs ? Math.min(opts.timeoutMs, 15000) : 15000);
482
+ const qrResult = await captureLoginQrFromPage(page, opts.timeoutMs ? Math.min(opts.timeoutMs, 15000) : 15000, opts.saveDebug ?? false);
481
483
  if (!qrResult.detected) {
482
484
  // Take a screenshot for debugging
483
485
  const screenshot = await page.screenshot({ encoding: "base64" });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-vr-fever",
3
3
  "description": "自用改型",
4
- "version": "0.0.1",
4
+ "version": "0.0.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [