Skip to content

Repository files navigation

Self-hosted filament inventory for 3D printing. Track spools, purchases and shop prices β€” get notified when a filament hits your target price.

License: MIT Docker build Docker Pulls Python 3.12+

Quick Start Β· Features Β· Configuration Β· Price Monitoring Β· Troubleshooting


Screenshots

Dashboard Inventory
Dashboard Inventory
Filament Detail Spools
Filament Detail Spools
Print Board New Print Job
Print Board New Print Job
3D Preview
3D Preview
Shop Rules Manufacturers
Shop Rules Manufacturers
API Keys
API Keys

πŸ“¦ Features

Inventory Filaments by manufacturer, material, color and diameter β€” including dual-color/co-extruded filaments. Spools track remaining weight, fill %, storage location and status.
Print Board Kanban board (Planned β†’ Printing β†’ Done) for print jobs β€” name, notes, filament lines, links to Printables/MakerWorld/Thingiverse or STL/3MF upload with in-browser 3D preview. Filament is only deducted when a job is marked Done, and spool status auto-updates (opened β†’ almost empty β†’ empty).
Manufacturers Dedicated manufacturer pages listing every product from that brand.
Purchase history Price per spool, lot number, currency β€” spools are auto-created on purchase.
Price monitoring Shop links with manual prices and automated scraping via ShopRules or built-in adapters.
Price alerts Alert when price ≀ target (absolute or per kg) β€” Discord and SMTP notifications.
Spool labels Printable QR-code labels per spool for physical tagging.
Backup & restore Full JSON export/import β€” additive, safe to re-run.
Dashboard Overview, low-stock list, material/color breakdown, active alerts, scheduler status.
User management Admin / Member / Viewer roles β€” Viewer is fully read-only.
REST API Full JSON API with bearer-token auth β€” read/write inventory, spools and print jobs. Interactive docs at /api/docs (Swagger UI).

πŸ”§ Requirements

  • Docker + Docker Compose

For local development: Python 3.12+


πŸš€ Quick Start

Option A β€” Docker Hub (recommended, no clone needed)

Create a compose.yaml:

services:
  web:
    image: sytxlabs/spoolbeacon:latest
    ports:
      - "${APP_PORT:-8080}:${APP_PORT:-8080}"
    env_file: .env
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mariadb:11
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: ${DB_PASSWORD}
      MARIADB_DATABASE: ${DB_NAME}
      MARIADB_USER: ${DB_USER}
      MARIADB_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db_data:

Create a .env next to it:

SECRET_KEY=       # generate: python -c "import secrets; print(secrets.token_hex(32))"
APP_PORT=8080
DB_HOST=db
DB_PORT=3306
DB_USER=spoolbeacon
DB_PASSWORD=changeme
DB_NAME=spoolbeacon
QUART_AUTH_COOKIE_SECURE=true

Pull and start:

docker compose up -d

Option B β€” From source (GitHub)

git clone https://github.com/Sytxlabs/SpoolBeacon.git
cd SpoolBeacon
cp .env.example .env   # edit SECRET_KEY and DB_PASSWORD
docker compose up --build -d

MariaDB starts automatically, migrations run on container start. The app is exposed on APP_PORT (default 8080) β€” only that port is mapped to the host, MariaDB stays internal to the compose network.

First admin account

Open http://your-host:8080/setup β€” only available when no users exist yet.


⬆️ Updating

Docker Hub install:

docker compose pull
docker compose up -d

From source:

git pull
docker compose up --build -d

Migrations run automatically on restart.


πŸ› οΈ Local Development

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
playwright install --with-deps chromium
cp .env.example .env   # fill in DB credentials
python migration.py upgrade head
python main.py         # runs on http://localhost:8080

Seed sample data:

python seed.py           # manufacturers, products, purchases, links, rules (idempotent)
python seed.py --reset   # wipe all tables (except users/settings) and re-seed
python seed_shops.py     # ShopRules only, no inventory data

βš™οΈ Configuration

All runtime settings are managed on the Settings page (/settings, admin only) β€” not via .env.

Section What you can configure
Scheduler Enable automatic price checks, set interval in minutes
Fetch engine playwright (default, JS-capable) or httpx (faster, no JS)
Discord Webhook URL, enable/disable, test message
Email (SMTP) Host, port, credentials, TLS, from/to address, test email
Spool code template Pattern for auto-generated spool codes
Backup & Restore Export full inventory as JSON, import additively (admin only)

πŸ“ˆ Price Monitoring

Built-in Adapters

These shops work out of the box without any manual configuration:

Shop Method
3djake.de CSS selector
prusa3d.com JSON-LD
anycubic.com Shopify JSON-LD
eu.store.bambulab.com JSON-LD (cloudscraper)
esun3dstore.com Shopify JSON-LD (cloudscraper)
esun3dstoreeu.com Shopify JSON-LD (cloudscraper)
elegoo.com Shopify og:price:amount

To add a new adapter: subclass BaseAdapter in app/shop_adapters/, implement extract(html, url) -> AdapterResult, register in registry.py via _reg(YourAdapter()).

ShopRules (generic)

For any other shop: create a rule at /shop-rules with domain, CSS price selector, and optional regex β€” or use the visual point-and-click picker to build one without touching CSS.


πŸ–¨οΈ Print Board

Navigate to Prints in the nav bar (or /prints/) for a Kanban-style board of your print jobs, grouped into Planned β†’ Printing β†’ Done columns.

Hit + New Print Job to plan a new job:

  1. Enter an optional print name and notes.
  2. Add one or more filament lines β€” select a spool from the grouped dropdown, enter planned grams. The live preview shows how much is left on that spool.
  3. Optionally attach print files: a link to Printables/MakerWorld/Thingiverse/etc., or upload an STL/3MF directly β€” uploaded files get an in-browser 3D preview (three.js, no external service).
  4. Hit Add to Board β€” the job lands in Planned with a generated job code (e.g. PJ-20260803-002, template configurable under Settings).

Move a card forward with Start / Mark Done, or back with the reopen button. Filament is only deducted from the spool once a job is marked Done β€” moving it back out of Done restores the weight. Planned/printing jobs can be edited (name, notes, filament lines, files) via the pencil icon; completed jobs are read-only history (reopen first to edit).

Supports multi-filament prints (e.g. dual-extrusion or colour changes mid-print) by adding multiple lines.


πŸ”Œ REST API

SpoolBeacon exposes a versioned JSON API at /api/v1/. Interactive documentation (Swagger UI) is available at /api/docs β€” no login required, just a bearer token.

Authentication

API keys are managed at /api-keys (admin only). Each key is shown once at creation time and stored as a SHA-256 hash.

Authorization: Bearer <your-token>

Endpoints

Method Path Description
GET /api/v1/health Health check (no auth required)
GET /api/v1/manufacturers List all manufacturers
GET /api/v1/products List all filament products
GET /api/v1/products/{id} Product detail including all spools
GET /api/v1/spools List spools β€” filter with ?status=new|opened|almost_empty|empty|archived
GET /api/v1/spools/{id} Single spool
PATCH /api/v1/spools/{id} Update remaining weight {"remaining_g": 450} β€” status auto-updates
GET /api/v1/prints Paginated print jobs (?page=, ?per_page= max 100)
POST /api/v1/prints Plan a new print job (status planned, no weight deducted yet)
PATCH /api/v1/prints/{id}/status Move a job between planned/printing/done

POST /api/v1/prints body

{
  "print_name": "Benchy",
  "notes": "Optional",
  "lines": [
    {
      "spool_id": 3,
      "used_g": 12.5
    },
    {
      "spool_id": 7,
      "used_g": 4.0
    }
  ]
}

The job is created with status planned. Spool weight is only deducted once the job is moved to done via PATCH /api/v1/prints/{id}/status ({"status": "done"}), and spool status auto-updates (new β†’ opened β†’ almost empty β†’ empty). Moving a job back out of done restores the deducted weight.

Quick example

TOKEN=your-token-here

# List active spools
curl -H "Authorization: Bearer $TOKEN" http://your-host:8080/api/v1/spools?status=opened

# Log a print job
curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"print_name":"Benchy","lines":[{"spool_id":1,"used_g":6.2}]}' \
  http://your-host:8080/api/v1/prints

Full schema and "Try it out" in Swagger UI: http://your-host:8080/api/docs


⚠️ Known Limitations

  • Amazon / eBay not supported β€” Amazon requires an authenticated session or the Product Advertising API; eBay blocks scraping via Cloudflare
  • Heavy WAFs (Cloudflare Enterprise) block even cloudscraper β€” a proxy or official API is needed
  • No printer / slicer integration β€” no Klipper, OrcaSlicer or automatic print job import; print jobs can be submitted via the REST API
  • No mobile app β€” web only, mobile-optimised responsive layout

🩺 Troubleshooting

App won't start β€” Database not initialized

Check DB credentials in .env. MariaDB must be reachable and the database must exist.

Migrations fail β€” Table already exists

Run python migration.py stamp head to mark the current state, then migrate.

Playwright checks time out

Increase playwright.timeout_ms in Settings (default: 30 000 ms).

Price not found

The shop's HTML structure changed. Use the Test button on /shop-rules and update the selector/regex.

Setup page unavailable

/setup is locked once a user exists. Add users via /users (admin only).


🐳 Docker Image

Pre-built images are published to Docker Hub on every push to master and on version tags:

Tag Description
sytxlabs/spoolbeacon:latest Latest stable build from master
sytxlabs/spoolbeacon:<version> Pinned release (e.g. 1.0.0)
docker pull sytxlabs/spoolbeacon:latest

πŸ“„ License

MIT β€” see the LICENSE file for details.

About

Self-hosted filament inventory, spool tracking, and price monitoring for 3D printing.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages