calendar2html

#!/bin/sh
# converts list of periodic calendar entries from calendar(1) into HTML
# © 2015 Nils Dagsson Moskopp (erlehmann) – license: GPLv3+
entries=$(timeout 10 cat)
if [ "" = "$entries" ]; then
 printf 'Usage: calendar | calendargen > calendar.html\n' >&2
 exit 1
fi

cat <<EOF
<!DOCTYPE html>
<meta charset=utf-8>
<style>
*{box-sizing:border-box;line-height:1.5;margin:0;padding:0;vertical-align:top}
:target{outline:1px dashed}
table,ol,li,td>a{display:block;width:100%}
@media (min-width: 70em) {
tr{display:inline-block;width:14.28%}
td,td>a,ol>li{display:block}
}
td>a,ol>li{padding:0.75em}
.entry:nth-of-type(2n){color:#333;background:#eee}
.entry:nth-of-type(2n+1){color:#333;background:#ddd}
</style>
EOF

date_min=$(printf '%s' "$entries" | head -n1 | cut -f1 | cut -d' ' -f1)
date_max=$(printf '%s' "$entries" | tail -n1 | cut -f1 | cut -d' ' -f1)

ts_now=$(date +%s -d $date_min)
ts_max=$(date +%s -d $date_max)

printf '<table>'
while true; do
  date_now=$(date -I -d @$ts_now)
  ts_now=$(date +%s -d $date_now)
  printf '<tr id=%s><td><a href="#%s"><time>%s</time></a></td><td><ol>' \
    "$date_now" "$date_now" "$date_now"
  entries_now=$(printf '%s' "$entries" | grep "$date_now" || true)
  IFS='
'
  for entry in $entries_now; do
    entry_title=$(printf '%s' "$entry" | sed "s/$date_now//")
    printf '<li class=entry>%s</li>' "$entry_title"
  done
  printf '</ol></td></tr>'
  if [ $ts_now -gt $ts_max ]; then
    break
  fi
  ts_now=$(( $ts_now + 90000 )) # 25 hours because of DST
done
printf '</table>'