mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 16:19:18 +00:00
🎈 pref: 优化直播切片,兼容 icqq 和 llo
This commit is contained in:
parent
44e3027f6c
commit
7ed883f18d
@ -85,6 +85,7 @@ import {
|
|||||||
truncateString,
|
truncateString,
|
||||||
urlTransformShortLink
|
urlTransformShortLink
|
||||||
} from "../utils/common.js";
|
} from "../utils/common.js";
|
||||||
|
import { convertFlvToMp4 } from "../utils/ffmpeg-util.js";
|
||||||
import { checkAndRemoveFile, deleteFolderRecursive, getMediaFilesAndOthers, mkdirIfNotExists } from "../utils/file.js";
|
import { checkAndRemoveFile, deleteFolderRecursive, getMediaFilesAndOthers, mkdirIfNotExists } from "../utils/file.js";
|
||||||
import GeneralLinkAdapter from "../utils/general-link-adapter.js";
|
import GeneralLinkAdapter from "../utils/general-link-adapter.js";
|
||||||
import { LagrangeAdapter } from "../utils/lagrange-adapter.js";
|
import { LagrangeAdapter } from "../utils/lagrange-adapter.js";
|
||||||
@ -260,6 +261,8 @@ export class tools extends plugin {
|
|||||||
this.douyinCompression = this.toolsConfig.douyinCompression;
|
this.douyinCompression = this.toolsConfig.douyinCompression;
|
||||||
// 加载抖音是否开启评论
|
// 加载抖音是否开启评论
|
||||||
this.douyinComments = this.toolsConfig.douyinComments;
|
this.douyinComments = this.toolsConfig.douyinComments;
|
||||||
|
// 加载抖音的是否开启兼容模式
|
||||||
|
this.douyinStreamCompatibility = this.toolsConfig.douyinStreamCompatibility;
|
||||||
// 加载小红书Cookie
|
// 加载小红书Cookie
|
||||||
this.xiaohongshuCookie = this.toolsConfig.xiaohongshuCookie;
|
this.xiaohongshuCookie = this.toolsConfig.xiaohongshuCookie;
|
||||||
// 翻译引擎
|
// 翻译引擎
|
||||||
@ -352,7 +355,6 @@ export class tools extends plugin {
|
|||||||
const webcastResp = await fetch(dyApi);
|
const webcastResp = await fetch(dyApi);
|
||||||
const webcastData = await webcastResp.json();
|
const webcastData = await webcastResp.json();
|
||||||
const item = webcastData.data.room;
|
const item = webcastData.data.room;
|
||||||
logger.info(item);
|
|
||||||
const { title, cover, user_count, stream_url } = item;
|
const { title, cover, user_count, stream_url } = item;
|
||||||
const dySendContent = `${ this.identifyPrefix }识别:抖音直播,${ title }`
|
const dySendContent = `${ this.identifyPrefix }识别:抖音直播,${ title }`
|
||||||
e.reply([segment.image(cover?.url_list?.[0]), dySendContent, `\n🏄♂️在线人数:${ user_count }人正在观看`]);
|
e.reply([segment.image(cover?.url_list?.[0]), dySendContent, `\n🏄♂️在线人数:${ user_count }人正在观看`]);
|
||||||
@ -481,8 +483,13 @@ export class tools extends plugin {
|
|||||||
* @param second
|
* @param second
|
||||||
*/
|
*/
|
||||||
async sendStreamSegment(e, stream_url, second = this.streamDuration) {
|
async sendStreamSegment(e, stream_url, second = this.streamDuration) {
|
||||||
const outputFilePath = `${ this.getCurDownloadPath(e) }/stream_${second}s.flv`;
|
let outputFilePath = `${ this.getCurDownloadPath(e) }/stream_${second}s.flv`;
|
||||||
await checkAndRemoveFile(outputFilePath);
|
// 删除临时文件
|
||||||
|
if (this.douyinStreamCompatibility) {
|
||||||
|
await checkAndRemoveFile(outputFilePath.replace("flv", "mp4"));
|
||||||
|
} else {
|
||||||
|
await checkAndRemoveFile(outputFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
// 创建一个取消令牌
|
// 创建一个取消令牌
|
||||||
const CancelToken = axios.CancelToken;
|
const CancelToken = axios.CancelToken;
|
||||||
@ -502,9 +509,17 @@ export class tools extends plugin {
|
|||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
logger.info(`[R插件][发送直播流] 直播下载 ${ second } 秒钟到,停止下载!`);
|
logger.info(`[R插件][发送直播流] 直播下载 ${ second } 秒钟到,停止下载!`);
|
||||||
// 取消请求
|
// 取消请求
|
||||||
source.cancel('下载时间到,停止请求');
|
source.cancel('[R插件][发送直播流] 下载时间到,停止请求');
|
||||||
response.data.unpipe(file); // 取消管道连接
|
response.data.unpipe(file); // 取消管道连接
|
||||||
file.end(); // 结束写入
|
file.end(); // 结束写入
|
||||||
|
// 这里判断是否开启兼容模式
|
||||||
|
if (this.douyinStreamCompatibility) {
|
||||||
|
logger.info(`[R插件][发送直播流] 开启兼容模式,开始转换mp4格式...`);
|
||||||
|
const resolvedOutputPath = await convertFlvToMp4(outputFilePath, outputFilePath.replace(".flv", ".mp4"));
|
||||||
|
fs.unlinkSync(outputFilePath);
|
||||||
|
outputFilePath = resolvedOutputPath;
|
||||||
|
logger.info(`[R插件][发送直播流] 转换完成,开始发送视频...`);
|
||||||
|
}
|
||||||
await this.sendVideoToUpload(e, outputFilePath);
|
await this.sendVideoToUpload(e, outputFilePath);
|
||||||
}, second * 1000);
|
}, second * 1000);
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ YouTubeGraphicsOptions: 720 #YouTobe的下载画质,0为原画,1080,720,
|
|||||||
douyinCookie: '' # douyin's cookie, 格式:odin_tt=xxx;passport_fe_beating_status=xxx;sid_guard=xxx;uid_tt=xxx;uid_tt_ss=xxx;sid_tt=xxx;sessionid=xxx;sessionid_ss=xxx;sid_ucp_v1=xxx;ssid_ucp_v1=xxx;passport_assist_user=xxx;ttwid=xxx;
|
douyinCookie: '' # douyin's cookie, 格式:odin_tt=xxx;passport_fe_beating_status=xxx;sid_guard=xxx;uid_tt=xxx;uid_tt_ss=xxx;sid_tt=xxx;sessionid=xxx;sessionid_ss=xxx;sid_ucp_v1=xxx;ssid_ucp_v1=xxx;passport_assist_user=xxx;ttwid=xxx;
|
||||||
douyinCompression: true # true-压缩,false-不压缩;是否使用压缩视频格式的抖音(默认使用),使用后加速视频发送
|
douyinCompression: true # true-压缩,false-不压缩;是否使用压缩视频格式的抖音(默认使用),使用后加速视频发送
|
||||||
douyinComments: false # true-开启评论,false-关闭评论
|
douyinComments: false # true-开启评论,false-关闭评论
|
||||||
|
douyinStreamCompatibility: false # 兼容模式,NCQQ不用开,其他ICQQ、LLO需要开启
|
||||||
|
|
||||||
xiaohongshuCookie: '' # 2024-8-2后反馈必须使用ck,不然无法解析
|
xiaohongshuCookie: '' # 2024-8-2后反馈必须使用ck,不然无法解析
|
||||||
|
|
||||||
|
@ -245,6 +245,12 @@ export function supportGuoba() {
|
|||||||
component: "Switch",
|
component: "Switch",
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: "tools.douyinStreamCompatibility",
|
||||||
|
label: "抖音直播是否开启兼容模式",
|
||||||
|
component: "Switch",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: "tools.xiaohongshuCookie",
|
field: "tools.xiaohongshuCookie",
|
||||||
label: "小红书的Cookie",
|
label: "小红书的Cookie",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取关键帧
|
* 提取关键帧
|
||||||
@ -34,22 +35,32 @@ export async function extractKeyframes(inputFilePath, outputFolderPath, frameCou
|
|||||||
* @param {string} outputFilePath - 输出的 MP4 文件路径
|
* @param {string} outputFilePath - 输出的 MP4 文件路径
|
||||||
* @returns {Promise<string>} - 返回一个 Promise,成功时返回输出文件路径,失败时返回错误信息
|
* @returns {Promise<string>} - 返回一个 Promise,成功时返回输出文件路径,失败时返回错误信息
|
||||||
*/
|
*/
|
||||||
function convertFlvToMp4(inputFilePath, outputFilePath) {
|
export function convertFlvToMp4(inputFilePath, outputFilePath) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const command = `ffmpeg -i ${inputFilePath} ${outputFilePath}`;
|
const resolvedInputPath = path.resolve(inputFilePath);
|
||||||
|
const resolvedOutputPath = path.resolve(outputFilePath);
|
||||||
|
|
||||||
logger.info(`[R插件][ffmpeg工具]执行命令:${command}`);
|
// 检查文件是否存在
|
||||||
|
fs.access(resolvedInputPath, fs.constants.F_OK, (err) => {
|
||||||
exec(command, (error, stdout, stderr) => {
|
if (err) {
|
||||||
if (error) {
|
reject(`[R插件][ffmpeg工具]输入文件不存在: ${resolvedInputPath}`);
|
||||||
reject(`执行 ffmpeg 命令时出错: ${error.message}`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stderr) {
|
|
||||||
reject(`ffmpeg 标准错误输出: ${stderr}`);
|
const command = `ffmpeg -y -i "${resolvedInputPath}" "${resolvedOutputPath}"`;
|
||||||
return;
|
logger.info(`[R插件][ffmpeg工具]执行命令:${command}`);
|
||||||
}
|
|
||||||
resolve(outputFilePath);
|
// 执行 ffmpeg 转换
|
||||||
|
exec(command, (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
reject(`[R插件][ffmpeg工具]执行 ffmpeg 命令时出错: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stderr) {
|
||||||
|
logger.warn(`[R插件][ffmpeg工具]ffmpeg 标准错误输出: ${stderr}`);
|
||||||
|
}
|
||||||
|
resolve(resolvedOutputPath);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user