Merge pull request #2 from Koha9/codex/add-token-based-authentication-for-plex-server

Implement Plex token login
This commit is contained in:
Koha9 2025-06-20 22:36:54 +09:00 committed by GitHub
commit 8fa0189a1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 53 additions and 16 deletions

View File

@ -12,6 +12,11 @@ PlexPlaylistSync 是一个用于同步 Plex 播放列表和本地 `.m3u`/`.m3u8`
- **低功耗运行**: 适合 NAS 或服务器 24 小时运行,优化资源使用,减少能耗。 - **低功耗运行**: 适合 NAS 或服务器 24 小时运行,优化资源使用,减少能耗。
- **Docker 部署**: 可通过 Docker 轻松部署和运行。 - **Docker 部署**: 可通过 Docker 轻松部署和运行。
### Token 登录
首次登录时使用用户名和密码连接 Plex 服务器,成功后程序会将获得的 `token` 保存在配置文件中,后续通信仅使用该 `token`,不再保存明文密码。
默认情况下 Plex 服务器使用 `32400` 端口,可在未修改服务器端口时直接使用该默认值。
## 安装 ## 安装
首先安装依赖: 首先安装依赖:

View File

@ -1,3 +1,6 @@
{ {
"theme": "light" "theme": "auto",
"token": "",
"server_url": "",
"server_port": "32400"
} }

View File

@ -4,6 +4,7 @@ from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from app.utils.plex_client import connect_plex
app = FastAPI() app = FastAPI()
templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "templates")) templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "templates"))
@ -31,16 +32,34 @@ async def login(
user: str = Form(...), user: str = Form(...),
pw: str = Form(...), pw: str = Form(...),
url: str = Form(...), url: str = Form(...),
port: str = Form(...), port: str = Form("32400")
library: str = Form(...)
): ):
config = load_config() config = load_config()
theme = config.get("theme", "auto") theme = config.get("theme", "auto")
# demo假装连接成功 try:
if user == "admin": connect_plex(config, user, pw, url, port)
return templates.TemplateResponse("login.html", {"request": request, "message": "连接成功", "success": True, "theme": theme, "path": "/login"}) save_config(config)
else: return templates.TemplateResponse(
return templates.TemplateResponse("login.html", {"request": request, "message": "连接失败:用户名错误", "success": False, "theme": theme, "path": "/login"}) "login.html",
{
"request": request,
"message": "连接成功",
"success": True,
"theme": theme,
"path": "/login",
},
)
except Exception as e:
return templates.TemplateResponse(
"login.html",
{
"request": request,
"message": f"连接失败:{str(e)}",
"success": False,
"theme": theme,
"path": "/login",
},
)
@app.get("/playlist", response_class=HTMLResponse) @app.get("/playlist", response_class=HTMLResponse)
async def get_playlist(request: Request): async def get_playlist(request: Request):

View File

@ -19,14 +19,7 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="port" class="form-label">端口</label> <label for="port" class="form-label">端口</label>
<input type="text" class="form-control" id="port" name="port" placeholder="32400"> <input type="text" class="form-control" id="port" name="port" value="32400">
</div>
<div class="mb-3">
<label for="library" class="form-label">选择库</label>
<select class="form-select" id="library" name="library">
<option>Music</option>
<option>Podcast</option>
</select>
</div> </div>
<button type="submit" class="btn btn-primary">连接</button> <button type="submit" class="btn btn-primary">连接</button>
</form> </form>

16
app/utils/plex_client.py Normal file
View File

@ -0,0 +1,16 @@
from plexapi.myplex import MyPlexAccount
from plexapi.server import PlexServer
def connect_plex(config, username, password, url, port="32400"):
"""Return a connected PlexServer instance and update config with token and server info."""
token = config.get("token")
if not token:
account = MyPlexAccount(username, password)
token = account.authenticationToken
config["token"] = token
base_url = f"http://{url}:{port}"
server = PlexServer(base_url, token)
config.update({"server_url": url, "server_port": port})
return server

View File

@ -2,3 +2,4 @@ fastapi
uvicorn[standard] uvicorn[standard]
jinja2 jinja2
python-multipart python-multipart
plexapi