diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-29 14:17:33 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-29 14:17:33 +0200 |
| commit | 9f6414838d4fabc174bb193f34225de8d9fc8079 (patch) | |
| tree | 486f00b96a2174a783122c0e11a5d13c6c5ca965 | |
| parent | 4300fb5a232a2edf5262073ab7b898b8cbb126e4 (diff) | |
| download | conky-theme-udt-9f6414838d4fabc174bb193f34225de8d9fc8079.tar.gz conky-theme-udt-9f6414838d4fabc174bb193f34225de8d9fc8079.zip | |
feat(immich): fall back to the past week's memories
A day with no memories left the card showing only a notice. When today
has none, immich-fetch.sh now merges the memories of each of the past
six days, skipping a day whose request fails, and marks the index with
a scope week line. The subtitle names where the photos come from,
Today or This week, before the i/n counter, and the empty notice reads
no memories this week.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | README.md | 7 | ||||
| -rwxr-xr-x | bin/immich-fetch.sh | 31 | ||||
| -rw-r--r-- | lib/data.lua | 5 | ||||
| -rw-r--r-- | test/test_data.lua | 2 | ||||
| -rw-r--r-- | widgets/immich.lua | 5 |
5 files changed, 39 insertions, 11 deletions
@@ -204,9 +204,10 @@ local time) and where, as city and country, or coordinates when Immich has no place name for them. `bin/immich-fetch.sh` runs every 30 minutes. It asks `/api/memories` for -today, downloads each photo's preview, converts it to PNG with ImageMagick -(Cairo loads nothing else) and writes an index beside the photos in -`~/.cache/udt/immich/`, dropping photos that are no longer today's. It needs +today, or for each of the past six days when today has none, downloads each +photo's preview, converts it to PNG with ImageMagick (Cairo loads nothing +else) and writes an index beside the photos in `~/.cache/udt/immich/`, +dropping photos that are no longer in it. It needs `curl`, `jq` and `magick`, and a key in `~/.config/udt/immich.env`: copy `immich.env.example`. The key wants `memory.read` and `asset.view`; with `asset.read` too, the card shows the place, and without it the row reads `--`. diff --git a/bin/immich-fetch.sh b/bin/immich-fetch.sh index 961cd63..0fb5b41 100755 --- a/bin/immich-fetch.sh +++ b/bin/immich-fetch.sh @@ -6,8 +6,10 @@ # Writes $CACHE_DIR/<asset id>.png per photo plus index.txt: # generated <epoch> # url <server URL> +# scope week (only when the past week's memories stand in for today's) # photo <asset id>|<memory year>|<localDateTime>|<place> -# An index with no photo lines means "no memories today", which the card shows +# When today has none, the past six days' memories are used instead. An +# index with no photo lines means "no memories this week", which the card shows # differently from a missing index ("the fetch never ran"). # # Leaves any existing cache untouched when the server cannot be reached, rather @@ -40,21 +42,40 @@ mkdir -p "$CACHE_DIR" TMP="$INDEX.tmp.$$" MEM="$CACHE_DIR/memories.json.tmp.$$" -trap 'rm -f "$TMP" "$MEM" "$CACHE_DIR"/*.part.$$' EXIT +trap 'rm -f "$TMP" "$MEM" "$CACHE_DIR"/*.part.$$ "$CACHE_DIR"/week.json.tmp.$$*' EXIT api() { curl -fsS --max-time 20 -H "x-api-key: $KEY" "${URL%/}/api/$1" } -if ! api "memories?for=$(date +%F)" > "$MEM" 2>/dev/null \ - || ! jq -e 'type == "array"' "$MEM" > /dev/null 2>&1; then +memories() { + api "memories?for=$1" > "$MEM" 2>/dev/null \ + && jq -e 'type == "array"' "$MEM" > /dev/null 2>&1 +} + +if ! memories "$(date +%F)"; then echo "immich-fetch: memories request failed" >&2 exit 1 fi +# No memories today: fall back to the past week's, so the card still shows +# something. Each day's memories go in one merged array; a day that fails is +# skipped rather than failing the whole fetch. +if ! jq -e 'any(.[]; .type == "on_this_day")' "$MEM" > /dev/null; then + WEEK="$CACHE_DIR/week.json.tmp.$$" + echo '[]' > "$WEEK" + for d in 1 2 3 4 5 6; do + memories "$(date -d "$d days ago" +%F)" || continue + jq -s 'add' "$WEEK" "$MEM" > "$WEEK.new" && mv -f "$WEEK.new" "$WEEK" + done + mv -f "$WEEK" "$MEM" + SCOPE=week +fi + echo "generated $(date +%s)" > "$TMP" # For the card's click-through to the photo in Immich's web UI. echo "url ${URL%/}" >> "$TMP" +[ -n "${SCOPE:-}" ] && echo "scope $SCOPE" >> "$TMP" # One line per asset: id, the memory's year, and when the photo was taken. # localDateTime is the camera's wall clock, which is what "taken at" means; @@ -88,7 +109,7 @@ done mv -f "$TMP" "$INDEX" -# Drop photos no longer in today's memories, so the directory holds one day. +# Drop photos no longer in the index, so the directory holds one fetch's worth. for f in "$CACHE_DIR"/*.png; do [ -e "$f" ] || continue id=$(basename "$f" .png) diff --git a/lib/data.lua b/lib/data.lua index 1173fce..c66aa42 100644 --- a/lib/data.lua +++ b/lib/data.lua @@ -594,7 +594,8 @@ end -- The Immich memories index written by bin/immich-fetch.sh. -- -- Returns a list of { id, year, taken = { y, m, d, H, M }, place }, plus --- .url, the server's address for a click-through, or nil when +-- .url, the server's address for a click-through, and .week, true when the +-- photos are the past week's fallback rather than today's, or nil when -- the index is absent or carries no 'generated' key. nil means "the fetch never -- ran"; an empty list means "no memories today", which the card names -- differently. `place` is nil when the key lacks asset.read or the photo has no @@ -608,6 +609,8 @@ function M.immich_parse(text) generated = true elseif kind == 'url' then out.url = rest + elseif kind == 'scope' then + out.week = rest == 'week' elseif kind == 'photo' then -- The place is last and takes the rest of the line, so a pipe in a -- place name cannot shift a field. diff --git a/test/test_data.lua b/test/test_data.lua index 7b84b3d..4ed58f8 100644 --- a/test/test_data.lua +++ b/test/test_data.lua @@ -457,5 +457,7 @@ assert(data.immich_parse('photo a|2014||\n') == nil, 'no generated key: nil') assert(data.immich_parse(nil) == nil, 'nil index: nil') local none = data.immich_parse('generated 1\n') assert(none and #none == 0, 'no memories today: empty list, not nil') +assert(not im.week, 'no scope line: today') +assert(data.immich_parse('generated 1\nscope week\n').week, 'scope week parses') print('test_data: all assertions passed') diff --git a/widgets/immich.lua b/widgets/immich.lua index a9caca7..8590dbf 100644 --- a/widgets/immich.lua +++ b/widgets/immich.lua @@ -69,7 +69,7 @@ function M.draw(cr, rect, colors) return end if #photos == 0 then - card.notice(cr, inner, colors, 'MEMORIES', 'no memories today', + card.notice(cr, inner, colors, 'MEMORIES', 'no memories this week', os.date('%d/%m')) return end @@ -81,7 +81,8 @@ function M.draw(cr, rect, colors) local ago = p.year and (tonumber(os.date('%Y')) - p.year) or nil local big = ago and tostring(ago) or '--' - local sub = n > 1 and string.format('%d/%d', i, n) or '' + local sub = (photos.week and 'This week' or 'Today') + .. (n > 1 and string.format(' %d/%d', i, n) or '') local t = p.taken local taken = t and string.format('%02d/%02d/%04d %02d:%02d', t[3], t[2], t[1], t[4], t[5]) or '--' |
