mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 16:19:18 +00:00
🦄 refactor: 重写index & acfun重写合成 & 🎈 perf: 搜书增加健壮性
This commit is contained in:
parent
931ef68684
commit
81a027219f
@ -299,6 +299,10 @@ export class query extends plugin {
|
|||||||
// 搜书
|
// 搜书
|
||||||
async searchBook(e) {
|
async searchBook(e) {
|
||||||
let keyword = e.msg.replace(/#|搜书/g, "").trim();
|
let keyword = e.msg.replace(/#|搜书/g, "").trim();
|
||||||
|
if (_.isEmpty(keyword)) {
|
||||||
|
e.reply(`请输入书名,例如:#搜书 非暴力沟通`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const thisBookMethod = this;
|
const thisBookMethod = this;
|
||||||
// 主要数据来源
|
// 主要数据来源
|
||||||
await Promise.all([getZHelper(e, keyword), getYiBook(e, keyword)]).then(async allRes => {
|
await Promise.all([getZHelper(e, keyword), getYiBook(e, keyword)]).then(async allRes => {
|
||||||
@ -323,6 +327,11 @@ export class query extends plugin {
|
|||||||
// 通过id搜书
|
// 通过id搜书
|
||||||
async searchBookById(e) {
|
async searchBookById(e) {
|
||||||
let keyword = e.msg.replace(/#bookid/, "").trim();
|
let keyword = e.msg.replace(/#bookid/, "").trim();
|
||||||
|
if (_.isEmpty(keyword)) {
|
||||||
|
e.reply(`请输入书名,例如:#搜书 12`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
let id, source;
|
let id, source;
|
||||||
if (keyword.includes(" ")) {
|
if (keyword.includes(" ")) {
|
||||||
[id, source] = keyword.split(" ");
|
[id, source] = keyword.split(" ");
|
||||||
|
40
index.js
40
index.js
@ -1,21 +1,29 @@
|
|||||||
import fs from 'node:fs'
|
import fs from "node:fs";
|
||||||
import RConfig from './model/index.js'
|
import RConfig from "./model/index.js";
|
||||||
|
|
||||||
const versionData = RConfig.getConfig('version')
|
const versionData = RConfig.getConfig("version");
|
||||||
|
|
||||||
logger.info('--------------------------')
|
logger.info(`R插件${versionData[0].version}初始化`);
|
||||||
logger.info(`rconsole插件${versionData[0].version}初始化~`)
|
|
||||||
logger.info('--------------------------')
|
|
||||||
|
|
||||||
// 读取功能
|
const files = fs.readdirSync("./plugins/rconsole-plugin/apps").filter(file => file.endsWith(".js"));
|
||||||
const files = fs
|
|
||||||
.readdirSync('./plugins/rconsole-plugin/apps')
|
|
||||||
.filter((file) => file.endsWith('.js'))
|
|
||||||
|
|
||||||
let apps = {}
|
let ret = [];
|
||||||
for (let file of files) {
|
|
||||||
let name = file.replace('.js', '')
|
files.forEach(file => {
|
||||||
apps[name] = (await import(`./apps/${file}`))[name]
|
ret.push(import(`./apps/${file}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
ret = await Promise.allSettled(ret);
|
||||||
|
|
||||||
|
let apps = {};
|
||||||
|
for (let i in files) {
|
||||||
|
let name = files[i].replace(".js", "");
|
||||||
|
|
||||||
|
if (ret[i].status !== "fulfilled") {
|
||||||
|
logger.error(`载入插件错误:${logger.red(name)}`);
|
||||||
|
logger.error(ret[i].reason);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
apps[name] = ret[i].value[Object.keys(ret[i].value)[0]];
|
||||||
}
|
}
|
||||||
|
export { apps };
|
||||||
export { apps }
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import axios from 'axios'
|
import axios from "axios";
|
||||||
import fs from 'node:fs'
|
import fs from "node:fs";
|
||||||
import path from 'path'
|
import path from "path";
|
||||||
import child_process from 'node:child_process'
|
import child_process from "node:child_process";
|
||||||
|
import util from "util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 去除JSON的一些转义 \\" -> \" ->"
|
* 去除JSON的一些转义 \\" -> \" ->"
|
||||||
@ -11,7 +12,7 @@ function escapeSpecialChars(str) {
|
|||||||
return str.replace(/\\\\"/g, '\\"').replace(/\\"/g, '"');
|
return str.replace(/\\\\"/g, '\\"').replace(/\\"/g, '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseVideoName = (videoInfo) => {
|
const parseVideoName = videoInfo => {
|
||||||
const strAc号 = "ac" + (videoInfo?.dougaId || "");
|
const strAc号 = "ac" + (videoInfo?.dougaId || "");
|
||||||
const str标题 = videoInfo?.title;
|
const str标题 = videoInfo?.title;
|
||||||
const str作者 = videoInfo?.user.name;
|
const str作者 = videoInfo?.user.name;
|
||||||
@ -19,14 +20,14 @@ const parseVideoName = (videoInfo) => {
|
|||||||
const str描述 = videoInfo?.description;
|
const str描述 = videoInfo?.description;
|
||||||
|
|
||||||
const raw = [strAc号, str标题, str作者, str上传时间, str描述]
|
const raw = [strAc号, str标题, str作者, str上传时间, str描述]
|
||||||
.map((d) => d || "")
|
.map(d => d || "")
|
||||||
.join("_")
|
.join("_")
|
||||||
.slice(0, 100);
|
.slice(0, 100);
|
||||||
|
|
||||||
return raw;
|
return raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseVideoNameFixed = (videoInfo) => {
|
const parseVideoNameFixed = videoInfo => {
|
||||||
const f = parseVideoName(videoInfo);
|
const f = parseVideoName(videoInfo);
|
||||||
const t = f.replaceAll(" ", "-");
|
const t = f.replaceAll(" ", "-");
|
||||||
return t;
|
return t;
|
||||||
@ -38,7 +39,7 @@ async function parseUrl(videoUrlAddress) {
|
|||||||
const url = videoUrlAddress + urlSuffix;
|
const url = videoUrlAddress + urlSuffix;
|
||||||
|
|
||||||
const raw = await axios.get(url).then(resp => {
|
const raw = await axios.get(url).then(resp => {
|
||||||
return resp.data
|
return resp.data;
|
||||||
});
|
});
|
||||||
// Split
|
// Split
|
||||||
const strsRemoveHeader = raw.split("window.pageInfo = window.videoInfo =");
|
const strsRemoveHeader = raw.split("window.pageInfo = window.videoInfo =");
|
||||||
@ -56,7 +57,7 @@ async function parseUrl(videoUrlAddress) {
|
|||||||
const ksPlay = JSON.parse(ksPlayJson);
|
const ksPlay = JSON.parse(ksPlayJson);
|
||||||
|
|
||||||
const representations = ksPlay.adaptationSet[0].representation;
|
const representations = ksPlay.adaptationSet[0].representation;
|
||||||
const urlM3u8s = representations.map((d) => d.url);
|
const urlM3u8s = representations.map(d => d.url);
|
||||||
|
|
||||||
return { urlM3u8s, videoName };
|
return { urlM3u8s, videoName };
|
||||||
}
|
}
|
||||||
@ -69,15 +70,14 @@ async function parseM3u8(m3u8Url) {
|
|||||||
/** 过滤头部 */
|
/** 过滤头部 */
|
||||||
const m3u8RelativeLinks = rawPieces.slice(1);
|
const m3u8RelativeLinks = rawPieces.slice(1);
|
||||||
/** 修改尾部 去掉尾部多余的结束符 */
|
/** 修改尾部 去掉尾部多余的结束符 */
|
||||||
const patchedTail =
|
const patchedTail = m3u8RelativeLinks[m3u8RelativeLinks.length - 1].split("\n")[0];
|
||||||
m3u8RelativeLinks[m3u8RelativeLinks.length - 1].split("\n")[0];
|
|
||||||
m3u8RelativeLinks[m3u8RelativeLinks.length - 1] = patchedTail;
|
m3u8RelativeLinks[m3u8RelativeLinks.length - 1] = patchedTail;
|
||||||
|
|
||||||
/** 完整链接,直接加m3u8Url的通用前缀 */
|
/** 完整链接,直接加m3u8Url的通用前缀 */
|
||||||
const m3u8Prefix = m3u8Url.split("/").slice(0, -1).join("/");
|
const m3u8Prefix = m3u8Url.split("/").slice(0, -1).join("/");
|
||||||
const m3u8FullUrls = m3u8RelativeLinks.map((d) => m3u8Prefix + "/" + d);
|
const m3u8FullUrls = m3u8RelativeLinks.map(d => m3u8Prefix + "/" + d);
|
||||||
/** aria2c下载的文件名,就是取url最后一段,去掉末尾url参数(?之后是url参数) */
|
/** aria2c下载的文件名,就是取url最后一段,去掉末尾url参数(?之后是url参数) */
|
||||||
const tsNames = m3u8RelativeLinks.map((d) => d.split("?")[0]);
|
const tsNames = m3u8RelativeLinks.map(d => d.split("?")[0]);
|
||||||
/** 文件夹名,去掉文件名末尾分片号 */
|
/** 文件夹名,去掉文件名末尾分片号 */
|
||||||
let outputFolderName = tsNames[0].slice(0, -9);
|
let outputFolderName = tsNames[0].slice(0, -9);
|
||||||
/** 输出最后合并的文件名,加个通用mp4后缀 */
|
/** 输出最后合并的文件名,加个通用mp4后缀 */
|
||||||
@ -92,82 +92,71 @@ async function parseM3u8(m3u8Url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 下载m3u8
|
// 下载m3u8
|
||||||
async function downloadM3u8Videos(
|
async function downloadM3u8Videos(m3u8FullUrls, outputFolderName) {
|
||||||
m3u8FullUrls,
|
|
||||||
outputFolderName
|
|
||||||
) {
|
|
||||||
/** 新建下载文件夹 在当前运行目录下 */
|
/** 新建下载文件夹 在当前运行目录下 */
|
||||||
const outPath = outputFolderName;
|
const outPath = outputFolderName;
|
||||||
|
|
||||||
/** 批下载 */
|
/** 批下载 */
|
||||||
const strDownloadParamFiles = m3u8FullUrls
|
const strDownloadParamFiles = m3u8FullUrls.map(async (d, i) => {
|
||||||
.map(async (d, i) => {
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const writer = fs.createWriteStream(outPath + `${i}.ts`);
|
const writer = fs.createWriteStream(outPath + `${i}.ts`);
|
||||||
axios.get(d, {
|
axios
|
||||||
|
.get(d, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent":
|
"User-Agent":
|
||||||
"Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
|
"Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
|
||||||
},
|
},
|
||||||
responseType: "stream",
|
responseType: "stream",
|
||||||
}).then(dres => {
|
})
|
||||||
|
.then(dres => {
|
||||||
dres.data.pipe(writer);
|
dres.data.pipe(writer);
|
||||||
writer.on("finish", () => resolve(true));
|
writer.on("finish", () => resolve(true));
|
||||||
writer.on("error", () => reject);
|
writer.on("error", () => reject);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
/** 写入下载链接列表文件 */
|
/** 写入下载链接列表文件 */
|
||||||
// fs.writeFileSync(path.resolve(outPath, "urls.txt"), str下载参数文件);
|
// fs.writeFileSync(path.resolve(outPath, "urls.txt"), str下载参数文件);
|
||||||
return Promise.all(strDownloadParamFiles);
|
return Promise.all(strDownloadParamFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function mergeAcFileToMp4(tsNames, FullFileName, outputFileName, shouldDelete = true) {
|
||||||
function mergeAcFileToMp4(tsNames, FullFileName, outputFileName, shouldDelete = true) {
|
|
||||||
|
|
||||||
/** 合并参数列表 格式file path */
|
/** 合并参数列表 格式file path */
|
||||||
const concatStrs = tsNames.map(
|
const concatStrs = tsNames.map(
|
||||||
(d, i) => `file ${path.resolve(FullFileName, i + ".ts").replace(/\\/g, "/")}`
|
(d, i) => `file ${path.resolve(FullFileName, i + ".ts").replace(/\\/g, "/")}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ffmpegList = path.resolve(FullFileName, 'file.txt');
|
const ffmpegList = path.resolve(FullFileName, "file.txt");
|
||||||
fs.writeFileSync(ffmpegList, concatStrs.join("\n"));
|
fs.writeFileSync(ffmpegList, concatStrs.join("\n"));
|
||||||
const outPath = path.resolve(outputFileName);
|
const outPath = path.resolve(outputFileName);
|
||||||
|
|
||||||
// 执行命令
|
|
||||||
let cmd = 'ffmpeg';
|
|
||||||
// 判断当前环境
|
// 判断当前环境
|
||||||
let env;
|
let env;
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
env = process.env
|
env = process.env;
|
||||||
} else if (process.platform === "linux") {
|
} else if (process.platform === "linux") {
|
||||||
env = {
|
env = {
|
||||||
...process.env,
|
...process.env,
|
||||||
PATH: '/usr/local/bin:' + child_process.execSync('echo $PATH').toString(),
|
PATH: "/usr/local/bin:" + child_process.execSync("echo $PATH").toString(),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
console.log("暂时不支持当前操作系统!")
|
console.log("暂时不支持当前操作系统!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
const execFile = util.promisify(child_process.execFile);
|
||||||
child_process.exec(
|
try {
|
||||||
`${ cmd } -y -f concat -safe 0 -i "${ ffmpegList }" -c copy "${ outPath }"`,
|
const cmd = "ffmpeg";
|
||||||
{ env },
|
const args = ["-y", "-f", "concat", "-safe", "0", "-i", ffmpegList, "-c", "copy", outPath];
|
||||||
err => {
|
await execFile(cmd, args, { env });
|
||||||
|
|
||||||
if (shouldDelete) {
|
if (shouldDelete) {
|
||||||
fs.unlink(FullFileName, f => f);
|
await fs.promises.unlink(FullFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
return { outputFileName };
|
||||||
reject(err);
|
} catch (err) {
|
||||||
|
logger.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({ outputFileName });
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 }
|
export { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user