From 178fb2eb37da51d39003af3df59f6c7e0c272ce7 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Thu, 20 Aug 2026 08:43:21 -0400 Subject: [PATCH] feat(sync): serve web highlight colors to KOReader (mapped to its palette) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverses the earlier "no colors to the device" decision now that the echo machinery makes it safe: GetMetadata maps the stored web hex to KOReader's fixed color names (#ce93d8→purple, #90caf9→blue, #a5d6a7→green, #ffd54f→yellow; pink maps to purple as the closest — round-trip drift is prevented on the device by echo suppression, and a device edit still wins). mapColorToKOReader restored for serving; ingest (name→hex, preserve-on-echo) unchanged. --- internal/handlers/koreader.go | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/internal/handlers/koreader.go b/internal/handlers/koreader.go index cb16c72..9771a66 100644 --- a/internal/handlers/koreader.go +++ b/internal/handlers/koreader.go @@ -993,10 +993,12 @@ func (h *KOReaderHandler) GetMetadata(c *echo.Context) error { Text: ann.SelectionText, Pos0: pos0, Pos1: pos1, - // No color served: devices render their own default and - // cannot round-trip web colors — the web color only changes - // when the highlight is edited on the device (push carries - // the device color, ingested with the name→hex map). + // Web colors flow to the device, mapped to KOReader's named + // palette. Round-trip safety: the device suppresses the color + // when echoing un-edited applied entries (a pink→purple + // palette mismatch must not rewrite the stored hex), and an + // actual device edit pushes its color, which wins. + Color: mapColorToKOReader(ann.Color.String), Datetime: ann.CreatedAt.Time.Format(time.RFC3339), DedupKey: ann.DedupKey.String, } @@ -1196,6 +1198,25 @@ func mapColorFromKOReader(name string) string { return "#ffd54f" } +var koreaderColorFromHex = map[string]string{ + "#ffd54f": "yellow", + "#a5d6a7": "green", + "#90caf9": "blue", + "#ce93d8": "purple", + "#f48fb1": "purple", +} + +// mapColorToKOReader normalizes a web hex swatch to the nearest KOReader +// color name (default yellow) when serving to devices. Pink maps to purple +// (the palette's closest); round-trip drift is prevented on the device by +// suppressing echo colors for un-edited applied entries. +func mapColorToKOReader(hex string) string { + if name, ok := koreaderColorFromHex[strings.ToLower(strings.TrimSpace(hex))]; ok { + return name + } + return "yellow" +} + // 1. A device-native CRE xpointer ("/body/...") in startPosition wins — // round-trip identical for KOReader-pushed annotations (converting the // stored CFI instead could drift and duplicate on the device).