Initial commit
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
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")
|
||||
Reference in New Issue
Block a user