Add explicit Documents & Texts tab and native Image-to-PDF converter (/api/convert_pdf)
This commit is contained in:
89
server.py
89
server.py
@@ -1407,6 +1407,95 @@ class Handler(BaseHTTPRequestHandler):
|
||||
paths = [r["path"] for r in filtered[:MAX_SELECT]]
|
||||
self._json({"paths": paths, "total": len(filtered), "capped": len(filtered) > MAX_SELECT})
|
||||
|
||||
elif self.path.startswith("/api/documents"):
|
||||
parsed_url = urllib.parse.urlparse(self.path)
|
||||
params = urllib.parse.parse_qs(parsed_url.query)
|
||||
try:
|
||||
limit = max(1, min(200, int(params.get("limit", ["60"])[0])))
|
||||
except ValueError:
|
||||
limit = 60
|
||||
try:
|
||||
offset = max(0, int(params.get("offset", ["0"])[0]))
|
||||
except ValueError:
|
||||
offset = 0
|
||||
records = load_search_index()
|
||||
docs = [r for r in records if r.get("category") == "Screenshots & Documents" or r.get("route") == "screenshot" or "text:" in (r.get("desc") or "").lower()]
|
||||
total = len(docs)
|
||||
page = [{k: v for k, v in r.items() if k not in ("_hay", "_mtime", "_ext")} for r in docs[offset:offset + limit]]
|
||||
self._json({"results": page, "total": total, "offset": offset, "limit": limit})
|
||||
|
||||
elif self.path.startswith("/api/convert_pdf"):
|
||||
parsed_url = urllib.parse.urlparse(self.path)
|
||||
params = urllib.parse.parse_qs(parsed_url.query)
|
||||
paths_param = params.get("paths", [""])[0] or params.get("path", [""])[0]
|
||||
if not paths_param:
|
||||
self._json({"error": "path parameter is required"}, 400); return
|
||||
paths = [p for p in paths_param.split(",") if p and os.path.exists(p)]
|
||||
if not paths:
|
||||
self._json({"error": "files not found"}, 404); return
|
||||
|
||||
if len(paths) == 1:
|
||||
src = paths[0]
|
||||
base_name = os.path.splitext(os.path.basename(src))[0] + ".pdf"
|
||||
tmp_pdf = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
|
||||
tmp_pdf.close()
|
||||
try:
|
||||
cmd = ["sips", "-s", "format", "pdf", src, "--out", tmp_pdf.name]
|
||||
r = subprocess.run(cmd, capture_output=True, timeout=30)
|
||||
if r.returncode != 0 or not os.path.exists(tmp_pdf.name):
|
||||
raise RuntimeError(f"sips failed: {r.stderr.decode(errors='replace')}")
|
||||
with open(tmp_pdf.name, "rb") as f:
|
||||
pdf_data = f.read()
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/pdf")
|
||||
self.send_header("Content-Disposition", f'attachment; filename="{base_name}"')
|
||||
self.send_header("Content-Length", str(len(pdf_data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(pdf_data)
|
||||
except Exception as e:
|
||||
self._json({"error": f"Failed converting image to PDF: {e}"}, 500)
|
||||
finally:
|
||||
try: os.remove(tmp_pdf.name)
|
||||
except Exception: pass
|
||||
else:
|
||||
tmp_zip = tempfile.NamedTemporaryFile(suffix=".zip", delete=False)
|
||||
tmp_zip.close()
|
||||
tmp_dir = tempfile.mkdtemp(prefix="photon_pdf_zip_")
|
||||
try:
|
||||
used_names = set()
|
||||
with zipfile.ZipFile(tmp_zip.name, "w", zipfile.ZIP_STORED, allowZip64=True) as zf:
|
||||
for src in paths:
|
||||
base = os.path.splitext(os.path.basename(src))[0]
|
||||
pdf_name = base + ".pdf"
|
||||
i = 1
|
||||
while pdf_name in used_names:
|
||||
pdf_name = f"{base}_{i}.pdf"
|
||||
i += 1
|
||||
used_names.add(pdf_name)
|
||||
out_pdf = os.path.join(tmp_dir, pdf_name)
|
||||
cmd = ["sips", "-s", "format", "pdf", src, "--out", out_pdf]
|
||||
r = subprocess.run(cmd, capture_output=True, timeout=30)
|
||||
if r.returncode == 0 and os.path.exists(out_pdf):
|
||||
zf.write(out_pdf, arcname=pdf_name)
|
||||
size = os.path.getsize(tmp_zip.name)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/zip")
|
||||
self.send_header("Content-Disposition", f'attachment; filename="photon_documents_pdf.zip"')
|
||||
self.send_header("Content-Length", str(size))
|
||||
self.end_headers()
|
||||
with open(tmp_zip.name, "rb") as f:
|
||||
while True:
|
||||
chunk = f.read(1024 * 1024)
|
||||
if not chunk: break
|
||||
self.wfile.write(chunk)
|
||||
except Exception as e:
|
||||
self._json({"error": f"Failed converting batch PDFs: {e}"}, 500)
|
||||
finally:
|
||||
try: os.remove(tmp_zip.name)
|
||||
except Exception: pass
|
||||
try: shutil.rmtree(tmp_dir)
|
||||
except Exception: pass
|
||||
|
||||
elif self.path.startswith("/api/search"):
|
||||
parsed_url = urllib.parse.urlparse(self.path)
|
||||
params = urllib.parse.parse_qs(parsed_url.query)
|
||||
|
||||
Reference in New Issue
Block a user