aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-29 14:17:33 +0200
committerDanilo M. <danix@danix.xyz>2026-09-29 14:17:33 +0200
commit9f6414838d4fabc174bb193f34225de8d9fc8079 (patch)
tree486f00b96a2174a783122c0e11a5d13c6c5ca965
parent4300fb5a232a2edf5262073ab7b898b8cbb126e4 (diff)
downloadconky-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.md7
-rwxr-xr-xbin/immich-fetch.sh31
-rw-r--r--lib/data.lua5
-rw-r--r--test/test_data.lua2
-rw-r--r--widgets/immich.lua5
5 files changed, 39 insertions, 11 deletions
diff --git a/README.md b/README.md
index e68827e..a78371e 100644
--- a/README.md
+++ b/README.md
@@ -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 '--'