koishi-plugin-booth-get 5.2.1 → 5.2.3

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.
Files changed (3) hide show
  1. package/README.md +8 -1
  2. package/lib/index.js +33 -54
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1 +1,8 @@
1
- 简单获取booth.pm页面的插件
1
+ 简单获取booth.pm页面的插件
2
+ 适用用于“vrchat”“MMD模型”“周边”“游戏”“Live2D”“视频”
3
+ 在使用vrchat的搜索时由于booth.pm的特殊性《指令摊:位搜索》会以最新发布商品为第一检索
4
+ 默认情况下,插件会自动获取最新发布商品,如需获取其他商品,请自行修改插件代码
5
+ ============================================================
6
+ 后续更新会以卡片样式web版进行更新
7
+ 优化更好且简介的样式面板
8
+ ============================================================
package/lib/index.js CHANGED
@@ -31,10 +31,9 @@ var QRCode = require("qrcode");
31
31
  var name = "booth-get";
32
32
  var inject = ["puppeteer"];
33
33
  var Config = import_koishi.Schema.object({
34
- loadTimeout: import_koishi.Schema.natural().role("ms").description("加载页面的最长时间").default(import_koishi.Time.second * 5),
34
+ loadTimeout: import_koishi.Schema.natural().role("ms").description("加载页面的最长时间").default(import_koishi.Time.second * 10),
35
35
  idleTimeout: import_koishi.Schema.natural().role("ms").description("等待页面空闲的最长时间").default(import_koishi.Time.second * 30),
36
- proxyServer: import_koishi.Schema.string().description("代理服务器地址").default(""),
37
- Text: import_koishi.Schema.title("摊位卡片生成器").description("生成BOOTH商品的摊位卡片,由VRCBBS提供"),
36
+ proxyServer: import_koishi.Schema.string().description("代理服务器地址").default("61.216.156.222:60808"),
38
37
 
39
38
  }).description("booth-get");
40
39
 
@@ -348,7 +347,7 @@ async function getBoothItem(id) {
348
347
  fetch(`https://booth.pm/zh-cn/items/${id}.json`),
349
348
  fetch(`https://accounts.booth.pm/wish_lists.json?item_ids%5B%5D=${id}`)
350
349
  ]);
351
-
350
+
352
351
  const itemData = await itemRes.json();
353
352
  const wishData = await wishRes.json();
354
353
 
@@ -361,7 +360,7 @@ async function getBoothItem(id) {
361
360
  category: itemData.category?.name,
362
361
  parent_category: itemData.category?.parent?.name,
363
362
  author: itemData.shop?.name,
364
- author_thumbnail_url: itemData.shop?.icon?.thumb?.original || itemData.shop?.icon?.small?.original,
363
+ author_thumbnail_url: itemData.shop?.thumbnail_url,
365
364
  likes: wishData.wishlists_counts[id] || 0,
366
365
  tags: itemData.tags
367
366
  };
@@ -394,19 +393,21 @@ async function captureCard(ctx, id) {
394
393
  if (!item) return null;
395
394
 
396
395
  const relatedItems = await fetchRelatedItems(item.author);
397
-
396
+
398
397
  const html = generateCardHTML(item, relatedItems);
399
398
 
400
399
  const page = await ctx.puppeteer.page();
401
400
  try {
402
401
  await page.setRequestInterception(true);
403
402
  page.on('request', (request) => request.continue());
404
-
405
- await page.setContent(html, {
406
- waitUntil: 'networkidle0',
407
- timeout: ctx.config.loadTimeout
403
+
404
+ await page.setContent(html, {
405
+ waitUntil: 'domcontentloaded',
406
+ timeout: ctx.config.loadTimeout || import_koishi.Time.second * 10
408
407
  });
409
-
408
+
409
+ await new Promise(resolve => setTimeout(resolve, 2000));
410
+
410
411
  await page.setViewport({ width: 640, height: 1200 });
411
412
  const container = await page.$('.container');
412
413
  return await container.screenshot({
@@ -437,52 +438,30 @@ function apply(ctx, config) {
437
438
  }
438
439
  });
439
440
 
440
- ctx.command("摊位名称 <query>")
441
+ ctx.command("摊位名称 <query>")
441
442
  .action(async ({ session }, query) => {
442
443
  if (!query) return "请输入商品名称";
443
-
444
- const searchUrl = `https://booth.pm/zh-cn/search/${encodeURIComponent(query)}?in_stock=true`;
444
+
445
+ const tags = ['Vrchat'];
446
+ const tagsParams = tags.map(tag => `tags[]=${encodeURIComponent(tag)}`).join('&');
447
+ const searchUrl = `https://booth.pm/zh-cn/search/${encodeURIComponent(query)}?${tagsParams}&min_price=0&in_stock=true`;
448
+
445
449
  const page = await ctx.puppeteer.page();
446
-
450
+
447
451
  try {
448
- await page.goto(searchUrl, { waitUntil: 'networkidle0', timeout: 10000 });
452
+ await page.goto(searchUrl, { waitUntil: 'networkidle0', timeout: ctx.config.loadTimeout || import_koishi.Time.second * 10 });
449
453
  const content = await page.content();
450
-
451
- const itemRegex = /item-card__wrap" id="item_(\d+)".*?<h2 class="item-card__title">([^<]+)<\/h2>/gs;
454
+
455
+ const itemRegex = /item-card__wrap"[\s\S]*?id="item_(\d+)"/g;
452
456
  const matches = [...content.matchAll(itemRegex)];
453
-
457
+
454
458
  if (!matches.length) return "没有找到相关商品";
455
-
456
- const items = matches.map(match => ({
457
- id: match[1],
458
- name: match[2].trim()
459
- }));
460
-
461
- const exactMatches = items.filter(item => item.name === query);
462
- if (exactMatches.length === 1) {
463
-
464
- const buffer = await captureCard(ctx, exactMatches[0].id);
465
- return buffer ? import_koishi.h.image(buffer, "image/png") : "卡片生成失败";
466
- } else if (exactMatches.length > 1) {
467
-
468
- const buffer = await captureCard(ctx, exactMatches[0].id);
469
- return buffer ? import_koishi.h.image(buffer, "image/png") : "卡片生成失败";
470
- }
471
-
472
- const queryLower = query.toLowerCase();
473
- const scoredItems = items.map(item => ({
474
- ...item,
475
- score: getSimilarity(queryLower, item.name.toLowerCase())
476
- })).sort((a, b) => b.score - a.score);
477
-
478
- const bestMatch = scoredItems[0];
479
- if (bestMatch.score < 0.3) {
480
- return `没有找到完全匹配的商品,最接近的是:${bestMatch.name}`;
481
- }
482
-
483
- const buffer = await captureCard(ctx, bestMatch.id);
459
+
460
+ const itemId = matches[0][1];
461
+
462
+ const buffer = await captureCard(ctx, itemId);
484
463
  return buffer ? import_koishi.h.image(buffer, "image/png") : "卡片生成失败";
485
-
464
+
486
465
  } catch (error) {
487
466
  logger.error("搜索失败:", error);
488
467
  return "搜索失败,请检查商品名称或稍后再试";
@@ -490,28 +469,28 @@ function apply(ctx, config) {
490
469
  await page.close();
491
470
  }
492
471
  });
493
-
472
+
494
473
  function getSimilarity(a, b) {
495
474
  if (a === b) return 1;
496
475
  if (a.length < 2 || b.length < 2) return 0;
497
-
476
+
498
477
  const bigramsA = new Set();
499
478
  for (let i = 0; i < a.length - 1; i++) {
500
479
  bigramsA.add(a.substring(i, i + 2));
501
480
  }
502
-
481
+
503
482
  let matches = 0;
504
483
  for (let i = 0; i < b.length - 1; i++) {
505
484
  if (bigramsA.has(b.substring(i, i + 2))) matches++;
506
485
  }
507
-
486
+
508
487
  return (2 * matches) / (a.length + b.length - 2);
509
488
  }
510
489
 
511
490
  ctx.middleware(async (session, next) => {
512
491
  const boothUrlRegex = /https:\/\/booth.pm\/[\w-]+\/items\/(\d+)/;
513
492
  const match = session.content.match(boothUrlRegex);
514
-
493
+
515
494
  if (match) {
516
495
  try {
517
496
  const buffer = await captureCard(ctx, match[1]);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-booth-get",
3
3
  "description": "通过url与名称检查摊位物品并反馈用户搜索的图片",
4
- "version": "5.2.1",
4
+ "version": "5.2.3",
5
5
  "contributors": [
6
6
  "rixiang <1148147857@qq.com>"
7
7
  ],