2023-01-12 22:55:40 +08:00
|
|
|
|
import config from '../config';
|
|
|
|
|
import * as path from 'path';
|
|
|
|
|
import * as fs from 'fs-extra';
|
|
|
|
|
|
|
|
|
|
import AutoPlanConfigDto from '../entity/dto/AutoPlanConfigDto';
|
|
|
|
|
import GlobalConfig from 'entity/po/GlobalConfig';
|
|
|
|
|
import GlobalConfigService from './GlobalConfigService';
|
2023-02-16 21:08:03 +08:00
|
|
|
|
import ErrorHelper from '../util/ErrorHelper';
|
|
|
|
|
import TimeUtil from '../util/TimeUtil';
|
|
|
|
|
import { isSub, isVideo } from '../util/MediaUtil';
|
|
|
|
|
import log from '../util/LogUtil';
|
2023-01-12 22:55:40 +08:00
|
|
|
|
const autoConfigCode = "autoConfig";
|
2023-02-16 21:08:03 +08:00
|
|
|
|
let isReadDir = false;
|
2023-01-31 20:41:38 +08:00
|
|
|
|
/**
|
|
|
|
|
* 需要处理的文件
|
|
|
|
|
*/
|
2023-01-31 23:06:08 +08:00
|
|
|
|
let needDeal = [];
|
2023-01-31 20:41:38 +08:00
|
|
|
|
/**
|
|
|
|
|
* 文件夹变更记录。key:变更前的目录,value:变更后的目录.当needDeal为空时清理pathMap
|
|
|
|
|
*/
|
|
|
|
|
let pathMap = {};
|
|
|
|
|
/**
|
|
|
|
|
* 自动化配置
|
|
|
|
|
*/
|
|
|
|
|
let autoConfig: AutoPlanConfigDto = null;
|
|
|
|
|
|
2023-01-12 22:55:40 +08:00
|
|
|
|
|
|
|
|
|
class AutoPlanService {
|
2023-01-31 20:41:38 +08:00
|
|
|
|
|
|
|
|
|
static async init() {
|
|
|
|
|
let str = await GlobalConfigService.getVal(autoConfigCode);
|
|
|
|
|
if (str != null) {
|
|
|
|
|
} else {
|
|
|
|
|
autoConfig = JSON.parse(str);
|
|
|
|
|
}
|
2023-02-16 21:08:03 +08:00
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
while (true) {
|
|
|
|
|
try {
|
|
|
|
|
await TimeUtil.sleep(1000);
|
|
|
|
|
await work();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.log(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, 1000);
|
2023-01-31 20:41:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-12 22:55:40 +08:00
|
|
|
|
/**
|
|
|
|
|
* 保存配置
|
|
|
|
|
*/
|
|
|
|
|
static async saveAutoConfig(body: AutoPlanConfigDto): Promise<void> {
|
2023-02-16 21:08:03 +08:00
|
|
|
|
if (isReadDir) {
|
|
|
|
|
throw ErrorHelper.Error400("正在处理中,请稍后再试");
|
|
|
|
|
}
|
2023-01-31 23:06:08 +08:00
|
|
|
|
if (body.start) {
|
|
|
|
|
if (body.paths.length == 0) {
|
|
|
|
|
throw ErrorHelper.Error400("视频路径为空");
|
|
|
|
|
}
|
|
|
|
|
if (body.rules.length == 0) {
|
|
|
|
|
throw ErrorHelper.Error400("规则为空");
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-12 22:55:40 +08:00
|
|
|
|
let configBody: GlobalConfig = {
|
|
|
|
|
code: autoConfigCode,
|
|
|
|
|
val: JSON.stringify(body),
|
|
|
|
|
description: "自动化计划配置"
|
|
|
|
|
};
|
|
|
|
|
await GlobalConfigService.insertOrReplace(configBody);
|
2023-01-31 20:41:38 +08:00
|
|
|
|
autoConfig = body;
|
|
|
|
|
if (body.start && !body.ignoreExist) {
|
2023-02-16 21:08:03 +08:00
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
isReadDir = true;
|
|
|
|
|
try {
|
|
|
|
|
await readDir(body.paths);
|
|
|
|
|
} finally {
|
|
|
|
|
isReadDir = false;
|
|
|
|
|
}
|
|
|
|
|
}, 1);
|
2023-01-31 20:41:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-16 21:08:03 +08:00
|
|
|
|
/**
|
|
|
|
|
* 读取目录,获取文件列表
|
|
|
|
|
* @param dirList 要读取的目录
|
|
|
|
|
*/
|
2023-01-31 23:06:08 +08:00
|
|
|
|
async function readDir(dirList: Array<string>): Promise<void> {
|
|
|
|
|
if (!dirList) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (let i in dirList) {
|
|
|
|
|
let pathStr = dirList[i];
|
2023-02-16 21:08:03 +08:00
|
|
|
|
if (checkIgnore(path.basename(pathStr))) {
|
2023-01-31 23:06:08 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!(await fs.stat(pathStr)).isDirectory()) {
|
2023-02-16 21:08:03 +08:00
|
|
|
|
let fileName = path.basename(pathStr);
|
|
|
|
|
let strs = fileName.split('.').reverse();
|
|
|
|
|
if (strs.length > 0 && (isSub(strs[0]) || isVideo(strs[1]))) {
|
|
|
|
|
needDeal.push(pathStr);
|
|
|
|
|
}
|
2023-01-31 23:06:08 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-02-16 21:08:03 +08:00
|
|
|
|
let childs = null;
|
|
|
|
|
try {
|
|
|
|
|
childs = await fs.readdir(pathStr);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn("读取报错:{}", error);
|
|
|
|
|
}
|
|
|
|
|
if (childs != null) {
|
|
|
|
|
await readDir(childs.map(item => path.join(pathStr, item)));
|
|
|
|
|
}
|
2023-01-31 23:06:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-31 20:41:38 +08:00
|
|
|
|
/**
|
|
|
|
|
* 检查文件名是否被忽略的
|
|
|
|
|
*/
|
|
|
|
|
function checkIgnore(str: string): boolean {
|
|
|
|
|
for (let i in autoConfig.ignorePaths) {
|
|
|
|
|
if (str.match(autoConfig.ignorePaths[i])) {
|
|
|
|
|
return true;
|
2023-01-12 22:55:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-31 20:41:38 +08:00
|
|
|
|
return false;
|
2023-01-12 22:55:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-16 21:08:03 +08:00
|
|
|
|
/**
|
|
|
|
|
* 开始处理
|
|
|
|
|
*/
|
|
|
|
|
async function work() {
|
|
|
|
|
if (autoConfig == null || !autoConfig.start) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (needDeal.length > 0) {
|
|
|
|
|
let file = needDeal.pop();
|
|
|
|
|
try {
|
|
|
|
|
await dealOnePath(file);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log.error("处理文件报错:{}", file);
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理一个文件路径
|
|
|
|
|
* @param filePath 路径
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
async function dealOnePath(filePath: string) {
|
|
|
|
|
let exist = await fs.pathExists(filePath);
|
|
|
|
|
if (!exist) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let basePath = null;
|
|
|
|
|
for (let i in autoConfig.paths) {
|
|
|
|
|
if (filePath.startsWith(autoConfig.paths[i])) {
|
|
|
|
|
basePath = autoConfig.paths[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (basePath == null) {
|
|
|
|
|
log.warn("无法识别的文件:{}", filePath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let relativePath = filePath.replace(basePath, "");
|
|
|
|
|
let pathArrs = relativePath.split(path.sep).filter(item => item.length > 0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-12 22:55:40 +08:00
|
|
|
|
export default AutoPlanService;
|