🦄 refactor: 重写index & acfun重写合成 & 🎈 perf: 搜书增加健壮性

This commit is contained in:
RrOrange 2023-03-30 23:48:30 +08:00
parent 931ef68684
commit 81a027219f
3 changed files with 75 additions and 69 deletions

View File

@ -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(" ");

View File

@ -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 }

View File

@ -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 };