koishi-plugin-dew-bot 1.0.263 → 1.0.264

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 (73) hide show
  1. package/README.md +7 -1
  2. package/assets/official-qq-group.jpg +0 -0
  3. package/assets/signin-portraits/01-bunny-hostess.webp +0 -0
  4. package/assets/signin-portraits/02-forest-mage.webp +0 -0
  5. package/assets/signin-portraits/03-silver-goddess.webp +0 -0
  6. package/assets/signin-portraits/04-blue-knight.webp +0 -0
  7. package/assets/signin-portraits/05-steampunk-engineer.webp +0 -0
  8. package/assets/signin-portraits/06-naval-officer.webp +0 -0
  9. package/assets/signin-portraits/07-jade-qipao.webp +0 -0
  10. package/assets/signin-portraits/08-violet-mage.webp +0 -0
  11. package/assets/signin-portraits/09-ivory-adventurer.webp +0 -0
  12. package/assets/signin-portraits/10-sakura-kimono.webp +0 -0
  13. package/assets/signin-portraits/11-red-velvet-lady.webp +0 -0
  14. package/assets/signin-portraits/12-elven-ranger.webp +0 -0
  15. package/assets/signin-portraits/13-black-tuxedo.webp +0 -0
  16. package/assets/signin-portraits/14-ocean-blue-lady.webp +0 -0
  17. package/assets/signin-portraits/15-amber-witch.webp +0 -0
  18. package/assets/signin-portraits/16-classic-maid.webp +0 -0
  19. package/assets/signin-portraits/17-ice-blue-winter.webp +0 -0
  20. package/assets/signin-portraits/18-violet-office.webp +0 -0
  21. package/assets/signin-portraits/19-sapphire-gown.webp +0 -0
  22. package/assets/signin-portraits/20-silver-tech-jacket.webp +0 -0
  23. package/assets/signin-portraits/21-desert-linen.webp +0 -0
  24. package/assets/signin-portraits/22-forest-ranger.webp +0 -0
  25. package/assets/signin-portraits/23-moonlight-hanfu.webp +0 -0
  26. package/assets/signin-portraits/24-white-uniform.webp +0 -0
  27. package/assets/signin-portraits/25-gothic-lace.webp +0 -0
  28. package/assets/signin-portraits/26-orange-racer.webp +0 -0
  29. package/assets/signin-portraits/27-blue-alchemist.webp +0 -0
  30. package/assets/signin-portraits/28-rose-leather.webp +0 -0
  31. package/assets/signin-portraits/29-lilac-elf.webp +0 -0
  32. package/assets/signin-portraits/30-sun-gown.webp +0 -0
  33. package/assets/signin-portraits/31-pirate-captain.webp +0 -0
  34. package/assets/signin-portraits/32-green-scholar.webp +0 -0
  35. package/assets/signin-portraits/33-blue-streetwear.webp +0 -0
  36. package/assets/signin-portraits/34-cream-ballgown.webp +0 -0
  37. package/assets/signin-portraits/35-white-coat.webp +0 -0
  38. package/assets/signin-portraits/36-emerald-priestess.webp +0 -0
  39. package/assets/signin-portraits/37-peach-floral.webp +0 -0
  40. package/assets/signin-portraits/38-casino-hostess.webp +0 -0
  41. package/assets/signin-portraits/39-red-gold-armor.webp +0 -0
  42. package/assets/signin-portraits/40-opera-gown.webp +0 -0
  43. package/assets/signin-portraits/41-teal-officer.webp +0 -0
  44. package/assets/signin-portraits/42-guild-uniform.webp +0 -0
  45. package/assets/signin-portraits/43-charcoal-qipao.webp +0 -0
  46. package/assets/signin-portraits/44-sci-fi-pilot.webp +0 -0
  47. package/assets/signin-portraits/45-athlete-jacket.webp +0 -0
  48. package/assets/signin-portraits/46-teal-traditional.webp +0 -0
  49. package/assets/signin-portraits/47-violet-queen.webp +0 -0
  50. package/assets/signin-portraits/48-magic-explorer.webp +0 -0
  51. package/assets/signin-portraits/49-red-floral-qipao.webp +0 -0
  52. package/assets/signin-portraits/50-summer-dress.webp +0 -0
  53. package/lib/index.js +605 -27
  54. package/lib/plugin/signinCardAssets.d.ts +9 -0
  55. package/lib/plugin/signinCardStyles.d.ts +2 -0
  56. package/lib/plugin/signinCardTemplate.d.ts +9 -0
  57. package/lib/plugin/signinPortraits.d.ts +8 -0
  58. package/lib/plugin/skillCard.d.ts +2 -1
  59. package/lib/shared/face/index.d.ts +17 -0
  60. package/package.json +1 -1
  61. package/src/plugin/cardLayout.ts +22 -0
  62. package/src/plugin/equipmentCardTemplate.ts +1 -1
  63. package/src/plugin/serverHandel/handel_base.ts +2 -2
  64. package/src/plugin/serverHandel/image.ts +2 -2
  65. package/src/plugin/serverHandel/qqMessagePreview.ts +1 -0
  66. package/src/plugin/signinCardAssets.ts +63 -0
  67. package/src/plugin/signinCardStyles.ts +48 -0
  68. package/src/plugin/signinCardTemplate.ts +42 -0
  69. package/src/plugin/signinPortraits.ts +310 -0
  70. package/src/plugin/skillCard.ts +27 -12
  71. package/src/plugin/skillCardTemplate.ts +0 -1
  72. package/src/shared/bot/serviceProto.ts +92 -1
  73. package/src/shared/face/index.ts +18 -0
package/lib/index.js CHANGED
@@ -67,7 +67,7 @@ var serviceProto;
67
67
  var init_serviceProto = __esm({
68
68
  "src/shared/bot/serviceProto.ts"() {
69
69
  serviceProto = {
70
- "version": 39,
70
+ "version": 41,
71
71
  "services": [
72
72
  {
73
73
  "id": 0,
@@ -307,6 +307,23 @@ var init_serviceProto = __esm({
307
307
  }
308
308
  },
309
309
  "optional": true
310
+ },
311
+ {
312
+ "id": 18,
313
+ "name": "plainText",
314
+ "type": {
315
+ "type": "Boolean"
316
+ },
317
+ "optional": true
318
+ },
319
+ {
320
+ "id": 19,
321
+ "name": "signinCard",
322
+ "type": {
323
+ "type": "Reference",
324
+ "target": "messageFace/SigninCardData"
325
+ },
326
+ "optional": true
310
327
  }
311
328
  ]
312
329
  },
@@ -1970,6 +1987,80 @@ var init_serviceProto = __esm({
1970
1987
  }
1971
1988
  ]
1972
1989
  },
1990
+ "messageFace/SigninCardData": {
1991
+ "type": "Interface",
1992
+ "properties": [
1993
+ {
1994
+ "id": 0,
1995
+ "name": "cycleDays",
1996
+ "type": {
1997
+ "type": "Number"
1998
+ }
1999
+ },
2000
+ {
2001
+ "id": 1,
2002
+ "name": "completedDays",
2003
+ "type": {
2004
+ "type": "Number"
2005
+ }
2006
+ },
2007
+ {
2008
+ "id": 2,
2009
+ "name": "portraitId",
2010
+ "type": {
2011
+ "type": "Number"
2012
+ }
2013
+ },
2014
+ {
2015
+ "id": 3,
2016
+ "name": "days",
2017
+ "type": {
2018
+ "type": "Array",
2019
+ "elementType": {
2020
+ "type": "Interface",
2021
+ "properties": [
2022
+ {
2023
+ "id": 0,
2024
+ "name": "day",
2025
+ "type": {
2026
+ "type": "Number"
2027
+ }
2028
+ },
2029
+ {
2030
+ "id": 1,
2031
+ "name": "itemId",
2032
+ "type": {
2033
+ "type": "String"
2034
+ }
2035
+ },
2036
+ {
2037
+ "id": 2,
2038
+ "name": "name",
2039
+ "type": {
2040
+ "type": "String"
2041
+ }
2042
+ },
2043
+ {
2044
+ "id": 3,
2045
+ "name": "count",
2046
+ "type": {
2047
+ "type": "Number"
2048
+ }
2049
+ },
2050
+ {
2051
+ "id": 4,
2052
+ "name": "artworkUrl",
2053
+ "type": {
2054
+ "type": "String"
2055
+ },
2056
+ "optional": true
2057
+ }
2058
+ ]
2059
+ }
2060
+ }
2061
+ }
2062
+ ]
2063
+ },
1973
2064
  "PtlMessage/ReqMessage": {
1974
2065
  "type": "Interface",
1975
2066
  "extends": [
@@ -2777,7 +2868,7 @@ function flower(x, y, scale) {
2777
2868
  return `<g transform="translate(${x} ${y}) scale(${scale})">${petals}${inner}<circle r="3.4" fill="var(--accent)" stroke="#fffefa" stroke-width=".8"/>${stamens}</g>`;
2778
2869
  }
2779
2870
  __name(flower, "flower");
2780
- var slimLeaf = /* @__PURE__ */ __name((path2, vein) => `<path d="${path2}" fill="url(#character-leaf)" stroke="var(--light-edge)" stroke-width="1.15"/><path d="${vein}" fill="none" stroke="var(--leaf-light)" stroke-width=".65"/>`, "slimLeaf");
2871
+ var slimLeaf = /* @__PURE__ */ __name((path3, vein) => `<path d="${path3}" fill="url(#character-leaf)" stroke="var(--light-edge)" stroke-width="1.15"/><path d="${vein}" fill="none" stroke="var(--leaf-light)" stroke-width=".65"/>`, "slimLeaf");
2781
2872
  function characterTierOrnament(tier) {
2782
2873
  const leaves = `<g class="ornament-leaves"><path d="M13 151C7 105 10 51 39 25c25-20 66-15 103-17" fill="none" stroke="url(#character-metal)" stroke-width="3.6"/><path d="M13 150C10 90 17 42 48 24s69-13 97-15" fill="none" stroke="#fffefa" stroke-width=".65"/>${slimLeaf("M23 86C1 74 4 52 7 40c12 14 24 22 16 46Z", "M23 85 9 45")}${slimLeaf("M58 23C67 5 85 5 99 7 90 19 78 33 58 23Z", "M59 23 96 9")}</g>`;
2783
2874
  const flowers = `<g class="ornament-flowers">${flower(34, 34, 0.87)}${slimLeaf("M33 68C34 47 50 44 60 39 57 57 46 69 33 68Z", "M34 67 57 43")}</g>`;
@@ -3222,6 +3313,31 @@ var import_node_crypto = require("node:crypto");
3222
3313
  // src/plugin/cardLayout.ts
3223
3314
  async function layoutCard(document2 = globalThis.document) {
3224
3315
  await document2.fonts.ready;
3316
+ if (document2.getElementById("capture")?.classList.contains("signin-sheet")) {
3317
+ await Promise.all([...document2.querySelectorAll(".signin-item-art,.signin-item-glow,.signin-portrait-art")].map(async (image2) => {
3318
+ try {
3319
+ await image2.decode();
3320
+ } catch {
3321
+ image2.remove();
3322
+ }
3323
+ }));
3324
+ for (const label of document2.querySelectorAll(".signin-reward-label")) {
3325
+ const container = label.parentElement;
3326
+ const style = document2.defaultView.getComputedStyle(container);
3327
+ const available = container.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight) - 1;
3328
+ const maximum = parseFloat(document2.defaultView.getComputedStyle(label).fontSize);
3329
+ let size = maximum;
3330
+ for (let attempt = 0; attempt < 6; attempt++) {
3331
+ const width = label.getBoundingClientRect().width;
3332
+ if (width <= available) break;
3333
+ size = Math.max(1, size * available / width * 0.98);
3334
+ label.style.fontSize = size + "px";
3335
+ label.style.gap = 3.79 * size / maximum + "px";
3336
+ label.style.webkitTextStrokeWidth = 1.14 * size / maximum + "px";
3337
+ }
3338
+ }
3339
+ return;
3340
+ }
3225
3341
  for (const name3 of document2.querySelectorAll("#character-name,#companion-name")) {
3226
3342
  const style = document2.defaultView.getComputedStyle(name3);
3227
3343
  const maximum = parseFloat(style.fontSize);
@@ -3415,8 +3531,8 @@ function leaderboardHtml(data, _headerImage, backgroundImage) {
3415
3531
  __name(leaderboardHtml, "leaderboardHtml");
3416
3532
 
3417
3533
  // src/plugin/skillCard.ts
3418
- var import_promises = __toESM(require("node:fs/promises"));
3419
- var import_node_path = __toESM(require("node:path"));
3534
+ var import_promises2 = __toESM(require("node:fs/promises"));
3535
+ var import_node_path2 = __toESM(require("node:path"));
3420
3536
 
3421
3537
  // src/plugin/skillCardTemplate.ts
3422
3538
  var escape2 = /* @__PURE__ */ __name((value) => String(value ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]), "escape");
@@ -3457,7 +3573,6 @@ function skillCardHtml(card, _frame = "", artwork) {
3457
3573
  <div class="card-inner"><header class="card-titlebar"><span class="title-glyph" aria-hidden="true">◇</span><h1>${escape2(card.name)}</h1><span class="title-star" aria-hidden="true">✦</span></header>
3458
3574
  <div class="card-hero"><div class="hero-copy"><div class="hero-meta"><span class="skill-type">${card.passive ? "被动技能" : "主动技能"}</span><span class="quality-badge"><b>${quality}</b> 级</span></div><div class="tags">${tags.map((tag) => `<span class="tag ${tagClass(tag)}">${escape2(tag)}</span>`).join("")}</div></div><div class="hero-icon-wrap">${qualityMagicCircle(quality)}<div class="art-fallback" aria-hidden="true">${card.passive ? "静" : "势"}</div>${artwork ? `<img class="skill-artwork" alt="${escape2(card.name)}图标" src="${escape2(artwork)}">` : ""}${qualityIconFrame(quality)}</div></div>
3459
3575
  <div class="card-body"><div class="effect-stats">
3460
- ${row("技能等级", `${escape2(card.level)} <small class="param-unit">/ ${escape2(card.maxLevel)}</small>`, true)}
3461
3576
  ${row("消耗", escape2(card.cost || "无消耗"), true)}
3462
3577
  ${row("冷却", cooldownValue, true)}
3463
3578
  ${power ? row("战力", escape2(power.replace(/^(?:🔥\s*)?战力\s*[::]\s*/, "")), true) : ""}
@@ -3481,7 +3596,7 @@ function equipmentCardHtml(card, artwork, unknownFallback = false) {
3481
3596
  ...card.referencePrice ? [cardStatRow("参考价格", card.referencePrice)] : []
3482
3597
  ].join("");
3483
3598
  const affixes = card.affixes?.length ? '<div class="detail-list">' + card.affixes.map((affix) => cardStatRow(affix.name, affix.value)).join("") + "</div>" : '<p class="description">暂无附加属性</p>';
3484
- const skills2 = card.skills?.length ? cardSection("附带技能", '<div class="detail-list">' + card.skills.map((skill) => cardStatRow(skill.name, skill.rank)).join("") + "</div>") : "";
3599
+ const skills2 = card.skills?.length ? cardSection("附带技能", '<div class="detail-list">' + card.skills.map((skill) => cardStatRow(skill.name, "")).join("") + "</div>") : "";
3485
3600
  const description = card.description?.trim() ? cardSection("装备描述", '<p class="description">' + cardEscape(card.description.trim()) + "</p>") : "";
3486
3601
  const notes = card.notes?.filter((note) => note?.trim()).length ? cardSection("附加信息", '<p class="description">' + card.notes.filter((note) => note?.trim()).map((note) => cardEscape(note)).join("\n") + "</p>") : "";
3487
3602
  return detailCardHtml({
@@ -3745,6 +3860,458 @@ async function loadCardEntryArtwork(card) {
3745
3860
  }
3746
3861
  __name(loadCardEntryArtwork, "loadCardEntryArtwork");
3747
3862
 
3863
+ // src/plugin/signinCardStyles.ts
3864
+ var signinCardStyles = `
3865
+ body { margin: 0; background: #edf0e4; }
3866
+
3867
+ #capture.signin-sheet { font-family: "Microsoft YaHei", "PingFang SC", sans-serif; padding: 22.72px 20.2px 30.3px; }
3868
+ #capture.signin-sheet * { box-sizing: border-box; }
3869
+ #capture.signin-sheet .signin-poster { width: 100%; max-width: 719.6px; margin: 0 auto; padding-top: 111.1px; color: #4b493f; }
3870
+ #capture.signin-sheet .signin-banner { position: relative; isolation: isolate; z-index: 1; height: 218.41px; padding: 35.35px 35.35px 27.77px; border-radius: 30.3px 30.3px 0 0; background: linear-gradient(108deg, #b5cb65, #c6d879 54%, #8daa5f); box-shadow: 0 -2.52px 0 #dbe6ab inset; }
3871
+ #capture.signin-sheet .signin-banner::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: radial-gradient(ellipse at 16% 0%, #e0eba778, transparent 48%), repeating-linear-gradient(45deg, #6b852c06 0 5.05px, transparent 5.05px 15.15px); }
3872
+ #capture.signin-sheet .signin-eyebrow { position: relative; z-index: 2; color: #47612e; font-size: 12.62px; font-weight: 700; letter-spacing: 4.42px; margin-bottom: 10.1px; }
3873
+ #capture.signin-sheet .signin-title { position: relative; z-index: 2; width: fit-content; margin: 0; font-size: 54.29px; font-weight: 900; letter-spacing: 2.52px; line-height: 1.2; color: #fffde8; -webkit-text-stroke: 1.39px #4a5c2e; paint-order: stroke fill; text-shadow: 0 3.79px 0 #566632, 0 6.31px 7.57px #71803c25; }
3874
+ #capture.signin-sheet .signin-progress { position: relative; z-index: 2; display: inline-flex; align-items: center; gap: 10.1px; margin-top: 20.2px; padding: 5.05px 15.15px 5.05px 10.1px; color: #fbf7d3; background: #4d642bcc; border-radius: 10.1px; font-size: 21.46px; font-weight: 700; line-height: 1.25; font-variant-numeric: tabular-nums; }
3875
+ #capture.signin-sheet .signin-progress svg { width: 22.72px; height: 22.72px; }
3876
+ #capture.signin-sheet .signin-progress small { font-size: 13.89px; font-weight: 400; opacity: .85; padding-left: 5.05px; }
3877
+ #capture.signin-sheet .signin-portrait { position: absolute; z-index: 0; inset: -107.31px -3.79px 0 auto; width: 366.11px; overflow: hidden; border: 0; padding: 0; background: none; }
3878
+ #capture.signin-sheet .signin-portrait::before { content: ""; position: absolute; width: 277.74px; height: 277.74px; right: 10.1px; bottom: -42.92px; border-radius: 50%; background: radial-gradient(circle, #e3e8b88c 0%, #9fba6e36 65%, transparent 70%); }
3879
+ #capture.signin-sheet .signin-portrait img { position: absolute; top: 0; left: -38%; width: 170%; max-width: none; height: auto; filter: drop-shadow(0 3.79px 3.79px #3f542415); }
3880
+ #capture.signin-sheet .signin-leaf { position: absolute; z-index: 1; width: 37.87px; height: 15.15px; border-radius: 100% 0 100% 0; background: #eff2ae70; transform: rotate(-32deg); }
3881
+ #capture.signin-sheet .leaf-a { top: 25.25px; left: 44%; }
3882
+ #capture.signin-sheet .leaf-b { top: 87.11px; left: 51%; width: 23.99px; height: 10.1px; transform: rotate(22deg); }
3883
+ #capture.signin-sheet .leaf-c { bottom: 40.4px; left: 46%; width: 55.55px; height: 22.72px; transform: rotate(-50deg); opacity: .6; }
3884
+ #capture.signin-sheet .signin-refresh { position: absolute; bottom: 21.46px; right: 25.25px; z-index: 2; display: flex; align-items: center; gap: 6.31px; padding: 5.05px 10.1px; border-radius: 6.31px; color: #35472f; background: #f8f8dddc; font-size: 13.89px; }
3885
+ #capture.signin-sheet .signin-refresh svg { width: 16.41px; height: 16.41px; }
3886
+ #capture.signin-sheet .signin-eyebrow, #capture.signin-sheet .signin-title, #capture.signin-sheet .signin-progress, #capture.signin-sheet .signin-refresh, #capture.signin-sheet .signin-leaf { pointer-events: none; }
3887
+ #capture.signin-sheet .signin-board { position: relative; z-index: 3; background: #f8f5ec; border-radius: 20.2px; padding: 18.94px; margin-top: -2.52px; box-shadow: 0 11.36px 35.35px #474c3220, 0 0 0 1.26px #d9d8cc; }
3888
+ #capture.signin-sheet .signin-seam { height: 0; border-top: 2.52px dashed #6d78555a; margin: -17.67px 5.05px 16.41px; }
3889
+ #capture.signin-sheet .signin-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 11.36px; }
3890
+ #capture.signin-sheet .signin-day { position: relative; display: flex; flex-direction: column; align-items: center; min-width: 0; aspect-ratio: .72; padding: 0; overflow: hidden; border: 0; border-radius: 11.36px; color: #615346; background: linear-gradient(158deg, #ead1a3, #f4e2c4 62%, #efe0ca); box-shadow: inset 0 0 0 1.26px #dfc49b70; font-family: inherit; transition: transform .15s ease, box-shadow .15s ease; }
3891
+ #capture.signin-sheet .signin-day::after { content: ""; position: absolute; inset: auto 0 0; height: 5.05px; background: linear-gradient(to right, #daa04d, #f0bc6c); }
3892
+ #capture.signin-sheet .signin-number { position: absolute; top: 6.31px; left: 8.84px; color: #fff9e5ce; font-size: 31.56px; font-weight: 400; letter-spacing: -1.89px; line-height: 1; }
3893
+ #capture.signin-sheet .signin-reward { display: flex; align-items: center; justify-content: center; flex: 1; min-height: 0; width: 100%; padding: 36.61px 6.31px 3.79px; }
3894
+ #capture.signin-sheet .signin-art-wrap { position: relative; isolation: isolate; display: block; width: 90.9px; height: 90.9px; max-width: 100%; flex-shrink: 0; }
3895
+ #capture.signin-sheet .signin-item-art { display: block; position: relative; width: 100%; height: 100%; max-width: 100%; object-fit: contain; border-radius: 24%; box-shadow: 0 3.79px 11.36px #68533416, inset 0 0 0 1.26px #fff9e936; }
3896
+ #capture.signin-sheet .signin-reward-info { display: flex; align-items: flex-end; justify-content: center; flex-shrink: 0; width: 100%; height: 37.87px; padding: 0 2.52px 11.36px; background: none; text-align: center; }
3897
+ #capture.signin-sheet .signin-reward-label { display: inline-flex; align-items: baseline; gap: 3.79px; flex-shrink: 0; color: #fff; font-size: 16.41px; font-weight: 600; line-height: 1; white-space: nowrap; -webkit-text-stroke: 1.14px #26231f; paint-order: stroke fill; text-shadow: 0 1.26px 1.26px #0004; }
3898
+ #capture.signin-sheet .signin-item-name { display: inline; color: inherit; font-size: inherit; font-weight: inherit; line-height: inherit; }
3899
+ #capture.signin-sheet .signin-quantity { display: inline; color: inherit; font-size: inherit; font-weight: inherit; line-height: inherit; font-variant-numeric: tabular-nums; }
3900
+ #capture.signin-sheet .signin-claimed-overlay { position: absolute; z-index: 4; inset: 0; background: #211e187d; pointer-events: none; }
3901
+ #capture.signin-sheet .signin-check { position: absolute; z-index: 5; inset: 0; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: #fff; opacity: .82; background: none; border: 0; box-shadow: none; pointer-events: none; }
3902
+ #capture.signin-sheet .signin-check svg { width: 52% !important; height: 52% !important; max-width: 68.17px; max-height: 68.17px; stroke-width: 3px; }
3903
+
3904
+ #capture.signin-sheet { box-sizing: border-box; width: 760px; background: linear-gradient(160deg, #edf1e5, #e8e9e0); }
3905
+ #capture.signin-sheet .signin-portrait.full-body img { width: 170%; left: -38%; top: 0; }
3906
+ #capture.signin-sheet .signin-portrait.waist-up img { width: 100%; left: 0; top: 10px; }
3907
+ #capture.signin-sheet .signin-item-glow { position: absolute; z-index: -1; inset: -4px; width: calc(100% + 8px); height: calc(100% + 8px); object-fit: cover; border-radius: 26%; filter: blur(9px); opacity: .42; transform: translateY(4px) scale(1.03); }
3908
+ #capture.signin-sheet .signin-day { cursor: default; }
3909
+ #capture.signin-sheet .signin-day::after { z-index: 1; }
3910
+ `;
3911
+
3912
+ // src/plugin/signinCardTemplate.ts
3913
+ var check = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m20 6-11 11-5-5"/></svg>';
3914
+ var progressCheck = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 11 3 3L22 4"/><path d="M21 12v1a9 9 0 1 1-5.34-8.23"/></svg>';
3915
+ var clock = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 6v6h4"/></svg>';
3916
+ function signinCardHtml(card, artwork = [], portrait) {
3917
+ if (card.cycleDays !== 30 || card.days.length !== 30 || card.days.some((day, index) => day.day !== index + 1)) throw new Error("签到卡片必须包含固定 30 天奖励");
3918
+ const completed = Math.min(30, Math.max(0, Math.trunc(card.completedDays)));
3919
+ const days = card.days.map((day, index) => {
3920
+ const image2 = artwork[index];
3921
+ const claimed = day.day <= completed;
3922
+ return `<div class="signin-day${claimed ? " is-claimed" : ""}" data-day="${day.day}" aria-label="第 ${day.day} 天,${cardEscape(day.name)} ×${cardEscape(day.count)}${claimed ? ",已签到" : ""}">
3923
+ <span class="signin-number">${String(day.day).padStart(2, "0")}</span>
3924
+ <div class="signin-reward"><span class="signin-art-wrap">${image2 ? `<img class="signin-item-glow" src="${cardEscape(image2)}" alt="" aria-hidden="true"><img class="signin-item-art" src="${cardEscape(image2)}" alt="${cardEscape(day.name)}">` : ""}</span></div>
3925
+ <div class="signin-reward-info"><span class="signin-reward-label"><span class="signin-item-name">${cardEscape(day.name)}</span><span class="signin-quantity">×${cardEscape(day.count)}</span></span></div>
3926
+ ${claimed ? `<span class="signin-claimed-overlay" aria-hidden="true"></span><span class="signin-check">${check}</span>` : ""}
3927
+ </div>`;
3928
+ }).join("");
3929
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${signinCardStyles}</style></head><body><main id="capture" class="signin-sheet" data-portrait-id="${cardEscape(card.portraitId)}">
3930
+ <article class="signin-poster" aria-label="每日签到,固定 30 天周期">
3931
+ <header class="signin-banner">
3932
+ ${portrait ? `<div class="signin-portrait ${portrait.framing === "full-body" ? "full-body" : "waist-up"}"><img class="signin-portrait-art" src="${cardEscape(portrait.src)}" alt="${cardEscape(portrait.name)}"></div>` : ""}
3933
+ <span class="signin-leaf leaf-a" aria-hidden="true"></span><span class="signin-leaf leaf-b" aria-hidden="true"></span><span class="signin-leaf leaf-c" aria-hidden="true"></span>
3934
+ <div class="signin-eyebrow">DAILY CHECK-IN</div><h1 class="signin-title">每日签到</h1>
3935
+ <div class="signin-progress">${progressCheck}<span>${completed} / 30</span><small>本轮签到</small></div>
3936
+ <div class="signin-refresh">${clock}每日 00:00 刷新</div>
3937
+ </header>
3938
+ <section class="signin-board" aria-label="30 天奖励日历"><div class="signin-seam" aria-hidden="true"></div><div class="signin-grid">${days}</div></section>
3939
+ </article>
3940
+ </main></body></html>`;
3941
+ }
3942
+ __name(signinCardHtml, "signinCardHtml");
3943
+
3944
+ // src/plugin/signinCardAssets.ts
3945
+ var import_promises = __toESM(require("node:fs/promises"));
3946
+ var import_node_path = __toESM(require("node:path"));
3947
+
3948
+ // src/plugin/signinPortraits.ts
3949
+ var SIGNIN_PORTRAITS = [
3950
+ {
3951
+ "id": 1,
3952
+ "name": "银发兔女郎",
3953
+ "file": "01-bunny-hostess.webp",
3954
+ "framing": "full-body"
3955
+ },
3956
+ {
3957
+ "id": 2,
3958
+ "name": "森林法师",
3959
+ "file": "02-forest-mage.webp",
3960
+ "framing": "waist-up"
3961
+ },
3962
+ {
3963
+ "id": 3,
3964
+ "name": "银发女神",
3965
+ "file": "03-silver-goddess.webp",
3966
+ "framing": "waist-up"
3967
+ },
3968
+ {
3969
+ "id": 4,
3970
+ "name": "蓝甲女骑士",
3971
+ "file": "04-blue-knight.webp",
3972
+ "framing": "waist-up"
3973
+ },
3974
+ {
3975
+ "id": 5,
3976
+ "name": "蒸汽朋克工程师",
3977
+ "file": "05-steampunk-engineer.webp",
3978
+ "framing": "waist-up"
3979
+ },
3980
+ {
3981
+ "id": 6,
3982
+ "name": "海军礼服军官",
3983
+ "file": "06-naval-officer.webp",
3984
+ "framing": "waist-up"
3985
+ },
3986
+ {
3987
+ "id": 7,
3988
+ "name": "翡翠旗袍佳人",
3989
+ "file": "07-jade-qipao.webp",
3990
+ "framing": "waist-up"
3991
+ },
3992
+ {
3993
+ "id": 8,
3994
+ "name": "紫罗兰女法师",
3995
+ "file": "08-violet-mage.webp",
3996
+ "framing": "waist-up"
3997
+ },
3998
+ {
3999
+ "id": 9,
4000
+ "name": "米白衬衫冒险家",
4001
+ "file": "09-ivory-adventurer.webp",
4002
+ "framing": "waist-up"
4003
+ },
4004
+ {
4005
+ "id": 10,
4006
+ "name": "樱花和服佳人",
4007
+ "file": "10-sakura-kimono.webp",
4008
+ "framing": "waist-up"
4009
+ },
4010
+ {
4011
+ "id": 11,
4012
+ "name": "红丝绒礼裙淑女",
4013
+ "file": "11-red-velvet-lady.webp",
4014
+ "framing": "waist-up"
4015
+ },
4016
+ {
4017
+ "id": 12,
4018
+ "name": "精灵绿裙游侠",
4019
+ "file": "12-elven-ranger.webp",
4020
+ "framing": "waist-up"
4021
+ },
4022
+ {
4023
+ "id": 13,
4024
+ "name": "黑礼服西装佳人",
4025
+ "file": "13-black-tuxedo.webp",
4026
+ "framing": "waist-up"
4027
+ },
4028
+ {
4029
+ "id": 14,
4030
+ "name": "海蓝披肩佳人",
4031
+ "file": "14-ocean-blue-lady.webp",
4032
+ "framing": "waist-up"
4033
+ },
4034
+ {
4035
+ "id": 15,
4036
+ "name": "琥珀女巫",
4037
+ "file": "15-amber-witch.webp",
4038
+ "framing": "waist-up"
4039
+ },
4040
+ {
4041
+ "id": 16,
4042
+ "name": "经典黑白女仆",
4043
+ "file": "16-classic-maid.webp",
4044
+ "framing": "waist-up"
4045
+ },
4046
+ {
4047
+ "id": 17,
4048
+ "name": "冰蓝冬装佳人",
4049
+ "file": "17-ice-blue-winter.webp",
4050
+ "framing": "waist-up"
4051
+ },
4052
+ {
4053
+ "id": 18,
4054
+ "name": "紫色职场西装佳人",
4055
+ "file": "18-violet-office.webp",
4056
+ "framing": "waist-up"
4057
+ },
4058
+ {
4059
+ "id": 19,
4060
+ "name": "红发蓝宝石礼裙",
4061
+ "file": "19-sapphire-gown.webp",
4062
+ "framing": "waist-up"
4063
+ },
4064
+ {
4065
+ "id": 20,
4066
+ "name": "银发科技夹克",
4067
+ "file": "20-silver-tech-jacket.webp",
4068
+ "framing": "waist-up"
4069
+ },
4070
+ {
4071
+ "id": 21,
4072
+ "name": "沙漠旅者",
4073
+ "file": "21-desert-linen.webp",
4074
+ "framing": "waist-up"
4075
+ },
4076
+ {
4077
+ "id": 22,
4078
+ "name": "森林游侠",
4079
+ "file": "22-forest-ranger.webp",
4080
+ "framing": "waist-up"
4081
+ },
4082
+ {
4083
+ "id": 23,
4084
+ "name": "月白汉服",
4085
+ "file": "23-moonlight-hanfu.webp",
4086
+ "framing": "waist-up"
4087
+ },
4088
+ {
4089
+ "id": 24,
4090
+ "name": "白色军装",
4091
+ "file": "24-white-uniform.webp",
4092
+ "framing": "waist-up"
4093
+ },
4094
+ {
4095
+ "id": 25,
4096
+ "name": "紫发哥特礼裙",
4097
+ "file": "25-gothic-lace.webp",
4098
+ "framing": "waist-up"
4099
+ },
4100
+ {
4101
+ "id": 26,
4102
+ "name": "赛车夹克",
4103
+ "file": "26-orange-racer.webp",
4104
+ "framing": "waist-up"
4105
+ },
4106
+ {
4107
+ "id": 27,
4108
+ "name": "蓝发炼金师",
4109
+ "file": "27-blue-alchemist.webp",
4110
+ "framing": "waist-up"
4111
+ },
4112
+ {
4113
+ "id": 28,
4114
+ "name": "玫瑰短发皮夹克",
4115
+ "file": "28-rose-leather.webp",
4116
+ "framing": "waist-up"
4117
+ },
4118
+ {
4119
+ "id": 29,
4120
+ "name": "淡紫成人精灵",
4121
+ "file": "29-lilac-elf.webp",
4122
+ "framing": "waist-up"
4123
+ },
4124
+ {
4125
+ "id": 30,
4126
+ "name": "太阳纹礼裙",
4127
+ "file": "30-sun-gown.webp",
4128
+ "framing": "waist-up"
4129
+ },
4130
+ {
4131
+ "id": 31,
4132
+ "name": "海盗船长",
4133
+ "file": "31-pirate-captain.webp",
4134
+ "framing": "waist-up"
4135
+ },
4136
+ {
4137
+ "id": 32,
4138
+ "name": "墨绿学院学者",
4139
+ "file": "32-green-scholar.webp",
4140
+ "framing": "waist-up"
4141
+ },
4142
+ {
4143
+ "id": 33,
4144
+ "name": "街头拉链外套",
4145
+ "file": "33-blue-streetwear.webp",
4146
+ "framing": "waist-up"
4147
+ },
4148
+ {
4149
+ "id": 34,
4150
+ "name": "奶油色舞会礼裙",
4151
+ "file": "34-cream-ballgown.webp",
4152
+ "framing": "waist-up"
4153
+ },
4154
+ {
4155
+ "id": 35,
4156
+ "name": "赤褐马尾医师",
4157
+ "file": "35-white-coat.webp",
4158
+ "framing": "waist-up"
4159
+ },
4160
+ {
4161
+ "id": 36,
4162
+ "name": "铂金圣职祭司",
4163
+ "file": "36-emerald-priestess.webp",
4164
+ "framing": "waist-up"
4165
+ },
4166
+ {
4167
+ "id": 37,
4168
+ "name": "桃色复古花裙",
4169
+ "file": "37-peach-floral.webp",
4170
+ "framing": "waist-up"
4171
+ },
4172
+ {
4173
+ "id": 38,
4174
+ "name": "紫发赌场主持",
4175
+ "file": "38-casino-hostess.webp",
4176
+ "framing": "waist-up"
4177
+ },
4178
+ {
4179
+ "id": 39,
4180
+ "name": "红金轻甲骑士",
4181
+ "file": "39-red-gold-armor.webp",
4182
+ "framing": "waist-up"
4183
+ },
4184
+ {
4185
+ "id": 40,
4186
+ "name": "玫瑰歌剧女伶",
4187
+ "file": "40-opera-gown.webp",
4188
+ "framing": "waist-up"
4189
+ },
4190
+ {
4191
+ "id": 41,
4192
+ "name": "青发军官",
4193
+ "file": "41-teal-officer.webp",
4194
+ "framing": "waist-up"
4195
+ },
4196
+ {
4197
+ "id": 42,
4198
+ "name": "金棕公会接待",
4199
+ "file": "42-guild-uniform.webp",
4200
+ "framing": "waist-up"
4201
+ },
4202
+ {
4203
+ "id": 43,
4204
+ "name": "炭灰旗袍佳人",
4205
+ "file": "43-charcoal-qipao.webp",
4206
+ "framing": "waist-up"
4207
+ },
4208
+ {
4209
+ "id": 44,
4210
+ "name": "银蓝飞行员",
4211
+ "file": "44-sci-fi-pilot.webp",
4212
+ "framing": "waist-up"
4213
+ },
4214
+ {
4215
+ "id": 45,
4216
+ "name": "小麦肤运动员",
4217
+ "file": "45-athlete-jacket.webp",
4218
+ "framing": "waist-up"
4219
+ },
4220
+ {
4221
+ "id": 46,
4222
+ "name": "青裙盘髻佳人",
4223
+ "file": "46-teal-traditional.webp",
4224
+ "framing": "waist-up"
4225
+ },
4226
+ {
4227
+ "id": 47,
4228
+ "name": "紫披肩女王",
4229
+ "file": "47-violet-queen.webp",
4230
+ "framing": "waist-up"
4231
+ },
4232
+ {
4233
+ "id": 48,
4234
+ "name": "魔法探险者",
4235
+ "file": "48-magic-explorer.webp",
4236
+ "framing": "waist-up"
4237
+ },
4238
+ {
4239
+ "id": 49,
4240
+ "name": "白发红花旗袍",
4241
+ "file": "49-red-floral-qipao.webp",
4242
+ "framing": "waist-up"
4243
+ },
4244
+ {
4245
+ "id": 50,
4246
+ "name": "草莓金夏日裙",
4247
+ "file": "50-summer-dress.webp",
4248
+ "framing": "waist-up"
4249
+ }
4250
+ ];
4251
+
4252
+ // src/plugin/signinCardAssets.ts
4253
+ var portraits = /* @__PURE__ */ new Map();
4254
+ var ICON_CONCURRENCY2 = 8;
4255
+ var ICON_BUDGET_MS2 = 6e3;
4256
+ async function loadSigninPortrait(id) {
4257
+ const entry = SIGNIN_PORTRAITS.find((portrait) => portrait.id === id);
4258
+ if (!entry) throw new Error("签到立绘编号无效");
4259
+ if (!portraits.has(id)) portraits.set(id, (async () => {
4260
+ for (const base2 of ["../assets/signin-portraits", "../../assets/signin-portraits"]) {
4261
+ try {
4262
+ const bytes = await import_promises.default.readFile(import_node_path.default.resolve(__dirname, base2, entry.file));
4263
+ return { src: "data:image/webp;base64," + bytes.toString("base64"), name: entry.name, framing: entry.framing };
4264
+ } catch (error) {
4265
+ if (error.code !== "ENOENT") throw error;
4266
+ }
4267
+ }
4268
+ return void 0;
4269
+ })().then((value) => {
4270
+ if (!value) portraits.delete(id);
4271
+ return value;
4272
+ }, (error) => {
4273
+ portraits.delete(id);
4274
+ throw error;
4275
+ }));
4276
+ return portraits.get(id);
4277
+ }
4278
+ __name(loadSigninPortrait, "loadSigninPortrait");
4279
+ async function loadSigninCardAssets(card) {
4280
+ const portraitPromise = loadSigninPortrait(card.portraitId);
4281
+ const addresses = [...new Set(card.days.map((day) => day.artworkUrl).filter((address) => Boolean(address)))];
4282
+ const loaded = /* @__PURE__ */ new Map();
4283
+ let cursor = 0;
4284
+ let stopped = false;
4285
+ let timer;
4286
+ const work = Promise.all(Array.from({ length: Math.min(ICON_CONCURRENCY2, addresses.length) }, async () => {
4287
+ while (!stopped && cursor < addresses.length) {
4288
+ const address = addresses[cursor++];
4289
+ let image2;
4290
+ try {
4291
+ image2 = await loadSkillArtwork(address);
4292
+ } catch {
4293
+ }
4294
+ if (!stopped && image2) loaded.set(address, image2);
4295
+ }
4296
+ }));
4297
+ let portrait;
4298
+ try {
4299
+ ;
4300
+ [portrait] = await Promise.all([portraitPromise, Promise.race([work, new Promise((resolve2) => {
4301
+ timer = setTimeout(() => {
4302
+ stopped = true;
4303
+ resolve2();
4304
+ }, ICON_BUDGET_MS2);
4305
+ })])]);
4306
+ } finally {
4307
+ if (timer) clearTimeout(timer);
4308
+ stopped = true;
4309
+ }
4310
+ if (!portrait) throw new Error("签到立绘素材缺失");
4311
+ return { portrait, artwork: card.days.map((day) => day.artworkUrl ? loaded.get(day.artworkUrl) : void 0) };
4312
+ }
4313
+ __name(loadSigninCardAssets, "loadSigninCardAssets");
4314
+
3748
4315
  // src/plugin/skillCard.ts
3749
4316
  var running = 0;
3750
4317
  var waiting = [];
@@ -3754,7 +4321,7 @@ async function staticAsset(folder, file) {
3754
4321
  if (!staticAssets.has(key)) staticAssets.set(key, (async () => {
3755
4322
  for (const base2 of [`../assets/${folder}`, `../../assets/${folder}`]) {
3756
4323
  try {
3757
- return "data:image/webp;base64," + (await import_promises.default.readFile(import_node_path.default.resolve(__dirname, base2, file))).toString("base64");
4324
+ return "data:image/webp;base64," + (await import_promises2.default.readFile(import_node_path2.default.resolve(__dirname, base2, file))).toString("base64");
3758
4325
  } catch {
3759
4326
  }
3760
4327
  }
@@ -3772,7 +4339,7 @@ async function leaderboardHeader() {
3772
4339
  for (const base2 of ["../assets/leaderboard", "../../assets/leaderboard"]) {
3773
4340
  for (const [file, mime] of [["header.png", "image/png"], ["header.jpg", "image/jpeg"], ["header.webp", "image/webp"], ["header.svg", "image/svg+xml"]]) {
3774
4341
  try {
3775
- return "data:" + mime + ";base64," + (await import_promises.default.readFile(import_node_path.default.resolve(__dirname, base2, file))).toString("base64");
4342
+ return "data:" + mime + ";base64," + (await import_promises2.default.readFile(import_node_path2.default.resolve(__dirname, base2, file))).toString("base64");
3776
4343
  } catch (error) {
3777
4344
  if (error.code !== "ENOENT") throw error;
3778
4345
  }
@@ -3833,9 +4400,10 @@ function rememberRender(key, image2) {
3833
4400
  }
3834
4401
  }
3835
4402
  __name(rememberRender, "rememberRender");
3836
- async function renderSkillCard(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard) {
4403
+ async function renderSkillCard(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard, signinCard) {
3837
4404
  if (!ctx.puppeteer) throw new Error("Puppeteer 未启用");
3838
- if (JSON.stringify(titleCard ?? bloodlineCard ?? equipmentCard ?? companionCard ?? characterCard ?? itemCard ?? card ?? leaderboard ?? {}).length > 24e3) throw new Error("卡片内容过长");
4405
+ if (JSON.stringify(signinCard ?? titleCard ?? bloodlineCard ?? equipmentCard ?? companionCard ?? characterCard ?? itemCard ?? card ?? leaderboard ?? {}).length > 24e3) throw new Error("卡片内容过长");
4406
+ if (signinCard) return (await renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard, signinCard)).image;
3839
4407
  const key = leaderboard && !titleCard && !bloodlineCard && !equipmentCard && !companionCard ? void 0 : renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard);
3840
4408
  if (!key) return (await renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard)).image;
3841
4409
  const hit = cachedRender(key);
@@ -3853,7 +4421,7 @@ async function renderSkillCard(ctx, card, leaderboard, itemCard, characterCard,
3853
4421
  return work;
3854
4422
  }
3855
4423
  __name(renderSkillCard, "renderSkillCard");
3856
- async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard) {
4424
+ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard, signinCard) {
3857
4425
  if (running >= 2) {
3858
4426
  if (waiting.length >= 16) throw new Error("绘图繁忙");
3859
4427
  await new Promise((resolve2) => waiting.push(resolve2));
@@ -3870,15 +4438,16 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
3870
4438
  }, "release");
3871
4439
  try {
3872
4440
  const work = /* @__PURE__ */ __name(async () => {
3873
- const remoteAddress = titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl;
3874
- const isEquipment = !titleCard && !bloodlineCard && Boolean(equipmentCard);
3875
- const isCharacter = !titleCard && !bloodlineCard && !equipmentCard && !companionCard && Boolean(characterCard);
3876
- const [remoteArt, fallbackArt, entryArtwork, characterAssets, header] = await Promise.all([
4441
+ const remoteAddress = signinCard ? void 0 : titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl;
4442
+ const isEquipment = !signinCard && !titleCard && !bloodlineCard && Boolean(equipmentCard);
4443
+ const isCharacter = !signinCard && !titleCard && !bloodlineCard && !equipmentCard && !companionCard && Boolean(characterCard);
4444
+ const [remoteArt, fallbackArt, entryArtwork, characterAssets, header, signinAssets] = await Promise.all([
3877
4445
  loadSkillArtwork(remoteAddress),
3878
4446
  isEquipment ? equipmentFallback() : void 0,
3879
- loadCardEntryArtwork(!titleCard && !bloodlineCard && !equipmentCard ? companionCard : void 0),
4447
+ loadCardEntryArtwork(!signinCard && !titleCard && !bloodlineCard && !equipmentCard ? companionCard : void 0),
3880
4448
  isCharacter ? Promise.all([characterAsset(), loadSkillArtwork(characterCard.titleImageUrl)]) : void 0,
3881
- !titleCard && !bloodlineCard && !equipmentCard && !companionCard && !characterCard && !itemCard && leaderboard ? leaderboardHeader() : void 0,
4449
+ !signinCard && !titleCard && !bloodlineCard && !equipmentCard && !companionCard && !characterCard && !itemCard && leaderboard ? leaderboardHeader() : void 0,
4450
+ signinCard ? loadSigninCardAssets(signinCard) : void 0,
3882
4451
  ctx.puppeteer.page().then(async (created) => {
3883
4452
  if (expired || finished) {
3884
4453
  await created.close();
@@ -3893,7 +4462,9 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
3893
4462
  let html;
3894
4463
  let loadedCharacterTitle;
3895
4464
  let localAssetsReady = true;
3896
- if (titleCard) {
4465
+ if (signinCard) {
4466
+ html = signinCardHtml(signinCard, signinAssets.artwork, signinAssets.portrait);
4467
+ } else if (titleCard) {
3897
4468
  html = titleCardHtml(titleCard, art);
3898
4469
  } else if (bloodlineCard) {
3899
4470
  html = bloodlineCardHtml(bloodlineCard, art);
@@ -3916,7 +4487,7 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
3916
4487
  }
3917
4488
  if (expired) throw new Error("绘图超时");
3918
4489
  if (!page) throw new Error("卡片页面缺失");
3919
- await page.setViewport({ width: 760, height: 1107, deviceScaleFactor: titleCard || (companionCard || characterCard) && !bloodlineCard && !equipmentCard ? 2 : 1 });
4490
+ await page.setViewport({ width: 760, height: 1107, deviceScaleFactor: signinCard ? 1.5 : titleCard || (companionCard || characterCard) && !bloodlineCard && !equipmentCard ? 2 : 1 });
3920
4491
  await page.setJavaScriptEnabled(false);
3921
4492
  await page.setRequestInterception(true);
3922
4493
  page.on("request", (req) => {
@@ -3925,6 +4496,12 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
3925
4496
  });
3926
4497
  await page.setContent(html, { waitUntil: "load", timeout: 1e4 });
3927
4498
  await page.evaluate(layoutCard);
4499
+ if (signinCard && signinAssets) {
4500
+ const decodedDays = await page.evaluate(() => [...document.querySelectorAll(".signin-item-art")].map((image2) => Number(image2.closest(".signin-day")?.dataset.day)));
4501
+ signinAssets.artwork.forEach((image2, index) => {
4502
+ if (image2 && !decodedDays.includes(signinCard.days[index].day)) discardSkillArtwork(signinCard.days[index].artworkUrl, image2);
4503
+ });
4504
+ }
3928
4505
  let titleDecoded = true;
3929
4506
  if (titleCard && art) {
3930
4507
  titleDecoded = await page.evaluate((expected) => {
@@ -3955,7 +4532,7 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
3955
4532
  if (!target) throw new Error("卡片元素缺失");
3956
4533
  const bounds = await target.boundingBox();
3957
4534
  if (!bounds || bounds.height > 1e4) throw new Error("卡片内容过长");
3958
- return { image: Buffer.from(await target.screenshot({ type: "jpeg", quality: 90 })), cacheable: localAssetsReady && titleDecoded && entryArtwork.complete && decodedIcons === expectedIcons && (!remoteAddress || Boolean(!titleCard && !bloodlineCard && equipmentCard ? dedicatedArt : art)) };
4535
+ return { image: Buffer.from(await target.screenshot({ type: "jpeg", quality: signinCard ? 82 : 90 })), cacheable: !signinCard && localAssetsReady && titleDecoded && entryArtwork.complete && decodedIcons === expectedIcons && (!remoteAddress || Boolean(!titleCard && !bloodlineCard && equipmentCard ? dedicatedArt : art)) };
3959
4536
  }, "work");
3960
4537
  workPromise = work();
3961
4538
  return await Promise.race([workPromise, new Promise((_, reject) => {
@@ -4008,8 +4585,8 @@ var handel_base = class {
4008
4585
  this.ctx.logger.info("session not found", data.userId, data.channelId);
4009
4586
  return;
4010
4587
  }
4011
- let finalContent = data.notification ? content.trimEnd() : content;
4012
- if (messageType === "text" && !data.notification && session.event?.platform === "qq" && session.event?.channel?.type === 0) {
4588
+ let finalContent = data.notification || data.plainText ? content.trimEnd() : content;
4589
+ if (messageType === "text" && !data.notification && !data.plainText && session.event?.platform === "qq" && session.event?.channel?.type === 0) {
4013
4590
  finalContent = "Ciallo~(∠・ω< )\n" + content;
4014
4591
  }
4015
4592
  const sendStartedAt = this.timing ? performance.now() : 0;
@@ -4841,6 +5418,7 @@ __name(renderQQStoryMarkdown, "renderQQStoryMarkdown");
4841
5418
 
4842
5419
  // src/plugin/serverHandel/qqMessagePreview.ts
4843
5420
  function renderQQMessagePreview(data, showGreeting = false) {
5421
+ if (data.plainText) return { kind: "text", text: data.line.map((item) => item.content).join("\n").trimEnd() };
4844
5422
  const plain = new AnalysisMsg().parse(data);
4845
5423
  const text = data.notification ? plain.trimEnd() : plain;
4846
5424
  let keyboard;
@@ -4954,8 +5532,8 @@ var ImageHandler = class extends handel_base {
4954
5532
  let rendered = false;
4955
5533
  const renderStartedAt = this.timing ? performance.now() : 0;
4956
5534
  try {
4957
- if (!data.titleCard && !data.companionCard && !data.characterCard && !data.itemCard && !data.card && !data.leaderboard && !data.equipmentCard && !data.bloodlineCard) throw new Error("缺少卡片数据");
4958
- const image2 = await renderSkillCard(this.ctx, data.card, data.leaderboard, data.itemCard, data.characterCard, data.equipmentCard, data.bloodlineCard, data.companionCard, data.titleCard);
5535
+ if (!data.signinCard && !data.titleCard && !data.companionCard && !data.characterCard && !data.itemCard && !data.card && !data.leaderboard && !data.equipmentCard && !data.bloodlineCard) throw new Error("缺少卡片数据");
5536
+ const image2 = await renderSkillCard(this.ctx, data.card, data.leaderboard, data.itemCard, data.characterCard, data.equipmentCard, data.bloodlineCard, data.companionCard, data.titleCard, data.signinCard);
4959
5537
  if (this.timing) this.timing.imageBytes = image2.length;
4960
5538
  content = import_koishi.h.image(image2, "image/jpeg").toString();
4961
5539
  rendered = true;
@@ -5072,7 +5650,7 @@ function apply(ctx, config) {
5072
5650
  __name(apply, "apply");
5073
5651
 
5074
5652
  // src/index.ts
5075
- var import_node_path2 = require("node:path");
5653
+ var import_node_path3 = require("node:path");
5076
5654
  var inject = { optional: ["puppeteer", "console"] };
5077
5655
  var name = "dew-bot";
5078
5656
  var filter = false;
@@ -5084,8 +5662,8 @@ function apply2(ctx, config) {
5084
5662
  ctx.inject(["console"], async (consoleCtx) => {
5085
5663
  const { default: StatisticsProvider2 } = await Promise.resolve().then(() => (init_statistics(), statistics_exports));
5086
5664
  consoleCtx.plugin(StatisticsProvider2, {
5087
- dev: (0, import_node_path2.resolve)(__dirname, "../client/index.ts"),
5088
- prod: (0, import_node_path2.resolve)(__dirname, "../dist")
5665
+ dev: (0, import_node_path3.resolve)(__dirname, "../client/index.ts"),
5666
+ prod: (0, import_node_path3.resolve)(__dirname, "../dist")
5089
5667
  });
5090
5668
  });
5091
5669
  }