Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 37 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
![logo](https://github.com/moddroid94/STLVault/blob/main/frontend/assets/android-chrome-192x192.png)
# STLVault

# STLVault

![Project Status](https://img.shields.io/badge/Status-Beta-orange?style=for-the-badge)
![GitHub Release](https://img.shields.io/github/v/release/moddroid94/STLVault?display_name=release&style=for-the-badge&logo=github)
Expand All @@ -11,8 +12,6 @@

![License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge)



**STLVault** is a containerized 3D Model library manager and organizer, designed specifically for 3D printing enthusiasts. It provides a clean, modern web interface to manage your growing collection of STL, STEP, and 3MF files.

> **Note:** This project is currently in Beta. While the core functionality (importing, organizing, viewing) works, expect changes and improvements.
Expand All @@ -23,7 +22,7 @@

- **📂 Nestable Folders:** Organize your models into a deep hierarchy that makes sense to you.
- **🪄 Open in Slicer:** Let's you open the model direclty in your slicer.
- **🔗 URL Import:** Import multiple files from Printables URL, with granular file selection. (Only models URL, not collections)
- **🔗 URL Import:** Import multiple files from Printables URL, with granular file selection. (Only models URL)
- **🖱️ Drag n' Drop:** Seamlessly import new models or move files between folders.
- **📦 Bulk Actions:** Tag, move, delete, download, or upload multiple files at once.
- **👁️ 3D Preview:** Integrated web-based 3D viewer for STL and 3MF files.
Expand All @@ -38,7 +37,7 @@
- **Backend:** Python (FastAPI)
- **Database:** SQLite
- **Package Manager:** NPM, UV
- **Containerization:** Docker & Docker Compose
- **Containerization:** Docker & Docker Compose

---

Expand All @@ -49,17 +48,44 @@
![Upload Modal Preview](https://github.com/user-attachments/assets/34f995d3-bc09-489f-92f3-1408bf0196a0)
![Model Viewer/Info Preview](https://github.com/user-attachments/assets/ac373cf5-3952-4336-8b56-e2864127c3aa)



---

## 🚀 Deployment

The recommended way to deploy STLVault is using **Docker Compose** or via a container management tool like **Portainer**.

**Images are available on docker-hub, just replace the build steps with the image tag in the docker-compose. (you will need to set the API Host in the app settings)**

### Option 1: Docker Compose (CLI)
## Docker Compose with Images

```
services:
stlvbackend:
image: moddroid94/stlvault-backend:latest
pull_policy: build
environment:
- FILE_STORAGE=/app/uploads
- DB_PATH=/app/data/data.db
- WEBUI_URL=http://192.168.178.21:8999
ports:
- '8998:8080'
volumes:
- YOUR_FOLDER_PATH:/app/uploads
- YOUR_FOLDER_PATH:/app/data
restart: always
stlvfrontend:
image: moddroid94/stlvault-frontend:latest
pull_policy: build
volumes:
- node_modules:/app/node_modules
ports:
- '8999:5173'
depends_on:
- stlvbackend
restart: always
volumes:
node_modules: null
```

### Docker Compose (CLI)

1. **Clone the repository:**

Expand Down Expand Up @@ -88,7 +114,7 @@ The recommended way to deploy STLVault is using **Docker Compose** or via a cont
4. **Access the App:**
Open your browser and navigate to `http://localhost:8989` (or the port you configured).

### Option 2: Portainer or GitOps (Recommended)
### Portainer

You can deploy STLVault directly from Portainer using the repository as a stack source.

Expand Down
35 changes: 34 additions & 1 deletion backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import time
import shutil
import sqlite3
import base64
from fastapi import (
FastAPI,
UploadFile,
Expand Down Expand Up @@ -396,7 +397,7 @@ def replace_model_file(
pass

filename_str = file.filename or ".stl"
ext = os.path.splitext(filename_str)[1] or ".stl"
ext = os.path.splitext(filename_str)[-1] or ".stl"
filename = f"{model_id}{ext}"
path = os.path.join(UPLOAD_DIR, filename)
size = save_upload_file(file, path)
Expand All @@ -411,6 +412,38 @@ def replace_model_file(
return row_to_model(row)


@app.put("/api/models/{model_id}/thumbnail")
def replace_model_thumbnail(
model_id: str, file: UploadFile = File(...)
):
filename_str = file.filename
ext = os.path.splitext(filename_str)[-1]
if not ext:
raise HTTPException(status_code=429, detail="File not Valid, Extension not found")

filebytes = file.file.read()
encoded_string = base64.b64encode(filebytes)
baseext = ext[1:]
thumbnail = "data:image/" + baseext + ";base64," + encoded_string.decode()

conn = get_db_conn()
cur = conn.cursor()

m = cur.execute("SELECT * FROM models WHERE id=?", (model_id,)).fetchone()
if not m:
conn.close()
raise HTTPException(status_code=404, detail="Model not found")

cur.execute(
"UPDATE models SET thumbnail=? WHERE id=?",
(thumbnail, model_id),
)
conn.commit()
row = cur.execute("SELECT * FROM models WHERE id=?", (model_id,)).fetchone()
conn.close()
return row_to_model(row)


@app.get("/api/storage-stats")
def storage_stats():
used = 0
Expand Down
7 changes: 4 additions & 3 deletions frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ const App = () => {
model.name,
model.parentId,
model.previewPath,
importFolderId
importFolderId,
model.typeName
);
setUploadQueue((prev) => prev - 1);
setModels((prev) => [newModel, ...prev]);
Expand Down Expand Up @@ -987,8 +988,8 @@ const App = () => {
{/* File List */}
<div
className={`static overflow-auto px-2 ${
visualViewport.height > 900 ? "h-[700px]" : "h-[400px]"
}`}
visualViewport.height > 900 ? "h-[700px]" : "h-[400px]"
}`}
>
{Array.from(folderOptions).map((f) => (
<div>
Expand Down
Loading