diff --git a/backend/src/main.py b/backend/src/main.py index 66e5a4d4..33fa74e8 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -1,8 +1,12 @@ import logging import uvicorn -from module.api import router +from fastapi import FastAPI +from module.api import v1 +from module.api.proxy import router as proxy_router +from module.api.web import router as web_router from module.conf import settings, setup_logger +from starlette.types import ASGIApp setup_logger(reset=True) logger = logging.getLogger(__name__) @@ -20,9 +24,22 @@ uvicorn_logging_config = { }, } + +def create_app() -> ASGIApp: + app = FastAPI() + + # mount routers + app.include_router(web_router) + app.include_router(proxy_router) + app.include_router(v1, prefix="/api") + + return app + +app = create_app() + if __name__ == "__main__": uvicorn.run( - router, + app, host="0.0.0.0", port=settings.program.webui_port, log_config=uvicorn_logging_config, diff --git a/backend/src/module/api/__init__.py b/backend/src/module/api/__init__.py index e90516af..08b499f7 100644 --- a/backend/src/module/api/__init__.py +++ b/backend/src/module/api/__init__.py @@ -1 +1,19 @@ -from .web import router +from fastapi import APIRouter + +from .auth import router as auth_router +from .bangumi import router as bangumi_router +from .config import router as config_router +from .download import router as download_router +from .log import router as log_router +from .program import router as program_router + +__all__ = 'v1' + +# API 1.0 +v1 = APIRouter(prefix="/v1") +v1.include_router(auth_router) +v1.include_router(log_router) +v1.include_router(program_router) +v1.include_router(download_router) +v1.include_router(bangumi_router) +v1.include_router(config_router) diff --git a/backend/src/module/api/auth.py b/backend/src/module/api/auth.py index 1dd63859..925241f3 100644 --- a/backend/src/module/api/auth.py +++ b/backend/src/module/api/auth.py @@ -1,6 +1,6 @@ from datetime import timedelta -from fastapi import Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from module.models.user import User @@ -11,10 +11,10 @@ from module.security import ( update_user_info, ) -from .program import router +router = APIRouter(prefix="/auth", tags=["auth"]) -@router.post("/api/v1/auth/login", response_model=dict, tags=["auth"]) +@router.post("/login", response_model=dict) async def login(form_data: OAuth2PasswordRequestForm = Depends()): username = form_data.username password = form_data.password @@ -26,7 +26,7 @@ async def login(form_data: OAuth2PasswordRequestForm = Depends()): return {"access_token": token, "token_type": "bearer", "expire": 86400} -@router.get("/api/v1/auth/refresh_token", response_model=dict, tags=["auth"]) +@router.get("/refresh_token", response_model=dict) async def refresh(current_user: User = Depends(get_current_user)): if not current_user: raise HTTPException( @@ -39,7 +39,7 @@ async def refresh(current_user: User = Depends(get_current_user)): return {"access_token": token, "token_type": "bearer", "expire": 86400} -@router.get("/api/v1/auth/logout", response_model=dict, tags=["auth"]) +@router.get("/logout", response_model=dict) async def logout(current_user: User = Depends(get_current_user)): if not current_user: raise HTTPException( @@ -48,7 +48,7 @@ async def logout(current_user: User = Depends(get_current_user)): return {"message": "logout success"} -@router.post("/api/v1/auth/update", response_model=dict, tags=["auth"]) +@router.post("/update", response_model=dict) async def update_user(user_data: User, current_user: User = Depends(get_current_user)): if not current_user: raise HTTPException( diff --git a/backend/src/module/api/bangumi.py b/backend/src/module/api/bangumi.py index 8be82d41..cea508e2 100644 --- a/backend/src/module/api/bangumi.py +++ b/backend/src/module/api/bangumi.py @@ -1,15 +1,15 @@ -from fastapi import Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status from fastapi.responses import JSONResponse from module.manager import TorrentManager from module.models import BangumiData from module.security import get_current_user -from .log import router +router = APIRouter(prefix="/bangumi", tags=["bangumi"]) @router.get( - "/api/v1/bangumi/getAll", tags=["bangumi"], response_model=list[BangumiData] + "/getAll", response_model=list[BangumiData] ) async def get_all_data(current_user=Depends(get_current_user)): if not current_user: @@ -21,7 +21,7 @@ async def get_all_data(current_user=Depends(get_current_user)): @router.get( - "/api/v1/bangumi/getData/{bangumi_id}", tags=["bangumi"], response_model=BangumiData + "/getData/{bangumi_id}", response_model=BangumiData ) async def get_data(bangumi_id: str, current_user=Depends(get_current_user)): if not current_user: @@ -32,7 +32,7 @@ async def get_data(bangumi_id: str, current_user=Depends(get_current_user)): return torrent.search_one(bangumi_id) -@router.post("/api/v1/bangumi/updateRule", tags=["bangumi"]) +@router.post("/updateRule") async def update_rule(data: BangumiData, current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -42,7 +42,7 @@ async def update_rule(data: BangumiData, current_user=Depends(get_current_user)) return torrent.update_rule(data) -@router.delete("/api/v1/bangumi/deleteRule/{bangumi_id}", tags=["bangumi"]) +@router.delete("/deleteRule/{bangumi_id}") async def delete_rule(bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -52,7 +52,7 @@ async def delete_rule(bangumi_id: str, file: bool = False, current_user=Depends( return torrent.delete_rule(bangumi_id, file) -@router.delete("/api/v1/bangumi/disableRule/{bangumi_id}", tags=["bangumi"]) +@router.delete("/disableRule/{bangumi_id}") async def disable_rule( bangumi_id: str, file: bool = False, current_user=Depends(get_current_user) ): @@ -64,7 +64,7 @@ async def disable_rule( return torrent.disable_rule(bangumi_id, file) -@router.get("/api/v1/bangumi/enableRule/{bangumi_id}", tags=["bangumi"]) +@router.get("/enableRule/{bangumi_id}") async def enable_rule(bangumi_id: str, current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -74,7 +74,7 @@ async def enable_rule(bangumi_id: str, current_user=Depends(get_current_user)): return torrent.enable_rule(bangumi_id) -@router.get("/api/v1/bangumi/resetAll", tags=["bangumi"]) +@router.get("/resetAll") async def reset_all(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( diff --git a/backend/src/module/api/config.py b/backend/src/module/api/config.py index 98f8da3c..9519071e 100644 --- a/backend/src/module/api/config.py +++ b/backend/src/module/api/config.py @@ -1,17 +1,16 @@ import logging -from fastapi import Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status from module.conf import settings from module.models import Config from module.security import get_current_user -from .bangumi import router - +router = APIRouter(tags=["config"]) logger = logging.getLogger(__name__) -@router.get("/api/v1/getConfig", tags=["config"], response_model=Config) +@router.get("/getConfig", response_model=Config) async def get_config(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -20,7 +19,7 @@ async def get_config(current_user=Depends(get_current_user)): return settings -@router.post("/api/v1/updateConfig", tags=["config"]) +@router.post("/updateConfig") async def update_config(config: Config, current_user=Depends(get_current_user)): if not current_user: raise HTTPException( diff --git a/backend/src/module/api/download.py b/backend/src/module/api/download.py index 56a4c601..d70b481d 100644 --- a/backend/src/module/api/download.py +++ b/backend/src/module/api/download.py @@ -1,4 +1,4 @@ -from fastapi import Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status from module.manager import SeasonCollector from module.models import BangumiData @@ -6,10 +6,9 @@ from module.models.api import RssLink from module.rss import analyser from module.security import get_current_user -from .config import router +router = APIRouter(prefix="/download", tags=["download"]) - -@router.post("/api/v1/download/analysis", tags=["download"]) +@router.post("/analysis") async def analysis(link: RssLink, current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -22,7 +21,7 @@ async def analysis(link: RssLink, current_user=Depends(get_current_user)): return {"status": "Failed to parse link"} -@router.post("/api/v1/download/collection", tags=["download"]) +@router.post("/collection") async def download_collection( data: BangumiData, current_user=Depends(get_current_user) ): @@ -40,7 +39,7 @@ async def download_collection( return {"status": "Failed to parse link"} -@router.post("/api/v1/download/subscribe", tags=["download"]) +@router.post("/subscribe") async def subscribe(data: BangumiData, current_user=Depends(get_current_user)): if not current_user: raise HTTPException( diff --git a/backend/src/module/api/log.py b/backend/src/module/api/log.py index 13a6ad44..3cce4718 100644 --- a/backend/src/module/api/log.py +++ b/backend/src/module/api/log.py @@ -1,14 +1,14 @@ import os -from fastapi import Depends, HTTPException, Response, status +from fastapi import APIRouter, Depends, HTTPException, Response, status from module.conf import LOG_PATH from module.security import get_current_user -from .auth import router +router = APIRouter(prefix='/log', tags=["log"]) -@router.get("/api/v1/log", tags=["log"]) +@router.get("") async def get_log(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -21,7 +21,7 @@ async def get_log(current_user=Depends(get_current_user)): return Response("Log file not found", status_code=404) -@router.get("/api/v1/log/clear", tags=["log"]) +@router.get("/clear") async def clear_log(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( diff --git a/backend/src/module/api/program.py b/backend/src/module/api/program.py index 5e3cf6b5..60d75fd0 100644 --- a/backend/src/module/api/program.py +++ b/backend/src/module/api/program.py @@ -2,14 +2,14 @@ import logging import os import signal -from fastapi import Depends, FastAPI, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status from module.core import Program from module.security import get_current_user logger = logging.getLogger(__name__) program = Program() -router = FastAPI() +router = APIRouter(tags=["program"]) @router.on_event("startup") @@ -22,7 +22,7 @@ async def shutdown(): program.stop() -@router.get("/api/v1/restart", tags=["program"]) +@router.get("/restart") async def restart(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -37,7 +37,7 @@ async def restart(current_user=Depends(get_current_user)): raise HTTPException(status_code=500, detail="Failed to restart program") -@router.get("/api/v1/start", tags=["program"]) +@router.get("/start") async def start(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -51,7 +51,7 @@ async def start(current_user=Depends(get_current_user)): raise HTTPException(status_code=500, detail="Failed to start program") -@router.get("/api/v1/stop", tags=["program"]) +@router.get("/stop") async def stop(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -60,7 +60,7 @@ async def stop(current_user=Depends(get_current_user)): return program.stop() -@router.get("/api/v1/status", tags=["program"]) +@router.get("/status") async def program_status(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -72,7 +72,7 @@ async def program_status(current_user=Depends(get_current_user)): return {"status": "running"} -@router.get("/api/v1/shutdown", tags=["program"]) +@router.get("/shutdown") async def shutdown_program(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -85,7 +85,7 @@ async def shutdown_program(current_user=Depends(get_current_user)): # Check status -@router.get("/api/v1/check/downloader", tags=["check"]) +@router.get("/check/downloader", tags=["check"]) async def check_downloader_status(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( @@ -94,7 +94,7 @@ async def check_downloader_status(current_user=Depends(get_current_user)): return program.check_downloader() -@router.get("/api/v1/check/rss", tags=["check"]) +@router.get("/check/rss", tags=["check"]) async def check_rss_status(current_user=Depends(get_current_user)): if not current_user: raise HTTPException( diff --git a/backend/src/module/api/proxy.py b/backend/src/module/api/proxy.py index 86aeebf6..2b50cbdf 100644 --- a/backend/src/module/api/proxy.py +++ b/backend/src/module/api/proxy.py @@ -1,13 +1,14 @@ import logging import re +from fastapi import APIRouter from fastapi.exceptions import HTTPException from fastapi.responses import Response from module.conf import settings from module.network import RequestContent -from .download import router +router = APIRouter() logger = logging.getLogger(__name__) diff --git a/backend/src/module/api/web.py b/backend/src/module/api/web.py index 62836441..bac07749 100644 --- a/backend/src/module/api/web.py +++ b/backend/src/module/api/web.py @@ -1,11 +1,11 @@ -from fastapi import Request +from fastapi import APIRouter, Request from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from module.conf import VERSION -from .proxy import router +router = APIRouter() if VERSION != "DEV_VERSION": router.mount("/assets", StaticFiles(directory="templates/assets"), name="assets") @@ -29,9 +29,7 @@ if VERSION != "DEV_VERSION": def index(request: Request): context = {"request": request} return templates.TemplateResponse("index.html", context) - else: - @router.get("/", status_code=302, tags=["html"]) def index(): return RedirectResponse("/docs")