Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
51c6ec9986 | |||
|
a0e0186c63 | ||
|
652105f534 | ||
|
bbc4bfd52f | ||
|
f85890bda8 | ||
67f542fe01 | |||
|
95a382835a | ||
922a74be41 | |||
|
1ebd7acf5a | ||
6444d9a612 | |||
|
6759333fb4 | ||
|
62d9296b46 | ||
|
711423dbe1 | ||
|
f3f31e5b5c | ||
|
4c8c1a355c | ||
|
f3bcacfc4a | ||
2e50b9653a | |||
|
861d5f35bf | ||
|
55af6bd54e | ||
|
8c6416ec87 | ||
|
f04d3bf636 | ||
|
0b87ecae94 | ||
|
9c001c5403 | ||
|
4b8a7829d9 | ||
|
164553abf0 | ||
|
cabe83d07d | ||
|
69dcbd22b0 | ||
|
4002db4c22 | ||
|
851234ab76 | ||
|
1876e98a0e | ||
|
7ab3a49323 | ||
|
3f8b659462 | ||
|
f25e5d7bc7 | ||
|
ea859cc6c3 | ||
|
3f0d519a99 | ||
|
b0f1901731 | ||
|
faedc09771 | ||
|
f502348786 | ||
|
ae9a2d53c5 | ||
|
6c8184fb1c | ||
|
7d6006d1fd | ||
|
94a90ba359 | ||
|
ea0d68036b | ||
|
85f614f414 | ||
|
dd6def02ac | ||
|
0b7f4a155c | ||
|
9a55460f11 | ||
|
11f28f12fa | ||
|
1d4e61f9ef |
@ -1,7 +1,9 @@
|
|||||||
FROM node:lts-buster-slim
|
FROM node:lts-buster-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./openRenamerBackend /app
|
COPY ./openRenamerBackend /app
|
||||||
RUN chmod 777 -R /app
|
# RUN chmod 777 -R /app && npm install -g pnpm typescript --registry https://registry.npmmirror.com
|
||||||
|
# 注意此处未添加npm代理
|
||||||
|
RUN chmod 777 -R /app && npm install -g pnpm typescript
|
||||||
ENV PORT 80
|
ENV PORT 80
|
||||||
CMD ["bash", "start.sh"]
|
CMD ["bash", "start.sh"]
|
||||||
|
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
![预览图](https://s3.fleyx.com/picbed/2022/11/18386180128d01eb1a59b8eacf652895.png)
|
![预览图](https://s3.fleyx.com/picbed/2022/11/18386180128d01eb1a59b8eacf652895.png)
|
||||||
|
|
||||||
renamer 的开源实现版本,BS 应用,支持 arm/x86 部署使用
|
renamer 的开源实现版本,BS 应用,支持 arm/x86 部署使用,两种使用方式:
|
||||||
已打包镜像到 dockerhub 中:[hub.docker.com/r/fleyx/open-renamer](https://hub.docker.com/r/fleyx/open-renamer)
|
|
||||||
|
1. 部署容器到 nas
|
||||||
|
已打包到 dockerhub 中:[hub.docker.com/r/fleyx/open-renamer](https://hub.docker.com/r/fleyx/open-renamer)
|
||||||
|
|
||||||
|
2. 下载桌面应用使用,目前仅支持 windows,后续计划支持 mac,linux[下载地址](https://github.com/FleyX/open-renamer/releases/latest)
|
||||||
|
|
||||||
[点击查看参考文档](https://blog.fleyx.com/blog/detail/20221130)
|
[点击查看参考文档](https://blog.fleyx.com/blog/detail/20221130)
|
||||||
|
6
build.sh
6
build.sh
@ -2,7 +2,9 @@
|
|||||||
base=$(cd "$(dirname "$0")";pwd)
|
base=$(cd "$(dirname "$0")";pwd)
|
||||||
cd $base
|
cd $base
|
||||||
rm -rf openRenamerBackend/dist
|
rm -rf openRenamerBackend/dist
|
||||||
docker run -it --rm --name buildOpenRenamer --user ${UID} -v $base/openRenamerFront:/opt/front node:lts-slim bash -c "cd /opt/front && npm install -g pnpm --registry https://registry.npmmirror.com && pnpm install --registry https://registry.npmmirror.com && pnpm run build"
|
# 注意此处未添加npm代理
|
||||||
|
# docker run -it --rm --name buildOpenRenamer --user ${UID} -v $base/openRenamerFront:/opt/front node:lts-slim bash -c "cd /opt/front && npm install -g pnpm --registry https://registry.npmmirror.com && pnpm install --registry https://registry.npmmirror.com && pnpm run build"
|
||||||
|
docker run -it --rm --name buildOpenRenamer --user ${UID} -v $base/openRenamerFront:/opt/front node:lts-slim bash -c "cd /opt/front && npm install -g pnpm && pnpm install && pnpm run build"
|
||||||
|
|
||||||
rm -rf openRenamerBackend/static/*
|
rm -rf openRenamerBackend/static/*
|
||||||
touch openRenamerBackend/static/.gitkeep
|
touch openRenamerBackend/static/.gitkeep
|
||||||
@ -13,4 +15,4 @@ rm -rf openRenamerBackend/node_modules
|
|||||||
#docker build -t fleyx/open-renamer:$0 --push .
|
#docker build -t fleyx/open-renamer:$0 --push .
|
||||||
# 多平台打包并推送
|
# 多平台打包并推送
|
||||||
docker buildx build -t fleyx/open-renamer:$1 --platform linux/amd64,linux/arm64 --push .
|
docker buildx build -t fleyx/open-renamer:$1 --platform linux/amd64,linux/arm64 --push .
|
||||||
docker buildx build -t fleyx/open-renamer:latset --platform linux/amd64,linux/arm64 --push .
|
docker buildx build -t fleyx/open-renamer:latest --platform linux/amd64,linux/arm64 --push .
|
||||||
|
6
electron/.gitignore
vendored
Normal file
6
electron/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
openRenamerBackend
|
||||||
|
build
|
||||||
|
.idea
|
||||||
|
*.exe
|
1
electron/.npmrc
Normal file
1
electron/.npmrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
electron_mirror=https://npmmirror.com/mirrors/electron/
|
12
electron/build.sh
Normal file
12
electron/build.sh
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
cd ../openRenamerFront
|
||||||
|
yarn
|
||||||
|
npm run build
|
||||||
|
cd ../openRenamerBackend
|
||||||
|
yarn
|
||||||
|
tsc
|
||||||
|
rm -rf ./static/js
|
||||||
|
rm -rf ./static/css
|
||||||
|
cp -r ../openRenamerFront/dist/* ./static
|
||||||
|
cd ../electron
|
||||||
|
mkdir -p dist
|
||||||
|
npm run build
|
70
electron/index.html
Normal file
70
electron/index.html
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<html lang="">
|
||||||
|
<head>
|
||||||
|
<title>open-renamer</title>
|
||||||
|
</head>
|
||||||
|
<body class="center">
|
||||||
|
<div class="center" style="flex-direction: column">
|
||||||
|
<div class="loading"></div>
|
||||||
|
<div id="text" style="font: 1.2em">loading...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.center {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: -webkit-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: relative;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
animation: satellite 3s infinite linear;
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading:before,
|
||||||
|
.loading:after {
|
||||||
|
position: absolute;
|
||||||
|
left: 1px;
|
||||||
|
top: 1px;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
content: "";
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
box-shadow: 0 0 10px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading:after {
|
||||||
|
right: 0;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes satellite {
|
||||||
|
from {
|
||||||
|
transform: rotate(0) translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg) translateZ(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
let text = document.getElementById("text");
|
||||||
|
let count = 1;
|
||||||
|
setInterval(() => {
|
||||||
|
if (count > 3) {
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
text.innerText = "Loading" + (count == 3 ? '...' : count == 2 ? '..' : '.');
|
||||||
|
count++;
|
||||||
|
}, 500);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
139
electron/main.js
Normal file
139
electron/main.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// main.js
|
||||||
|
// 控制应用生命周期和创建原生浏览器窗口的模组
|
||||||
|
const {app, BrowserWindow, Menu} = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
const fs = require('fs');
|
||||||
|
const {spawn} = require('child_process');
|
||||||
|
const net = require('net');
|
||||||
|
const log = require('electron-log');
|
||||||
|
|
||||||
|
|
||||||
|
const userHome = process.env.HOME || process.env.USERPROFILE;
|
||||||
|
const dataPath = path.join(userHome, "openRenamer");
|
||||||
|
|
||||||
|
log.transports.file.resolvePathFn = () => path.join(dataPath, 'logs/main.log');
|
||||||
|
|
||||||
|
async function createWindow() {
|
||||||
|
// 隐藏菜单栏
|
||||||
|
Menu.setApplicationMenu(null)
|
||||||
|
// 创建浏览器窗口
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
//width: 800, //窗口宽度,单位像素. 默认是 800
|
||||||
|
//height: 600, //窗口高度,单位像素. 默认是 600
|
||||||
|
icon: './logo.ico', // 设置窗口左上角的图标
|
||||||
|
show: false, //窗口创建的时候是否显示. 默认为 true
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true, // 是否完整支持node。默认为 true
|
||||||
|
preload: path.join(__dirname, 'preload.js') //界面的其它脚本运行之前预先加载一个指定脚本。
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//打开调试
|
||||||
|
// win.webContents.openDevTools();
|
||||||
|
|
||||||
|
win.loadFile('./index.html');
|
||||||
|
let startTime = Date.now();
|
||||||
|
|
||||||
|
// 下面这两行代码配合上面 new BrowserWindow 里面的 show: false,可以实现打开时窗口最大化
|
||||||
|
win.maximize()
|
||||||
|
win.show()
|
||||||
|
log.info(__dirname);
|
||||||
|
let port = await startBackend()
|
||||||
|
log.info("backend service started")
|
||||||
|
|
||||||
|
let diff = Date.now() - startTime;
|
||||||
|
let time = 2000;
|
||||||
|
if (diff < time) {
|
||||||
|
await sleep(time - diff);
|
||||||
|
}
|
||||||
|
win.loadURL(`http://localhost:` + port);
|
||||||
|
// win.webContents.openDevTools()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Electron会在初始化完成并且准备好创建浏览器窗口时调用这个方法
|
||||||
|
// 部分 API 在 ready 事件触发后才能使用。
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
// 当所有窗口都被关闭后退出
|
||||||
|
app.on('windows-all-closed', () => {
|
||||||
|
// 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
|
||||||
|
// 否则绝大部分应用及其菜单栏会保持激活。
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
app.on('activate', () => {
|
||||||
|
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
|
||||||
|
// 通常在应用程序中重新创建一个窗口。
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动后台服务
|
||||||
|
* @returns {Promise<number>}
|
||||||
|
*/
|
||||||
|
async function startBackend() {
|
||||||
|
let port = 51000;
|
||||||
|
while (true) {
|
||||||
|
let ok = await checkPort(port);
|
||||||
|
if (ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
port = port + 1;
|
||||||
|
}
|
||||||
|
log.info("start check folder exist", __dirname, __filename)
|
||||||
|
let exist = fs.existsSync("openRenamerBackend");
|
||||||
|
const childProcess = spawn('node', [(exist ? '' : '../') + 'openRenamerBackend/dist/index.js'], {
|
||||||
|
env: {
|
||||||
|
"PORT": port,
|
||||||
|
"DATA_PATH": dataPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
childProcess.stdout.on('data', (data) => {
|
||||||
|
log.info(`stdout: ${data}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
childProcess.stderr.on('data', (data) => {
|
||||||
|
log.error(`stderr: ${data}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
childProcess.on('close', (code) => {
|
||||||
|
log.info(`child process exited with code ${code}`);
|
||||||
|
});
|
||||||
|
log.info("check service start");
|
||||||
|
while (true) {
|
||||||
|
await sleep(100);
|
||||||
|
let success = !(await checkPort(port));
|
||||||
|
if (success) {
|
||||||
|
log.info("service start");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断端口是否可用
|
||||||
|
* @param port
|
||||||
|
* @returns {Promise<unknown>}
|
||||||
|
*/
|
||||||
|
function checkPort(port) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let server = net.createServer().listen(port);
|
||||||
|
server.on("listening", function () {
|
||||||
|
server.close();
|
||||||
|
resolve(true);
|
||||||
|
})
|
||||||
|
server.on("error", function (err) {
|
||||||
|
console.error(err);
|
||||||
|
resolve(false);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(time) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => resolve(), time);
|
||||||
|
})
|
||||||
|
}
|
72
electron/package.json
Normal file
72
electron/package.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"name": "renamer",
|
||||||
|
"version": "1.8.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "electron .",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"build": "electron-builder --win --x64"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"electron": "^28.0.0",
|
||||||
|
"electron-builder": "^24.9.1"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"productName": "openRenamer",
|
||||||
|
"appId": "openRenamer.app",
|
||||||
|
"directories": {
|
||||||
|
"output": "build"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"main.js",
|
||||||
|
"preload.js",
|
||||||
|
"index.html"
|
||||||
|
],
|
||||||
|
"extraFiles": [
|
||||||
|
{
|
||||||
|
"from": "../openRenamerBackend",
|
||||||
|
"to": "openRenamerBackend"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyright": "open-renamer",
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": false,
|
||||||
|
"allowElevation": true,
|
||||||
|
"allowToChangeInstallationDirectory": true,
|
||||||
|
"installerIcon": "./renamer.ico",
|
||||||
|
"uninstallerIcon": "./renamer.ico",
|
||||||
|
"installerHeaderIcon": "./renamer.ico",
|
||||||
|
"createDesktopShortcut": true,
|
||||||
|
"createStartMenuShortcut": true,
|
||||||
|
"shortcutName": "openRenamer"
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"icon": "./renamer.ico",
|
||||||
|
"target": [
|
||||||
|
"nsis",
|
||||||
|
"zip"
|
||||||
|
],
|
||||||
|
"extraFiles": [
|
||||||
|
{
|
||||||
|
"from": "windows/node.exe",
|
||||||
|
"to": "node.exe"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mac": {
|
||||||
|
"target": [
|
||||||
|
"dmg",
|
||||||
|
"zip"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"icon": "build/icons"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"electron-log": "^5.0.1"
|
||||||
|
}
|
||||||
|
}
|
12
electron/preload.js
Normal file
12
electron/preload.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// preload.js
|
||||||
|
// 所有Node.js API都可以在预加载过程中使用。
|
||||||
|
// 它拥有与Chrome扩展一样的沙盒。
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const replaceText = (selector, text) => {
|
||||||
|
const element = document.getElementById(selector)
|
||||||
|
if (element) element.innerText = text
|
||||||
|
}
|
||||||
|
for (const dependency of ['chrome', 'node', 'electron']) {
|
||||||
|
replaceText(`${dependency}-version`, process.versions[dependency])
|
||||||
|
}
|
||||||
|
})
|
1
electron/readme.md
Normal file
1
electron/readme.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
需要下载windows版的node.js压缩包,将其中的node.exe 放到windowes目录下
|
BIN
electron/renamer.ico
Normal file
BIN
electron/renamer.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
1705
electron/yarn.lock
Normal file
1705
electron/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
openRenamerBackend/.idea/openRenamerBackend.iml
generated
1
openRenamerBackend/.idea/openRenamerBackend.iml
generated
@ -4,6 +4,7 @@
|
|||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.vscode" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Context } from "koa";
|
import {Context} from "koa";
|
||||||
import service from "../service/QbService";
|
import service from "../service/QbService";
|
||||||
|
|
||||||
const router = {};
|
const router = {};
|
||||||
@ -7,7 +7,21 @@ const router = {};
|
|||||||
* 获取单个配置
|
* 获取单个配置
|
||||||
*/
|
*/
|
||||||
router["POST /qb/saveQbInfo"] = async function (ctx: Context) {
|
router["POST /qb/saveQbInfo"] = async function (ctx: Context) {
|
||||||
ctx.body = await service.saveAddress(ctx.request.body);
|
ctx.body = await service.saveAddress(ctx.request.body);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取qb配置
|
||||||
|
*/
|
||||||
|
router["GET /qb/config"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await service.getConfig();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取qb配置
|
||||||
|
*/
|
||||||
|
router["GET /qb/bt/list"] = async function (ctx: Context) {
|
||||||
|
ctx.body = await service.getBtList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,26 +1,29 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as process from "process";
|
||||||
|
|
||||||
//后台所在绝对路径
|
//后台所在绝对路径
|
||||||
const rootPath = path.resolve(__dirname, '..');
|
const rootPath = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
let config = {
|
let config = {
|
||||||
rootPath,
|
rootPath,
|
||||||
port: process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
dataPath: process.env.DATA_PATH ? process.env.DATA_PATH : path.join(rootPath, 'data'),
|
||||||
token: process.env.TOKEN ? process.env.TOKEN : null,
|
port: process.env.PORT ? parseInt(process.env.PORT) : 8089,
|
||||||
urlPrefix: '/openRenamer/api',
|
token: process.env.TOKEN ? process.env.TOKEN : null,
|
||||||
//是否为windows平台
|
urlPrefix: '/openRenamer/api',
|
||||||
isWindows: process.platform.toLocaleLowerCase().includes("win"),
|
//是否为windows平台
|
||||||
bodyLimit: {
|
isWindows: process.platform.toLocaleLowerCase().includes("win"),
|
||||||
formLimit: '2mb',
|
bodyLimit: {
|
||||||
urlencoded: true,
|
formLimit: '200mb',
|
||||||
multipart: true,
|
jsonLimit: '200mb',
|
||||||
formidable: {
|
urlencoded: true,
|
||||||
uploadDir: path.join(rootPath, 'files', 'temp', 'uploads'),
|
multipart: true,
|
||||||
keepExtenstions: true,
|
formidable: {
|
||||||
maxFieldsSize: 1024 * 1024
|
uploadDir: path.join(rootPath, 'files', 'temp', 'uploads'),
|
||||||
}
|
keepExtenstions: true,
|
||||||
},
|
maxFieldsSize: 1024 * 1024 * 200
|
||||||
publicPath: new Set(["POST/public/checkToken"])
|
}
|
||||||
|
},
|
||||||
|
publicPath: new Set(["POST/public/checkToken"])
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import RuleInterface from "./RuleInterface";
|
import RuleInterface from "./RuleInterface";
|
||||||
import FileObj from "../../vo/FileObj";
|
import FileObj from "../../vo/FileObj";
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import {getSeason} from "../../../util/MediaUtil";
|
||||||
|
|
||||||
|
|
||||||
let pattern = new RegExp(/s(eason)?(\d+)/);
|
let pattern = new RegExp(/s(eason)?(\d+)/);
|
||||||
@ -35,14 +36,12 @@ export default class InsertRule implements RuleInterface {
|
|||||||
deal(file: FileObj): void {
|
deal(file: FileObj): void {
|
||||||
//识别到的内容
|
//识别到的内容
|
||||||
let getStr = null;
|
let getStr = null;
|
||||||
let patternRes = path.basename(file.path).replace(/[ ]+/, "").toLocaleLowerCase().match(pattern);
|
let season = getSeason(path.basename(file.path));
|
||||||
if (this.type === 'season') {
|
if (this.type === 'season') {
|
||||||
if (patternRes && patternRes[2]) {
|
getStr = season;
|
||||||
getStr = patternRes[2];
|
|
||||||
}
|
|
||||||
} else if (this.type === 'name') {
|
} else if (this.type === 'name') {
|
||||||
let originName = null;
|
let originName = null;
|
||||||
if (patternRes && patternRes[2]) {
|
if (season && season.length > 0) {
|
||||||
//说明是剧集,取父文件夹的父文件夹名称
|
//说明是剧集,取父文件夹的父文件夹名称
|
||||||
originName = path.basename(path.resolve(file.path, '..'));
|
originName = path.basename(path.resolve(file.path, '..'));
|
||||||
} else {
|
} else {
|
||||||
@ -59,7 +58,7 @@ export default class InsertRule implements RuleInterface {
|
|||||||
}
|
}
|
||||||
} else if (this.type === 'eNum') {
|
} else if (this.type === 'eNum') {
|
||||||
let lowName = file.originName.toLocaleLowerCase().replace(/ /g, '')
|
let lowName = file.originName.toLocaleLowerCase().replace(/ /g, '')
|
||||||
.replace(/\d+[a-df-z]/g, '')//去除4k,1080p等
|
.replace(/\d+[kp]/g, '')//去除4k,1080p等
|
||||||
.replace(/[xh]\d+/g, '')//去除x264,h264等 ;
|
.replace(/[xh]\d+/g, '')//去除x264,h264等 ;
|
||||||
for (let i in eNumPatternArr) {
|
for (let i in eNumPatternArr) {
|
||||||
let patternRes = lowName.match(eNumPatternArr[i]);
|
let patternRes = lowName.match(eNumPatternArr[i]);
|
||||||
|
@ -1,92 +1,99 @@
|
|||||||
import RuleInterface from "./RuleInterface";
|
import RuleInterface from "./RuleInterface";
|
||||||
|
import {dealFileName} from "./RuleInterface";
|
||||||
import FileObj from "../../vo/FileObj";
|
import FileObj from "../../vo/FileObj";
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export default class DeleteRule implements RuleInterface {
|
export default class DeleteRule implements RuleInterface {
|
||||||
/**
|
/**
|
||||||
* 类别:deletePart:部分删除,deleteAll:全部删除
|
* 类别:deletePart:部分删除,deleteAll:全部删除
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
/**
|
/**
|
||||||
* 部分删除时的开始信息
|
* 部分删除时的开始信息
|
||||||
*/
|
*/
|
||||||
start: DeleteRuleItem;
|
start: DeleteRuleItem;
|
||||||
/**
|
/**
|
||||||
* 部分删除时的结束信息
|
* 部分删除时的结束信息
|
||||||
|
|
||||||
*/
|
*/
|
||||||
end: DeleteRuleItem;
|
end: DeleteRuleItem;
|
||||||
/**
|
/**
|
||||||
* 忽略拓展名,true:忽略,false:不忽略
|
* 忽略拓展名,true:忽略,false:不忽略
|
||||||
*/
|
*/
|
||||||
ignorePostfix: boolean;
|
ignorePostfix: boolean;
|
||||||
|
/*
|
||||||
|
* 是否区分大小写
|
||||||
|
*/
|
||||||
|
regI: boolean;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
this.type = data.type;
|
this.type = data.type;
|
||||||
this.start = new DeleteRuleItem(data.start);
|
this.regI = data.regI != undefined && data.regI;
|
||||||
this.end = new DeleteRuleItem(data.end);
|
this.start = new DeleteRuleItem(data.start, this.regI);
|
||||||
this.ignorePostfix = data.ignorePostfix;
|
this.end = new DeleteRuleItem(data.end, this.regI);
|
||||||
}
|
this.ignorePostfix = data.ignorePostfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deal(file: FileObj): void {
|
||||||
deal(file: FileObj): void {
|
let target = "";
|
||||||
if (this.type === 'deleteAll') {
|
if (this.type === 'deleteAll') {
|
||||||
file.realName = "";
|
target = "";
|
||||||
if (!this.ignorePostfix) {
|
} else {
|
||||||
file.expandName = "";
|
let str = file.realName + (this.ignorePostfix ? "" : file.expandName);
|
||||||
}
|
let startIndex = this.start.calIndex(str, false);
|
||||||
} else {
|
let endIndex = this.end.calIndex(str, true);
|
||||||
let str = file.realName + (this.ignorePostfix ? "" : file.expandName);
|
if (startIndex < 0 || endIndex < 0 || startIndex > endIndex) {
|
||||||
let startIndex = this.start.calIndex(str);
|
return;
|
||||||
let endIndex = this.end.calIndex(str);
|
}
|
||||||
if (startIndex < 0 || endIndex < 0) {
|
str = str.substring(0, startIndex) + str.substring(endIndex + 1);
|
||||||
return;
|
target = str;
|
||||||
}
|
}
|
||||||
str = str.substring(0, startIndex) + str.substring(endIndex + 1);
|
dealFileName(file, target, this.ignorePostfix);
|
||||||
if (this.ignorePostfix) {
|
}
|
||||||
file.realName = str;
|
|
||||||
} else {
|
|
||||||
file.expandName = path.extname(str);
|
|
||||||
if (file.expandName.length > 0) {
|
|
||||||
file.realName = str.substring(0, str.lastIndexOf("."));
|
|
||||||
} else {
|
|
||||||
file.realName = str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file.name = file.realName + file.expandName;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteRuleItem {
|
class DeleteRuleItem {
|
||||||
/**
|
/**
|
||||||
* location:位置,text:文本,end:直到末尾
|
* location:位置,text:文本,end:直到末尾
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
/**
|
/**
|
||||||
* 对应的值
|
* 对应的值
|
||||||
*/
|
*/
|
||||||
value: string;
|
value: string;
|
||||||
|
/**
|
||||||
|
* 正则对象
|
||||||
|
*/
|
||||||
|
reg: RegExp;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any, regI: boolean) {
|
||||||
this.type = data.type;
|
this.type = data.type;
|
||||||
this.value = data.value;
|
this.value = data.value;
|
||||||
}
|
if (this.type === 'reg') {
|
||||||
|
this.reg = regI ? new RegExp(this.value) : new RegExp(this.value, 'i');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算位置
|
* 计算位置
|
||||||
*/
|
* @param str 字符串
|
||||||
calIndex(str: string): number {
|
* @param end 是否末尾计算
|
||||||
if (this.type === 'location') {
|
*/
|
||||||
return parseInt(this.value) - 1;
|
calIndex(str: string, end: boolean): number {
|
||||||
} else if (this.type === 'text') {
|
if (this.type === 'location') {
|
||||||
return str.indexOf(this.value);
|
let val = parseInt(this.value);
|
||||||
} else if (this.type === 'end') {
|
return val > 0 ? val - 1 : str.length + val;
|
||||||
return str.length - 1;
|
} else if (this.type === 'text') {
|
||||||
}
|
let index = str.indexOf(this.value);
|
||||||
return -1;
|
return index + (end ? this.value.length - 1 : 0);
|
||||||
}
|
} else if (this.type === 'end') {
|
||||||
|
return str.length - 1;
|
||||||
|
} else if (this.type === 'reg') {
|
||||||
|
let res = this.reg.exec(str);
|
||||||
|
return res == null ? -1 : (res.index + (end ? res[0].length - 1 : 0));
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,98 +1,95 @@
|
|||||||
import RuleInterface from "./RuleInterface";
|
import RuleInterface from "./RuleInterface";
|
||||||
import FileObj from "../../vo/FileObj";
|
import FileObj from "../../vo/FileObj";
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import {getSeason} from "../../../util/MediaUtil";
|
||||||
|
|
||||||
|
|
||||||
let pattern = new RegExp(/s(eason)?(\d+)/);
|
|
||||||
export default class InsertRule implements RuleInterface {
|
export default class InsertRule implements RuleInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插入内容
|
* 插入内容
|
||||||
*/
|
*/
|
||||||
insertContent: string;
|
insertContent: string;
|
||||||
/**
|
/**
|
||||||
* 操作类别,front:前缀,backend:后缀,at:位置,replace:替换当前文件名
|
* 操作类别,front:前缀,backend:后缀,at:位置,replace:替换当前文件名
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
/**
|
/**
|
||||||
* 当type为at,时的位置,从1开始
|
* 当type为at,时的位置,从1开始
|
||||||
*/
|
*/
|
||||||
atInput: number;
|
atInput: number;
|
||||||
/**
|
/**
|
||||||
* 当type为at,时的方向,true:从右到左,false:从左到右
|
* 当type为at,时的方向,true:从右到左,false:从左到右
|
||||||
*/
|
*/
|
||||||
atIsRightToleft: boolean;
|
atIsRightToleft: boolean;
|
||||||
/**
|
/**
|
||||||
* 忽略拓展名,true:忽略,false:不忽略
|
* 忽略拓展名,true:忽略,false:不忽略
|
||||||
*/
|
*/
|
||||||
ignorePostfix: boolean;
|
ignorePostfix: boolean;
|
||||||
/**
|
/**
|
||||||
自动识别季号
|
自动识别季号
|
||||||
*/
|
*/
|
||||||
autoSeason: boolean;
|
autoSeason: boolean;
|
||||||
/**
|
/**
|
||||||
后缀过滤是否开启
|
后缀过滤是否开启
|
||||||
*/
|
*/
|
||||||
endFilter: boolean;
|
endFilter: boolean;
|
||||||
/**
|
/**
|
||||||
有效后缀
|
有效后缀
|
||||||
*/
|
*/
|
||||||
validEnd: Array<String>;
|
validEnd: Array<String>;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
this.insertContent = data.insertContent;
|
this.insertContent = data.insertContent;
|
||||||
this.type = data.type;
|
this.type = data.type;
|
||||||
this.atInput = data.atInput;
|
this.atInput = data.atInput;
|
||||||
this.atIsRightToleft = data.atIsRightToleft;
|
this.atIsRightToleft = data.atIsRightToleft;
|
||||||
this.ignorePostfix = data.ignorePostfix;
|
this.ignorePostfix = data.ignorePostfix;
|
||||||
this.autoSeason = data.autoSeason;
|
this.autoSeason = data.autoSeason;
|
||||||
this.endFilter = data.endFilter;
|
this.endFilter = data.endFilter;
|
||||||
this.validEnd = data.validEnd;
|
this.validEnd = data.validEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
deal(file: FileObj): void {
|
deal(file: FileObj): void {
|
||||||
if (this.endFilter && file.expandName.length > 0 && this.validEnd.indexOf(file.expandName.substring(1)) == -1) {
|
if (this.endFilter && file.expandName.length > 0 && this.validEnd.indexOf(file.expandName.substring(1)) == -1) {
|
||||||
//拓展名不符,跳过
|
//拓展名不符,跳过
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let str = this.ignorePostfix ? file.realName : file.name;
|
let str = this.ignorePostfix ? file.realName : file.name;
|
||||||
let season = '';
|
let season = '';
|
||||||
|
|
||||||
if (this.autoSeason) {
|
if (this.autoSeason) {
|
||||||
let patternRes = path.basename(file.path).replace(/[ ]+/, "").toLocaleLowerCase().match(pattern);
|
season = getSeason(path.basename(file.path));
|
||||||
if (patternRes && patternRes[2]) {
|
}
|
||||||
season = patternRes[2];
|
switch (this.type) {
|
||||||
}
|
case "front":
|
||||||
}
|
str = this.insertContent + season + str;
|
||||||
switch (this.type) {
|
break;
|
||||||
case "front":
|
case "backend":
|
||||||
str = this.insertContent + season + str;
|
str = str + this.insertContent + season;
|
||||||
break;
|
break;
|
||||||
case "backend":
|
case "at":
|
||||||
str = str + this.insertContent + season;
|
let index = this.atIsRightToleft ? str.length - this.atInput + 1 : this.atInput - 1;
|
||||||
break;
|
str = str.substring(0, index) + this.insertContent + season + str.substring(index);
|
||||||
case "at":
|
break;
|
||||||
let index = this.atIsRightToleft ? str.length - this.atInput + 1 : this.atInput - 1;
|
case "replace":
|
||||||
str = str.substring(0, index) + this.insertContent + season + str.substring(index);
|
str = this.insertContent + season;
|
||||||
break;
|
break;
|
||||||
case "replace":
|
}
|
||||||
str = this.insertContent + season;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (this.ignorePostfix) {
|
if (this.ignorePostfix) {
|
||||||
file.realName = str;
|
file.realName = str;
|
||||||
} else {
|
} else {
|
||||||
file.expandName = path.extname(str);
|
file.expandName = path.extname(str);
|
||||||
if (file.expandName.length > 0) {
|
if (file.expandName.length > 0) {
|
||||||
file.realName = str.substring(0, str.lastIndexOf("."));
|
file.realName = str.substring(0, str.lastIndexOf("."));
|
||||||
} else {
|
} else {
|
||||||
file.realName = str;
|
file.realName = str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file.name = file.realName + file.expandName;
|
file.name = file.realName + file.expandName;
|
||||||
}
|
}
|
||||||
}
|
}
|
112
openRenamerBackend/entity/bo/rules/ReplaceRule.ts
Normal file
112
openRenamerBackend/entity/bo/rules/ReplaceRule.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import RuleInterface from "./RuleInterface";
|
||||||
|
import * as ValUtil from "../../../util/ValUtil";
|
||||||
|
import FileObj from "../../vo/FileObj";
|
||||||
|
import {dealFileName} from './RuleInterface';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
|
||||||
|
export default class ReplaceRule implements RuleInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1:替换第一个,2:替换最后一个,3:全部替换
|
||||||
|
*/
|
||||||
|
type: number;
|
||||||
|
/**
|
||||||
|
* 源
|
||||||
|
*/
|
||||||
|
source: string;
|
||||||
|
/**
|
||||||
|
* 目标
|
||||||
|
*/
|
||||||
|
target: string;
|
||||||
|
/**
|
||||||
|
* 是否正则模式
|
||||||
|
*/
|
||||||
|
regFlag: boolean;
|
||||||
|
/**
|
||||||
|
* 是否区分大小写
|
||||||
|
*/
|
||||||
|
regI: boolean;
|
||||||
|
/**
|
||||||
|
* 是否护理拓展名
|
||||||
|
*/
|
||||||
|
ignorePostfix: boolean;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.type = data.type;
|
||||||
|
this.source = data.source;
|
||||||
|
this.target = data.target;
|
||||||
|
this.regFlag = ValUtil.nullToDefault(data.regFlag, false);
|
||||||
|
this.regI = ValUtil.nullToDefault(data.regI, false);
|
||||||
|
this.ignorePostfix = ValUtil.nullToDefault(data.ignorePostfix, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deal(file: FileObj): void {
|
||||||
|
let targetStr = this.ignorePostfix ? file.realName : file.name;
|
||||||
|
let res = this.regFlag ? this.dealReg(targetStr) : this.dealNoReg(targetStr);
|
||||||
|
dealFileName(file, res, this.ignorePostfix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private dealNoReg(targetStr: string): string {
|
||||||
|
let start = 0;
|
||||||
|
let arr: number[] = [];
|
||||||
|
for (let i = 0; i < (this.type == 1 ? 1 : 1000); i++) {
|
||||||
|
let one = targetStr.indexOf(this.source, start);
|
||||||
|
if (one == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
arr.push(one);
|
||||||
|
start = one + this.source.length;
|
||||||
|
}
|
||||||
|
if (arr.length == 0) {
|
||||||
|
return targetStr;
|
||||||
|
}
|
||||||
|
let res = "";
|
||||||
|
let needDealArr: number[] = this.type === 1 ? [arr[0]] : this.type === 2 ? [arr[arr.length - 1]] : arr;
|
||||||
|
let lastIndex = 0;
|
||||||
|
for (let i = 0; i < needDealArr.length; i++) {
|
||||||
|
res += targetStr.substring(lastIndex, needDealArr[i]) + this.target;
|
||||||
|
lastIndex = needDealArr[i] + this.source.length;
|
||||||
|
}
|
||||||
|
res += targetStr.substring(lastIndex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private dealReg(targetStr: string): string {
|
||||||
|
let templateReg = new RegExp("#\{group(\\d+\)}", "g");
|
||||||
|
let templateArr: string[][] = [];
|
||||||
|
while (true) {
|
||||||
|
let one = templateReg.exec(this.target);
|
||||||
|
if (one == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
templateArr.push([one[0], one[1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let reg = new RegExp(this.source, this.regI ? "g" : "ig");
|
||||||
|
let arr: RegExpExecArray[] = [];
|
||||||
|
for (let i = 0; i < (this.type == 1 ? 1 : 1000); i++) {
|
||||||
|
let one = reg.exec(targetStr);
|
||||||
|
if (one == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
arr.push(one);
|
||||||
|
}
|
||||||
|
if (arr.length == 0) {
|
||||||
|
return targetStr;
|
||||||
|
}
|
||||||
|
let res = "";
|
||||||
|
let needDealReg: RegExpExecArray[] = this.type === 1 ? [arr[0]] : this.type === 2 ? [arr[arr.length - 1]] : arr;
|
||||||
|
let lastIndex = 0;
|
||||||
|
for (let i = 0; i < needDealReg.length; i++) {
|
||||||
|
let reg = needDealReg[i];
|
||||||
|
let target = this.target;
|
||||||
|
templateArr.forEach(item => target = target.replace(item[0], ValUtil.nullToDefault(reg[parseInt(item[1])], '')));
|
||||||
|
res += targetStr.substring(lastIndex, reg.index) + target;
|
||||||
|
lastIndex = reg.index + reg[0].length;
|
||||||
|
}
|
||||||
|
res += targetStr.substring(lastIndex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,27 @@
|
|||||||
import FileObj from "../../vo/FileObj";
|
import FileObj from "../../vo/FileObj";
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
export default interface RuleInterface {
|
export default interface RuleInterface {
|
||||||
|
|
||||||
deal(file: FileObj): void;
|
deal(file: FileObj): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新处理文件名
|
||||||
|
* @param file
|
||||||
|
* @param newFileName
|
||||||
|
* @param ignorePostfix
|
||||||
|
*/
|
||||||
|
export function dealFileName(file: FileObj, newFileName: string, ignorePostfix: boolean) {
|
||||||
|
if (ignorePostfix) {
|
||||||
|
file.realName = newFileName;
|
||||||
|
} else {
|
||||||
|
file.expandName = path.extname(newFileName);
|
||||||
|
if (file.expandName.length > 0) {
|
||||||
|
file.realName = newFileName.substring(0, newFileName.lastIndexOf("."));
|
||||||
|
} else {
|
||||||
|
file.realName = newFileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.name = file.realName + file.expandName;
|
||||||
}
|
}
|
@ -3,78 +3,85 @@ import FileObj from "../../vo/FileObj";
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export default class InsertRule implements RuleInterface {
|
export default class InsertRule implements RuleInterface {
|
||||||
/**
|
/**
|
||||||
* 开始位置
|
* 开始位置
|
||||||
*/
|
*/
|
||||||
start: number;
|
start: number;
|
||||||
/**
|
/**
|
||||||
* 记录当前的值是多少
|
* 记录当前的值是多少
|
||||||
*/
|
*/
|
||||||
currentIndex: number;
|
currentIndexMap: Map<string, number>;
|
||||||
/**
|
/**
|
||||||
* 增量
|
* 增量
|
||||||
*/
|
*/
|
||||||
increment: number;
|
increment: number;
|
||||||
/**
|
/**
|
||||||
* 是否填充0
|
* 是否填充0
|
||||||
*/
|
*/
|
||||||
addZero: boolean;
|
addZero: boolean;
|
||||||
/**
|
/**
|
||||||
* 填充后长度
|
* 填充后长度
|
||||||
*/
|
*/
|
||||||
numLength: number;
|
numLength: number;
|
||||||
/**
|
/**
|
||||||
* 插入位置,front:前缀,backend:后缀,at:位置
|
* 插入位置,front:前缀,backend:后缀,at:位置
|
||||||
*/
|
*/
|
||||||
insertType: string;
|
insertType: string;
|
||||||
/**
|
/**
|
||||||
* 插入的位置
|
* 插入的位置
|
||||||
*/
|
*/
|
||||||
insertValue: number;
|
insertValue: number;
|
||||||
/**
|
/**
|
||||||
* 忽略拓展名
|
* 忽略拓展名
|
||||||
*/
|
*/
|
||||||
ignorePostfix: boolean;
|
ignorePostfix: boolean;
|
||||||
|
/**
|
||||||
|
* 拓展名分组
|
||||||
|
*/
|
||||||
|
postfixGroup: boolean;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
this.start = data.start;
|
this.start = data.start;
|
||||||
this.currentIndex = data.start;
|
this.currentIndexMap = new Map<string, number>();
|
||||||
this.increment = data.increment;
|
this.increment = data.increment;
|
||||||
this.addZero = data.addZero;
|
this.addZero = data.addZero;
|
||||||
this.numLength = data.numLength;
|
this.numLength = data.numLength;
|
||||||
this.insertType = data.insertType;
|
this.insertType = data.insertType;
|
||||||
this.insertValue = data.insertValue;
|
this.insertValue = data.insertValue;
|
||||||
this.ignorePostfix = data.ignorePostfix;
|
this.ignorePostfix = data.ignorePostfix;
|
||||||
}
|
this.postfixGroup = data.postfixGroup;
|
||||||
|
}
|
||||||
|
|
||||||
deal(file: FileObj): void {
|
deal(file: FileObj): void {
|
||||||
let length = this.currentIndex.toString().length;
|
let expand = this.postfixGroup ? file.expandName : "";
|
||||||
let numStr = (this.addZero && this.numLength > length ? "0".repeat(this.numLength - length) : "") + this.currentIndex;
|
let currentIndex = this.currentIndexMap.has(expand) ? this.currentIndexMap.get(expand) : this.start;
|
||||||
let str = this.ignorePostfix ? file.realName : file.name;
|
let length = currentIndex.toString().length;
|
||||||
switch (this.insertType) {
|
let numStr = (this.addZero && this.numLength > length ? "0".repeat(this.numLength - length) : "") + currentIndex;
|
||||||
case "front":
|
let str = this.ignorePostfix ? file.realName : file.name;
|
||||||
str = numStr + str;
|
switch (this.insertType) {
|
||||||
break;
|
case "front":
|
||||||
case "backend":
|
str = numStr + str;
|
||||||
str = str + numStr;
|
break;
|
||||||
break;
|
case "backend":
|
||||||
case "at":
|
str = str + numStr;
|
||||||
str = str.substring(0, this.insertValue - 1) + numStr + str.substring(this.insertValue - 1);
|
break;
|
||||||
break;
|
case "at":
|
||||||
}
|
str = str.substring(0, this.insertValue - 1) + numStr + str.substring(this.insertValue - 1);
|
||||||
this.currentIndex += this.increment;
|
break;
|
||||||
|
}
|
||||||
|
this.currentIndexMap.set(expand, currentIndex + this.increment);
|
||||||
|
|
||||||
if (this.ignorePostfix) {
|
if (this.ignorePostfix) {
|
||||||
file.realName = str;
|
file.realName = str;
|
||||||
} else {
|
} else {
|
||||||
file.expandName = path.extname(str);
|
file.expandName = path.extname(str);
|
||||||
if (file.expandName.length > 0) {
|
if (file.expandName.length > 0) {
|
||||||
file.realName = str.substring(0, str.lastIndexOf("."));
|
file.realName = str.substring(0, str.lastIndexOf("."));
|
||||||
} else {
|
} else {
|
||||||
file.realName = str;
|
file.realName = str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file.name = file.realName + file.expandName;
|
file.name = file.realName + file.expandName;
|
||||||
}
|
}
|
||||||
}
|
}
|
32
openRenamerBackend/entity/bo/rules/TranslateRole.ts
Normal file
32
openRenamerBackend/entity/bo/rules/TranslateRole.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import RuleInterface from "./RuleInterface";
|
||||||
|
import FileObj from "../../vo/FileObj";
|
||||||
|
import * as TranslateUtil from "../../../util/TranslateUtil";
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
|
||||||
|
export default class TranslateRole implements RuleInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1:简体转繁体 2:繁体转简体
|
||||||
|
*/
|
||||||
|
type: number;
|
||||||
|
/**
|
||||||
|
* 0、繁体中文,1、港澳繁体,2、台湾正体
|
||||||
|
*/
|
||||||
|
traditionalType: number;
|
||||||
|
|
||||||
|
constructor(data: any) {
|
||||||
|
this.type = data.type;
|
||||||
|
this.traditionalType = data.traditionalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deal(file: FileObj): void {
|
||||||
|
if (this.type == 1) {
|
||||||
|
file.realName = TranslateUtil.toTraditionalChinese(file.realName, this.traditionalType);
|
||||||
|
} else if (this.type == 2) {
|
||||||
|
file.realName = TranslateUtil.toSimplifiedChinese(file.realName, this.traditionalType);
|
||||||
|
}
|
||||||
|
file.name = file.realName + file.expandName;
|
||||||
|
}
|
||||||
|
}
|
28
openRenamerBackend/entity/dto/BtListItemDto.ts
Normal file
28
openRenamerBackend/entity/dto/BtListItemDto.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export default interface BtListItemDto {
|
||||||
|
hash: string;
|
||||||
|
/**
|
||||||
|
* 添加时间
|
||||||
|
*/
|
||||||
|
added_on: number;
|
||||||
|
/**
|
||||||
|
* left bytes num
|
||||||
|
*/
|
||||||
|
amount_left: number;
|
||||||
|
/**
|
||||||
|
* Percentage of file pieces currently available
|
||||||
|
*/
|
||||||
|
availability: number;
|
||||||
|
category: string;
|
||||||
|
/**
|
||||||
|
* Amount of transfer data completed (bytes)
|
||||||
|
*/
|
||||||
|
completed: number;
|
||||||
|
/**
|
||||||
|
* Time (Unix Epoch) when the torrent completed
|
||||||
|
*/
|
||||||
|
completion_on: number;
|
||||||
|
/**
|
||||||
|
* Absolute path of torrent content (root path for multifile torrents, absolute file path for singlefile torrents)
|
||||||
|
*/
|
||||||
|
content_path: string;
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
export default interface QbAddressDto {
|
|
||||||
address: string;
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
22
openRenamerBackend/entity/dto/QbConfigDto.ts
Normal file
22
openRenamerBackend/entity/dto/QbConfigDto.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export default interface QbConfigDto {
|
||||||
|
address: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
valid: boolean;
|
||||||
|
/**
|
||||||
|
* qb version,null if config is error
|
||||||
|
*/
|
||||||
|
version: string;
|
||||||
|
/**
|
||||||
|
* Qbittorrent's download
|
||||||
|
*/
|
||||||
|
qbDownloadPath: string;
|
||||||
|
/**
|
||||||
|
* Qbittorrent's download path corresponds to current system path
|
||||||
|
*/
|
||||||
|
renameQbDownloadPath: string;
|
||||||
|
/**
|
||||||
|
* config path to select convenient
|
||||||
|
*/
|
||||||
|
configPaths: Array<string>;
|
||||||
|
}
|
@ -3,21 +3,22 @@ import {isVideo, isSub, isNfo} from "../../util/MediaUtil"
|
|||||||
|
|
||||||
export default class FileObj {
|
export default class FileObj {
|
||||||
/**
|
/**
|
||||||
* 文件名
|
* 变更后的文件名(包含拓展名)
|
||||||
*/
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
/**
|
/**
|
||||||
原始名字
|
* 去掉拓展名后的名字(不包含拓展名)
|
||||||
|
*/
|
||||||
|
realName: string;
|
||||||
|
/**
|
||||||
|
原始文件名(不变)
|
||||||
*/
|
*/
|
||||||
originName: string;
|
originName: string;
|
||||||
/**
|
/**
|
||||||
* 拓展名
|
* 拓展名(最新的拓展名,每次应用规则后重新计算)
|
||||||
*/
|
*/
|
||||||
expandName: string;
|
expandName: string;
|
||||||
/**
|
|
||||||
* 去掉拓展名后的名字
|
|
||||||
*/
|
|
||||||
realName: string;
|
|
||||||
/**
|
/**
|
||||||
* 所属路径
|
* 所属路径
|
||||||
*/
|
*/
|
||||||
|
@ -2,34 +2,41 @@ import DeleteRule from "../bo/rules/DeleteRule";
|
|||||||
import InsertRule from "../bo/rules/InsertRule";
|
import InsertRule from "../bo/rules/InsertRule";
|
||||||
import SerializationRule from "../bo/rules/SerializationRule";
|
import SerializationRule from "../bo/rules/SerializationRule";
|
||||||
import AutoRule from "../bo/rules/AutoRule";
|
import AutoRule from "../bo/rules/AutoRule";
|
||||||
|
import ReplaceRule from "../bo/rules/ReplaceRule";
|
||||||
|
import TranslateRole from "../bo/rules/TranslateRole";
|
||||||
|
|
||||||
export default class RuleObj {
|
export default class RuleObj {
|
||||||
type: string;
|
type: string;
|
||||||
message: string;
|
message: string;
|
||||||
/**
|
/**
|
||||||
* 具体参数
|
* 具体参数
|
||||||
*/
|
*/
|
||||||
data: any;
|
data: any;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
this.type = data.type;
|
this.type = data.type;
|
||||||
this.message = data.message;
|
this.message = data.message;
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case "delete":
|
case "delete":
|
||||||
this.data = new DeleteRule(data.data);
|
this.data = new DeleteRule(data.data);
|
||||||
break;
|
break;
|
||||||
case "insert":
|
case "insert":
|
||||||
this.data = new InsertRule(data.data);
|
this.data = new InsertRule(data.data);
|
||||||
break;
|
break;
|
||||||
case "serialization":
|
case "serialization":
|
||||||
this.data = new SerializationRule(data.data);
|
this.data = new SerializationRule(data.data);
|
||||||
break;
|
break;
|
||||||
case "auto":
|
case "auto":
|
||||||
this.data = new AutoRule(data.data);
|
this.data = new AutoRule(data.data);
|
||||||
break;
|
break;
|
||||||
default:
|
case "replace":
|
||||||
throw new Error("不支持的规则:" + this.type);
|
this.data = new ReplaceRule(data.data);
|
||||||
|
break;
|
||||||
}
|
case "translate":
|
||||||
}
|
this.data = new TranslateRole(data.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("不支持的规则:" + this.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,8 +9,8 @@ import handleError from "./middleware/handleError";
|
|||||||
import init from "./middleware/init";
|
import init from "./middleware/init";
|
||||||
import SqliteUtil from './util/SqliteHelper';
|
import SqliteUtil from './util/SqliteHelper';
|
||||||
import log from './util/LogUtil';
|
import log from './util/LogUtil';
|
||||||
import {updateQbInfo} from './util/QbApiUtil';
|
import QbService from './service/QbService';
|
||||||
|
import qbService from "./service/QbService";
|
||||||
|
|
||||||
console.log(config);
|
console.log(config);
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ app.use(handleError);
|
|||||||
app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
app.use(RouterMW(router, path.join(config.rootPath, "dist/api")));
|
||||||
(async () => {
|
(async () => {
|
||||||
await SqliteUtil.createPool();
|
await SqliteUtil.createPool();
|
||||||
await updateQbInfo(null, null);
|
await qbService.init();
|
||||||
app.listen(config.port);
|
app.listen(config.port);
|
||||||
log.info(`server listened `, config.port);
|
log.info(`server listened `, config.port);
|
||||||
})();
|
})();
|
||||||
|
@ -9,22 +9,20 @@
|
|||||||
"author": "fxb",
|
"author": "fxb",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/fs-extra": "^5.0.4",
|
"@types/fs-extra": "5.0.4",
|
||||||
"@types/koa": "^2.0.47",
|
"@types/koa": "2.13.12",
|
||||||
"@types/node": "^11.13.4",
|
"@types/node": "11.13.4",
|
||||||
"axios": "^0.21.4",
|
"axios": "0.21.4",
|
||||||
"fs-extra": "^7.0.0",
|
"fs-extra": "7.0.0",
|
||||||
"koa": "^2.5.3",
|
"koa": "2.5.3",
|
||||||
"koa-body": "^4.0.4",
|
"koa-body": "4.0.4",
|
||||||
"koa-router": "^7.4.0",
|
"koa-router": "7.4.0",
|
||||||
"koa-static": "^5.0.0",
|
"koa-static": "5.0.0",
|
||||||
"koa2-cors": "^2.0.6",
|
"koa2-cors": "2.0.6",
|
||||||
"log4js": "^6.3.0",
|
"log4js": "6.3.0",
|
||||||
"moment": "^2.22.2",
|
"moment": "2.22.2",
|
||||||
"mysql2": "^2.2.5",
|
"sqlite": "4.0.23",
|
||||||
"sqlite": "^4.0.23",
|
"sqlite3": "5.0.2",
|
||||||
"sqlite3": "^5.0.2",
|
"uuid": "3.3.2"
|
||||||
"uuid": "^3.3.2",
|
|
||||||
"winston": "^3.1.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2014
openRenamerBackend/pnpm-lock.yaml
generated
2014
openRenamerBackend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,52 @@
|
|||||||
import QbAddressDto from "../entity/dto/QbAddressDto";
|
import QbConfigDto from "../entity/dto/QbConfigDto";
|
||||||
import { tryLogin, updateQbInfo } from '../util/QbApiUtil';
|
import {tryLogin, get, post, updateQbInfo, getQbInfo} from '../util/QbApiUtil';
|
||||||
import GlobalConfigService from "./GlobalConfigService";
|
import GlobalConfigService from "./GlobalConfigService";
|
||||||
import GlobalConfig from "../entity/po/GlobalConfig";
|
import GlobalConfig from "../entity/po/GlobalConfig";
|
||||||
|
import BtListItemDto from "../entity/dto/BtListItemDto";
|
||||||
|
|
||||||
class QbService {
|
class QbService {
|
||||||
|
|
||||||
static async saveAddress(body: QbAddressDto) {
|
/**
|
||||||
await tryLogin(body.address, body.username, body.password, false);
|
* 保存地址
|
||||||
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbAddress", body.address, "qbAdress"));
|
* @param body
|
||||||
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbUsername", body.username, ""));
|
*/
|
||||||
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbPassword", body.password, ""));
|
static async saveAddress(body: QbConfigDto): Promise<QbConfigDto> {
|
||||||
await updateQbInfo(body, true);
|
if (body.address.endsWith("/")) {
|
||||||
}
|
body.address = body.address.substring(0, body.address.length - 1);
|
||||||
|
}
|
||||||
|
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbConfig", JSON.stringify(body), "qb config"));
|
||||||
|
updateQbInfo(body);
|
||||||
|
body.valid = await tryLogin();
|
||||||
|
body.version = body ? (await get("/app/version", null)) : null;
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
a
|
||||||
|
/**
|
||||||
|
* 获取当前配置
|
||||||
|
*/
|
||||||
|
static async getConfig(): Promise<QbConfigDto> {
|
||||||
|
return getQbInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get torrents list from qb
|
||||||
|
*/
|
||||||
|
static async getBtList(): Promise<Array<BtListItemDto>> {
|
||||||
|
let res = await get("/api/v2/torrents/info?category=&sort=added_on", null);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
static async init() {
|
||||||
|
let config = await GlobalConfigService.getVal("qbConfig");
|
||||||
|
let qbInfo: QbConfigDto = config == null ? {} : JSON.parse(config);
|
||||||
|
updateQbInfo(qbInfo);
|
||||||
|
qbInfo.valid = await tryLogin();
|
||||||
|
qbInfo.version = qbInfo.valid ? (await get("/app/version", null)) : null;
|
||||||
|
return qbInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default QbService;
|
export default QbService;
|
||||||
|
@ -14,10 +14,10 @@ class RenamerService {
|
|||||||
for (let i in fileList) {
|
for (let i in fileList) {
|
||||||
let obj = fileList[i];
|
let obj = fileList[i];
|
||||||
ruleObjs.forEach(item => (item.data as RuleInterface).deal(obj));
|
ruleObjs.forEach(item => (item.data as RuleInterface).deal(obj));
|
||||||
if (newNameSet.has(obj.name)) {
|
if (newNameSet.has(obj.path + obj.name)) {
|
||||||
obj.errorMessage = "重名";
|
obj.errorMessage = "重名";
|
||||||
}
|
}
|
||||||
newNameSet.add(obj.name);
|
newNameSet.add(obj.path + obj.name);
|
||||||
}
|
}
|
||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
INSERT INTO application_rule (createdDate, updatedDate, name, comment, content, defaults) VALUES (1669648328180, 1678279879110, '推荐剧集模板', '此模板为系统创建12121212', '[{"type":"delete","message":"删除:全部删除","data":{"type":"deleteAll","start":{"type":"location","value":"1"},"end":{"type":"location","value":"1"},"ignorePostfix":true},"checked":false},{"type":"auto","message":"自动识别:\"剧名/电影名识别\";","data":{"type":"name","frontAdd":"","endAdd":"","eNumWidth":2},"checked":false},{"type":"auto","message":"自动识别:\"季号识别\";前缀添加:.s","data":{"type":"season","frontAdd":".s","endAdd":"","eNumWidth":2},"checked":false},{"type":"auto","message":"自动识别:\"集数识别\";集数宽度:3;前缀添加:e","data":{"type":"eNum","frontAdd":"e","endAdd":"","eNumWidth":3},"checked":false},{"type":"auto","message":"自动识别:\"分辨率识别\";前缀添加:.","data":{"type":"resolution","frontAdd":".","endAdd":"","eNumWidth":2},"checked":false}]', 0);
|
INSERT INTO application_rule (createdDate, updatedDate, name, comment, content ) VALUES (1669648328180, 1678279879110, '推荐剧集模板', '此模板为系统创建12121212', '[{"type":"delete","message":"删除:全部删除","data":{"type":"deleteAll","start":{"type":"location","value":"1"},"end":{"type":"location","value":"1"},"ignorePostfix":true},"checked":false},{"type":"auto","message":"自动识别:\"剧名/电影名识别\";","data":{"type":"name","frontAdd":"","endAdd":"","eNumWidth":2},"checked":false},{"type":"auto","message":"自动识别:\"季号识别\";前缀添加:.s","data":{"type":"season","frontAdd":".s","endAdd":"","eNumWidth":2},"checked":false},{"type":"auto","message":"自动识别:\"集数识别\";集数宽度:3;前缀添加:e","data":{"type":"eNum","frontAdd":"e","endAdd":"","eNumWidth":3},"checked":false},{"type":"auto","message":"自动识别:\"分辨率识别\";前缀添加:.","data":{"type":"resolution","frontAdd":".","endAdd":"","eNumWidth":2},"checked":false}]');
|
||||||
|
@ -1 +1 @@
|
|||||||
npm install -g pnpm typescript --registry https://registry.npmmirror.com && pnpm install --registry https://registry.npmmirror.com && tsc && node dist/index.js
|
pnpm install --registry https://registry.npmmirror.com && tsc && node dist/index.js
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"rootDir": "./",
|
"rootDir": "./",
|
||||||
"watch": false,
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictNullChecks": false,
|
"strictNullChecks": false,
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
const path = require("path")
|
||||||
const videoSet = new Set(["flv", 'avi', 'wmv', 'dat', 'vob', 'mpg', 'mpeg', 'mp4', '3gp', '3g2', 'mkv', 'rm', 'rmvb', 'mov', 'qt', 'ogg', 'ogv', 'oga', 'mod']);
|
const videoSet = new Set(["flv", 'avi', 'wmv', 'dat', 'vob', 'mpg', 'mpeg', 'mp4', '3gp', '3g2', 'mkv', 'rm', 'rmvb', 'mov', 'qt', 'ogg', 'ogv', 'oga', 'mod']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,3 +35,50 @@ export function isNfo(str: string) {
|
|||||||
}
|
}
|
||||||
return "nfo" == str;
|
return "nfo" == str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pattern1 = new RegExp(/s(eason)?\.?(\d+)/);
|
||||||
|
let pattern2 = new RegExp(/(\d+)/);
|
||||||
|
let pattern3 = new RegExp(/([一二三四五六七八九十]+)/);
|
||||||
|
let chineseNumMap = {
|
||||||
|
"一": "1",
|
||||||
|
"二": "2",
|
||||||
|
"三": "3",
|
||||||
|
"四": "4",
|
||||||
|
"五": "5",
|
||||||
|
"六": "6",
|
||||||
|
"七": "7",
|
||||||
|
"八": "8",
|
||||||
|
"九": "9",
|
||||||
|
"十": "1"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别季号
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
export function getSeason(name: string): string {
|
||||||
|
name = name.replace(/[ ]+/, "").toLocaleLowerCase();
|
||||||
|
let patternRes = name.match(pattern1);
|
||||||
|
if (patternRes && patternRes[2]) {
|
||||||
|
return patternRes[2];
|
||||||
|
}
|
||||||
|
patternRes = name.match(pattern2);
|
||||||
|
if (patternRes && patternRes[1]) {
|
||||||
|
return patternRes[1];
|
||||||
|
}
|
||||||
|
//中文支持
|
||||||
|
patternRes = name.match(pattern3);
|
||||||
|
if (patternRes && patternRes[1]) {
|
||||||
|
let str = patternRes[1];
|
||||||
|
let strs = str.split("");
|
||||||
|
if (strs.length == 1) {
|
||||||
|
return str == '十' ? "10" : chineseNumMap[str];
|
||||||
|
} else if (strs.length == 2) {
|
||||||
|
return strs[0] == '十' ? ("1" + chineseNumMap[strs[1]]) : chineseNumMap[strs[0]] + "0";
|
||||||
|
} else if (strs.length == 3) {
|
||||||
|
return chineseNumMap[strs[0]] + chineseNumMap[strs[2]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
@ -1,108 +0,0 @@
|
|||||||
import mysql from "mysql2/promise";
|
|
||||||
import config from '../config';
|
|
||||||
import * as fs from "fs-extra";
|
|
||||||
import * as path from 'path';
|
|
||||||
import log from '../util/LogUtil';
|
|
||||||
|
|
||||||
const HISTORY_NAME = "history.json";
|
|
||||||
|
|
||||||
interface Res {
|
|
||||||
rows: any;
|
|
||||||
fields: mysql.FieldPacket;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MysqlUtil {
|
|
||||||
public static pool: mysql.Pool = null;
|
|
||||||
|
|
||||||
static async createPool(mysqlConfig: any) {
|
|
||||||
MysqlUtil.pool = await mysql.createPool(mysqlConfig);
|
|
||||||
let basePath = path.join(config.rootPath, "sqls");
|
|
||||||
let hisPath = path.join(basePath, HISTORY_NAME);
|
|
||||||
let history: Array<string>;
|
|
||||||
if (fs.existsSync(hisPath)) {
|
|
||||||
history = JSON.parse(await fs.readFile(hisPath, "utf-8"));
|
|
||||||
} else {
|
|
||||||
history = new Array();
|
|
||||||
}
|
|
||||||
//执行数据库
|
|
||||||
let files = (await fs.readdir(basePath)).sort((a, b) => a.localeCompare(b)).filter(item => !(item === HISTORY_NAME));
|
|
||||||
let error = null;
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
if (history.indexOf(files[i]) > -1) {
|
|
||||||
log.info("sql无需重复执行:", files[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let sqlLines = (await fs.readFile(path.join(basePath, files[i]), 'utf-8')).split(/[\r\n]/g);
|
|
||||||
try {
|
|
||||||
let sql = "";
|
|
||||||
for (let j = 0; j < sqlLines.length; j++) {
|
|
||||||
sql = sql + sqlLines[j];
|
|
||||||
if (sqlLines[j].endsWith(";")) {
|
|
||||||
await MysqlUtil.pool.execute(sql);
|
|
||||||
sql = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info("sql执行成功:", files[i]);
|
|
||||||
history.push(files[i]);
|
|
||||||
} catch (err) {
|
|
||||||
error = err;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await fs.writeFile(hisPath, JSON.stringify(history));
|
|
||||||
if (error != null) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async getRows(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<Array<any>> {
|
|
||||||
return (await MysqlUtil.execute(sql, params, connection)).rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static async getRow(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<any> {
|
|
||||||
let rows = (await MysqlUtil.execute(sql, params, connection)).rows;
|
|
||||||
return rows.length > 0 ? rows[0] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async getSingle(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<any> {
|
|
||||||
let rows = (await MysqlUtil.execute(sql, params, connection)).rows;
|
|
||||||
if (rows.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let row = rows[0];
|
|
||||||
return row[Object.keys(row)[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static async execute(sql: string, params: Array<any>, connection: mysql.PoolConnection = null): Promise<Res> {
|
|
||||||
let res: any = {};
|
|
||||||
if (connection == null) {
|
|
||||||
let [rows, fields] = await MysqlUtil.pool.query(sql, params);
|
|
||||||
res['rows'] = fields === undefined ? null : rows;
|
|
||||||
res['fields'] = fields === undefined ? rows : fields;
|
|
||||||
} else {
|
|
||||||
let [rows, fields] = await connection.query(sql, params);
|
|
||||||
res['rows'] = rows;
|
|
||||||
res['fields'] = fields;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static async test() {
|
|
||||||
let connection = await MysqlUtil.pool.getConnection();
|
|
||||||
connection.beginTransaction();
|
|
||||||
connection.query(`insert into url value(6,"GET","asd","public")`);
|
|
||||||
connection.query(`insert into url value(7,"GET","asd","public")`);
|
|
||||||
await connection.commit();
|
|
||||||
connection.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
MysqlUtil,
|
|
||||||
Res,
|
|
||||||
mysql
|
|
||||||
}
|
|
@ -1,102 +1,83 @@
|
|||||||
import { Method } from "axios";
|
import {Method} from "axios";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import QbAddressDto from "../entity/dto/QbAddressDto";
|
import querystring from "querystring";
|
||||||
|
import QbConfigDto from "../entity/dto/QbConfigDto";
|
||||||
import GlobalService from '../service/GlobalConfigService';
|
import GlobalService from '../service/GlobalConfigService';
|
||||||
import { setUncaughtExceptionCaptureCallback } from "process";
|
|
||||||
|
|
||||||
//qb状态,true正常,false:无法访问
|
let qbInfo: QbConfigDto = null;
|
||||||
let qbStatus = true;
|
let cookie: any = null;
|
||||||
let qbInfo: QbAddressDto = null;
|
|
||||||
let cookie: string = null;
|
|
||||||
|
|
||||||
export function getQbStatus() {
|
export function updateQbInfo(info: QbConfigDto) {
|
||||||
return qbStatus;
|
qbInfo = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateQbInfo(info: QbAddressDto, status: boolean) {
|
export function getQbInfo() {
|
||||||
if (!info) {
|
return qbInfo;
|
||||||
let obj = await GlobalService.getMultVal(["qbAddress", "qbUsername", "qbPassword"]);
|
|
||||||
if (!obj.qbAddress) {
|
|
||||||
qbStatus = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qbInfo.address = obj.qbAddress;
|
|
||||||
qbInfo.username = obj.qbUsername;
|
|
||||||
qbInfo.password = obj.qbPassword;
|
|
||||||
} else {
|
|
||||||
qbInfo = info;
|
|
||||||
}
|
|
||||||
if (status) {
|
|
||||||
qbStatus = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.defaults.baseURL = qbInfo.address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get() {
|
export async function get(url: string, data: object) {
|
||||||
|
return await request("get", url, data, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function post() {
|
export async function post(url: string, data: object, isForm = false) {
|
||||||
|
return await request("post", url, null, data, isForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function request(method: Method, url: string, query: any, body: any, isForm = false) {
|
async function request(method: Method, url: string, query: any, body: any, isForm = false) {
|
||||||
if (!qbStatus) {
|
if (!qbInfo.valid) {
|
||||||
throw new Error("qbittorrent无法连接,请检查配置");
|
throw new Error("qbittorrent无法连接,请检查配置");
|
||||||
}
|
}
|
||||||
let isTryLogin = false;
|
let isTryLogin = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
let headers = { "Cookie": cookie };
|
let headers = {"Cookie": cookie};
|
||||||
if (isForm) {
|
if (isForm) {
|
||||||
headers['content-type'] = "multipart/form-data";
|
headers['content-type'] = "multipart/form-data";
|
||||||
} else if (method == "post") {
|
} else if (method == "post") {
|
||||||
headers['content-type'] = "application/json";
|
headers['content-type'] = "application/json";
|
||||||
}
|
}
|
||||||
let res = await axios.request({
|
let res = await axios.request({
|
||||||
baseURL: qbInfo.address,
|
baseURL: qbInfo.address,
|
||||||
url: url,
|
url: "/api/v2" + url,
|
||||||
method,
|
method,
|
||||||
params: query,
|
params: query,
|
||||||
data: body,
|
data: body,
|
||||||
headers,
|
headers,
|
||||||
});
|
});
|
||||||
if (res.status == 200) {
|
if (res.status == 200) {
|
||||||
return res.data;
|
return res.data;
|
||||||
} if (res.status == 403) {
|
}
|
||||||
if (isTryLogin) {
|
if (res.status == 403) {
|
||||||
throw new Error("qb用户名密码设置有误");
|
if (isTryLogin) {
|
||||||
} else {
|
throw new Error("qb用户名密码设置有误");
|
||||||
await tryLogin(qbInfo.address, qbInfo.username, qbInfo.password, true);
|
} else {
|
||||||
isTryLogin = true;
|
await tryLogin();
|
||||||
}
|
isTryLogin = true;
|
||||||
} else {
|
}
|
||||||
throw new Error("请求报错:" + res.data);
|
} else {
|
||||||
}
|
throw new Error("请求报错:" + res.data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function tryLogin(address: string, username: string, password: string, updateStatus: boolean): Promise<void> {
|
export async function tryLogin(): Promise<boolean> {
|
||||||
let body = { username, password };
|
if (qbInfo == null || qbInfo.address == null || qbInfo.address == "") {
|
||||||
try {
|
return false;
|
||||||
let res = await axios.post(address + "/api/v2/auth/login", body, {
|
}
|
||||||
headers: { "Content-Type": "multipart/form-data;boundary=--------------------------125002698093981740970152" }
|
let body = {username: qbInfo.username, password: qbInfo.password};
|
||||||
});
|
try {
|
||||||
let success = res.data.toLocaleLowerCase().contains('ok');
|
let res = await axios.post(qbInfo.address + `/api/v2/auth/login`, querystring.stringify(body), {
|
||||||
if (updateStatus) {
|
headers: {"Content-Type": "application/x-www-form-urlencoded"}
|
||||||
qbStatus = success;
|
});
|
||||||
}
|
let success = res.data.toLocaleLowerCase().indexOf('ok') > -1;
|
||||||
if (!success) {
|
if (success) {
|
||||||
throw new Error("登录失败");
|
cookie = res.headers['set-cookie'];
|
||||||
} else {
|
}
|
||||||
cookie = res.headers['Cookie'];
|
qbInfo.valid = success;
|
||||||
}
|
return success;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("登录报错:", error);
|
console.error("登录报错:", error);
|
||||||
if (updateStatus) {
|
return false;
|
||||||
qbStatus = false;
|
|
||||||
}
|
}
|
||||||
throw new Error("登录出错");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlite3 from 'sqlite3';
|
import sqlite3 from 'sqlite3';
|
||||||
import { open, Database } from 'sqlite';
|
import {open, Database} from 'sqlite';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import * as fs from "fs-extra";
|
import * as fs from "fs-extra";
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@ -12,9 +12,9 @@ class SqliteHelper {
|
|||||||
public static pool: Database = null;
|
public static pool: Database = null;
|
||||||
|
|
||||||
static async createPool() {
|
static async createPool() {
|
||||||
let dataFolder = path.join(config.rootPath, "data");
|
let dataFolder = config.dataPath;
|
||||||
if (!fs.existsSync(dataFolder)) {
|
if (!fs.existsSync(dataFolder)) {
|
||||||
fs.mkdir(dataFolder);
|
await fs.mkdir(dataFolder);
|
||||||
}
|
}
|
||||||
SqliteHelper.pool = await open({
|
SqliteHelper.pool = await open({
|
||||||
filename: path.join(dataFolder, "database.db"),
|
filename: path.join(dataFolder, "database.db"),
|
||||||
@ -26,7 +26,7 @@ class SqliteHelper {
|
|||||||
if (fs.existsSync(hisPath)) {
|
if (fs.existsSync(hisPath)) {
|
||||||
history = JSON.parse(await fs.readFile(hisPath, "utf-8"));
|
history = JSON.parse(await fs.readFile(hisPath, "utf-8"));
|
||||||
} else {
|
} else {
|
||||||
history = new Array();
|
history = [];
|
||||||
}
|
}
|
||||||
//执行数据库
|
//执行数据库
|
||||||
let files = (await fs.readdir(basePath)).sort((a, b) => a.localeCompare(b)).filter(item => !(item === HISTORY_NAME));
|
let files = (await fs.readdir(basePath)).sort((a, b) => a.localeCompare(b)).filter(item => !(item === HISTORY_NAME));
|
||||||
|
344
openRenamerBackend/util/TranslateUtil.ts
Normal file
344
openRenamerBackend/util/TranslateUtil.ts
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
// ToolGood.Words.Translate.js
|
||||||
|
// 2020, Lin Zhijun, https://github.com/toolgood/ToolGood.Words
|
||||||
|
// Licensed under the Apache License 2.0
|
||||||
|
import {_s2t_s, _s2t_t, _t2hk_t, _t2hk_hk, _t2s_s, _t2tw_t, _t2s_t, _t2tw_tw} from './TranslateWord'
|
||||||
|
|
||||||
|
class TrieNode {
|
||||||
|
Index = 0;
|
||||||
|
Layer = 0;
|
||||||
|
End = false;
|
||||||
|
Char = '';
|
||||||
|
Results = [];
|
||||||
|
m_values = {};
|
||||||
|
Failure = null;
|
||||||
|
Parent = null;
|
||||||
|
|
||||||
|
public Add(c) {
|
||||||
|
if (this.m_values[c] != null) {
|
||||||
|
return this.m_values[c];
|
||||||
|
}
|
||||||
|
var node = new TrieNode();
|
||||||
|
node.Parent = this;
|
||||||
|
node.Char = c;
|
||||||
|
this.m_values[c] = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SetResults(index) {
|
||||||
|
if (this.End == false) {
|
||||||
|
this.End = true;
|
||||||
|
}
|
||||||
|
this.Results.push(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TrieNode2 {
|
||||||
|
End = false;
|
||||||
|
Results = [];
|
||||||
|
m_values = {};
|
||||||
|
minflag = 1;
|
||||||
|
maxflag = 0;
|
||||||
|
|
||||||
|
public Add(c, node3) {
|
||||||
|
if (typeof c !== 'number') {
|
||||||
|
c = parseInt(c);
|
||||||
|
}
|
||||||
|
if (this.minflag > c) {
|
||||||
|
this.minflag = c;
|
||||||
|
}
|
||||||
|
if (this.maxflag < c) {
|
||||||
|
this.maxflag = c;
|
||||||
|
}
|
||||||
|
this.m_values[c] = node3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetResults(index) {
|
||||||
|
if (this.End == false) {
|
||||||
|
this.End = true;
|
||||||
|
}
|
||||||
|
if (this.Results.indexOf(index) == -1) {
|
||||||
|
this.Results.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HasKey(c) {
|
||||||
|
return this.m_values[c] != undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TryGetValue(c) {
|
||||||
|
if (this.minflag <= c && this.maxflag >= c) {
|
||||||
|
return this.m_values[c];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class WordsSearch {
|
||||||
|
|
||||||
|
|
||||||
|
_first: TrieNode2 = null;
|
||||||
|
_keywords = [];
|
||||||
|
_others = [];
|
||||||
|
|
||||||
|
public SetKeywords(keywords) {
|
||||||
|
this._keywords = keywords;
|
||||||
|
let root = new TrieNode();
|
||||||
|
|
||||||
|
let allNodeLayer = {};
|
||||||
|
for (let i = 0; i < this._keywords.length; i++) {
|
||||||
|
let p = this._keywords[i];
|
||||||
|
let nd = root;
|
||||||
|
for (let j = 0; j < p.length; j++) {
|
||||||
|
nd = nd.Add(p.charCodeAt(j));
|
||||||
|
if (nd.Layer == 0) {
|
||||||
|
nd.Layer = j + 1;
|
||||||
|
if (allNodeLayer[nd.Layer]) {
|
||||||
|
allNodeLayer[nd.Layer].push(nd)
|
||||||
|
} else {
|
||||||
|
allNodeLayer[nd.Layer] = [];
|
||||||
|
allNodeLayer[nd.Layer].push(nd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nd.SetResults(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let allNode: TrieNode[] = [];
|
||||||
|
allNode.push(root);
|
||||||
|
for (let key in allNodeLayer) {
|
||||||
|
let nds = allNodeLayer[key];
|
||||||
|
for (let i = 0; i < nds.length; i++) {
|
||||||
|
allNode.push(nds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allNodeLayer = null;
|
||||||
|
|
||||||
|
for (let i = 1; i < allNode.length; i++) {
|
||||||
|
let nd: TrieNode = allNode[i];
|
||||||
|
nd.Index = i;
|
||||||
|
let r = nd.Parent.Failure;
|
||||||
|
let c = nd.Char;
|
||||||
|
while (r != null && !r.m_values[c])
|
||||||
|
r = r.Failure;
|
||||||
|
if (r == null)
|
||||||
|
nd.Failure = root;
|
||||||
|
else {
|
||||||
|
nd.Failure = r.m_values[c];
|
||||||
|
for (let key2 in nd.Failure.Results) {
|
||||||
|
if (nd.Failure.Results.hasOwnProperty(key2) == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let result = nd.Failure.Results[key2];
|
||||||
|
nd.SetResults(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root.Failure = root;
|
||||||
|
|
||||||
|
let allNode2 = [];
|
||||||
|
for (let i = 0; i < allNode.length; i++) {
|
||||||
|
allNode2.push(new TrieNode2());
|
||||||
|
}
|
||||||
|
for (let i = 0; i < allNode2.length; i++) {
|
||||||
|
let oldNode = allNode[i];
|
||||||
|
let newNode = allNode2[i];
|
||||||
|
|
||||||
|
for (let key in oldNode.m_values) {
|
||||||
|
if (oldNode.m_values.hasOwnProperty(key) == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let index = oldNode.m_values[key].Index;
|
||||||
|
newNode.Add(key, allNode2[index]);
|
||||||
|
}
|
||||||
|
for (let index = 0; index < oldNode.Results.length; index++) {
|
||||||
|
let item = oldNode.Results[index];
|
||||||
|
newNode.SetResults(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
oldNode = oldNode.Failure;
|
||||||
|
while (oldNode != root) {
|
||||||
|
for (let key in oldNode.m_values) {
|
||||||
|
if (oldNode.m_values.hasOwnProperty(key) == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (newNode.HasKey(key) == false) {
|
||||||
|
let index = oldNode.m_values[key].Index;
|
||||||
|
newNode.Add(key, allNode2[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let index = 0; index < oldNode.Results.length; index++) {
|
||||||
|
let item = oldNode.Results[index];
|
||||||
|
newNode.SetResults(item);
|
||||||
|
}
|
||||||
|
oldNode = oldNode.Failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allNode = null;
|
||||||
|
root = null;
|
||||||
|
this._first = allNode2[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public FindAll(text) {
|
||||||
|
var ptr = null;
|
||||||
|
var list = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < text.length; i++) {
|
||||||
|
var t = text.charCodeAt(i);
|
||||||
|
var tn = null;
|
||||||
|
if (ptr == null) {
|
||||||
|
tn = this._first.TryGetValue(t);
|
||||||
|
} else {
|
||||||
|
tn = ptr.TryGetValue(t);
|
||||||
|
if (!tn) {
|
||||||
|
tn = this._first.TryGetValue(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tn != null) {
|
||||||
|
if (tn.End) {
|
||||||
|
for (let j = 0; j < tn.Results.length; j++) {
|
||||||
|
var item = tn.Results[j];
|
||||||
|
var keyword = this._keywords[item];
|
||||||
|
list.push({
|
||||||
|
Keyword: keyword,
|
||||||
|
Success: true,
|
||||||
|
End: i,
|
||||||
|
Start: i + 1 - this._keywords[item].length,
|
||||||
|
Index: item,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr = tn;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------
|
||||||
|
var s2tSearch = null; // WordsSearch
|
||||||
|
var t2sSearch = null;// WordsSearch
|
||||||
|
var t2twSearch = null;// WordsSearch
|
||||||
|
var tw2tSearch = null;// WordsSearch
|
||||||
|
var t2hkSearch = null;// WordsSearch
|
||||||
|
var hk2tSearch = null;// WordsSearch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转繁体中文
|
||||||
|
* @param {any} text 原文本
|
||||||
|
* @param {any} type 0、繁体中文,1、港澳繁体,2、台湾正体
|
||||||
|
*/
|
||||||
|
export function toTraditionalChinese(text: any, type: any) {
|
||||||
|
if (type == undefined) {
|
||||||
|
type = 0;
|
||||||
|
}
|
||||||
|
if (type > 2 || type < 0) {
|
||||||
|
throw "type 不支持该类型";
|
||||||
|
}
|
||||||
|
|
||||||
|
var s2t = GetWordsSearch(true, 0);
|
||||||
|
text = TransformationReplace(text, s2t);
|
||||||
|
if (type > 0) {
|
||||||
|
var t2 = GetWordsSearch(true, type);
|
||||||
|
text = TransformationReplace(text, t2);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转简体中文
|
||||||
|
* @param {any} text 原文本
|
||||||
|
* @param {any} srcType 0、繁体中文,1、港澳繁体,2、台湾正体
|
||||||
|
*/
|
||||||
|
export function toSimplifiedChinese(text: string, srcType: any) {
|
||||||
|
if (srcType == undefined) {
|
||||||
|
srcType = 0;
|
||||||
|
}
|
||||||
|
if (srcType > 2 || srcType < 0) {
|
||||||
|
throw "srcType 不支持该类型";
|
||||||
|
}
|
||||||
|
if (srcType > 0) {
|
||||||
|
var t2 = GetWordsSearch(false, srcType);
|
||||||
|
text = TransformationReplace(text, t2);
|
||||||
|
}
|
||||||
|
var s2t = GetWordsSearch(false, 0);
|
||||||
|
text = TransformationReplace(text, s2t);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TransformationReplace(text: any, wordsSearch: any) {
|
||||||
|
var ts = wordsSearch.FindAll(text);
|
||||||
|
|
||||||
|
var sb = "";
|
||||||
|
var index = 0;
|
||||||
|
while (index < text.length) {
|
||||||
|
var t = null;
|
||||||
|
var max = -1;
|
||||||
|
for (var i = 0; i < ts.length; i++) {
|
||||||
|
var f = ts[i];
|
||||||
|
if (f.Start == index && f.End > max) {
|
||||||
|
max = f.End;
|
||||||
|
t = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t == null) {
|
||||||
|
sb += text[index];
|
||||||
|
index++;
|
||||||
|
} else {
|
||||||
|
sb += wordsSearch._others[t.Index]
|
||||||
|
index = t.End + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetWordsSearch(s2t: boolean, srcType: number) {
|
||||||
|
if (s2t) {
|
||||||
|
if (srcType === 0) {
|
||||||
|
if (s2tSearch == null) {
|
||||||
|
s2tSearch = BuildWordsSearch(_s2t_s, _s2t_t);
|
||||||
|
}
|
||||||
|
return s2tSearch;
|
||||||
|
} else if (srcType === 1) {
|
||||||
|
if (t2hkSearch == null) {
|
||||||
|
t2hkSearch = BuildWordsSearch(_t2hk_t, _t2hk_hk);
|
||||||
|
}
|
||||||
|
return t2hkSearch;
|
||||||
|
} else if (srcType == 2) {
|
||||||
|
if (t2twSearch == null) {
|
||||||
|
t2twSearch = BuildWordsSearch(_t2tw_t, _t2tw_tw);
|
||||||
|
}
|
||||||
|
return t2twSearch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (srcType == 0) {
|
||||||
|
if (t2sSearch == null) {
|
||||||
|
t2sSearch = BuildWordsSearch(_t2s_t, _t2s_s);
|
||||||
|
}
|
||||||
|
return t2sSearch;
|
||||||
|
} else if (srcType == 1) {
|
||||||
|
if (hk2tSearch == null) {
|
||||||
|
hk2tSearch = BuildWordsSearch(_t2hk_hk, _t2hk_t);
|
||||||
|
}
|
||||||
|
return hk2tSearch;
|
||||||
|
} else if (srcType == 2) {
|
||||||
|
if (tw2tSearch == null) {
|
||||||
|
tw2tSearch = BuildWordsSearch(_t2tw_tw, _t2tw_t);
|
||||||
|
}
|
||||||
|
return tw2tSearch;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function BuildWordsSearch(keywords: string[], toWords: any[]) {
|
||||||
|
var wordsSearch = new WordsSearch();
|
||||||
|
wordsSearch.SetKeywords(keywords);
|
||||||
|
wordsSearch._others = toWords;
|
||||||
|
return wordsSearch;
|
||||||
|
}
|
8
openRenamerBackend/util/TranslateWord.ts
Normal file
8
openRenamerBackend/util/TranslateWord.ts
Normal file
File diff suppressed because one or more lines are too long
8
openRenamerBackend/util/ValUtil.ts
Normal file
8
openRenamerBackend/util/ValUtil.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* null to default
|
||||||
|
* @param value
|
||||||
|
* @param defaultVal
|
||||||
|
*/
|
||||||
|
export function nullToDefault(value: any, defaultVal: any): any {
|
||||||
|
return value === undefined || value == null ? defaultVal : value;
|
||||||
|
}
|
@ -8,21 +8,21 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.0.10",
|
"@element-plus/icons-vue": "2.0.10",
|
||||||
"axios": "^0.21.1",
|
"axios": "1.6.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "3.35.0",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "1.10.7",
|
||||||
"element-plus": "^2.2.25",
|
"element-plus": "2.2.25",
|
||||||
"vue": "^3.2.45",
|
"vue": "3.2.45",
|
||||||
"vue-router": "^4.0.0-0"
|
"vue-router": "4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "~5.0.8",
|
"@vue/cli-plugin-babel": "5.0.8",
|
||||||
"@vue/cli-plugin-router": "~5.0.8",
|
"@vue/cli-plugin-router": "5.0.8",
|
||||||
"@vue/cli-service": "~5.0.8",
|
"@vue/cli-service": "5.0.8",
|
||||||
"@vue/compiler-sfc": "^3.0.0",
|
"@vue/compiler-sfc": "3.0.0",
|
||||||
"less": "^3.0.4",
|
"less": "3.0.4",
|
||||||
"less-loader": "^5.0.0",
|
"less-loader": "5.0.0",
|
||||||
"prettier": "^2.2.1"
|
"prettier": "2.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9458
openRenamerFront/pnpm-lock.yaml
generated
9458
openRenamerFront/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,6 @@
|
|||||||
//设置上一节获取到的key
|
//设置上一节获取到的key
|
||||||
window.qieziStatisticKey = "13ec82dd91294ae4a88b0d2cc6cbdf76";
|
window.qieziStatisticKey = "13ec82dd91294ae4a88b0d2cc6cbdf76";
|
||||||
</script>
|
</script>
|
||||||
<script src="https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js" type="text/javascript"></script>
|
<script src="https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js" type="text/javascript" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -14,21 +14,23 @@
|
|||||||
<router-view/>
|
<router-view/>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">版本:
|
<div class="footer">版本:
|
||||||
<el-tooltip effect="dark" content="点击查看更新内容" placement="top">
|
<el-tooltip effect="dark" content="点击查看更新记录" placement="top">
|
||||||
<a href="https://blog.fleyx.com/blog/detail/20221130/#13" target="_blank">
|
<a href="https://blog.fleyx.com/blog/detail/20221130/#%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95"
|
||||||
|
target="_blank">
|
||||||
{{ version }}</a>
|
{{ version }}</a>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<template v-if="latestVersion && latestVersion>version">
|
<template v-if="latestVersion && showNewVersion">
|
||||||
最新版本:
|
最新版本:
|
||||||
<el-tooltip effect="dark" content="点击查看更新文档" placement="top">
|
<el-tooltip effect="dark" content="点击查看更新文档" placement="top">
|
||||||
<a href="https://blog.fleyx.com/blog/detail/20221130/#%e5%8d%87%e7%ba%a7" target="_blank">
|
<a href="https://blog.fleyx.com/blog/detail/20221130/#%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95"
|
||||||
|
target="_blank">
|
||||||
{{ latestVersion }}</a>
|
{{ latestVersion }}</a>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
开源地址:<a href="https://github.com/FleyX/open-renamer">open-renamer</a>
|
开源地址:<a href="https://github.com/FleyX/open-renamer" target="_blank">open-renamer</a>
|
||||||
<a href="https://github.com/FleyX/open-renamer/issues">反馈</a>
|
<a href="https://github.com/FleyX/open-renamer/issues" target="_blank">反馈</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -40,25 +42,44 @@ export default {
|
|||||||
name: "Home",
|
name: "Home",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
version: 1.3,
|
version: "1.8.0",
|
||||||
latestVersion: null,
|
latestVersion: null,
|
||||||
activeIndex: location.pathname,
|
activeIndex: location.pathname,
|
||||||
|
showNewVersion: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
async beforeCreate() {
|
||||||
|
window.token = localStorage.getItem("token");
|
||||||
|
window.isWindows = await httpUtil.get("/file/isWindows");
|
||||||
|
},
|
||||||
async created() {
|
async created() {
|
||||||
//获取最新版本
|
//获取最新版本
|
||||||
let config = await httpUtil.get("https://s3.fleyx.com/picbed/openRenamer/config.json");
|
let config = await httpUtil.get("https://s3.fleyx.com/picbed/openRenamer/config.json");
|
||||||
this.latestVersion = config.version;
|
this.latestVersion = config.version;
|
||||||
window.token = localStorage.getItem("token");
|
this.showNewVersion = checkVersion(this.version, this.latestVersion);
|
||||||
window.isWindows = await httpUtil.get("/file/isWindows");
|
|
||||||
console.log(this.$route);
|
|
||||||
console.log(this.activeIndex);
|
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
console.log(this.$route);
|
console.log(this.$route);
|
||||||
console.log(location);
|
console.log(location);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function checkVersion(version, latestVersion) {
|
||||||
|
let versions = version.split(".");
|
||||||
|
let latestVersions = latestVersion.split('.');
|
||||||
|
for (let i = 0; i < versions.length; i++) {
|
||||||
|
if (i >= latestVersions.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let versionNum = parseInt(versions[i]);
|
||||||
|
let latestVersionNum = parseInt(latestVersions[i]);
|
||||||
|
if (versionNum !== latestVersionNum) {
|
||||||
|
return versionNum < latestVersionNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@ -122,7 +122,7 @@ export default {
|
|||||||
},
|
},
|
||||||
//全选
|
//全选
|
||||||
selectAll(status) {
|
selectAll(status) {
|
||||||
this.filterFileList.filter((item) => !item.isFolder).forEach((item) => (item.checked = status));
|
this.filterFileList.forEach((item) => (item.checked = status));
|
||||||
},
|
},
|
||||||
//根据index构建路径
|
//根据index构建路径
|
||||||
createPath(index) {
|
createPath(index) {
|
||||||
|
@ -3,15 +3,18 @@
|
|||||||
<el-menu style="width: 8em" mode="vertical" :default-active="currentIndex" @select="menuChange">
|
<el-menu style="width: 8em" mode="vertical" :default-active="currentIndex" @select="menuChange">
|
||||||
<el-menu-item :disabled="editRule != null" index="insert">插入</el-menu-item>
|
<el-menu-item :disabled="editRule != null" index="insert">插入</el-menu-item>
|
||||||
<el-menu-item :disabled="editRule != null" index="delete">删除</el-menu-item>
|
<el-menu-item :disabled="editRule != null" index="delete">删除</el-menu-item>
|
||||||
<!-- <el-menu-item index="replace">替换</el-menu-item> -->
|
<el-menu-item :disabled="editRule != null" index="replace">替换</el-menu-item>
|
||||||
<el-menu-item :disabled="editRule != null || isAutoPlan" index="serialization">序列化</el-menu-item>
|
<el-menu-item :disabled="editRule != null || isAutoPlan" index="serialization">序列化</el-menu-item>
|
||||||
<el-menu-item :disabled="editRule != null" index="auto">自动识别</el-menu-item>
|
<el-menu-item :disabled="editRule != null" index="auto">自动识别</el-menu-item>
|
||||||
|
<el-menu-item :disabled="editRule != null" index="translate">简繁转换</el-menu-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
<div class="rule">
|
<div class="rule">
|
||||||
<insert-rule ref="rule" :editRule="editRule" v-if="currentIndex == 'insert'" />
|
<insert-rule ref="rule" :editRule="editRule" v-if="currentIndex === 'insert'"/>
|
||||||
<delete-rule ref="rule" :editRule="editRule" v-else-if="currentIndex == 'delete'" />
|
<delete-rule ref="rule" :editRule="editRule" v-else-if="currentIndex === 'delete'"/>
|
||||||
<serialization-rule ref="rule" :editRule="editRule" v-else-if="currentIndex == 'serialization'" />
|
<replace-rule ref="rule" :editRule="editRule" v-else-if="currentIndex === 'replace'"/>
|
||||||
<auto-rule ref="rule" :editRule="editRule" v-else-if="currentIndex == 'auto'" />
|
<serialization-rule ref="rule" :editRule="editRule" v-else-if="currentIndex === 'serialization'"/>
|
||||||
|
<auto-rule ref="rule" :editRule="editRule" v-else-if="currentIndex === 'auto'"/>
|
||||||
|
<translate-rule ref="rule" :editRule="editRule" v-else-if="currentIndex === 'translate'"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align: center">
|
<div style="text-align: center">
|
||||||
@ -24,27 +27,30 @@ import InsertRule from "./rules/InsertRule.vue";
|
|||||||
import DeleteRule from "./rules/DeleteRule.vue";
|
import DeleteRule from "./rules/DeleteRule.vue";
|
||||||
import SerializationRule from "./rules/SerializationRule.vue";
|
import SerializationRule from "./rules/SerializationRule.vue";
|
||||||
import AutoRule from "./rules/AutoRule";
|
import AutoRule from "./rules/AutoRule";
|
||||||
|
import ReplaceRule from "@/components/rules/ReplaceRule";
|
||||||
|
import TranslateRule from '@/components/rules/TranslateRule.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { InsertRule, DeleteRule, SerializationRule, AutoRule },
|
components: {InsertRule, DeleteRule, SerializationRule, AutoRule, ReplaceRule, TranslateRule},
|
||||||
props: ["editRule", "isAutoPlan"],
|
props: ["editRule", "isAutoPlan"],
|
||||||
emits: ["ruleAdd"],
|
emits: ["ruleAdd"],
|
||||||
name: "Rule",
|
name: "Rule",
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentIndex: "insert",
|
currentIndex: "insert",
|
||||||
options: [{ label: "插入", value: "insert" }],
|
options: [{label: "插入", value: "insert"}],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
if (this.editRule) {
|
if (this.editRule) {
|
||||||
this.currentIndex = this.editRule.type;
|
this.currentIndex = this.editRule.type;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
menuChange (index) {
|
menuChange(index) {
|
||||||
this.currentIndex = index;
|
this.currentIndex = index;
|
||||||
},
|
},
|
||||||
submit () {
|
submit() {
|
||||||
let data = this.$refs["rule"].exportObj();
|
let data = this.$refs["rule"].exportObj();
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
this.$emit("ruleAdd", data);
|
this.$emit("ruleAdd", data);
|
||||||
|
@ -6,22 +6,30 @@
|
|||||||
<div>开始</div>
|
<div>开始</div>
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<el-radio v-model="ruleObj.data.start.type" label="location" :disabled="deleteAll">位置:</el-radio>
|
<el-radio v-model="ruleObj.data.start.type" label="location" :disabled="deleteAll">位置:</el-radio>
|
||||||
<el-input-number :min="1" size="small" :disabled="deleteAll" v-model="startIndex" />
|
<el-input-number :min="1" size="small" :disabled="deleteAll" v-model="startIndex"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<el-radio v-model="ruleObj.data.start.type" label="text" :disabled="deleteAll">文本:</el-radio>
|
<el-radio v-model="ruleObj.data.start.type" label="text" :disabled="deleteAll">文本:</el-radio>
|
||||||
<el-input v-model="startText" size="small" :disabled="deleteAll" />
|
<el-input v-model="startText" size="small" :disabled="deleteAll"/>
|
||||||
|
</div>
|
||||||
|
<div class="line">
|
||||||
|
<el-radio v-model="ruleObj.data.start.type" label="reg" :disabled="deleteAll">正则:</el-radio>
|
||||||
|
<el-input v-model="startReg" size="small" :disabled="deleteAll"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-left: 4em">
|
<div style="margin-left: 4em">
|
||||||
<div>结束</div>
|
<div>结束</div>
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<el-radio v-model="ruleObj.data.end.type" label="location" :disabled="deleteAll">位置:</el-radio>
|
<el-radio v-model="ruleObj.data.end.type" label="location" :disabled="deleteAll">位置:</el-radio>
|
||||||
<el-input-number size="small" :disabled="deleteAll" v-model="endIndex" />
|
<el-input-number size="small" :disabled="deleteAll" v-model="endIndex"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<el-radio v-model="ruleObj.data.end.type" label="text" :disabled="deleteAll">文本:</el-radio>
|
<el-radio v-model="ruleObj.data.end.type" label="text" :disabled="deleteAll">文本:</el-radio>
|
||||||
<el-input v-model="endText" size="small" :disabled="deleteAll" />
|
<el-input v-model="endText" size="small" :disabled="deleteAll"/>
|
||||||
|
</div>
|
||||||
|
<div class="line">
|
||||||
|
<el-radio v-model="ruleObj.data.end.type" label="reg" :disabled="deleteAll">正则:</el-radio>
|
||||||
|
<el-input v-model="endReg" size="small" :disabled="deleteAll"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<el-radio v-model="ruleObj.data.end.type" label="end" :disabled="deleteAll">直到末尾</el-radio>
|
<el-radio v-model="ruleObj.data.end.type" label="end" :disabled="deleteAll">直到末尾</el-radio>
|
||||||
@ -29,14 +37,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="ruleObj.data.start.type==='reg' || ruleObj.data.end.type==='reg'" class="flex">
|
||||||
|
<div class="left">区分大小写:</div>
|
||||||
|
<el-switch v-model="ruleObj.data.regI"/>
|
||||||
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="left">全部删除:</div>
|
<div class="left">全部删除:</div>
|
||||||
<el-switch v-model="deleteAll" @change="allDeleteChange" />
|
<el-switch v-model="deleteAll" @change="allDeleteChange"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="left">忽略拓展名:</div>
|
<div class="left">忽略拓展名:</div>
|
||||||
<el-switch v-model="ruleObj.data.ignorePostfix" />
|
<el-switch v-model="ruleObj.data.ignorePostfix"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -60,28 +72,36 @@ export default {
|
|||||||
value: "",
|
value: "",
|
||||||
},
|
},
|
||||||
ignorePostfix: true,
|
ignorePostfix: true,
|
||||||
|
regI: false,//reg是否区分大小写
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
startIndex: 1,
|
startIndex: 1,
|
||||||
endIndex: 1,
|
endIndex: 1,
|
||||||
startText: "",
|
startText: "",
|
||||||
|
startReg: "",
|
||||||
endText: "",
|
endText: "",
|
||||||
|
endReg: "",
|
||||||
deleteAll: false,
|
deleteAll: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.editRule) {
|
if (this.editRule) {
|
||||||
this.ruleObj = JSON.parse(JSON.stringify(this.editRule));
|
this.ruleObj = JSON.parse(JSON.stringify(this.editRule));
|
||||||
if (this.ruleObj.data.type == "deletePart") {
|
if (this.ruleObj.data.type === "deletePart") {
|
||||||
if (this.ruleObj.data.start.type == "location") {
|
if (this.ruleObj.data.start.type === "location") {
|
||||||
this.startIndex = parseInt(this.ruleObj.data.start.value);
|
this.startIndex = parseInt(this.ruleObj.data.start.value);
|
||||||
} else {
|
} else if (this.ruleObj.data.start.type === "text") {
|
||||||
this.startText = this.ruleObj.data.start.value;
|
this.startText = this.ruleObj.data.start.value;
|
||||||
}
|
|
||||||
if (this.ruleObj.data.end.type == "location") {
|
|
||||||
this.endIndex = parseInt(this.ruleObj.data.end.value);
|
|
||||||
} else {
|
} else {
|
||||||
|
this.startReg = this.ruleObj.data.start.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ruleObj.data.end.type === "location") {
|
||||||
|
this.endIndex = parseInt(this.ruleObj.data.end.value);
|
||||||
|
} else if (this.ruleObj.data.end.type === "text") {
|
||||||
this.endText = this.ruleObj.data.end.value;
|
this.endText = this.ruleObj.data.end.value;
|
||||||
|
} else {
|
||||||
|
this.endReg = this.ruleObj.data.end.value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.deleteAll = true;
|
this.deleteAll = true;
|
||||||
@ -91,13 +111,15 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
exportObj() {
|
exportObj() {
|
||||||
if (this.ruleObj.data.type.length == 0) {
|
if (this.ruleObj.data.type.length == 0) {
|
||||||
this.$message({ message: "请填写完整", type: "warning" });
|
this.$message({message: "请填写完整", type: "warning"});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (this.ruleObj.data.type == "deletePart") {
|
if (this.ruleObj.data.type === "deletePart") {
|
||||||
if (
|
if (
|
||||||
(this.ruleObj.data.start.type == "text" && this.startText.length == 0) ||
|
('text' === this.ruleObj.data.start.type && this.startText.length === 0) ||
|
||||||
(this.ruleObj.data.start.type == "text" && this.startText.length == 0)
|
('text' === this.ruleObj.data.end.type && this.endText.length === 0) ||
|
||||||
|
('reg' === this.ruleObj.data.start.type && this.startReg.length === 0) ||
|
||||||
|
('reg' === this.ruleObj.data.end.type && this.endReg.length === 0)
|
||||||
) {
|
) {
|
||||||
this.$message({
|
this.$message({
|
||||||
message: "开始或者结束文本不能为空",
|
message: "开始或者结束文本不能为空",
|
||||||
@ -106,19 +128,20 @@ export default {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.ruleObj.data.start.value = this.ruleObj.data.start.type == "location" ? this.startIndex.toString() : this.startText;
|
let startType = this.ruleObj.data.start.type;
|
||||||
this.ruleObj.data.end.value = this.ruleObj.data.end.type == "location" ? this.endIndex.toString() : this.endText;
|
this.ruleObj.data.start.value = startType === "location" ? this.startIndex.toString() : startType === 'text' ? this.startText : this.startReg;
|
||||||
|
let endType = this.ruleObj.data.end.type;
|
||||||
|
this.ruleObj.data.end.value = endType === "location" ? this.endIndex.toString() : endType === 'text' ? this.endText : this.endReg;
|
||||||
let message = `删除:`;
|
let message = `删除:`;
|
||||||
if (this.deleteAll) {
|
if (this.deleteAll) {
|
||||||
message += "全部删除";
|
message += "全部删除";
|
||||||
} else {
|
} else {
|
||||||
message += `从"${this.ruleObj.data.start.value}"到"${this.ruleObj.data.end.type == "untilEnd" ? "末尾" : this.ruleObj.data.end.value}"`;
|
message += `从"${this.ruleObj.data.start.value}"到"${this.ruleObj.data.end.type === "end" ? "末尾" : this.ruleObj.data.end.value}"`;
|
||||||
}
|
}
|
||||||
this.ruleObj.message = message;
|
this.ruleObj.message = message;
|
||||||
return this.ruleObj;
|
return this.ruleObj;
|
||||||
},
|
},
|
||||||
allDeleteChange(val) {
|
allDeleteChange(val) {
|
||||||
console.log(val);
|
|
||||||
this.deleteAll = val;
|
this.deleteAll = val;
|
||||||
this.ruleObj.data.type = val ? "deleteAll" : "deletePart";
|
this.ruleObj.data.type = val ? "deleteAll" : "deletePart";
|
||||||
},
|
},
|
||||||
|
120
openRenamerFront/src/components/rules/ReplaceRule.vue
Normal file
120
openRenamerFront/src/components/rules/ReplaceRule.vue
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="left">源:</span>
|
||||||
|
<el-input style="width:20em" v-model="ruleObj.data.source" />
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="left">目标:</span>
|
||||||
|
<el-input style="width:20em" v-model="ruleObj.data.target" />
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="left">正则模式:</div>
|
||||||
|
<el-switch v-model="ruleObj.data.regFlag" />
|
||||||
|
<el-tooltip effect="dark" :content="regTip" placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="left">区分大小写:</div>
|
||||||
|
<el-switch v-model="ruleObj.data.regI" />
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="left">替换选项:</span>
|
||||||
|
<div class="location">
|
||||||
|
<el-radio v-for="item in radioList" :key="item.code" v-model="ruleObj.data.type" :label="item.code"
|
||||||
|
>{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="left">忽略拓展名:</div>
|
||||||
|
<el-switch v-model="ruleObj.data.ignorePostfix"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { InfoFilled } from "@element-plus/icons-vue";
|
||||||
|
import { nullToDefault } from "@/utils/ValUtil";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ReplaceRule",
|
||||||
|
components: { InfoFilled },
|
||||||
|
props: ["editRule"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
regTip: `开启支持js正则匹配,支持分组匹配,目标字符串支持模板#{groupN},N表示匹配到的第几组。比如#{group1}将被替换为匹配到的第一组数据`,
|
||||||
|
radioList: [
|
||||||
|
{
|
||||||
|
label: "替换第一个",
|
||||||
|
code: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "替换最后一个",
|
||||||
|
code: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "全部替换",
|
||||||
|
code: 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
ruleObj: {
|
||||||
|
type: "replace",
|
||||||
|
message: "",
|
||||||
|
data: {
|
||||||
|
source: "",
|
||||||
|
target: "",
|
||||||
|
type: 1, //1:替换第一个,2:替换最后一个,3:全部替换
|
||||||
|
ignorePostfix: true, //忽略拓展名
|
||||||
|
regFlag: false, //正则模式
|
||||||
|
regI: false //是否区分大小写
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.editRule) {
|
||||||
|
console.log(this.editRule);
|
||||||
|
this.ruleObj = JSON.parse(JSON.stringify(this.editRule));
|
||||||
|
//兼容历史数据
|
||||||
|
this.ruleObj.data.ignorePostfix = nullToDefault(this.ruleObj.data.ignorePostfix, true);
|
||||||
|
this.ruleObj.data.regFlag = nullToDefault(this.ruleObj.data.regFlag, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
exportObj() {
|
||||||
|
if (!this.ruleObj.data.source) {
|
||||||
|
this.$message({ message: "源不能为空", type: "warning" });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!this.ruleObj.data.type) {
|
||||||
|
this.$message({ message: "请选择替换选项", type: "warning" });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.ruleObj.message = `替换:将${this.ruleObj.data.source}替换为${this.ruleObj.data.target};`
|
||||||
|
+ this.radioList.filter(item => item.code === this.ruleObj.data.type)[0].label;
|
||||||
|
return this.ruleObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 1em;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location {
|
||||||
|
justify-content: left;
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -11,21 +11,25 @@
|
|||||||
<el-button type="primary" size="small" @click="editClick">
|
<el-button type="primary" size="small" @click="editClick">
|
||||||
<el-tooltip effect="dark" content="编辑规则" placement="top">
|
<el-tooltip effect="dark" content="编辑规则" placement="top">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<edit />
|
<edit/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="small" @click="move('top')">
|
<el-button type="primary" size="small" @click="move('top')">
|
||||||
<el-tooltip effect="dark" content="上移规则" placement="top">
|
<el-tooltip effect="dark" content="上移规则" placement="top">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<top />
|
<top/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="small" @click="move('bottom')">
|
<el-button type="primary" size="small" @click="move('bottom')">
|
||||||
<el-tooltip effect="dark" content="下移规则" placement="top"
|
<el-tooltip effect="dark" content="下移规则" placement="top"
|
||||||
><el-icon> <bottom /> </el-icon
|
>
|
||||||
></el-tooltip>
|
<el-icon>
|
||||||
|
<bottom/>
|
||||||
|
</el-icon
|
||||||
|
>
|
||||||
|
</el-tooltip>
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -38,11 +42,12 @@
|
|||||||
<el-button type="primary" size="small" text @click="addRuleDialogShow = true">+ 新增规则</el-button>
|
<el-button type="primary" size="small" text @click="addRuleDialogShow = true">+ 新增规则</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog :title="editRule ? '编辑规则' : '新增规则'" v-model="addRuleDialogShow" width="70%" @close="ruleDialogClose">
|
<el-dialog :title="editRule ? '编辑规则' : '新增规则'" v-model="addRuleDialogShow" width="70%"
|
||||||
<rule :editRule="editRule" @ruleAdd="ruleAdd" v-if="addRuleDialogShow" :isAutoPlan="rules != undefined" />
|
@close="ruleDialogClose">
|
||||||
|
<rule :editRule="editRule" @ruleAdd="ruleAdd" v-if="addRuleDialogShow" :isAutoPlan="rules != undefined"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="模板管理" v-model="ruleTemplateShow" width="70%">
|
<el-dialog title="模板管理" v-model="ruleTemplateShow" width="70%">
|
||||||
<application-rule-list v-if="ruleTemplateShow" :curId="chosedTemplate.id" @templateUpdate="templateUpdate" />
|
<application-rule-list v-if="ruleTemplateShow" :curId="chosedTemplate.id" @templateUpdate="templateUpdate"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -51,7 +56,8 @@
|
|||||||
import Rule from "@/components/Rule";
|
import Rule from "@/components/Rule";
|
||||||
import ApplicationRuleList from "./ApplicationRuleList";
|
import ApplicationRuleList from "./ApplicationRuleList";
|
||||||
import HttpUtil from "@/utils/HttpUtil";
|
import HttpUtil from "@/utils/HttpUtil";
|
||||||
import { Top, Bottom, Edit } from "@element-plus/icons-vue";
|
import {Top, Bottom, Edit} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "RuleBlock",
|
name: "RuleBlock",
|
||||||
props: ["rules"],
|
props: ["rules"],
|
||||||
@ -79,12 +85,12 @@ export default {
|
|||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
//如果外部传入了规则
|
//如果外部传入了规则
|
||||||
if (this.rules != undefined) {
|
if (this.rules !== undefined) {
|
||||||
this.ruleList = JSON.parse(JSON.stringify(this.rules));
|
this.ruleList = JSON.parse(JSON.stringify(this.rules));
|
||||||
} else {
|
} else {
|
||||||
this.chosedTemplate = await HttpUtil.get("/applicationRule/default");
|
this.chosedTemplate = await HttpUtil.get("/applicationRule/default");
|
||||||
this.ruleList = JSON.parse(this.chosedTemplate.content);
|
this.ruleList = JSON.parse(this.chosedTemplate.content);
|
||||||
await this.ruleUpdate();
|
await this.ruleUpdate(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -95,9 +101,14 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
//规则更新
|
//规则更新
|
||||||
ruleUpdate() {
|
ruleUpdate(preview) {
|
||||||
|
if (preview !== undefined && preview === false) {
|
||||||
|
preview = false;
|
||||||
|
} else {
|
||||||
|
preview = true;
|
||||||
|
}
|
||||||
let temp = this.ruleList.filter((item) => !item.blocked);
|
let temp = this.ruleList.filter((item) => !item.blocked);
|
||||||
this.$emit("ruleUpdate", temp);
|
this.$emit("ruleUpdate", temp, preview);
|
||||||
},
|
},
|
||||||
//模板内容提交
|
//模板内容提交
|
||||||
async templateSubmit() {
|
async templateSubmit() {
|
||||||
@ -107,7 +118,9 @@ export default {
|
|||||||
},
|
},
|
||||||
//切换模板
|
//切换模板
|
||||||
async templateUpdate(newVal) {
|
async templateUpdate(newVal) {
|
||||||
|
console.debug("新的模板:", newVal);
|
||||||
this.ruleList = JSON.parse(newVal.content);
|
this.ruleList = JSON.parse(newVal.content);
|
||||||
|
this.chosedTemplate = newVal;
|
||||||
this.ruleUpdate();
|
this.ruleUpdate();
|
||||||
this.ruleTemplateShow = false;
|
this.ruleTemplateShow = false;
|
||||||
},
|
},
|
||||||
@ -127,11 +140,11 @@ export default {
|
|||||||
//禁用/启用
|
//禁用/启用
|
||||||
async block() {
|
async block() {
|
||||||
this.ruleList
|
this.ruleList
|
||||||
.filter((item) => item.checked)
|
.filter((item) => item.checked)
|
||||||
.forEach((item) => {
|
.forEach((item) => {
|
||||||
item.blocked = !item.blocked;
|
item.blocked = !item.blocked;
|
||||||
item.checked = false;
|
item.checked = false;
|
||||||
});
|
});
|
||||||
await this.ruleUpdate();
|
await this.ruleUpdate();
|
||||||
},
|
},
|
||||||
//删除规则
|
//删除规则
|
||||||
|
@ -2,20 +2,20 @@
|
|||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span class="left">起始数:</span>
|
<span class="left">起始数:</span>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<el-input-number :min="1" size="small" v-model="ruleObj.data.start" />
|
<el-input-number :min="1" size="small" v-model="ruleObj.data.start"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span class="left">增量:</span>
|
<span class="left">增量:</span>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<el-input-number :min="1" size="small" v-model="ruleObj.data.increment" />
|
<el-input-number :min="1" size="small" v-model="ruleObj.data.increment"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<span class="left">填充0补足:</span>
|
<span class="left">填充0补足:</span>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<el-switch v-model="ruleObj.data.addZero" />
|
<el-switch v-model="ruleObj.data.addZero"/>
|
||||||
<el-input-number size="small" :min="1" :disabled="!ruleObj.data.addZero" v-model="ruleObj.data.numLength" />
|
<el-input-number size="small" :min="1" :disabled="!ruleObj.data.addZero" v-model="ruleObj.data.numLength"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@ -24,21 +24,34 @@
|
|||||||
<el-radio style="margin-top: 1em" v-model="ruleObj.data.insertType" label="front">前缀</el-radio>
|
<el-radio style="margin-top: 1em" v-model="ruleObj.data.insertType" label="front">前缀</el-radio>
|
||||||
<el-radio style="margin-top: 1em" v-model="ruleObj.data.insertType" label="backend">后缀</el-radio>
|
<el-radio style="margin-top: 1em" v-model="ruleObj.data.insertType" label="backend">后缀</el-radio>
|
||||||
<el-radio style="margin-top: 1em" v-model="ruleObj.data.insertType" label="at"
|
<el-radio style="margin-top: 1em" v-model="ruleObj.data.insertType" label="at"
|
||||||
>位置:<el-input-number size="small" :min="1" :disabled="ruleObj.data.insertType !== 'at'" v-model="ruleObj.data.insertValue" />
|
>位置:
|
||||||
|
<el-input-number size="small" :min="1" :disabled="ruleObj.data.insertType !== 'at'"
|
||||||
|
v-model="ruleObj.data.insertValue"/>
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="left">忽略拓展名:</div>
|
<div class="left">忽略拓展名:</div>
|
||||||
<el-switch v-model="ruleObj.data.ignorePostfix" />
|
<el-switch v-model="ruleObj.data.ignorePostfix"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="left">拓展名分组:</div>
|
||||||
|
<el-switch v-model="ruleObj.data.postfixGroup"/>
|
||||||
|
<el-tooltip effect="dark" content="按照文件拓展名分别计数,方便多种类型文件同时生成序列" placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import {InfoFilled} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SerializationRule",
|
name: "SerializationRule",
|
||||||
|
components: {InfoFilled},
|
||||||
props: ["editRule"],
|
props: ["editRule"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -53,6 +66,7 @@ export default {
|
|||||||
ignorePostfix: true,
|
ignorePostfix: true,
|
||||||
insertType: "front",
|
insertType: "front",
|
||||||
insertValue: 1,
|
insertValue: 1,
|
||||||
|
postfixGroup: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
77
openRenamerFront/src/components/rules/TranslateRule.vue
Normal file
77
openRenamerFront/src/components/rules/TranslateRule.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="left">操作:</span>
|
||||||
|
<div class="location">
|
||||||
|
<el-radio v-model="ruleObj.data.type" :label="1">简体转繁体</el-radio>
|
||||||
|
<el-radio v-model="ruleObj.data.type" :label="2">繁体转简体</el-radio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
|
<span class="left">繁体类型:</span>
|
||||||
|
<div class="location">
|
||||||
|
<el-radio v-model="ruleObj.data.traditionalType" :label="0">繁体中文</el-radio>
|
||||||
|
<el-radio v-model="ruleObj.data.traditionalType" :label="1">港澳繁体</el-radio>
|
||||||
|
<el-radio v-model="ruleObj.data.traditionalType" :label="2">台湾正体</el-radio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {InfoFilled} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const traTypeMap = {
|
||||||
|
"0": "繁体中文",
|
||||||
|
"1": "港澳繁体",
|
||||||
|
"2": "台湾正体"
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InsertRule",
|
||||||
|
props: ["editRule"],
|
||||||
|
components: {InfoFilled},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
ruleObj: {
|
||||||
|
type: "translate",
|
||||||
|
message: "",
|
||||||
|
data: {
|
||||||
|
type: 1,
|
||||||
|
traditionalType: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.editRule) {
|
||||||
|
console.log(this.editRule);
|
||||||
|
this.ruleObj = JSON.parse(JSON.stringify(this.editRule));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
exportObj() {
|
||||||
|
this.ruleObj.message = `简繁转换:"${this.ruleObj.data.type === 1 ? '简体转繁体' : '繁体转简体'}",繁体类型:${traTypeMap[this.ruleObj.data.traditionalType]}`;
|
||||||
|
return this.ruleObj;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 1em;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location {
|
||||||
|
justify-content: left;
|
||||||
|
//flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
9
openRenamerFront/src/utils/ValUtil.js
Normal file
9
openRenamerFront/src/utils/ValUtil.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* 空转default
|
||||||
|
* @param val
|
||||||
|
* @param defaultVal
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function nullToDefault(val, defaultVal) {
|
||||||
|
return val === undefined || val == null ? defaultVal : val;
|
||||||
|
}
|
@ -1,13 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>配置qb</div>
|
<div>配置qb</div>
|
||||||
<div class="item">
|
<el-form :model="data.qbConfig" label-width="8em">
|
||||||
<div class="left">qb信息</div>
|
<el-form-item label="qb版本">
|
||||||
<div class="right">{{ qbInfo }}<el-button @click="editInfo = true">编辑</el-button></div>
|
{{ data.qbConfig.version ? data.qbConfig.version : "配置错误,无法访问" }}
|
||||||
</div>
|
</el-form-item>
|
||||||
<el-form v-if="editInfo" :model="qbBody" label-width="4em">
|
<el-form-item label="访问地址">
|
||||||
<el-form-item label="qb地址"><el-input type="text" v-model="qbBody.address" placeholder="例如:http://192.168.1.4:8080" /></el-form-item>
|
<el-input type="text" v-model="data.qbConfig.address" placeholder="例如:http://localhost:8080(仅支持v4.1及以上)"/>
|
||||||
<el-form-item label="用户名"><el-input type="text" v-model="qbBody.username" placeholder="qb访问用户名" /></el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="密码"><el-input type="password" v-model="qbBody.password" placeholder="qb访问密码" /></el-form-item>
|
<el-form-item label="用户名">
|
||||||
|
<el-input type="text" v-model="data.qbConfig.username" placeholder="qb访问用户名"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码">
|
||||||
|
<el-input type="password" v-model="data.qbConfig.password" placeholder="qb访问密码"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="qb下载路径">
|
||||||
|
<el-input type="text" v-model="data.qbConfig.qbDownloadPath" placeholder="qb下载路径(qb中选择的下载路径)"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="对应本系统路径">
|
||||||
|
<el-input type="text" v-model="data.qbConfig.renameQbDownloadPath" placeholder="qb下载路径对应到本软件中的路径"/>
|
||||||
|
</el-form-item>
|
||||||
<div style="text-align: center">
|
<div style="text-align: center">
|
||||||
<el-button type="" @click="editInfo = false">取消</el-button>
|
<el-button type="" @click="editInfo = false">取消</el-button>
|
||||||
<el-button type="primary" @click="submitQb">提交</el-button>
|
<el-button type="primary" @click="submitQb">提交</el-button>
|
||||||
@ -16,34 +27,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, computed } from "vue";
|
import {ref, reactive, onMounted, computed} from "vue";
|
||||||
import http from "@/utils/HttpUtil";
|
import http from "@/utils/HttpUtil";
|
||||||
//表单
|
//表单
|
||||||
const qbBody = reactive({
|
const data = reactive({
|
||||||
address: "",
|
qbConfig: {},
|
||||||
username: "",
|
|
||||||
password: "",
|
|
||||||
});
|
});
|
||||||
//配置中心数据
|
|
||||||
let downloadConfig = reactive({});
|
|
||||||
//qb是否可访问
|
//qb是否可访问
|
||||||
let qbReach = ref(true);
|
|
||||||
let editInfo = ref(false);
|
let editInfo = ref(false);
|
||||||
|
|
||||||
const qbInfo = computed(() => {
|
|
||||||
if (downloadConfig.qbAddress) {
|
|
||||||
return downloadConfig.qbAddress + " 用户名:" + downloadConfig.qbUsername;
|
|
||||||
} else {
|
|
||||||
return "尚未配置";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
downloadConfig = reactive(await http.post("/config/multCode", null, ["qbAddress", "qbUsername", "qbPassword"]));
|
data.qbConfig = await http.get("/qb/config");
|
||||||
});
|
});
|
||||||
|
|
||||||
async function submitQb() {
|
async function submitQb() {
|
||||||
let res = await http.post("");
|
data.qbConfig = await http.post("/qb/saveQbInfo", null, data.qbConfig);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -52,10 +50,12 @@ async function submitQb() {
|
|||||||
display: flex;
|
display: flex;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-bottom: 0.5em;
|
padding-bottom: 0.5em;
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
width: 6em;
|
width: 6em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px">
|
<div style="margin-top: 5px">
|
||||||
<el-button type="primary" size="small" @click="selectAllFiles">反选</el-button>
|
<el-button type="primary" size="small" @click="selectAllFiles">{{ allChecked ? "不选" : "全选" }}</el-button>
|
||||||
<el-tooltip effect="dark" content="一键选中所有的非视频、字幕文件和小于5MB的视频文件" placement="bottom">
|
<el-tooltip effect="dark" content="一键选中所有的非视频、字幕文件和小于5MB的视频文件" placement="bottom">
|
||||||
<el-button type="success" size="small" @click="choseAdFile">一键选择</el-button>
|
<el-button type="success" size="small" @click="choseAdFile">一键选择</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -59,16 +59,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="fileBlock">
|
<div class="fileBlock">
|
||||||
<!-- 左侧原始文件名 -->
|
<!-- 左侧原始文件名 -->
|
||||||
<div style="flex: 4">
|
<div style="width:50%;">
|
||||||
<div v-for="(item, index) in fileList" :key="index" class="oneLine">
|
<div v-for="(item, index) in showFileList" :key="index" class="oneLine">
|
||||||
<el-checkbox v-model="item.checked" style="height: 1.2em">{{ item.name }}</el-checkbox>
|
<el-checkbox class="oneLineText" style="width: 95%" v-model="item.checked">
|
||||||
|
<el-tooltip show-after="300" style="color:white" effect="dark" :content="item.name" placement="top">
|
||||||
|
<span class="oneLineText" style="width: 100%;display: inline-block">{{ item.name }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右边的预览文件名 -->
|
<!-- 右边的预览文件名 -->
|
||||||
<div style="flex: 4">
|
<div style="width:50%">
|
||||||
<div v-for="(item, index) in changedFileList" :key="index" class="oneLine">
|
<div v-for="(item, index) in showChangedFileList" :key="index" class="oneLine">
|
||||||
<div style="flex: 4">{{ item.name }}</div>
|
<div style="display:inline-block;width:72%;" class="oneLineText">
|
||||||
<div style="color: red; flex: 1">{{ item.errorMessage }}</div>
|
<el-tooltip show-after="300" style="color:white" effect="dark" :content="item.name" placement="top">
|
||||||
|
<span class="oneLineText" style="width: 100%;display: inline-block">{{ item.name }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<div style="display:inline-block;color: red; width: 25%">{{ item.errorMessage }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -120,7 +128,17 @@ export default {
|
|||||||
showNameEditDialog: false //显示编辑文件弹窗
|
showNameEditDialog: false //显示编辑文件弹窗
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {
|
||||||
|
allChecked() {
|
||||||
|
return this.fileList.length > 0 && this.fileList.filter(item => item.checked).length === this.fileList.length;
|
||||||
|
},
|
||||||
|
showFileList() {
|
||||||
|
return this.fileList.length > 500 ? this.fileList.slice(0, 500) : this.fileList;
|
||||||
|
},
|
||||||
|
showChangedFileList() {
|
||||||
|
return this.changedFileList && this.changedFileList.length > 500 ? this.changedFileList.slice(0, 500) : this.changedFileList;
|
||||||
|
}
|
||||||
|
},
|
||||||
async created() {
|
async created() {
|
||||||
this.savePathList = await HttpUtil.get("/file/path");
|
this.savePathList = await HttpUtil.get("/file/path");
|
||||||
window.isWindows = await HttpUtil.get("/file/isWindows");
|
window.isWindows = await HttpUtil.get("/file/isWindows");
|
||||||
@ -137,12 +155,18 @@ export default {
|
|||||||
this.dialogVisible = false;
|
this.dialogVisible = false;
|
||||||
await this.showResult();
|
await this.showResult();
|
||||||
},
|
},
|
||||||
async ruleUpdate(rules) {
|
async ruleUpdate(rules, preview) {
|
||||||
|
console.log(rules, preview);
|
||||||
this.ruleList = rules;
|
this.ruleList = rules;
|
||||||
await this.showResult();
|
if (preview) {
|
||||||
|
await this.showResult();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
//预览结果
|
//预览结果
|
||||||
async showResult() {
|
async showResult() {
|
||||||
|
if (this.fileList.length > 500) {
|
||||||
|
this.$message.info("文件数过多,仅展示前500个(不影响重命名)");
|
||||||
|
}
|
||||||
this.changedFileList = [];
|
this.changedFileList = [];
|
||||||
if (!this.checkRuleAndFile()) {
|
if (!this.checkRuleAndFile()) {
|
||||||
return;
|
return;
|
||||||
@ -214,9 +238,9 @@ export default {
|
|||||||
this.showNameEditDialog = false;
|
this.showNameEditDialog = false;
|
||||||
await this.showResult();
|
await this.showResult();
|
||||||
},
|
},
|
||||||
//反选
|
|
||||||
selectAllFiles() {
|
selectAllFiles() {
|
||||||
this.fileList.forEach((item) => (item.checked = !item.checked));
|
let checked = !this.allChecked;
|
||||||
|
this.fileList.forEach((item) => (item.checked = checked));
|
||||||
},
|
},
|
||||||
//检查规则和文件
|
//检查规则和文件
|
||||||
checkRuleAndFile() {
|
checkRuleAndFile() {
|
||||||
@ -351,15 +375,28 @@ function readChar(a, i, n) {
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
.el-checkbox__label {
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.oneLine {
|
.oneLine {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-top: 1px solid rgb(214, 212, 212);
|
border-top: 1px solid rgb(214, 212, 212);
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
padding-top: 0.1em;
|
padding-top: 0.1em;
|
||||||
padding-bottom: 0.1em;
|
padding-bottom: 0.1em;
|
||||||
padding-right: 0.2em;
|
padding-right: 0.2em;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oneLineText {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oneFileName {
|
.oneFileName {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
devServer: {
|
devServer: {
|
||||||
proxy: "http://localhost:8089",
|
proxy: "http://localhost:8089",
|
||||||
},
|
},
|
||||||
|
publicPath: "./"
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user