Files
2026-06-30 18:30:24 +00:00

96 lines
2.8 KiB
Python

from fastapi import FastAPI, UploadFile, File, HTTPException, Form
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
import os, json, uuid, shutil, re
from datetime import datetime
PDF_DIR = "/files"
META = "/files/.metadata.json"
app = FastAPI()
def load_meta():
if os.path.exists(META):
with open(META) as f:
return json.load(f)
return {}
def save_meta(m):
with open(META, "w") as f:
json.dump(m, f, indent=2)
def safe_name(name):
return re.sub(r'[^\w\-. ]', '_', name)[:200]
@app.get("/api/list")
def list_pdfs():
meta = load_meta()
items = []
for fid, info in meta.items():
path = os.path.join(PDF_DIR, info["filename"])
if os.path.exists(path):
items.append({
"id": fid,
"title": info.get("title", info["filename"]),
"filename": info["filename"],
"tag": info.get("tag", ""),
"size": os.path.getsize(path),
"uploaded": info.get("uploaded", ""),
})
items.sort(key=lambda x: x["uploaded"], reverse=True)
return items
@app.post("/api/upload")
async def upload(file: UploadFile = File(...), title: str = Form(""), tag: str = Form("")):
if not file.filename.lower().endswith(".pdf"):
raise HTTPException(400, "PDFs only")
fid = uuid.uuid4().hex[:12]
fname = safe_name(file.filename)
path = os.path.join(PDF_DIR, f"{fid}_{fname}")
with open(path, "wb") as f:
shutil.copyfileobj(file.file, f)
meta = load_meta()
meta[fid] = {
"filename": f"{fid}_{fname}",
"title": title or fname.rsplit(".", 1)[0],
"tag": tag,
"uploaded": datetime.utcnow().isoformat(),
}
save_meta(meta)
return {"id": fid}
@app.delete("/api/delete/{fid}")
def delete(fid: str):
meta = load_meta()
if fid not in meta:
raise HTTPException(404)
path = os.path.join(PDF_DIR, meta[fid]["filename"])
if os.path.exists(path):
os.remove(path)
del meta[fid]
save_meta(meta)
return {"ok": True}
@app.get("/view/{fid}")
def view(fid: str):
meta = load_meta()
if fid not in meta:
raise HTTPException(404)
path = os.path.join(PDF_DIR, meta[fid]["filename"])
return FileResponse(path, media_type="application/pdf")
@app.patch("/api/update/{fid}")
async def update(fid: str, tag: str = Form(None), title: str = Form(None)):
meta = load_meta()
if fid not in meta:
raise HTTPException(404)
if tag is not None:
meta[fid]["tag"] = tag
if title is not None and title.strip():
meta[fid]["title"] = title.strip()
save_meta(meta)
return {"ok": True}
app.mount("/", StaticFiles(directory="/static", html=True), name="static")