koishi-plugin-bili-link-previewer 1.0.0
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 +7 -0
- package/lib/index.js +398 -0
- package/lib/model.d.ts +26 -0
- package/lib/template.d.ts +1 -0
- package/package.json +45 -0
- package/readme.md +5 -0
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name2 in all)
|
|
8
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.tsx
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
Config: () => Config,
|
|
24
|
+
apply: () => apply,
|
|
25
|
+
inject: () => inject,
|
|
26
|
+
name: () => name
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(src_exports);
|
|
29
|
+
var import_koishi = require("koishi");
|
|
30
|
+
var import_eta = require("eta");
|
|
31
|
+
|
|
32
|
+
// src/template.ts
|
|
33
|
+
var cardTemplate = String.raw`
|
|
34
|
+
<!DOCTYPE html>
|
|
35
|
+
<html lang="zh-CN">
|
|
36
|
+
<head>
|
|
37
|
+
<meta charset="UTF-8">
|
|
38
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
39
|
+
<title>Bilibili Card Vertical</title>
|
|
40
|
+
<style>
|
|
41
|
+
@import url('https://fonts.font.im/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap');
|
|
42
|
+
|
|
43
|
+
* {
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
margin: 0;
|
|
46
|
+
padding: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
body {
|
|
50
|
+
margin: 0;
|
|
51
|
+
padding: 0;
|
|
52
|
+
/* Background for body to avoid white edges if screenshot is slightly off, though we target #card */
|
|
53
|
+
background: transparent;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#card {
|
|
57
|
+
position: relative;
|
|
58
|
+
width: 600px;
|
|
59
|
+
/* min-height removed as requested */
|
|
60
|
+
height: fit-content; /* Allow growth */
|
|
61
|
+
background: #121212;
|
|
62
|
+
color: #fff;
|
|
63
|
+
overflow: hidden; /* Clip the absolute background */
|
|
64
|
+
font-family: 'Noto Sans SC', 'Microsoft YaHei', sans-serif;
|
|
65
|
+
/* No borderRadius if we want a clean rectangular export, or add if desired. Usually rectangular for social sharing is safe */
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Inner padding container */
|
|
69
|
+
.content-padding {
|
|
70
|
+
position: relative;
|
|
71
|
+
width: 100%;
|
|
72
|
+
height: 100%;
|
|
73
|
+
padding: 40px;
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: 24px;
|
|
77
|
+
z-index: 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Dynamic Background */
|
|
81
|
+
.bg-blur {
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: -10%;
|
|
84
|
+
left: -10%;
|
|
85
|
+
width: 120%;
|
|
86
|
+
height: 120%;
|
|
87
|
+
background-image: url('<%= it.coverUrl %>');
|
|
88
|
+
background-size: cover;
|
|
89
|
+
background-position: center;
|
|
90
|
+
filter: blur(50px) brightness(0.3);
|
|
91
|
+
z-index: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* 1. Title */
|
|
95
|
+
.title {
|
|
96
|
+
font-size: 32px;
|
|
97
|
+
font-weight: 700;
|
|
98
|
+
line-height: 1.4;
|
|
99
|
+
color: #ffffff;
|
|
100
|
+
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* 2. Meta: Author + Date */
|
|
104
|
+
.meta-row {
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 16px;
|
|
108
|
+
font-size: 18px;
|
|
109
|
+
color: rgba(255, 255, 255, 0.9);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.author {
|
|
113
|
+
font-weight: 500;
|
|
114
|
+
color: #fb7299;
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
gap: 6px;
|
|
118
|
+
background: rgba(255, 255, 255, 0.1);
|
|
119
|
+
padding: 6px 12px;
|
|
120
|
+
border-radius: 6px;
|
|
121
|
+
backdrop-filter: blur(4px);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.pubdate {
|
|
125
|
+
color: rgba(255, 255, 255, 0.6);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* 3. Cover Image */
|
|
129
|
+
.cover-wrapper {
|
|
130
|
+
width: 100%;
|
|
131
|
+
aspect-ratio: 16/10;
|
|
132
|
+
position: relative;
|
|
133
|
+
border-radius: 12px;
|
|
134
|
+
overflow: hidden;
|
|
135
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
136
|
+
background: #333;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.cover-image {
|
|
140
|
+
width: 100%;
|
|
141
|
+
height: 100%;
|
|
142
|
+
object-fit: cover;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.duration-badge {
|
|
146
|
+
position: absolute;
|
|
147
|
+
bottom: 12px;
|
|
148
|
+
right: 12px;
|
|
149
|
+
background: rgba(0, 0, 0, 0.8);
|
|
150
|
+
color: #fff;
|
|
151
|
+
font-size: 16px;
|
|
152
|
+
font-weight: 500;
|
|
153
|
+
padding: 4px 8px;
|
|
154
|
+
border-radius: 4px;
|
|
155
|
+
backdrop-filter: blur(2px);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* 4. Stats Grid */
|
|
159
|
+
.stats-grid {
|
|
160
|
+
display: grid;
|
|
161
|
+
grid-template-columns: repeat(4, 1fr);
|
|
162
|
+
gap: 12px;
|
|
163
|
+
background: rgba(0, 0, 0, 0.2);
|
|
164
|
+
padding: 16px;
|
|
165
|
+
border-radius: 12px;
|
|
166
|
+
backdrop-filter: blur(8px);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.stat-item {
|
|
170
|
+
display: flex;
|
|
171
|
+
flex-direction: column;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 8px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.stat-icon {
|
|
177
|
+
width: 40px;
|
|
178
|
+
height: 40px;
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: center;
|
|
182
|
+
background: rgba(255, 255, 255, 0.1);
|
|
183
|
+
border-radius: 50%;
|
|
184
|
+
padding: 4px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.icon {
|
|
188
|
+
width: 100%;
|
|
189
|
+
height: 100%;
|
|
190
|
+
fill: #fb7299;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.stat-value {
|
|
194
|
+
font-size: 20px;
|
|
195
|
+
font-weight: 600;
|
|
196
|
+
color: #eee;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* 5. Description */
|
|
200
|
+
.description {
|
|
201
|
+
font-size: 20px;
|
|
202
|
+
line-height: 1.6;
|
|
203
|
+
color: rgba(255, 255, 255, 0.8);
|
|
204
|
+
padding: 16px;
|
|
205
|
+
background: rgba(255, 255, 255, 0.05);
|
|
206
|
+
border-radius: 8px;
|
|
207
|
+
/* Remove truncation for adaptive height */
|
|
208
|
+
white-space: pre-wrap; /* Preserve formatting but wrap */
|
|
209
|
+
overflow-wrap: break-word;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
</style>
|
|
213
|
+
</head>
|
|
214
|
+
<body>
|
|
215
|
+
|
|
216
|
+
<div id="card">
|
|
217
|
+
<!-- Blurred Background -->
|
|
218
|
+
<div class="bg-blur"></div>
|
|
219
|
+
|
|
220
|
+
<!-- Main Content -->
|
|
221
|
+
<div class="content-padding">
|
|
222
|
+
|
|
223
|
+
<!-- 1. Title -->
|
|
224
|
+
<div class="title"><%= it.title %></div>
|
|
225
|
+
|
|
226
|
+
<!-- 2. Meta -->
|
|
227
|
+
<div class="meta-row">
|
|
228
|
+
<div class="author">
|
|
229
|
+
<svg class="icon" viewBox="0 0 24 24" style="width: 17px; height: 17px; fill: currentColor;">
|
|
230
|
+
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
|
|
231
|
+
</svg>
|
|
232
|
+
<span><%= it.author %></span>
|
|
233
|
+
</div>
|
|
234
|
+
<div class="pubdate"><%= it.pubDate %></div>
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<!-- 3. Cover -->
|
|
238
|
+
<div class="cover-wrapper">
|
|
239
|
+
<img src="<%= it.coverUrl %>" class="cover-image" alt="Cover">
|
|
240
|
+
<div class="duration-badge"><%= it.duration %></div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<!-- 4. Stats -->
|
|
244
|
+
<div class="stats-grid">
|
|
245
|
+
<!-- Views -->
|
|
246
|
+
<div class="stat-item">
|
|
247
|
+
<div class="stat-icon">
|
|
248
|
+
<svg class="icon" viewBox="0 0 24 24">
|
|
249
|
+
<path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
|
|
250
|
+
</svg>
|
|
251
|
+
</div>
|
|
252
|
+
<div class="stat-value"><%= it.views %></div>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<!-- Danmaku -->
|
|
256
|
+
<div class="stat-item">
|
|
257
|
+
<div class="stat-icon">
|
|
258
|
+
<svg class="icon" viewBox="0 0 24 24">
|
|
259
|
+
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-3 9h-2v2h2v-2zm4-4H3V5h18v2z"/>
|
|
260
|
+
</svg>
|
|
261
|
+
</div>
|
|
262
|
+
<div class="stat-value"><%= it.danmaku %></div>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<!-- Likes -->
|
|
266
|
+
<div class="stat-item">
|
|
267
|
+
<div class="stat-icon">
|
|
268
|
+
<svg class="icon" viewBox="0 0 24 24">
|
|
269
|
+
<path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z"/>
|
|
270
|
+
</svg>
|
|
271
|
+
</div>
|
|
272
|
+
<div class="stat-value"><%= it.likes %></div>
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
<!-- Favorites -->
|
|
276
|
+
<div class="stat-item">
|
|
277
|
+
<div class="stat-icon">
|
|
278
|
+
<svg class="icon" viewBox="0 0 24 24">
|
|
279
|
+
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
|
|
280
|
+
</svg>
|
|
281
|
+
</div>
|
|
282
|
+
<div class="stat-value"><%= it.favorites %></div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<!-- 5. Description -->
|
|
287
|
+
<% if (it.desc) { %>
|
|
288
|
+
<div class="description"><%= it.desc %></div>
|
|
289
|
+
<% } %>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
</body>
|
|
294
|
+
</html>
|
|
295
|
+
`;
|
|
296
|
+
|
|
297
|
+
// src/index.tsx
|
|
298
|
+
var name = "bili-link-previewer";
|
|
299
|
+
var inject = ["puppeteer"];
|
|
300
|
+
var Config = import_koishi.Schema.object({});
|
|
301
|
+
var bvNumberRegex = /[Bb][Vv][0-9a-zA-Z]{10}/;
|
|
302
|
+
var ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
303
|
+
var eta = new import_eta.Eta();
|
|
304
|
+
async function fetchInfo(ctx, bvNumber) {
|
|
305
|
+
const url = `https://api.bilibili.com/x/web-interface/view?bvid=${bvNumber}`;
|
|
306
|
+
return await ctx.http.get(url, {
|
|
307
|
+
headers: {
|
|
308
|
+
Host: "api.bilibili.com",
|
|
309
|
+
"User-Agent": ua
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
__name(fetchInfo, "fetchInfo");
|
|
314
|
+
function formatDuration(seconds) {
|
|
315
|
+
const hours = Math.floor(seconds / 3600);
|
|
316
|
+
const hourStr = hours > 9 ? `${hours}:` : hours > 0 ? `0${hours}:` : "";
|
|
317
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
318
|
+
const minutesStr = minutes > 9 ? `${minutes}:` : `0${minutes}:`;
|
|
319
|
+
const remainingSeconds = seconds % 60;
|
|
320
|
+
const secondsStr = remainingSeconds > 9 ? `${remainingSeconds}` : `0${remainingSeconds}`;
|
|
321
|
+
return `${hourStr}${minutesStr}${secondsStr}`;
|
|
322
|
+
}
|
|
323
|
+
__name(formatDuration, "formatDuration");
|
|
324
|
+
function formatTimestamp(timestamp) {
|
|
325
|
+
const datetime = new Date(timestamp * 1e3);
|
|
326
|
+
const year = datetime.getFullYear();
|
|
327
|
+
const month = datetime.getMonth() + 1;
|
|
328
|
+
const day = datetime.getDate();
|
|
329
|
+
const hour = datetime.getHours();
|
|
330
|
+
const hourStr = hour > 9 ? `${hour}` : `0${hour}`;
|
|
331
|
+
const minute = datetime.getMinutes();
|
|
332
|
+
const minuteStr = minute > 9 ? `${minute}` : `0${minute}`;
|
|
333
|
+
const second = datetime.getSeconds();
|
|
334
|
+
const secondStr = second > 9 ? `${second}` : `0${second}`;
|
|
335
|
+
return `${year}-${month}-${day} ${hourStr}:${minuteStr}:${secondStr}`;
|
|
336
|
+
}
|
|
337
|
+
__name(formatTimestamp, "formatTimestamp");
|
|
338
|
+
function formatStatNumber(num) {
|
|
339
|
+
if (num >= 1e4) {
|
|
340
|
+
const tenK = Math.floor(num / 1e4);
|
|
341
|
+
const k = Math.floor(num % 1e4 / 1e3);
|
|
342
|
+
return `${tenK}.${k} 万`;
|
|
343
|
+
}
|
|
344
|
+
return num;
|
|
345
|
+
}
|
|
346
|
+
__name(formatStatNumber, "formatStatNumber");
|
|
347
|
+
function apply(ctx) {
|
|
348
|
+
ctx.middleware(async (session, next) => {
|
|
349
|
+
const bv = bvNumberRegex.exec(session.stripped.content);
|
|
350
|
+
if (!bv) return next();
|
|
351
|
+
const bvNumber = bv[0];
|
|
352
|
+
const resp = await fetchInfo(ctx, bvNumber);
|
|
353
|
+
if (resp.code !== 0 || !resp.data) {
|
|
354
|
+
return `${bvNumber} 视频信息获取异常:${resp.message} (${resp.code})`;
|
|
355
|
+
}
|
|
356
|
+
const respData = resp.data;
|
|
357
|
+
const cardHtml = eta.renderString(cardTemplate, {
|
|
358
|
+
title: respData.title,
|
|
359
|
+
// 标题
|
|
360
|
+
coverUrl: respData.pic,
|
|
361
|
+
// 封面
|
|
362
|
+
duration: formatDuration(respData.duration),
|
|
363
|
+
// 时长
|
|
364
|
+
author: respData.owner?.name || "未知",
|
|
365
|
+
// 作者
|
|
366
|
+
pubDate: formatTimestamp(respData.pubdate),
|
|
367
|
+
// 发布时间
|
|
368
|
+
views: formatStatNumber(respData.stat?.view || 0),
|
|
369
|
+
// 播放量
|
|
370
|
+
danmaku: formatStatNumber(respData.stat?.danmaku || 0),
|
|
371
|
+
// 弹幕
|
|
372
|
+
likes: formatStatNumber(respData.stat?.like || 0),
|
|
373
|
+
// 点赞
|
|
374
|
+
favorites: formatStatNumber(respData.stat?.favorite || 0),
|
|
375
|
+
// 收藏
|
|
376
|
+
desc: respData.desc || "",
|
|
377
|
+
// 简介
|
|
378
|
+
w: 600,
|
|
379
|
+
h: 850
|
|
380
|
+
});
|
|
381
|
+
return await ctx.puppeteer.render(
|
|
382
|
+
cardHtml,
|
|
383
|
+
async (page, next2) => {
|
|
384
|
+
await page.setViewport({ width: 600, height: 850 });
|
|
385
|
+
const card = await page.$("#card");
|
|
386
|
+
return next2(card);
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
__name(apply, "apply");
|
|
392
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
393
|
+
0 && (module.exports = {
|
|
394
|
+
Config,
|
|
395
|
+
apply,
|
|
396
|
+
inject,
|
|
397
|
+
name
|
|
398
|
+
});
|
package/lib/model.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface BiliResp<T> {
|
|
2
|
+
code: number;
|
|
3
|
+
message?: string;
|
|
4
|
+
ttl?: number;
|
|
5
|
+
data?: T;
|
|
6
|
+
}
|
|
7
|
+
export interface VideoInfo {
|
|
8
|
+
title: string;
|
|
9
|
+
pic: string;
|
|
10
|
+
duration: number;
|
|
11
|
+
owner: Owner;
|
|
12
|
+
pubdate: number;
|
|
13
|
+
stat: Stat;
|
|
14
|
+
desc: string;
|
|
15
|
+
}
|
|
16
|
+
interface Owner {
|
|
17
|
+
name: string;
|
|
18
|
+
face: string;
|
|
19
|
+
}
|
|
20
|
+
interface Stat {
|
|
21
|
+
view: number;
|
|
22
|
+
danmaku: number;
|
|
23
|
+
like: number;
|
|
24
|
+
favorite: number;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cardTemplate: string;
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-bili-link-previewer",
|
|
3
|
+
"description": "B 站视频信息预览插件:渲染预览图,不用点开也能知道视频内容。 / A Bilibili video preview plugin that renders an image so you can see what the video is about without clicking in.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"chatbot",
|
|
14
|
+
"koishi",
|
|
15
|
+
"plugin",
|
|
16
|
+
"bilibili"
|
|
17
|
+
],
|
|
18
|
+
"author": "etnatker",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/etnatker/koishi-plugin-bili-link-previewer.git"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/etnatker/koishi-plugin-bili-link-previewer",
|
|
24
|
+
"koishi": {
|
|
25
|
+
"description": {
|
|
26
|
+
"en": "Bilibili video preview plugin that renders an image so you can see what the video is about without clicking in.",
|
|
27
|
+
"zh": "B 站视频信息预览插件:渲染预览图,不用点开也能知道视频内容。"
|
|
28
|
+
},
|
|
29
|
+
"service": {
|
|
30
|
+
"required": [
|
|
31
|
+
"puppeteer"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@koishijs/client": "^5.30.4",
|
|
37
|
+
"koishi-plugin-puppeteer": "^3.9.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"koishi": "^4.18.7"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"eta": "^4.5.0"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# koishi-plugin-bili-link-previewer
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/koishi-plugin-bili-link-previewer)
|
|
4
|
+
|
|
5
|
+
B 站视频信息预览插件:渲染预览图,不用点开也能知道视频内容。 / A Bilibili video preview plugin that renders an image so you can see what the video is about without clicking in.
|