diff --git a/index.html b/index.html index a75dee4..f844ae9 100644 --- a/index.html +++ b/index.html @@ -42,6 +42,7 @@ .hero .loc { font-size: 6rem; font-weight: 800; line-height: 1; margin: 6px 0; } .hero.ok .loc { color: #34d399; } .hero.warn .loc { color: #fbbf24; font-size: 2.4rem; } + .hero .desc { color: #9ca3af; font-size: .9rem; margin-top: 8px; } .status { font-size: 1.25rem; font-weight: 650; } .ok { color: #34d399; } .warn { color: #fbbf24; } .err { color: #f87171; } .muted { color: #9ca3af; } .rows { margin-top: 10px; display: flex; justify-content: space-between; align-items: baseline; font-size: 1.05rem; } @@ -100,7 +101,9 @@ let html = '
' + '
Put it away at
' + - '
' + (hasLoc ? escapeHtml(res.location) : 'no location') + '
'; + '
' + (hasLoc ? escapeHtml(res.location) : 'no location') + '
' + + (res.description ? '
' + escapeHtml(res.description) + '
' : '') + + ''; let status, rows = ''; if (res.previous_weight === undefined) { diff --git a/main.go b/main.go index ac16645..96ca095 100644 --- a/main.go +++ b/main.go @@ -32,6 +32,7 @@ type result struct { Image string `json:"image"` SpoolID string `json:"spool_id,omitempty"` URL string `json:"url,omitempty"` + Description string `json:"description,omitempty"` // brand/material/type/color Location string `json:"location,omitempty"` PreviousWeight *weightBreakdown `json:"previous_weight,omitempty"` // as read from spooldb NewWeight *weightBreakdown `json:"new_weight,omitempty"` // from the measured photo @@ -202,6 +203,7 @@ func processImg(img image.Image, name string, auth claude.Auth, dryRun bool) res } if info != nil { r.Location = info.Location + r.Description = info.Description r.PreviousWeight = &weightBreakdown{ Spool: ptr(info.EmptySpoolGrams), Filament: ptr(info.RemainingGrams), diff --git a/spooldb/client.go b/spooldb/client.go index a29c789..52650fd 100644 --- a/spooldb/client.go +++ b/spooldb/client.go @@ -191,6 +191,7 @@ func (c *Client) Login(ctx context.Context, email, password string) error { // SpoolInfo is the current state of a spool, read from its edit dialog. type SpoolInfo struct { Location string // location label, e.g. "H" (empty if unset) + Description string // brand/material/type/color, e.g. "Bambu Lab ABS GF - Black (41101)" TotalGrams float64 // weight including the spool (what the scale reads) RemainingGrams float64 // remaining filament the site tracks EmptySpoolGrams float64 // empty-spool weight used to derive remaining @@ -252,23 +253,31 @@ func (c *Client) SpoolInfo(ctx context.Context, spoolID string) (SpoolInfo, erro const js = `(() => { const val = id => { const e = document.getElementById(id); return e ? e.value : ''; }; const ph = id => { const e = document.getElementById(id); return e ? e.placeholder : ''; }; + const dialog = document.getElementById('weight_with_spool').closest('[role="dialog"]') || document.body; + // The dialog header reads "Edit Spool" then a descriptor line like + // "Bambu Lab ABS GF - Black (41101)" (brand, material, type, color). + const lines = dialog.innerText.split('\n').map(s => s.trim()); + const i = lines.indexOf('Edit Spool'); + const desc = i >= 0 ? (lines.slice(i + 1).find(s => s.length) || '') : ''; return JSON.stringify({ - location: val('location_label'), - total: val('weight_with_spool'), - remaining: val('remaining_grams'), - empty: val('empty_spool_weight') || ph('empty_spool_weight'), + location: val('location_label'), + total: val('weight_with_spool'), + remaining: val('remaining_grams'), + empty: val('empty_spool_weight') || ph('empty_spool_weight'), + description: desc, }); })()` var out string if err := c.run(ctx, 10*time.Second, chromedp.Evaluate(js, &out)); err != nil { return SpoolInfo{}, err } - var raw struct{ Location, Total, Remaining, Empty string } + var raw struct{ Location, Total, Remaining, Empty, Description string } if err := json.Unmarshal([]byte(out), &raw); err != nil { return SpoolInfo{}, fmt.Errorf("parse spool fields: %w", err) } return SpoolInfo{ Location: strings.TrimSpace(raw.Location), + Description: strings.TrimSpace(raw.Description), TotalGrams: parseGrams(raw.Total), RemainingGrams: parseGrams(raw.Remaining), EmptySpoolGrams: parseGrams(raw.Empty),