#!/usr/bin/env bash ############################################################################### # dlog — Reading log & completed content manager via dmenu # # Writes to krisyotam.com media.db (SQLite) # Tables: reading_log, reading_books, reading_audiobooks, reading_blogs, # reading_essays, reading_papers, reading_verse, short_stories # # Maintainer: Kris Yotam # License: MIT # Created: 2026-02-18 ############################################################################### DB="$HOME/dev/krisyotam.com/public/data/media.db" # ── Helpers ──────────────────────────────────────────────────── ask() { printf '' | dmenu -p "$1"; } pick() { dmenu -i -l "${2:-10}" -p "$1"; } esc() { printf '%s' "$1" | sed "s/'/''/g"; } today() { date +%Y-%m-%d; } # Duration: >99m displays as Xh Ym fmt_dur() { local m="$1" if [ "$m" -gt 99 ] 2>/dev/null; then printf '%dh %dm' "$((m / 60))" "$((m % 60))" else printf '%dm' "$m" fi } sql() { sqlite3 "$DB" "$1"; } # ── Log Entry (reading_log) ─────────────────────────────────── log_entry() { local dt title author type minutes dt=$(echo "$(today)" | pick "󰃭 Date:") [ -z "$dt" ] && return title=$(ask "󰗴 Title:") [ -z "$title" ] && return author=$(ask "󰏪 Author:") [ -z "$author" ] && return type=$(printf '%s\n' \ "󰂽 Book" \ "󰋋 Audiobook" \ "󰖟 Blog Post" \ "󰏫 Short Story" \ "󰎈 Verse" \ "󰧮 Essay" \ "󰈙 Paper" \ | pick "󰏗 Type:" 7) [ -z "$type" ] && return type=$(echo "$type" | sed 's/^[^ ]* *//') # Offer "+ Audiobook" if primary type isn't already Audiobook if [ "$type" != "Audiobook" ]; then local also also=$(printf '%s\n' "󰜺 No" "󰋋 + Audiobook" \ | pick "󰋋 Also listening?" 2) [[ -n "$also" && "$also" == *Audiobook* ]] && type="$type + Audiobook" fi minutes=$(printf '%s\n' 5 10 15 20 30 45 60 90 120 180 \ | pick "󱑂 Minutes:" 10) [ -z "$minutes" ] && return local dur dur=$(fmt_dur "$minutes") local ok ok=$(printf '%s\n' "󰄬 Confirm" "󰜺 Cancel" \ | pick "$title · $author · $type · $dur" 2) [[ -z "$ok" || "$ok" == *Cancel* ]] && return sql "INSERT INTO reading_log (date, title, author, type, minutes) VALUES ('$(esc "$dt")', '$(esc "$title")', '$(esc "$author")', '$(esc "$type")', $minutes);" notify-send "dlog" "󰎚 Logged: $title ($dur)" } # ── Completed: Books ────────────────────────────────────────── add_book() { local title subtitle author cover link title=$(ask "󰂽 Title:") [ -z "$title" ] && return subtitle=$(ask "󰂽 Subtitle:") author=$(ask "󰏪 Author:") [ -z "$author" ] && return cover=$(ask "󰋩 Cover URL:") link=$(ask "󰌹 Link:") sql "INSERT INTO reading_books (title, subtitle, author, cover, link) VALUES ('$(esc "$title")', '$(esc "$subtitle")', '$(esc "$author")', '$(esc "$cover")', '$(esc "$link")');" notify-send "dlog" "󰂽 Added: $title" } # ── Completed: Audiobooks ───────────────────────────────────── add_audiobook() { local title subtitle author cover link title=$(ask "󰋋 Title:") [ -z "$title" ] && return subtitle=$(ask "󰋋 Subtitle:") author=$(ask "󰏪 Author:") [ -z "$author" ] && return cover=$(ask "󰋩 Cover URL:") link=$(ask "󰌹 Link:") sql "INSERT INTO reading_audiobooks (title, subtitle, author, cover, link) VALUES ('$(esc "$title")', '$(esc "$subtitle")', '$(esc "$author")', '$(esc "$cover")', '$(esc "$link")');" notify-send "dlog" "󰋋 Added: $title" } # ── Completed: Blog Posts ───────────────────────────────────── add_blog() { local title author src arc year title=$(ask "󰖟 Title:") [ -z "$title" ] && return author=$(ask "󰏪 Author:") src=$(ask "󰌹 Source URL:") arc=$(ask "󰀼 Archive URL:") year=$(ask "󰃭 Year:") sql "INSERT INTO reading_blogs (title, author, source_link, archive_link, publication_year) VALUES ('$(esc "$title")', '$(esc "$author")', '$(esc "$src")', '$(esc "$arc")', ${year:-NULL});" notify-send "dlog" "󰖟 Added: $title" } # ── Completed: Short Stories ────────────────────────────────── add_short_story() { local title author year title=$(ask "󰏫 Title:") [ -z "$title" ] && return author=$(ask "󰏪 Author:") [ -z "$author" ] && return year=$(ask "󰃭 Year:") sql "INSERT INTO short_stories (title, author, publication_year) VALUES ('$(esc "$title")', '$(esc "$author")', ${year:-NULL});" notify-send "dlog" "󰏫 Added: $title" } # ── Completed: Verse ────────────────────────────────────────── add_verse() { local title author vtype src year title=$(ask "󰎈 Title:") [ -z "$title" ] && return author=$(ask "󰏪 Author:") [ -z "$author" ] && return vtype=$(printf '%s\n' \ "lyric poem" "narrative poem" "ballad" "sonnet" "epigram" \ "haiku" "ode" "elegy" "free verse" "epic" "limerick" "villanelle" \ | pick "󰎈 Form:" 12) src=$(ask "󰌹 Source URL:") year=$(ask "󰃭 Year:") sql "INSERT INTO reading_verse (title, author, verse_type, source_link, publication_year) VALUES ('$(esc "$title")', '$(esc "$author")', '$(esc "$vtype")', '$(esc "$src")', ${year:-NULL});" notify-send "dlog" "󰎈 Added: $title" } # ── Completed: Essays ───────────────────────────────────────── add_essay() { local title author src arc year title=$(ask "󰧮 Title:") [ -z "$title" ] && return author=$(ask "󰏪 Author:") [ -z "$author" ] && return src=$(ask "󰌹 Source URL:") arc=$(ask "󰀼 Archive URL:") year=$(ask "󰃭 Year:") sql "INSERT INTO reading_essays (title, author, source_link, archive_link, publication_year) VALUES ('$(esc "$title")', '$(esc "$author")', '$(esc "$src")', '$(esc "$arc")', ${year:-NULL});" notify-send "dlog" "󰧮 Added: $title" } # ── Completed: Papers ───────────────────────────────────────── add_paper() { local title src arc year local authors=() title=$(ask "󰈙 Title:") [ -z "$title" ] && return # Multi-author loop while true; do local a a=$(printf '%s\n' "󰄬 Done adding authors" \ | pick "󰏪 Author $((${#authors[@]} + 1)):" 1) [[ -z "$a" || "$a" == *Done* ]] && break authors+=("$a") done [ ${#authors[@]} -eq 0 ] && return # Build JSON array for author field local json='[' for i in "${!authors[@]}"; do [ "$i" -gt 0 ] && json+=',' json+="\"$(esc "${authors[$i]}")\"" done json+=']' src=$(ask "󰌹 Source URL:") arc=$(ask "󰀼 Archive URL:") year=$(ask "󰃭 Year:") sql "INSERT INTO reading_papers (title, author, source_link, archive_link, publication_year) VALUES ('$(esc "$title")', '$(esc "$json")', '$(esc "$src")', '$(esc "$arc")', ${year:-NULL});" notify-send "dlog" "󰈙 Added: $title (${#authors[@]} authors)" } # ── Completed Submenu ───────────────────────────────────────── completed_menu() { local choice choice=$(printf '%s\n' \ "󰂽 Books" \ "󰋋 Audiobooks" \ "󰖟 Blog Posts" \ "󰏫 Short Stories" \ "󰎈 Verse" \ "󰧮 Essays" \ "󰈙 Papers" \ | pick "󰄲 Completed" 7) [ -z "$choice" ] && return case "$choice" in *Books*) add_book ;; *Audiobooks*) add_audiobook ;; *Blog*) add_blog ;; *Short*) add_short_story ;; *Verse*) add_verse ;; *Essays*) add_essay ;; *Papers*) add_paper ;; esac } # ── Main ────────────────────────────────────────────────────── main=$(printf '%s\n' \ "󰎚 Log" \ "󰄲 Completed" \ | pick "󰎚 dlog" 2) [ -z "$main" ] && exit 0 case "$main" in *Log*) log_entry ;; *Completed*) completed_menu ;; esac