Sign inSign up

sytxlabs/spoolbeacon

By sytxlabs

•Updated about 2 months ago

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

Image
API management
Monitoring & observability
Web analytics
0

1.4K

sytxlabs/spoolbeacon repository overview

⁠SpoolBeacon⁠

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

DashboardInventory
DashboardInventory
Filament DetailSpools
Filament DetailSpools
Print BoardNew Print Job
Print BoardNew Print Job
3D Preview
3D Preview
Shop RulesManufacturers
Shop RulesManufacturers
API Keys
API Keys

⁠📦 Features

InventoryFilaments by manufacturer, material, color and diameter — including dual-color/co-extruded filaments. Spools track remaining weight, fill %, storage location and status.
Print BoardKanban 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).
ManufacturersDedicated manufacturer pages listing every product from that brand.
Purchase historyPrice per spool, lot number, currency — spools are auto-created on purchase.
Price monitoringShop links with manual prices and automated scraping via ShopRules or built-in adapters.
Price alertsAlert when price ≤ target (absolute or per kg) — Discord and SMTP notifications.
Spool labelsPrintable QR-code labels per spool for physical tagging.
Backup & restoreFull JSON export/import — additive, safe to re-run.
DashboardOverview, low-stock list, material/color breakdown, active alerts, scheduler status.
User managementAdmin / Member / Viewer roles — Viewer is fully read-only.
REST APIFull 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

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.

SectionWhat you can configure
SchedulerEnable automatic price checks, set interval in minutes
Fetch engineplaywright (default, JS-capable) or httpx (faster, no JS)
DiscordWebhook URL, enable/disable, test message
Email (SMTP)Host, port, credentials, TLS, from/to address, test email
Spool code templatePattern for auto-generated spool codes
Backup & RestoreExport full inventory as JSON, import additively (admin only)

⁠📈 Price Monitoring

⁠Built-in Adapters

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

ShopMethod
3djake.deCSS selector
prusa3d.comJSON-LD
anycubic.comShopify JSON-LD
eu.store.bambulab.comJSON-LD (cloudscraper)
esun3dstore.comShopify JSON-LD (cloudscraper)
esun3dstoreeu.comShopify JSON-LD (cloudscraper)
elegoo.comShopify 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
MethodPathDescription
GET/api/v1/healthHealth check (no auth required)
GET/api/v1/manufacturersList all manufacturers
GET/api/v1/productsList all filament products
GET/api/v1/products/{id}Product detail including all spools
GET/api/v1/spoolsList 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/printsPaginated print jobs (?page=, ?per_page= max 100)
POST/api/v1/printsPlan a new print job (status planned, no weight deducted yet)
PATCH/api/v1/prints/{id}/statusMove 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:

TagDescription
sytxlabs/spoolbeacon:latestLatest 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.

Tag summary

Content type

Image

Digest

sha256:c6c4d2528…

Size

355 MB

Last updated

about 2 months ago

docker pull sytxlabs/spoolbeacon