koishi-plugin-nitter 0.0.5 → 0.0.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.d.ts +1 -0
- package/lib/index.js +42 -30
- package/package.json +1 -2
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
Config: () => Config,
|
|
34
34
|
apply: () => apply,
|
|
35
|
+
downloadVideosToBase64: () => downloadVideosToBase64,
|
|
35
36
|
inject: () => inject,
|
|
36
37
|
name: () => name
|
|
37
38
|
});
|
|
@@ -154,13 +155,11 @@ __name(addTranslate, "addTranslate");
|
|
|
154
155
|
var import_rettiwt_api = require("rettiwt-api");
|
|
155
156
|
var import_node_cron = require("node-cron");
|
|
156
157
|
var import_fluent_ffmpeg = __toESM(require("fluent-ffmpeg"));
|
|
157
|
-
var import_ffmpeg_static = __toESM(require("ffmpeg-static"));
|
|
158
158
|
var import_path = __toESM(require("path"));
|
|
159
159
|
var import_promises = __toESM(require("fs/promises"));
|
|
160
|
-
var import_url = require("url");
|
|
161
160
|
var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
|
|
162
|
-
import_fluent_ffmpeg.default.setFfmpegPath(import_ffmpeg_static.default);
|
|
163
161
|
var name = "nitter";
|
|
162
|
+
var logger = new import_koishi.Logger(name);
|
|
164
163
|
var inject = ["puppeteer", "subscription"];
|
|
165
164
|
var Config = import_koishi.Schema.intersect([
|
|
166
165
|
import_koishi.Schema.object({
|
|
@@ -248,15 +247,14 @@ function apply(ctx, config) {
|
|
|
248
247
|
const [screenshot, imageUrls, hlsUrls] = await renderTweetScreenshot(ctx, tweetId, config);
|
|
249
248
|
let msg = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: "data:image/png;base64," + screenshot.toString("base64") });
|
|
250
249
|
let forwardMsg = [];
|
|
251
|
-
const videoUrls = await
|
|
250
|
+
const videoUrls = await downloadVideosToBase64(hlsUrls);
|
|
252
251
|
if (imageUrls.length > 0) {
|
|
253
252
|
forwardMsg.push(...imageUrls.map((url) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: url }) })));
|
|
254
253
|
}
|
|
255
254
|
if (videoUrls.length > 0) {
|
|
256
|
-
forwardMsg.push(...videoUrls.map((url) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("video", { src:
|
|
255
|
+
forwardMsg.push(...videoUrls.map((url) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("video", { src: url }) })));
|
|
257
256
|
}
|
|
258
257
|
await session.send(msg + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { forward: true, children: forwardMsg }));
|
|
259
|
-
await deleteFiles(videoUrls);
|
|
260
258
|
} catch (error) {
|
|
261
259
|
ctx.logger("nitter").error("获取推文失败:", error);
|
|
262
260
|
return "获取推文失败";
|
|
@@ -273,18 +271,17 @@ function apply(ctx, config) {
|
|
|
273
271
|
const [screenshot, imageUrls, hlsUrls] = await renderTweetScreenshot(ctx, tweetId, config);
|
|
274
272
|
const screenshotMsg = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: "data:image/png;base64," + screenshot.toString("base64") });
|
|
275
273
|
ctx.subscription.broadcast(config.app, account, screenshotMsg);
|
|
276
|
-
let forwardMsg =
|
|
277
|
-
const videoUrls = await
|
|
274
|
+
let forwardMsg = [];
|
|
275
|
+
const videoUrls = await downloadVideosToBase64(hlsUrls);
|
|
278
276
|
if (imageUrls.length > 0) {
|
|
279
|
-
forwardMsg
|
|
277
|
+
forwardMsg.push(...imageUrls.map((url) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: url }) })));
|
|
280
278
|
}
|
|
281
279
|
if (videoUrls.length > 0) {
|
|
282
|
-
forwardMsg
|
|
280
|
+
forwardMsg.push(...videoUrls.map((url) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("video", { src: url }) })));
|
|
283
281
|
}
|
|
284
282
|
if (forwardMsg.length > 0) {
|
|
285
283
|
await ctx.subscription.broadcastForward(config.app, account, forwardMsg);
|
|
286
284
|
}
|
|
287
|
-
await deleteFiles(videoUrls);
|
|
288
285
|
} catch (error) {
|
|
289
286
|
ctx.logger("nitter").error("获取推文失败:", error);
|
|
290
287
|
}
|
|
@@ -316,33 +313,47 @@ function apply(ctx, config) {
|
|
|
316
313
|
}
|
|
317
314
|
__name(apply, "apply");
|
|
318
315
|
var tempDir = import_path.default.join(process.cwd(), "tmp");
|
|
319
|
-
async function
|
|
316
|
+
async function downloadVideosToBase64(videoUrls) {
|
|
320
317
|
await import_promises.default.mkdir(tempDir, { recursive: true });
|
|
321
|
-
const
|
|
318
|
+
const results = [];
|
|
319
|
+
for (const url of videoUrls) {
|
|
320
|
+
let outputPath = null;
|
|
322
321
|
try {
|
|
323
|
-
|
|
322
|
+
outputPath = import_path.default.join(tempDir, `video_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.mp4`);
|
|
324
323
|
await new Promise((resolve, reject) => {
|
|
325
|
-
(0, import_fluent_ffmpeg.default)(url).
|
|
326
|
-
|
|
327
|
-
|
|
324
|
+
(0, import_fluent_ffmpeg.default)(url).inputOptions([
|
|
325
|
+
"-protocol_whitelist",
|
|
326
|
+
"file,http,https,tcp,tls,crypto"
|
|
327
|
+
]).outputOptions([
|
|
328
|
+
"-c",
|
|
329
|
+
"copy"
|
|
330
|
+
]).output(outputPath).on("end", () => resolve(outputPath)).on("error", reject).run();
|
|
328
331
|
});
|
|
329
|
-
|
|
332
|
+
const stats = await import_promises.default.stat(outputPath);
|
|
333
|
+
const fileSizeInMB = stats.size / (1024 * 1024);
|
|
334
|
+
if (fileSizeInMB > 10) {
|
|
335
|
+
logger.info(`视频大小 ${fileSizeInMB.toFixed(2)}MB 超过10MB限制,跳过转换`);
|
|
336
|
+
} else {
|
|
337
|
+
const fileBuffer = await import_promises.default.readFile(outputPath);
|
|
338
|
+
const base64String = fileBuffer.toString("base64");
|
|
339
|
+
const dataUrl = `data:video/mp4;base64,${base64String}`;
|
|
340
|
+
results.push(dataUrl);
|
|
341
|
+
}
|
|
330
342
|
} catch (error) {
|
|
331
343
|
console.error(`处理失败 (${url}):`, error.message);
|
|
332
|
-
|
|
344
|
+
results.push(null);
|
|
345
|
+
} finally {
|
|
346
|
+
if (outputPath) {
|
|
347
|
+
try {
|
|
348
|
+
await import_promises.default.unlink(outputPath);
|
|
349
|
+
} catch (deleteError) {
|
|
350
|
+
}
|
|
351
|
+
}
|
|
333
352
|
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return results.filter((path2) => path2 !== null);
|
|
337
|
-
}
|
|
338
|
-
__name(downloadAndConvertVideos, "downloadAndConvertVideos");
|
|
339
|
-
async function deleteFiles(filePaths) {
|
|
340
|
-
await Promise.allSettled(
|
|
341
|
-
filePaths.map((filePath) => import_promises.default.unlink(filePath).catch(() => {
|
|
342
|
-
}))
|
|
343
|
-
);
|
|
353
|
+
}
|
|
354
|
+
return results;
|
|
344
355
|
}
|
|
345
|
-
__name(
|
|
356
|
+
__name(downloadVideosToBase64, "downloadVideosToBase64");
|
|
346
357
|
async function renderTweetScreenshot(ctx, tweetId, config) {
|
|
347
358
|
const puppeteer = ctx.puppeteer;
|
|
348
359
|
if (!puppeteer) {
|
|
@@ -399,6 +410,7 @@ __name(renderTweetScreenshot, "renderTweetScreenshot");
|
|
|
399
410
|
0 && (module.exports = {
|
|
400
411
|
Config,
|
|
401
412
|
apply,
|
|
413
|
+
downloadVideosToBase64,
|
|
402
414
|
inject,
|
|
403
415
|
name
|
|
404
416
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-nitter",
|
|
3
3
|
"description": "使用Rettiwt-API订阅推文,并使用nitter渲染",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"node-cron": "^4.2.1",
|
|
26
26
|
"rettiwt-api": "^6.0.6",
|
|
27
|
-
"ffmpeg-static": "^5.2.0",
|
|
28
27
|
"fluent-ffmpeg": "^2.1.3"
|
|
29
28
|
}
|
|
30
29
|
}
|