koishi-plugin-booth-get 5.2.4 → 5.2.6
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 +454 -16
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -438,13 +438,27 @@ function apply(ctx, config) {
|
|
|
438
438
|
}
|
|
439
439
|
});
|
|
440
440
|
|
|
441
|
-
ctx.command("摊位名称 <query>")
|
|
442
|
-
.
|
|
441
|
+
ctx.command("摊位名称 <query:text>")
|
|
442
|
+
.option('author', '-a <author> 指定作者名称')
|
|
443
|
+
.action(async ({ session, options }, query) => {
|
|
443
444
|
if (!query) return "请输入搜索关键词";
|
|
444
445
|
|
|
446
|
+
let searchQuery = query;
|
|
447
|
+
let authorFilter = options.author;
|
|
448
|
+
|
|
449
|
+
if (!authorFilter && query.includes(' ')) {
|
|
450
|
+
const parts = query.split(' ');
|
|
451
|
+
if (parts.length >= 2) {
|
|
452
|
+
authorFilter = parts.pop();
|
|
453
|
+
searchQuery = parts.join(' ');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
let searchUrl = `https://booth.pm/zh-cn/search/${encodeURIComponent(searchQuery)}?in_stock=true`;
|
|
458
|
+
|
|
445
459
|
const tags = ['3Dモデル', 'Vrchat'];
|
|
446
460
|
const tagsParams = tags.map(tag => `tags[]=${encodeURIComponent(tag)}`).join('&');
|
|
447
|
-
|
|
461
|
+
searchUrl += `&${tagsParams}&min_price=4500`;
|
|
448
462
|
|
|
449
463
|
const page = await ctx.puppeteer.page();
|
|
450
464
|
|
|
@@ -473,10 +487,30 @@ function apply(ctx, config) {
|
|
|
473
487
|
}
|
|
474
488
|
|
|
475
489
|
const content = await page.content();
|
|
476
|
-
|
|
477
|
-
const
|
|
490
|
+
|
|
491
|
+
const itemRegex = /item-card__wrap"[\s\S]*?id="item_(\d+)"[\s\S]*?<h2[^>]*class="[^"]*item-card__title[^"]*"[^>]*>([^<]+)<\/h2>/g;
|
|
492
|
+
let matches = [];
|
|
493
|
+
let match;
|
|
494
|
+
|
|
495
|
+
while ((match = itemRegex.exec(content)) !== null) {
|
|
496
|
+
matches.push({
|
|
497
|
+
id: match[1],
|
|
498
|
+
title: match[2].trim()
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (matches.length === 0) {
|
|
503
|
+
const simpleRegex = /item-card__wrap"[\s\S]*?id="item_(\d+)"/g;
|
|
504
|
+
let simpleMatch;
|
|
505
|
+
while ((simpleMatch = simpleRegex.exec(content)) !== null) {
|
|
506
|
+
matches.push({
|
|
507
|
+
id: simpleMatch[1],
|
|
508
|
+
title: '未知商品'
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
478
512
|
|
|
479
|
-
if (
|
|
513
|
+
if (matches.length === 0) {
|
|
480
514
|
if (content.includes('検索結果はありません') ||
|
|
481
515
|
content.includes('没有找到') ||
|
|
482
516
|
content.includes('検索条件に合致する作品は見つかりませんでした') ||
|
|
@@ -486,10 +520,30 @@ function apply(ctx, config) {
|
|
|
486
520
|
return "没有找到相关商品";
|
|
487
521
|
}
|
|
488
522
|
|
|
489
|
-
|
|
523
|
+
let selectedItemId;
|
|
524
|
+
if (authorFilter) {
|
|
525
|
+
for (const item of matches) {
|
|
526
|
+
try {
|
|
527
|
+
const itemDetail = await getBoothItem(item.id);
|
|
528
|
+
if (itemDetail && itemDetail.author &&
|
|
529
|
+
itemDetail.author.toLowerCase().includes(authorFilter.toLowerCase())) {
|
|
530
|
+
selectedItemId = item.id;
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
} catch (err) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (!selectedItemId) {
|
|
539
|
+
return `找不到作者"${authorFilter}"的相关商品`;
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
selectedItemId = matches[0].id;
|
|
543
|
+
}
|
|
490
544
|
|
|
491
545
|
try {
|
|
492
|
-
const buffer = await captureCard(ctx,
|
|
546
|
+
const buffer = await captureCard(ctx, selectedItemId);
|
|
493
547
|
if (!buffer) {
|
|
494
548
|
return "卡片生成失败";
|
|
495
549
|
}
|
|
@@ -526,24 +580,326 @@ function apply(ctx, config) {
|
|
|
526
580
|
return (2 * matches) / (a.length + b.length - 2);
|
|
527
581
|
}
|
|
528
582
|
|
|
583
|
+
async function fetchAuthorItems(ctx, authorName, limit = 6) {
|
|
584
|
+
try {
|
|
585
|
+
const page = await ctx.puppeteer.page();
|
|
586
|
+
|
|
587
|
+
try {
|
|
588
|
+
await page.setRequestInterception(true);
|
|
589
|
+
page.on('request', (request) => {
|
|
590
|
+
const resourceType = request.resourceType();
|
|
591
|
+
if (['stylesheet', 'font'].includes(resourceType)) {
|
|
592
|
+
request.abort();
|
|
593
|
+
} else {
|
|
594
|
+
request.continue();
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
await page.goto(`https://${authorName}.booth.pm/items`, {
|
|
599
|
+
waitUntil: 'networkidle0',
|
|
600
|
+
timeout: ctx.config.loadTimeout || import_koishi.Time.second * 10
|
|
601
|
+
});
|
|
602
|
+
await page.waitForSelector('.item-list', { timeout: 5000 });
|
|
603
|
+
|
|
604
|
+
const items = await page.evaluate((limit) => {
|
|
605
|
+
const itemElements = Array.from(document.querySelectorAll('.js-mount-point-shop-item-card'));
|
|
606
|
+
return itemElements.slice(0, limit).map(el => {
|
|
607
|
+
try {
|
|
608
|
+
const dataItem = JSON.parse(el.getAttribute('data-item'));
|
|
609
|
+
const imageUrl = dataItem.thumbnail_image_urls?.[0] ||
|
|
610
|
+
dataItem.images?.[0]?.original ||
|
|
611
|
+
el.querySelector('.swap-image img')?.src ||
|
|
612
|
+
'https://s2.booth.pm/static-images/item/empty-preview.png';
|
|
613
|
+
|
|
614
|
+
let price = dataItem.price;
|
|
615
|
+
if (typeof price === 'string') {
|
|
616
|
+
const priceMatch = price.match(/[\d,]+/);
|
|
617
|
+
if (priceMatch) {
|
|
618
|
+
price = parseInt(priceMatch[0].replace(/,/g, '')) || 0;
|
|
619
|
+
} else {
|
|
620
|
+
price = 0;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return {
|
|
625
|
+
id: dataItem.id,
|
|
626
|
+
title: dataItem.name,
|
|
627
|
+
price: price,
|
|
628
|
+
image_url: imageUrl,
|
|
629
|
+
author: dataItem.shop?.name,
|
|
630
|
+
author_thumbnail_url: dataItem.shop?.thumbnail_url
|
|
631
|
+
};
|
|
632
|
+
} catch (e) {
|
|
633
|
+
try {
|
|
634
|
+
const titleEl = el.querySelector('.item-name a');
|
|
635
|
+
const priceEl = el.querySelector('.price');
|
|
636
|
+
const imgEl = el.querySelector('.swap-image img');
|
|
637
|
+
|
|
638
|
+
let price = 0;
|
|
639
|
+
if (priceEl) {
|
|
640
|
+
const priceText = priceEl.textContent.trim();
|
|
641
|
+
const priceMatch = priceText.match(/[\d,]+/);
|
|
642
|
+
if (priceMatch) {
|
|
643
|
+
price = parseInt(priceMatch[0].replace(/,/g, '')) || 0;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return {
|
|
648
|
+
id: null,
|
|
649
|
+
title: titleEl ? titleEl.textContent.trim() : '未知商品',
|
|
650
|
+
price: price,
|
|
651
|
+
image_url: imgEl ? imgEl.src : 'https://s2.booth.pm/static-images/item/empty-preview.png',
|
|
652
|
+
author: null,
|
|
653
|
+
author_thumbnail_url: null
|
|
654
|
+
};
|
|
655
|
+
} catch (e2) {
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}).filter(item => item !== null && item.image_url);
|
|
660
|
+
}, limit);
|
|
661
|
+
|
|
662
|
+
await page.close();
|
|
663
|
+
return items;
|
|
664
|
+
} catch (error) {
|
|
665
|
+
await page.close();
|
|
666
|
+
throw error;
|
|
667
|
+
}
|
|
668
|
+
} catch (error) {
|
|
669
|
+
console.error('获取作者商品失败:', error);
|
|
670
|
+
return [];
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function generateAuthorShopCardHTML(authorName, items = []) {
|
|
675
|
+
return `
|
|
676
|
+
<html>
|
|
677
|
+
<head>
|
|
678
|
+
<meta charset="utf-8">
|
|
679
|
+
<style>
|
|
680
|
+
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&family=Montserrat:wght@600;700;800&display=swap');
|
|
681
|
+
body {
|
|
682
|
+
margin: 0;
|
|
683
|
+
padding: 0;
|
|
684
|
+
font-family: 'Noto Sans SC', sans-serif;
|
|
685
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
686
|
+
display: flex;
|
|
687
|
+
justify-content: center;
|
|
688
|
+
align-items: center;
|
|
689
|
+
min-height: 100vh;
|
|
690
|
+
}
|
|
691
|
+
.container {
|
|
692
|
+
width: 640px;
|
|
693
|
+
background: white;
|
|
694
|
+
border-radius: 20px;
|
|
695
|
+
overflow: hidden;
|
|
696
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
697
|
+
position: relative;
|
|
698
|
+
}
|
|
699
|
+
.header {
|
|
700
|
+
background: linear-gradient(90deg, #9b59b6, #3498db);
|
|
701
|
+
padding: 25px;
|
|
702
|
+
text-align: center;
|
|
703
|
+
position: relative;
|
|
704
|
+
color: white;
|
|
705
|
+
}
|
|
706
|
+
.header::before {
|
|
707
|
+
content: "";
|
|
708
|
+
position: absolute;
|
|
709
|
+
top: 0;
|
|
710
|
+
left: 0;
|
|
711
|
+
right: 0;
|
|
712
|
+
bottom: 0;
|
|
713
|
+
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none"><circle cx="20" cy="20" r="10" fill="rgba(255,255,255,0.1)"/><circle cx="50" cy="50" r="15" fill="rgba(255,255,255,0.1)"/><circle cx="80" cy="80" r="8" fill="rgba(255,255,255,0.1)"/></svg>');
|
|
714
|
+
background-size: 100px 100px;
|
|
715
|
+
}
|
|
716
|
+
.label {
|
|
717
|
+
background: rgba(255, 255, 255, 0.2);
|
|
718
|
+
backdrop-filter: blur(10px);
|
|
719
|
+
padding: 8px 20px;
|
|
720
|
+
border-radius: 30px;
|
|
721
|
+
font-size: 14px;
|
|
722
|
+
font-weight: 500;
|
|
723
|
+
display: inline-block;
|
|
724
|
+
margin-bottom: 15px;
|
|
725
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
726
|
+
}
|
|
727
|
+
.booth-logo {
|
|
728
|
+
font-family: 'Montserrat', sans-serif;
|
|
729
|
+
font-weight: 800;
|
|
730
|
+
font-size: 36px;
|
|
731
|
+
letter-spacing: 2px;
|
|
732
|
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
|
733
|
+
}
|
|
734
|
+
.author-name-card {
|
|
735
|
+
font-size: 24px;
|
|
736
|
+
font-weight: 600;
|
|
737
|
+
margin-top: 10px;
|
|
738
|
+
}
|
|
739
|
+
.content {
|
|
740
|
+
padding: 30px;
|
|
741
|
+
}
|
|
742
|
+
.shop-info {
|
|
743
|
+
text-align: center;
|
|
744
|
+
margin-bottom: 30px;
|
|
745
|
+
padding: 20px;
|
|
746
|
+
background: #f8f9fa;
|
|
747
|
+
border-radius: 12px;
|
|
748
|
+
}
|
|
749
|
+
.shop-title {
|
|
750
|
+
font-size: 24px;
|
|
751
|
+
color: #2c3e50;
|
|
752
|
+
margin-bottom: 10px;
|
|
753
|
+
font-weight: 700;
|
|
754
|
+
}
|
|
755
|
+
.shop-description {
|
|
756
|
+
color: #7f8c8d;
|
|
757
|
+
font-size: 16px;
|
|
758
|
+
}
|
|
759
|
+
.items-grid {
|
|
760
|
+
display: grid;
|
|
761
|
+
grid-template-columns: repeat(2, 1fr);
|
|
762
|
+
gap: 20px;
|
|
763
|
+
margin-top: 20px;
|
|
764
|
+
}
|
|
765
|
+
.item-card {
|
|
766
|
+
background: white;
|
|
767
|
+
border-radius: 12px;
|
|
768
|
+
overflow: hidden;
|
|
769
|
+
box-shadow: 0 4px 8px rgba(0,0,0,0.08);
|
|
770
|
+
transition: all 0.3s ease;
|
|
771
|
+
}
|
|
772
|
+
.item-card:hover {
|
|
773
|
+
transform: translateY(-5px);
|
|
774
|
+
box-shadow: 0 10px 20px rgba(0,0,0,0.15);
|
|
775
|
+
}
|
|
776
|
+
.item-image {
|
|
777
|
+
height: 150px;
|
|
778
|
+
background-size: cover;
|
|
779
|
+
background-position: center;
|
|
780
|
+
}
|
|
781
|
+
.item-info {
|
|
782
|
+
padding: 15px;
|
|
783
|
+
}
|
|
784
|
+
.item-title {
|
|
785
|
+
font-size: 14px;
|
|
786
|
+
margin-bottom: 10px;
|
|
787
|
+
color: #2c3e50;
|
|
788
|
+
height: 40px;
|
|
789
|
+
overflow: hidden;
|
|
790
|
+
}
|
|
791
|
+
.item-price {
|
|
792
|
+
font-size: 18px;
|
|
793
|
+
font-weight: 700;
|
|
794
|
+
color: #e74c3c;
|
|
795
|
+
}
|
|
796
|
+
.footer {
|
|
797
|
+
background: #2c3e50;
|
|
798
|
+
padding: 20px;
|
|
799
|
+
text-align: center;
|
|
800
|
+
color: #ecf0f1;
|
|
801
|
+
font-size: 14px;
|
|
802
|
+
}
|
|
803
|
+
.link {
|
|
804
|
+
color: #3498db;
|
|
805
|
+
text-decoration: none;
|
|
806
|
+
font-weight: 500;
|
|
807
|
+
}
|
|
808
|
+
.link:hover {
|
|
809
|
+
text-decoration: underline;
|
|
810
|
+
}
|
|
811
|
+
</style>
|
|
812
|
+
</head>
|
|
813
|
+
<body>
|
|
814
|
+
<div class="container">
|
|
815
|
+
<div class="header">
|
|
816
|
+
<div class="label">AUTHOR'S SHOP</div>
|
|
817
|
+
<div class="booth-logo">${authorName}.booth.pm</div>
|
|
818
|
+
</div>
|
|
819
|
+
|
|
820
|
+
<div class="content">
|
|
821
|
+
<div class="shop-info">
|
|
822
|
+
<div class="shop-title">${authorName} 的店铺</div>
|
|
823
|
+
<div class="shop-description">以下是该作者的部分商品</div>
|
|
824
|
+
</div>
|
|
825
|
+
|
|
826
|
+
${items.length > 0 ? `
|
|
827
|
+
<div class="items-grid">
|
|
828
|
+
${items.map(item => `
|
|
829
|
+
<div class="item-card">
|
|
830
|
+
<div class="item-image" style="background-image:url('${item.image_url}')"></div>
|
|
831
|
+
<div class="item-info">
|
|
832
|
+
<div class="item-title">${item.title.slice(0, 25)}${item.title.length > 25 ? '...' : ''}</div>
|
|
833
|
+
<div class="item-price">¥${item.price.toLocaleString()}</div>
|
|
834
|
+
</div>
|
|
835
|
+
</div>
|
|
836
|
+
`).join('')}
|
|
837
|
+
</div>
|
|
838
|
+
` : `
|
|
839
|
+
<div style="text-align: center; padding: 40px; color: #7f8c8d;">
|
|
840
|
+
<h3>暂无商品信息</h3>
|
|
841
|
+
<p>该作者店铺暂无商品或获取商品信息失败</p>
|
|
842
|
+
</div>
|
|
843
|
+
`}
|
|
844
|
+
</div>
|
|
845
|
+
|
|
846
|
+
<div class="footer">
|
|
847
|
+
由VRCBBS提供 | BOOTH链接:
|
|
848
|
+
<a href="https://${authorName}.booth.pm/items/"
|
|
849
|
+
class="link">
|
|
850
|
+
https://${authorName}.booth.pm/items/
|
|
851
|
+
</a>
|
|
852
|
+
</div>
|
|
853
|
+
</div>
|
|
854
|
+
</body>
|
|
855
|
+
</html>`;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
async function captureAuthorShopCard(ctx, authorName) {
|
|
859
|
+
const logger = ctx.logger("booth-get");
|
|
860
|
+
const items = await fetchAuthorItems(ctx, authorName);
|
|
861
|
+
|
|
862
|
+
const html = generateAuthorShopCardHTML(authorName, items);
|
|
863
|
+
|
|
864
|
+
const page = await ctx.puppeteer.page();
|
|
865
|
+
try {
|
|
866
|
+
await page.setRequestInterception(true);
|
|
867
|
+
page.on('request', (request) => request.continue());
|
|
868
|
+
|
|
869
|
+
await page.setContent(html, {
|
|
870
|
+
waitUntil: 'domcontentloaded',
|
|
871
|
+
timeout: ctx.config.loadTimeout || import_koishi.Time.second * 10
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
875
|
+
|
|
876
|
+
await page.setViewport({ width: 640, height: 1200 });
|
|
877
|
+
const container = await page.$('.container');
|
|
878
|
+
return await container.screenshot({
|
|
879
|
+
type: 'png',
|
|
880
|
+
encoding: 'binary',
|
|
881
|
+
captureBeyondViewport: false
|
|
882
|
+
});
|
|
883
|
+
} catch (error) {
|
|
884
|
+
logger.error('生成失败:', error);
|
|
885
|
+
return null;
|
|
886
|
+
} finally {
|
|
887
|
+
await page.close();
|
|
888
|
+
}
|
|
889
|
+
}
|
|
529
890
|
ctx.middleware(async (session, next) => {
|
|
530
891
|
const boothUrlRegex = /https:\/\/booth.pm\/[\w-]+\/items\/(\d+)/;
|
|
892
|
+
const boothAuthorUrlRegex = /https:\/\/([\w-]+)\.booth\.pm\/items(?:\/(\d+))?/;
|
|
531
893
|
const match = session.content.match(boothUrlRegex);
|
|
894
|
+
const authorMatch = session.content.match(boothAuthorUrlRegex);
|
|
532
895
|
|
|
533
896
|
if (match) {
|
|
534
|
-
if (session.onebot) {
|
|
535
|
-
session.onebot._sned = session.send;
|
|
536
|
-
session.send = function (...args) {
|
|
537
|
-
return this._sned.apply(this, args);
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
897
|
const itemId = match[1];
|
|
542
898
|
try {
|
|
543
899
|
const buffer = await captureCard(ctx, itemId);
|
|
544
900
|
if (buffer) {
|
|
545
901
|
await session.send(import_koishi.h.image(buffer, "image/png"));
|
|
546
|
-
return;
|
|
902
|
+
return "";
|
|
547
903
|
} else {
|
|
548
904
|
return "商品解析失败";
|
|
549
905
|
}
|
|
@@ -551,9 +907,91 @@ function apply(ctx, config) {
|
|
|
551
907
|
logger.warn("链接解析失败:", error);
|
|
552
908
|
return "商品解析失败";
|
|
553
909
|
}
|
|
910
|
+
} else if (authorMatch) {
|
|
911
|
+
const authorName = authorMatch[1];
|
|
912
|
+
const itemId = authorMatch[2];
|
|
913
|
+
|
|
914
|
+
try {
|
|
915
|
+
if (itemId) {
|
|
916
|
+
const buffer = await captureCard(ctx, itemId);
|
|
917
|
+
if (buffer) {
|
|
918
|
+
await session.send(import_koishi.h.image(buffer, "image/png"));
|
|
919
|
+
return "";
|
|
920
|
+
} else {
|
|
921
|
+
return "商品解析失败";
|
|
922
|
+
}
|
|
923
|
+
} else {
|
|
924
|
+
const buffer = await captureAuthorShopCard(ctx, authorName);
|
|
925
|
+
if (buffer) {
|
|
926
|
+
await session.send(import_koishi.h.image(buffer, "image/png"));
|
|
927
|
+
return "";
|
|
928
|
+
} else {
|
|
929
|
+
return "作者店铺卡片生成失败";
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
} catch (error) {
|
|
933
|
+
logger.warn("作者链接解析失败:", error);
|
|
934
|
+
return "作者链接解析失败";
|
|
935
|
+
}
|
|
554
936
|
}
|
|
555
937
|
return next();
|
|
556
938
|
});
|
|
939
|
+
|
|
940
|
+
ctx.command("摊位作者 <authorName:text>")
|
|
941
|
+
.action(async ({ session }, authorName) => {
|
|
942
|
+
if (!authorName) return "请输入作者名称";
|
|
943
|
+
|
|
944
|
+
try {
|
|
945
|
+
const searchUrl = `https://booth.pm/zh-cn/search/${encodeURIComponent(authorName)}?in_stock=true`;
|
|
946
|
+
const page = await ctx.puppeteer.page();
|
|
947
|
+
|
|
948
|
+
await page.setRequestInterception(true);
|
|
949
|
+
page.on('request', (request) => {
|
|
950
|
+
const resourceType = request.resourceType();
|
|
951
|
+
if (['image', 'stylesheet', 'font'].includes(resourceType)) {
|
|
952
|
+
request.abort();
|
|
953
|
+
} else {
|
|
954
|
+
request.continue();
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
try {
|
|
959
|
+
await page.goto(searchUrl, { waitUntil: 'networkidle0', timeout: ctx.config.loadTimeout || import_koishi.Time.second * 10 });
|
|
960
|
+
|
|
961
|
+
const content = await page.content();
|
|
962
|
+
|
|
963
|
+
const brandRegex = /data-product-brand="([^"]+)"/g;
|
|
964
|
+
const brands = new Set();
|
|
965
|
+
let brandMatch;
|
|
966
|
+
|
|
967
|
+
while ((brandMatch = brandRegex.exec(content)) !== null) {
|
|
968
|
+
brands.add(brandMatch[1]);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const brandArray = Array.from(brands);
|
|
972
|
+
|
|
973
|
+
if (brandArray.length > 0) {
|
|
974
|
+
const matchedAuthor = brandArray[0];
|
|
975
|
+
const buffer = await captureAuthorShopCard(ctx, matchedAuthor);
|
|
976
|
+
if (buffer) {
|
|
977
|
+
return import_koishi.h.image(buffer, "image/png");
|
|
978
|
+
} else {
|
|
979
|
+
return "作者店铺卡片生成失败";
|
|
980
|
+
}
|
|
981
|
+
} else {
|
|
982
|
+
return `未找到作者 "${authorName}" 的店铺`;
|
|
983
|
+
}
|
|
984
|
+
} catch (error) {
|
|
985
|
+
logger.error('搜索作者失败:', error);
|
|
986
|
+
return "搜索作者失败";
|
|
987
|
+
} finally {
|
|
988
|
+
await page.close();
|
|
989
|
+
}
|
|
990
|
+
} catch (error) {
|
|
991
|
+
logger.error('处理作者搜索失败:', error);
|
|
992
|
+
return "处理作者搜索失败";
|
|
993
|
+
}
|
|
994
|
+
});
|
|
557
995
|
}
|
|
558
996
|
|
|
559
997
|
__name(apply, "apply");
|