diff --git a/backend/src/module/api/bangumi.py b/backend/src/module/api/bangumi.py index 45a7fe47..df18c687 100644 --- a/backend/src/module/api/bangumi.py +++ b/backend/src/module/api/bangumi.py @@ -10,6 +10,12 @@ from module.security.api import get_current_user, UNAUTHORIZED router = APIRouter(prefix="/bangumi", tags=["bangumi"]) +def str_to_list(data: Bangumi): + data.filter = data.filter.split(",") + data.rss_link = data.rss_link.split(",") + return data + + @router.get("/get/all", response_model=list[Bangumi]) async def get_all_data(current_user=Depends(get_current_user)): if not current_user: diff --git a/backend/src/module/api/program.py b/backend/src/module/api/program.py index c29fa7eb..411cab58 100644 --- a/backend/src/module/api/program.py +++ b/backend/src/module/api/program.py @@ -6,6 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import JSONResponse from module.core import Program +from module.models import APIResponse from module.conf import VERSION from module.security.api import get_current_user, UNAUTHORIZED @@ -24,20 +25,29 @@ async def shutdown(): program.stop() -@router.get("/restart") +@router.get("/restart", response_model=APIResponse) async def restart(current_user=Depends(get_current_user)): if not current_user: raise UNAUTHORIZED try: program.restart() - return {"status": "ok"} + return JSONResponse( + status_code=200, + content={"msg_en": "Restart program successfully.", "msg_zh": "重启程序成功。"}, + ) except Exception as e: logger.debug(e) logger.warning("Failed to restart program") - raise HTTPException(status_code=500, detail="Failed to restart program") + raise HTTPException( + status_code=500, + detail={ + "msg_en": "Failed to restart program.", + "msg_zh": "重启程序失败。", + } + ) -@router.get("/start") +@router.get("/start", response_model=APIResponse) async def start(current_user=Depends(get_current_user)): if not current_user: raise UNAUTHORIZED @@ -46,7 +56,13 @@ async def start(current_user=Depends(get_current_user)): except Exception as e: logger.debug(e) logger.warning("Failed to start program") - raise HTTPException(status_code=500, detail="Failed to start program") + raise HTTPException( + status_code=500, + detail={ + "msg_en": "Failed to start program.", + "msg_zh": "启动程序失败。", + } + ) @router.get("/stop") @@ -79,11 +95,14 @@ async def shutdown_program(current_user=Depends(get_current_user)): program.stop() logger.info("Shutting down program...") os.kill(os.getpid(), signal.SIGINT) - return {"status": "ok"} + return JSONResponse( + status_code=200, + content={"msg_en": "Shutdown program successfully.", "msg_zh": "关闭程序成功。"}, + ) # Check status -@router.get("/check/downloader", tags=["check"]) +@router.get("/check/downloader", tags=["check"], response_model=bool) async def check_downloader_status(current_user=Depends(get_current_user)): if not current_user: raise UNAUTHORIZED diff --git a/backend/src/module/api/response.py b/backend/src/module/api/response.py index b4705cc4..332d91ee 100644 --- a/backend/src/module/api/response.py +++ b/backend/src/module/api/response.py @@ -1,4 +1,5 @@ from fastapi.responses import JSONResponse +from fastapi.exceptions import HTTPException from module.models.response import ResponseModel @@ -7,7 +8,8 @@ def u_response(response_model: ResponseModel): return JSONResponse( status_code=response_model.status_code, content={ + "status": response_model.status, "msg_en": response_model.msg_en, "msg_zh": response_model.msg_zh, }, - ) + ) \ No newline at end of file diff --git a/backend/src/module/models/response.py b/backend/src/module/models/response.py index 73079631..9bd35272 100644 --- a/backend/src/module/models/response.py +++ b/backend/src/module/models/response.py @@ -9,5 +9,6 @@ class ResponseModel(BaseModel): class APIResponse(BaseModel): + status: bool = Field(..., example=True) msg_en: str = Field(..., example="Success") msg_zh: str = Field(..., example="成功") \ No newline at end of file diff --git a/backend/src/module/rss/engine.py b/backend/src/module/rss/engine.py index 621f3eba..45cf9658 100644 --- a/backend/src/module/rss/engine.py +++ b/backend/src/module/rss/engine.py @@ -47,7 +47,7 @@ class RSSEngine(Database): else: return ResponseModel( status=False, - status_code=400, + status_code=406, msg_en="RSS added failed.", msg_zh="RSS 添加失败。", ) diff --git a/webui/package.json b/webui/package.json index b29dde76..0c5b929e 100644 --- a/webui/package.json +++ b/webui/package.json @@ -26,6 +26,7 @@ "pinia": "^2.1.3", "vue": "^3.3.4", "vue-i18n": "^9.2.2", + "vue-inline-svg": "^3.1.2", "vue-router": "^4.2.1" }, "devDependencies": { diff --git a/webui/pnpm-lock.yaml b/webui/pnpm-lock.yaml index 9e0133aa..bfdf406c 100644 --- a/webui/pnpm-lock.yaml +++ b/webui/pnpm-lock.yaml @@ -29,6 +29,9 @@ dependencies: vue-i18n: specifier: ^9.2.2 version: 9.2.2(vue@3.3.4) + vue-inline-svg: + specifier: ^3.1.2 + version: 3.1.2(vue@3.3.4) vue-router: specifier: ^4.2.1 version: 4.2.1(vue@3.3.4) @@ -9769,6 +9772,14 @@ packages: vue: 3.3.4 dev: true + /vue-inline-svg@3.1.2(vue@3.3.4): + resolution: {integrity: sha512-K01sLANBnjosObee4JrBu/igXpYIFhQfy4EcEyVWxEWf6nmrxp7Isz6pmeRCsWx6XGrGWfrQH3uNwt4nOmrFdA==} + peerDependencies: + vue: ^3 + dependencies: + vue: 3.3.4 + dev: false + /vue-router@4.2.1(vue@3.3.4): resolution: {integrity: sha512-nW28EeifEp8Abc5AfmAShy5ZKGsGzjcnZ3L1yc2DYUo+MqbBClrRP9yda3dIekM4I50/KnEwo1wkBLf7kHH5Cw==} peerDependencies: diff --git a/webui/public/images/RSS.svg b/webui/public/images/RSS.svg new file mode 100644 index 00000000..57f7c996 --- /dev/null +++ b/webui/public/images/RSS.svg @@ -0,0 +1,3 @@ + + + diff --git a/webui/src/api/bangumi.ts b/webui/src/api/bangumi.ts index a5498ef6..e4e99a3d 100644 --- a/webui/src/api/bangumi.ts +++ b/webui/src/api/bangumi.ts @@ -1,5 +1,7 @@ import type { BangumiRule, BangumiUpdate } from '#/bangumi'; import type { ApiSuccess } from '#/api'; +import {forEach} from "lodash"; + export const apiBangumi = { /** @@ -8,7 +10,10 @@ export const apiBangumi = { */ async getAll() { const { data } = await axios.get('api/v1/bangumi/get/all'); - + forEach(data, (item) => { + item.rss_link = item.rss_link.split(','); + item.filter = item.filter.split(','); + }); return data; }, @@ -21,7 +26,8 @@ export const apiBangumi = { const { data } = await axios.get( `api/v1/bangumi/get/${bangumiId}` ); - + data.rss_link = data.rss_link.split(','); + data.filter = data.filter.split(','); return data; }, @@ -33,8 +39,9 @@ export const apiBangumi = { */ async updateRule(bangumiId: number, bangumiRule: BangumiRule) { const rule = omit(bangumiRule, ['id']); - - const { data } = await axios.patch( + rule.rss_link = rule.rss_link.join(','); + rule.filter = rule.filter.join(','); + const { data } = await axios.patch< ApiSuccess >( `api/v1/bangumi/update/${bangumiId}`, rule ); @@ -47,15 +54,23 @@ export const apiBangumi = { * @param file - 是否同时删除关联文件。 * @returns axios 请求返回的数据 */ - async deleteRule(bangumiId: number, file: boolean) { - const { data } = await axios.delete( - `api/v1/bangumi/delete/${bangumiId}`, - { - params: { - file, - }, - } - ); + async deleteRule(bangumiId: number | number[], file: boolean) { + let url = 'api/v1/bangumi/delete'; + let ids: undefined | number[]; + + if (typeof bangumiId === 'number') { + url = `${url}/${bangumiId}`; + } else { + url = `${url}/many`; + ids = bangumiId; + } + + const { data } = await axios.delete< ApiSuccess >(url, { + data: ids, + params: { + file, + }, + }); return data; }, @@ -65,15 +80,23 @@ export const apiBangumi = { * @param file - 是否同时删除关联文件。 * @returns axios 请求返回的数据 */ - async disableRule(bangumiId: number, file: boolean) { - const { data } = await axios.delete( - `api/v1/bangumi/disable/${bangumiId}`, - { - params: { - file, - }, - } - ); + async disableRule(bangumiId: number | number[], file: boolean) { + let url = 'api/v1/bangumi/disable'; + let ids: undefined | number[]; + + if (typeof bangumiId === 'number') { + url = `${url}/${bangumiId}`; + } else { + url = `${url}/many`; + ids = bangumiId; + } + + const { data } = await axios.delete< ApiSuccess >(url, { + data: ids, + params: { + file, + }, + }); return data; }, @@ -82,7 +105,7 @@ export const apiBangumi = { * @param bangumiId - 需要启用的 bangumi 的 id */ async enableRule(bangumiId: number) { - const { data } = await axios.get( + const { data } = await axios.get< ApiSuccess >( `api/v1/bangumi/enable/${bangumiId}` ); return data; @@ -92,9 +115,7 @@ export const apiBangumi = { * 重置所有 bangumi 数据 */ async resetAll() { - const { data } = await axios.get<{ - message: 'OK'; - }>('api/v1/bangumi/resetAll'); + const { data } = await axios.get< ApiSuccess >('api/v1/bangumi/resetAll'); return data; }, }; diff --git a/webui/src/api/check.ts b/webui/src/api/check.ts index 9d3289ef..a59a3a73 100644 --- a/webui/src/api/check.ts +++ b/webui/src/api/check.ts @@ -3,23 +3,8 @@ export const apiCheck = { * 检测下载器 */ async downloader() { - const { data } = await axios.get('api/v1/check/downloader'); + const { data } = await axios.get('api/v1/check/downloader'); return data; }, - /** - * 检测 RSS - */ - async rss() { - const { data } = await axios.get('api/v1/check/rss'); - return data; - }, - - /** - * 检测所有 - */ - async all() { - const { data } = await axios.get('api/v1/check'); - return data; - }, -}; +} \ No newline at end of file diff --git a/webui/src/api/config.ts b/webui/src/api/config.ts index 77e892f4..4fa5d6b1 100644 --- a/webui/src/api/config.ts +++ b/webui/src/api/config.ts @@ -1,11 +1,12 @@ import type { Config } from '#/config'; +import type { ApiSuccess } from '#/api'; export const apiConfig = { /** * 获取 config 数据 */ async getConfig() { - const { data } = await axios.get('api/v1/getConfig'); + const { data } = await axios.get('api/v1/config/get'); return data; }, @@ -14,10 +15,10 @@ export const apiConfig = { * @param newConfig - 需要更新的 config */ async updateConfig(newConfig: Config) { - const { data } = await axios.post<{ - message: 'Success' | 'Failed to update config'; - }>('api/v1/updateConfig', newConfig); - - return data.message === 'Success'; + const { data } = await axios.patch( + 'api/v1/config/update', + newConfig + ); + return data; }, }; diff --git a/webui/src/api/download.ts b/webui/src/api/download.ts index 52f25310..2aec1206 100644 --- a/webui/src/api/download.ts +++ b/webui/src/api/download.ts @@ -1,8 +1,5 @@ import type { BangumiRule } from '#/bangumi'; - -interface Status { - status: 'Success'; -} +import type { ApiSuccess } from '#/api'; export const apiDownload = { /** @@ -30,11 +27,11 @@ export const apiDownload = { * @param bangumiData - Bangumi 数据 */ async collection(bangumiData: BangumiRule) { - const { data } = await axios.post( + const { data } = await axios.post( 'api/v1/download/collection', bangumiData ); - return data.status === 'Success'; + return data; }, /** @@ -42,10 +39,10 @@ export const apiDownload = { * @param bangumiData - Bangumi 数据 */ async subscribe(bangumiData: BangumiRule) { - const { data } = await axios.post( + const { data } = await axios.post( 'api/v1/download/subscribe', bangumiData ); - return data.status === 'Success'; + return data; }, }; diff --git a/webui/src/api/log.ts b/webui/src/api/log.ts index 92e3e33e..b7492153 100644 --- a/webui/src/api/log.ts +++ b/webui/src/api/log.ts @@ -1,3 +1,5 @@ +import type { ApiSuccess } from "#/api"; + export const apiLog = { async getLog() { const { data } = await axios.get('api/v1/log'); @@ -5,7 +7,7 @@ export const apiLog = { }, async clearLog() { - const { data } = await axios.get<{ status: 'ok' }>('api/v1/log/clear'); - return data.status === 'ok'; + const { data } = await axios.get('api/v1/log/clear'); + return data; }, }; diff --git a/webui/src/api/program.ts b/webui/src/api/program.ts index 9bd7542b..d8ce5f0b 100644 --- a/webui/src/api/program.ts +++ b/webui/src/api/program.ts @@ -1,47 +1,47 @@ -interface Success { - status: 'ok'; -} +import type { ApiSuccess } from "#/api"; + export const apiProgram = { /** * 重启 */ async restart() { - const { data } = await axios.get('api/v1/restart'); - return data.status === 'ok'; + const { data } = await axios.get('api/v1/restart'); + return data; }, /** * 启动 */ async start() { - const { data } = await axios.get('api/v1/start'); - return data.status === 'ok'; + const { data } = await axios.get('api/v1/start'); + return data; }, /** * 停止 */ async stop() { - const { data } = await axios.get('api/v1/stop'); - return data.status === 'ok'; + const { data } = await axios.get('api/v1/stop'); + return data; }, /** * 状态 */ async status() { - const { data } = await axios.get<{ status: 'running' | 'stop' }>( + const { data } = await axios.get<{ status: boolean; version: string }>( 'api/v1/status' ); - return data.status === 'running'; + + return data!; }, /** * 终止 */ async shutdown() { - const { data } = await axios.get('api/v1/shutdown'); - return data.status === 'ok'; + const { data } = await axios.get('api/v1/shutdown'); + return data; }, }; diff --git a/webui/src/api/rss.ts b/webui/src/api/rss.ts new file mode 100644 index 00000000..b196cc1c --- /dev/null +++ b/webui/src/api/rss.ts @@ -0,0 +1,40 @@ +import type { RSS } from '#/rss'; +import type { Torrent } from '#/torrent'; +import type { ApiSuccess } from '#/api'; + +export const apiRSS = { + async get() { + const { data } = await axios.get('api/v1/rss'); + return data!; + }, + + async add(rss: RSS) { + const { data } = await axios.post('api/v1/rss/add', rss); + return data; + }, + + async delete(rss_id: number) { + const { data } = await axios.delete(`api/v1/rss/delete/${rss_id}`); + return data!; + }, + + async update(rss_id: number, rss: RSS) { + const { data } = await axios.patch(`api/v1/rss/update/${rss_id}`, rss); + return data!; + }, + + async refreshAll() { + const { data } = await axios.get('api/v1/rss/refresh/all'); + return data!; + }, + + async refresh(rss_id: number) { + const { data } = await axios.get(`api/v1/rss/refresh/${rss_id}`); + return data!; + }, + + async getTorrent(rss_id: number) { + const { data } = await axios.get(`api/v1/rss/torrent/${rss_id}`); + return data!; + }, +}; diff --git a/webui/src/api/search.ts b/webui/src/api/search.ts new file mode 100644 index 00000000..71878c34 --- /dev/null +++ b/webui/src/api/search.ts @@ -0,0 +1,11 @@ +export const apiSearch = { + async get(keyword: string, site = 'mikan') { + const { data } = await axios.get('api/v1/search', { + params: { + site, + keyword, + }, + }); + return data!; + }, +}; diff --git a/webui/src/components/ab-add-bangumi.vue b/webui/src/components/ab-add-bangumi.vue index 9a0e57f7..7c6668c8 100644 --- a/webui/src/components/ab-add-bangumi.vue +++ b/webui/src/components/ab-add-bangumi.vue @@ -1,7 +1,11 @@ + + + + \ No newline at end of file diff --git a/webui/src/components/basic/ab-add.vue b/webui/src/components/basic/ab-add.vue index 51ede24f..588dd532 100644 --- a/webui/src/components/basic/ab-add.vue +++ b/webui/src/components/basic/ab-add.vue @@ -1,10 +1,20 @@