diff --git a/openRenamerBackend/api/QbServiceApi.ts b/openRenamerBackend/api/QbServiceApi.ts index 6f2e69d..27e968f 100644 --- a/openRenamerBackend/api/QbServiceApi.ts +++ b/openRenamerBackend/api/QbServiceApi.ts @@ -1,4 +1,4 @@ -import { Context } from "koa"; +import {Context} from "koa"; import service from "../service/QbService"; const router = {}; @@ -7,7 +7,21 @@ const router = {}; * 获取单个配置 */ 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(); }; diff --git a/openRenamerBackend/entity/dto/BtListItemDto.ts b/openRenamerBackend/entity/dto/BtListItemDto.ts new file mode 100644 index 0000000..a363a29 --- /dev/null +++ b/openRenamerBackend/entity/dto/BtListItemDto.ts @@ -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; +} \ No newline at end of file diff --git a/openRenamerBackend/entity/dto/QbAddressDto.ts b/openRenamerBackend/entity/dto/QbAddressDto.ts deleted file mode 100644 index 0b8ccb0..0000000 --- a/openRenamerBackend/entity/dto/QbAddressDto.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default interface QbAddressDto { - address: string; - username: string; - password: string; -} \ No newline at end of file diff --git a/openRenamerBackend/entity/dto/QbConfigDto.ts b/openRenamerBackend/entity/dto/QbConfigDto.ts new file mode 100644 index 0000000..e2ca2f4 --- /dev/null +++ b/openRenamerBackend/entity/dto/QbConfigDto.ts @@ -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; +} \ No newline at end of file diff --git a/openRenamerBackend/index.ts b/openRenamerBackend/index.ts index 1272806..ad88780 100644 --- a/openRenamerBackend/index.ts +++ b/openRenamerBackend/index.ts @@ -9,9 +9,8 @@ import handleError from "./middleware/handleError"; import init from "./middleware/init"; import SqliteUtil from './util/SqliteHelper'; import log from './util/LogUtil'; -import {updateQbInfo} from './util/QbApiUtil'; -import TimeUtil from "./util/TimeUtil"; - +import QbService from './service/QbService'; +import qbService from "./service/QbService"; console.log(config); @@ -33,7 +32,7 @@ app.use(handleError); app.use(RouterMW(router, path.join(config.rootPath, "dist/api"))); (async () => { await SqliteUtil.createPool(); - await updateQbInfo(null, null); + await qbService.init(); app.listen(config.port); log.info(`server listened `, config.port); })(); diff --git a/openRenamerBackend/service/QbService.ts b/openRenamerBackend/service/QbService.ts index 877536d..7ebfb27 100644 --- a/openRenamerBackend/service/QbService.ts +++ b/openRenamerBackend/service/QbService.ts @@ -1,17 +1,52 @@ -import QbAddressDto from "../entity/dto/QbAddressDto"; -import { tryLogin, updateQbInfo } from '../util/QbApiUtil'; +import QbConfigDto from "../entity/dto/QbConfigDto"; +import {tryLogin, get, post, updateQbInfo, getQbInfo} from '../util/QbApiUtil'; import GlobalConfigService from "./GlobalConfigService"; import GlobalConfig from "../entity/po/GlobalConfig"; +import BtListItemDto from "../entity/dto/BtListItemDto"; 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); - } + /** + * 保存地址 + * @param body + */ + static async saveAddress(body: QbConfigDto): Promise { + 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 { + return getQbInfo(); + } + + /** + * get torrents list from qb + */ + static async getBtList(): Promise> { + 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; diff --git a/openRenamerBackend/util/QbApiUtil.ts b/openRenamerBackend/util/QbApiUtil.ts index 2097e12..59fc3d6 100644 --- a/openRenamerBackend/util/QbApiUtil.ts +++ b/openRenamerBackend/util/QbApiUtil.ts @@ -1,102 +1,83 @@ -import { Method } from "axios"; +import {Method} 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 { setUncaughtExceptionCaptureCallback } from "process"; -//qb状态,true正常,false:无法访问 -let qbStatus = true; -let qbInfo: QbAddressDto = null; -let cookie: string = null; +let qbInfo: QbConfigDto = null; +let cookie: any = null; -export function getQbStatus() { - return qbStatus; +export function updateQbInfo(info: QbConfigDto) { + qbInfo = info; } -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 getQbInfo() { + return qbInfo; } -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) { - 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); - } - } + if (!qbInfo.valid) { + 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: "/api/v2" + 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(); + isTryLogin = true; + } + } else { + throw new Error("请求报错:" + res.data); + } + } } -export async function tryLogin(address: string, username: string, password: string, updateStatus: boolean): Promise { - 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("登录出错"); - } +export async function tryLogin(): Promise { + if (qbInfo == null || qbInfo.address == null || qbInfo.address == "") { + return false; + } + let body = {username: qbInfo.username, password: qbInfo.password}; + try { + let res = await axios.post(qbInfo.address + `/api/v2/auth/login`, querystring.stringify(body), { + headers: {"Content-Type": "application/x-www-form-urlencoded"} + }); + let success = res.data.toLocaleLowerCase().indexOf('ok') > -1; + if (success) { + cookie = res.headers['set-cookie']; + } + qbInfo.valid = success; + return success; + } catch (error) { + console.error("登录报错:", error); + return false; + + } } diff --git a/openRenamerFront/src/App.vue b/openRenamerFront/src/App.vue index bf645fb..fc25c64 100644 --- a/openRenamerFront/src/App.vue +++ b/openRenamerFront/src/App.vue @@ -49,17 +49,6 @@ export default { }; }, async beforeCreate() { - console.log("beforeCreate"); - let queryMap = {}; - location.search.substring(1).split("&").forEach(item => { - let arr = item.split("="); - queryMap[arr[0]] = arr[1]; - }) - if (queryMap.port) { - window.baseUrl = "http://localhost:" + queryMap.port; - } else { - window.baseUrl = ""; - } window.token = localStorage.getItem("token"); window.isWindows = await httpUtil.get("/file/isWindows"); }, diff --git a/openRenamerFront/src/views/download/config/index.vue b/openRenamerFront/src/views/download/config/index.vue index e2b2782..346263b 100644 --- a/openRenamerFront/src/views/download/config/index.vue +++ b/openRenamerFront/src/views/download/config/index.vue @@ -1,13 +1,24 @@ @@ -52,12 +50,14 @@ async function submitQb() { display: flex; text-align: left; padding-bottom: 0.5em; + .left { width: 6em; font-weight: 600; } + .right { flex: 1; } } - + \ No newline at end of file