mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
feat: send video not need ffmpeg
This commit is contained in:
parent
8afe0af940
commit
a298377717
@ -6,7 +6,7 @@ import path from "node:path";
|
||||
import {selfInfo} from "./data";
|
||||
import {DATA_DIR} from "./utils";
|
||||
|
||||
export const HOOK_LOG = false;
|
||||
export const HOOK_LOG = true;
|
||||
|
||||
export const ALLOW_SEND_TEMP_MSG = false;
|
||||
|
||||
|
@ -11,7 +11,7 @@ import {getConfigUtil} from "../config";
|
||||
import {dbUtil} from "../db";
|
||||
import * as fileType from "file-type";
|
||||
import {net} from "electron";
|
||||
import ClientRequestConstructorOptions = Electron.Main.ClientRequestConstructorOptions;
|
||||
|
||||
|
||||
export function isGIF(path: string) {
|
||||
const buffer = Buffer.alloc(4);
|
||||
@ -191,68 +191,7 @@ export async function encodeSilk(filePath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getVideoInfo(filePath: string) {
|
||||
const size = fs.statSync(filePath).size;
|
||||
return new Promise<{
|
||||
width: number,
|
||||
height: number,
|
||||
time: number,
|
||||
format: string,
|
||||
size: number,
|
||||
filePath: string
|
||||
}>((resolve, reject) => {
|
||||
ffmpeg(filePath).ffprobe((err, metadata) => {
|
||||
if (err) {
|
||||
resolve({
|
||||
width: 720, height: 1080,
|
||||
time: 15,
|
||||
format: "mp4",
|
||||
size: fs.statSync(filePath).size,
|
||||
filePath
|
||||
})
|
||||
// reject(err);
|
||||
} else {
|
||||
const videoStream = metadata.streams.find(s => s.codec_type === 'video');
|
||||
if (videoStream) {
|
||||
console.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
|
||||
} else {
|
||||
console.log('未找到视频流信息。');
|
||||
}
|
||||
resolve({
|
||||
width: videoStream.width, height: videoStream.height,
|
||||
time: parseInt(videoStream.duration),
|
||||
format: metadata.format.format_name,
|
||||
size,
|
||||
filePath
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
export async function encodeMp4(filePath: string) {
|
||||
let videoInfo = await getVideoInfo(filePath);
|
||||
log("视频信息", videoInfo)
|
||||
if (videoInfo.format.indexOf("mp4") === -1) {
|
||||
log("视频需要转换为MP4格式", filePath)
|
||||
// 转成mp4
|
||||
const newPath: string = await new Promise<string>((resolve, reject) => {
|
||||
const newPath = filePath + ".mp4"
|
||||
ffmpeg(filePath)
|
||||
.toFormat('mp4')
|
||||
.on('error', (err) => {
|
||||
reject(`转换视频格式失败: ${err.message}`);
|
||||
})
|
||||
.on('end', () => {
|
||||
log('视频转换为MP4格式完成');
|
||||
resolve(newPath); // 返回转换后的文件路径
|
||||
})
|
||||
.save(newPath);
|
||||
});
|
||||
return await getVideoInfo(newPath)
|
||||
}
|
||||
return videoInfo
|
||||
}
|
||||
|
||||
export function calculateFileMD5(filePath: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -12,4 +12,5 @@ export const TEMP_DIR = path.join(DATA_DIR, "temp");
|
||||
export const PLUGIN_DIR = global.LiteLoader.plugins["LLOneBot"].path.plugin;
|
||||
if (!fs.existsSync(TEMP_DIR)) {
|
||||
fs.mkdirSync(TEMP_DIR);
|
||||
}
|
||||
}
|
||||
export {getVideoInfo} from "./video";
|
File diff suppressed because one or more lines are too long
@ -94,7 +94,7 @@ function onLoad() {
|
||||
}
|
||||
ipcMain.handle(CHANNEL_ERROR, async (event, arg) => {
|
||||
const ffmpegOk = await checkFfmpeg(getConfigUtil().getConfig().ffmpeg)
|
||||
llonebotError.ffmpegError = ffmpegOk ? "" : "没有找到ffmpeg,音频只能发送wav和silk,视频无法发送"
|
||||
llonebotError.ffmpegError = ffmpegOk ? "" : "没有找到ffmpeg,音频只能发送wav和silk,视频尺寸可能异常"
|
||||
let {httpServerError, wsServerError, otherError, ffmpegError} = llonebotError;
|
||||
let error = `${otherError}\n${httpServerError}\n${wsServerError}\n${ffmpegError}`
|
||||
error = error.replace("\n\n", "\n")
|
||||
|
@ -14,10 +14,9 @@ import {
|
||||
import {promises as fs} from "node:fs";
|
||||
import ffmpeg from "fluent-ffmpeg"
|
||||
import {NTQQFileApi} from "./api/file";
|
||||
import {calculateFileMD5, encodeSilk, getVideoInfo, isGIF} from "../common/utils/file";
|
||||
import {calculateFileMD5, encodeSilk, isGIF} from "../common/utils/file";
|
||||
import {log} from "../common/utils/log";
|
||||
import {sleep} from "../common/utils/helper";
|
||||
import pathLib from "path";
|
||||
import {defaultVideoThumb, getVideoInfo} from "../common/utils/video";
|
||||
|
||||
|
||||
export class SendMsgElementConstructor {
|
||||
@ -109,36 +108,45 @@ export class SendMsgElementConstructor {
|
||||
return element;
|
||||
}
|
||||
|
||||
static async video(filePath: string, fileName: string = "", diyThumbPath: string=""): Promise<SendVideoElement> {
|
||||
static async video(filePath: string, fileName: string = "", diyThumbPath: string = ""): Promise<SendVideoElement> {
|
||||
let {fileName: _fileName, path, fileSize, md5} = await NTQQFileApi.uploadFile(filePath, ElementType.VIDEO);
|
||||
if (fileSize === 0) {
|
||||
throw "文件异常,大小为0";
|
||||
}
|
||||
// const videoInfo = await encodeMp4(path);
|
||||
// path = videoInfo.filePath
|
||||
// md5 = videoInfo.md5;
|
||||
// fileSize = videoInfo.size;
|
||||
// log("上传视频", md5, path, fileSize, fileName || _fileName)
|
||||
const pathLib = require("path");
|
||||
let thumb = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`)
|
||||
thumb = pathLib.dirname(thumb)
|
||||
// log("thumb 目录", thumb)
|
||||
const videoInfo = await getVideoInfo(path);
|
||||
log("视频信息", videoInfo)
|
||||
let videoInfo ={
|
||||
width: 1920, height: 1080,
|
||||
time: 15,
|
||||
format: "mp4",
|
||||
size: fileSize,
|
||||
filePath
|
||||
};
|
||||
try {
|
||||
videoInfo = await getVideoInfo(path);
|
||||
log("视频信息", videoInfo)
|
||||
}catch (e) {
|
||||
log("获取视频信息失败", e)
|
||||
}
|
||||
const createThumb = new Promise<string>((resolve, reject) => {
|
||||
const thumbFileName = `${md5}_0.png`
|
||||
const thumbPath = pathLib.join(thumb, thumbFileName)
|
||||
if (diyThumbPath) {
|
||||
fs.copyFile(diyThumbPath, pathLib.join(thumb, thumbFileName)).then(() => {
|
||||
resolve(thumbPath);
|
||||
})
|
||||
return;
|
||||
}
|
||||
ffmpeg(filePath)
|
||||
.on("end", () => {
|
||||
})
|
||||
.on("error", (err) => {
|
||||
reject(err);
|
||||
log("获取视频封面失败,使用默认封面", err)
|
||||
if (diyThumbPath) {
|
||||
fs.copyFile(diyThumbPath, thumbPath).then(() => {
|
||||
resolve(thumbPath);
|
||||
}).catch(reject)
|
||||
} else {
|
||||
fs.writeFile(thumbPath, defaultVideoThumb).then(() => {
|
||||
resolve(thumbPath);
|
||||
}).catch(reject)
|
||||
}
|
||||
})
|
||||
.screenshots({
|
||||
timestamps: [0],
|
||||
|
@ -157,8 +157,8 @@ ob-setting-select::part(option-list) {
|
||||
}
|
||||
|
||||
#llonebot-error {
|
||||
color: red;
|
||||
height: 100px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
overflow: visible;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
Loading…
x
Reference in New Issue
Block a user