#!/usr/bin/env bash set -euo pipefail usage() { echo "Usage:" echo " noteurls [N]" echo "" echo "Open URLs from latest N notes (default: 100)" echo "" echo "fzf keys:" echo " TAB select/unselect URL" echo " ENTER open selected URLs" echo " CTRL-A select all" echo "" echo "Examples:" echo " noteurls" echo " noteurls 20" } case "${1:-}" in h|-h|--help) usage exit 0 ;; esac NOTES_DIR="${NOTES_DIR:-$HOME/notes}" N="${1:-100}" # should also work with older fzf versions export FZF_DEFAULT_OPTS="--pointer='>' --color=fg:-1,bg:-1,hl:-1,fg+:-1,bg+:-1,hl+:-1,info:-1,prompt:-1,spinner:-1,pointer:-1,marker:-1,border:-1" open_url() { local url="$1" if grep -qi microsoft /proc/version 2>/dev/null; then powershell.exe -NoProfile -Command "Start-Process '$url'" >/dev/null 2>&1 & disown || true elif command -v xdg-open >/dev/null 2>&1; then xdg-open "$url" >/dev/null 2>&1 & disown || true elif command -v open >/dev/null 2>&1; then open "$url" >/dev/null 2>&1 & disown || true else echo "No opener for: $url" fi } # --- get last N notes --- mapfile -t files < <( find "$NOTES_DIR" -maxdepth 1 -type f -name '*.md' \ -printf '%T@ %p\n' \ | sort -nr \ | head -n "$N" \ | cut -d' ' -f2- ) [[ ${#files[@]} -eq 0 ]] && { echo "No notes found" exit 0 } # --- collect urls --- # Use an array instead of a string urls_array=() for f in "${files[@]}"; do while IFS= read -r url; do # Clean the URL url=$(echo "$url" | sed 's/[),.;]*$//') # Add to array if not empty if [[ -n "$url" ]]; then urls_array+=("$url"$'\t'"$(basename "$f")") fi done < <(rg -o 'https?://[^[:space:]>"]+' "$f" | awk '!seen[$0]++') done [[ ${#urls_array[@]} -eq 0 ]] && { echo "No URLs found" exit 0 } # shellcheck disable=SC2016 # --- fzf selection --- # Use printf to output array elements with newlines selection=$(printf '%s\n' "${urls_array[@]}" | fzf --multi \ --marker='*' \ --bind 'tab:toggle' \ --delimiter='\t' \ --with-nth=1,2 \ --prompt="open urls> " \ --preview='fold -s -w "$FZF_PREVIEW_COLUMNS" "'"$NOTES_DIR"'"/{2} 2>/dev/null' \ --height=80% \ --reverse) [[ -z "$selection" ]] && exit 0 # --- open selected urls - Use array for selections --- mapfile -t selected_lines <<< "$selection" for line in "${selected_lines[@]}"; do # Extract URL and file using parameter expansion url="${line%%$'\t'*}" file="${line#*$'\t'}" [[ -z "$url" ]] && continue echo "Opening: $url ($file)" open_url "$url" sleep 0.1 done wait