Console Files upload page -> shared-media (visible in GIMP); GIMP /media rw

This commit is contained in:
2026-08-26 15:18:46 +10:00
parent 802def6a0b
commit 1cc159ef80
5 changed files with 111 additions and 2 deletions

View File

@@ -223,6 +223,67 @@ async def tool_embed(request: Request, tool_id: str) -> HTMLResponse:
return templates.TemplateResponse(request, "embed.html", ctx)
SHARED_DIR = Path(os.getenv("SHARED_DIR", "/shared-media"))
def _shared_files(username: str) -> list:
"""List this user's uploaded files in the shared-media folder (created on demand)."""
if not SHARED_DIR.is_dir():
return []
user_dir = SHARED_DIR / username
if not user_dir.is_dir():
return []
out = []
for f in sorted(user_dir.iterdir()):
if f.is_file():
out.append({"name": f.name, "size": f.stat().st_size})
return out
@app.get("/files", response_class=HTMLResponse)
async def files_page(request: Request) -> HTMLResponse:
user = await _current_user(request)
if user is None:
return RedirectResponse("/login", status_code=303)
return templates.TemplateResponse(
request, "files.html", {"user": user, "files": _shared_files(user.username)}
)
@app.post("/files/upload")
async def files_upload(request: Request, file: Annotated[UploadFile, File()]) -> HTMLResponse:
user = await _current_user(request)
if user is None:
return RedirectResponse("/login", status_code=303)
error = None
if not file or not file.filename:
error = "No file chosen."
else:
try:
name = Path(file.filename).name.lower()
# allow images + common docs (photos are the main use case)
if not name.endswith((".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg", ".psd", ".xcf", ".pdf", ".txt", ".md")):
error = f"File type not allowed: {file.filename}"
else:
SHARED_DIR.mkdir(exist_ok=True)
user_dir = SHARED_DIR / user.username
user_dir.mkdir(exist_ok=True)
data = await file.read()
if len(data) > 50 * 1024 * 1024:
error = "File too large (max 50 MB)."
else:
(user_dir / file.filename).write_bytes(data)
except Exception as exc: # noqa: BLE001
logger.warning("files upload failed", exc_info=True)
error = f"Upload failed: {exc}"
return templates.TemplateResponse(
request, "files.html",
{"user": user, "files": _shared_files(user.username),
"error": error, "ok": error is None and file and file.filename},
)
@app.get("/admin", response_class=HTMLResponse)
async def admin_panel(request: Request) -> HTMLResponse:
user = await _current_user(request)

View File

@@ -15,6 +15,7 @@
<a class="nav-wordmark" href="/">Home Lab</a>
<div class="nav-right">
<a href="/transcriber" class="button-utility">Transcriber</a>
<a href="/files" class="button-utility">Files</a>
{% if user.is_admin %}
<a href="/admin" class="button-utility">Admin</a>
{% endif %}

View File

@@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block title %}Files — {{ settings.APP_NAME }}{% endblock %}
{% block content %}
<div class="page" style="max-width:760px">
<h1 class="greeting">My files</h1>
<p class="muted">Upload pictures here from your computer — they instantly appear in the <strong>GIMP</strong> (and video/audio) apps, under the shared <code>/media</code> folder, in your own <code>{{ user.username }}/</code> subfolder.</p>
{% if ok %}<div class="form-success" style="background:#e8f7ec;color:#1aae39;border:1px solid #b8e6c7;padding:10px 12px;border-radius:8px">✅ Uploaded. It's now in GIMP under <code>{{ user.username }}/…</code></div>{% endif %}
{% if error %}<div class="form-error">{{ error }}</div>{% endif %}
<div class="admin-panel">
<div class="linkout-card stack">
<h2 class="section-title">Upload a picture</h2>
<form method="post" action="/files/upload" enctype="multipart/form-data">
<div class="form-field">
<input class="text-input" type="file" name="file" accept="image/*,.pdf,.txt,.md" required>
</div>
<button class="button button-primary width-full" type="submit">Upload</button>
</form>
<p class="faint margin-top" style="font: var(--type-caption)">
On your computer (e.g. <code>.27</code>) uploads go to the lab's shared folder on <code>.13</code>, which GIMP opens at <code>/media/{{ user.username }}/</code>.
</p>
</div>
<section class="stack">
<h2 class="section-title">Uploaded ({{ files|length }})</h2>
{% if files %}
<ul class="file-list">
{% for f in files %}
<li><span class="file-name" title="{{ f.name }}">{{ f.name }}</span><span class="faint">{{ (f.size/1024)|round(1) }} KB</span></li>
{% endfor %}
</ul>
<p class="faint margin-top" style="font: var(--type-caption)">
To open one in GIMP: go to <code>gimp.lab.audasmedia.com.au</code> → <strong>File → Open</strong> → <code>/media/{{ user.username }}/…</code>.
</p>
{% else %}
<p class="faint">Nothing uploaded yet.</p>
{% endif %}
</section>
</div>
</div>
{% endblock %}