Merge pull request 'dev' (#38) from dev into main

Reviewed-on: #38
This commit is contained in:
fanxb 2022-12-17 17:54:23 +08:00
commit 1e34dd7620
16 changed files with 337 additions and 9 deletions

View File

@ -1,15 +1,22 @@
import { Context } from "koa"; import { Context } from "koa";
import service from "../service/GlobalService"; import service from "../service/GlobalConfigService";
const router = {}; const router = {};
/** /**
* *
*/ */
router["GET /config/code"] = async function (ctx: Context) { router["GET /config/code"] = async function (ctx: Context) {
ctx.body = await service.getVal(ctx.request.query.code as string); ctx.body = await service.getVal(ctx.request.query.code as string);
}; };
/**
*
*/
router["POST /config/multCode"] = async function (ctx: Context) {
ctx.body = await service.getMultVal(ctx.request.body);
};
/** /**
* *
*/ */

View File

@ -0,0 +1,14 @@
import { Context } from "koa";
import service from "../service/QbService";
const router = {};
/**
*
*/
router["POST /qb/saveQbInfo"] = async function (ctx: Context) {
ctx.body = await service.saveAddress(ctx.request.body);
};
export default router;

View File

@ -43,7 +43,26 @@ export default class GlobalConfigDao {
static async getByCode(code: string): Promise<string> { static async getByCode(code: string): Promise<string> {
let res = await SqliteHelper.pool.get('select val from global_config where code=?', code); let res = await SqliteHelper.pool.get('select val from global_config where code=?', code);
return res ? res.val : null; return res ? res.val : null;
}
/**
* code
* @param code
*/
static async getByMulCode(codes: Array<string>): Promise<Array<GlobalConfig>> {
if (codes.length == 0) {
return new Array();
}
let codeStr = codes.map(item => `'${item}'`).join(',');
return await SqliteHelper.pool.all(`select * from global_config where code in (${codeStr})`);
}
/**
*
* @param body body
*/
static async insertOrReplace(body: GlobalConfig): Promise<void> {
await SqliteHelper.pool.run(`insert or replace into global_config values (?,?,?)`, body.code, body.val, body.description);
} }

View File

@ -4,7 +4,7 @@ import path from 'path';
let pattern = new RegExp(/s(eason)?(\d+)/); let pattern = new RegExp(/s(eason)?(\d+)/);
let eNumPatternArr = [new RegExp(/e(\d+)/), new RegExp(/\((\d+)\)/), new RegExp(/(\d+)/), new RegExp(/\.(\d+)\./), new RegExp(/-(\d+)/), new RegExp(/(\d+)/)]; let eNumPatternArr = [new RegExp(/e[p]?(\d+)/), new RegExp(/[\(\[](\d+)[\)\]]/), new RegExp(/[\.-](\d+)/), new RegExp(/(\d+)/)];
let resolutionPattern = new RegExp(/(\d{3,}[pP])/); let resolutionPattern = new RegExp(/(\d{3,}[pP])/);
let resolutionArr = ['1k', '1K', '2k', '2K', '4k', '4K', '8k', '8K']; let resolutionArr = ['1k', '1K', '2k', '2K', '4k', '4K', '8k', '8K'];
let charSet = new Set([' ', '[', '.', '(', '']); let charSet = new Set([' ', '[', '.', '(', '']);

View File

@ -0,0 +1,5 @@
export default interface QbAddressDto {
address: string;
username: string;
password: string;
}

View File

@ -9,6 +9,7 @@ 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';
console.log(config); console.log(config);
@ -30,6 +31,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);
app.listen(config.port); app.listen(config.port);
log.info(`server listened `, config.port); log.info(`server listened `, config.port);
})(); })();

View File

@ -12,7 +12,7 @@
"@types/fs-extra": "^5.0.4", "@types/fs-extra": "^5.0.4",
"@types/koa": "^2.0.47", "@types/koa": "^2.0.47",
"@types/node": "^11.13.4", "@types/node": "^11.13.4",
"axios": "^0.21.1", "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",

View File

@ -10,9 +10,24 @@ class GlobalConfigService {
return GlobalConfigDao.getByCode(code); return GlobalConfigDao.getByCode(code);
} }
/**
*
* @param codes codes
* @returns
*/
static async getMultVal(codes: Array<string>): Promise<any> {
let re = {};
(await GlobalConfigDao.getByMulCode(codes)).forEach(item => re[item.code] = item.val);
return re;
}
static async updateVal(code: string, val: string): Promise<void> { static async updateVal(code: string, val: string): Promise<void> {
return GlobalConfigDao.updateOne(code, val); return GlobalConfigDao.updateOne(code, val);
} }
static async insertOrReplace(body: GlobalConfig): Promise<void> {
return GlobalConfigDao.insertOrReplace(body);
}
} }
export default GlobalConfigService; export default GlobalConfigService;

View File

@ -0,0 +1,17 @@
import QbAddressDto from "../entity/dto/QbAddressDto";
import { tryLogin, updateQbInfo } from '../util/QbApiUtil';
import GlobalConfigService from "./GlobalConfigService";
import GlobalConfig from "../entity/po/GlobalConfig";
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"));
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbUsername", body.username, ""));
await GlobalConfigService.insertOrReplace(new GlobalConfig("qbPassword", body.password, ""));
await updateQbInfo(body, true);
}
}
export default QbService;

View File

@ -0,0 +1,102 @@
import { Method } from "axios";
import axios from "axios";
import QbAddressDto from "../entity/dto/QbAddressDto";
import GlobalService from '../service/GlobalConfigService';
import { setUncaughtExceptionCaptureCallback } from "process";
//qb状态true正常false:无法访问
let qbStatus = true;
let qbInfo: QbAddressDto = null;
let cookie: string = null;
export function getQbStatus() {
return qbStatus;
}
export async function updateQbInfo(info: QbAddressDto, status: boolean) {
if (!info) {
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 function post() {
}
async function request(method: Method, url: string, query: any, body: any, isForm = false) {
if (!qbStatus) {
throw new Error("qbittorrent无法连接请检查配置");
}
let isTryLogin = false;
while (true) {
let headers = { "Cookie": cookie };
if (isForm) {
headers['content-type'] = "multipart/form-data";
} else if (method == "post") {
headers['content-type'] = "application/json";
}
let res = await axios.request({
baseURL: qbInfo.address,
url: url,
method,
params: query,
data: body,
headers,
});
if (res.status == 200) {
return res.data;
} if (res.status == 403) {
if (isTryLogin) {
throw new Error("qb用户名密码设置有误");
} else {
await tryLogin(qbInfo.address, qbInfo.username, qbInfo.password, true);
isTryLogin = true;
}
} else {
throw new Error("请求报错:" + res.data);
}
}
}
export async function tryLogin(address: string, username: string, password: string, updateStatus: boolean): Promise<void> {
let body = { username, password };
try {
let res = await axios.post(address + "/api/v2/auth/login", body, {
headers: { "Content-Type": "multipart/form-data;boundary=--------------------------125002698093981740970152" }
});
let success = res.data.toLocaleLowerCase().contains('ok');
if (updateStatus) {
qbStatus = success;
}
if (!success) {
throw new Error("登录失败");
} else {
cookie = res.headers['Cookie'];
}
} catch (error) {
console.error("登录报错:", error);
if (updateStatus) {
qbStatus = false;
}
throw new Error("登录出错");
}
}

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"target": "ES6",
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@ -13,7 +13,7 @@
"core-js": "^3.6.5", "core-js": "^3.6.5",
"dayjs": "^1.10.7", "dayjs": "^1.10.7",
"element-plus": "^2.2.25", "element-plus": "^2.2.25",
"vue": "^3.0.0", "vue": "^3.2.45",
"vue-router": "^4.0.0-0" "vue-router": "^4.0.0-0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,7 +1,13 @@
<template> <template>
<div class="app"> <div class="app">
<el-menu :default-active="activeIndex" mode="horizontal" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" router> <el-menu :default-active="activeIndex" mode="horizontal" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" router>
<el-menu-item index="">重命名</el-menu-item> <el-menu-item index="/">重命名</el-menu-item>
<!-- <el-menu-item index="/auto">自动化</el-menu-item>
<el-sub-menu index="/download">
<template #title>bt下载</template>
<el-menu-item index="/download/center">下载中心</el-menu-item>
<el-menu-item index="/download/config">配置</el-menu-item>
</el-sub-menu> -->
</el-menu> </el-menu>
<div class="content"> <div class="content">
<router-view /> <router-view />
@ -17,13 +23,19 @@ export default {
data() { data() {
return { return {
version: "1.2", version: "1.2",
activeIndex: this.$route.hash, activeIndex: location.pathname,
}; };
}, },
async created() { async created() {
let token = localStorage.getItem("token"); let token = localStorage.getItem("token");
window.token = token; window.token = token;
await httpUtil.get("/file/isWindows"); await httpUtil.get("/file/isWindows");
console.log(this.$route);
console.log(this.activeIndex);
},
async mounted() {
console.log(this.$route);
console.log(location);
}, },
}; };
</script> </script>

View File

@ -7,8 +7,15 @@ const routes = [
path: "/", path: "/",
name: "Home", name: "Home",
component: Home, component: Home,
}, }, {
{ path: "/auto",
name: "Auto",
component: () => import("@/views/auto/index"),
}, {
path: "/download/config",
name: "downloadConfig",
component: () => import("@/views/download/config/index"),
}, {
path: "/public/login", path: "/public/login",
name: "login", name: "login",
component: Login, component: Login,

View File

@ -0,0 +1,53 @@
<template>
<div>自动化</div>
<div>
<el-button type="primary" @click="submit"> 保存自动化配置 </el-button>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from "vue";
import http from "@/utils/HttpUtil";
//
const qbBody = reactive({
address: "",
username: "",
password: "",
});
//
let downloadConfig = reactive({});
//qb访
let qbReach = ref(true);
let editInfo = ref(false);
const qbInfo = computed(() => {
if (downloadConfig.qbAddress) {
return downloadConfig.qbAddress + " 用户名:" + downloadConfig.qbUsername;
} else {
return "尚未配置";
}
});
onMounted(async () => {
downloadConfig = reactive(await http.post("/config/multCode", null, ["qbAddress", "qbUsername", "qbPassword"]));
});
async function submit() {
let res = await http.post("");
}
</script>
<style lang="less" scoped>
.item {
display: flex;
text-align: left;
padding-bottom: 0.5em;
.left {
width: 6em;
font-weight: 600;
}
.right {
flex: 1;
}
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<div>配置qb</div>
<div class="item">
<div class="left">qb信息</div>
<div class="right">{{ qbInfo }}<el-button @click="editInfo = true">编辑</el-button></div>
</div>
<el-form v-if="editInfo" :model="qbBody" label-width="4em">
<el-form-item label="qb地址"><el-input type="text" v-model="qbBody.address" placeholder="例如:http://192.168.1.4:8080" /></el-form-item>
<el-form-item label="用户名"><el-input type="text" v-model="qbBody.username" placeholder="qb访问用户名" /></el-form-item>
<el-form-item label="密码"><el-input type="password" v-model="qbBody.password" placeholder="qb访问密码" /></el-form-item>
<div style="text-align: center">
<el-button type="" @click="editInfo = false">取消</el-button>
<el-button type="primary" @click="submitQb">提交</el-button>
</div>
</el-form>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from "vue";
import http from "@/utils/HttpUtil";
//
const qbBody = reactive({
address: "",
username: "",
password: "",
});
//
let downloadConfig = reactive({});
//qb访
let qbReach = ref(true);
let editInfo = ref(false);
const qbInfo = computed(() => {
if (downloadConfig.qbAddress) {
return downloadConfig.qbAddress + " 用户名:" + downloadConfig.qbUsername;
} else {
return "尚未配置";
}
});
onMounted(async () => {
downloadConfig = reactive(await http.post("/config/multCode", null, ["qbAddress", "qbUsername", "qbPassword"]));
});
async function submitQb() {
let res = await http.post("");
}
</script>
<style lang="less" scoped>
.item {
display: flex;
text-align: left;
padding-bottom: 0.5em;
.left {
width: 6em;
font-weight: 600;
}
.right {
flex: 1;
}
}
</style>