#!/bin/sh
start_time=$(date +%s)
domain="https://btxx.org"
timestamp_file="timestamps.tsv"
# Check the operating system and set aliases
case $(uname -s) in
OpenBSD)
alias sed=gsed
alias date=gdate
alias rsync=openrsync
;;
Darwin)
alias sed=gsed
alias date=gdate
;;
esac
set -eu
MARKDOWN=lowdown
IFS=$'\t'
# Precompute values used in multiple places
header_title=$(sed -n '/^# /{s/# //p; q}' index.md)
git_user_name=$(git config user.name)
first_commit_date=$(git log --pretty='format:%ai' . | cut -d ' ' -f1 | tail -1)
now=$(date +%FT%TZ)
now_rss=$(date -u +"%a, %d %b %Y %H:%M:%S %z")
# Update the timestamp for a markdown file
update_timestamp() {
local filename=$1
local timestamp=$(date -r "$filename" +%s)
# Remove old timestamp and add new
awk -v file="$filename" -v ts="$timestamp" '$1 != file {print $0}' "$timestamp_file" > "${timestamp_file}.tmp"
echo "$filename $timestamp" >> "${timestamp_file}.tmp"
mv "${timestamp_file}.tmp" "$timestamp_file"
}
# Check if the markdown file needs rebuilding
needs_rebuilding() {
local filename=$1
local last_mod=$(date -r "$filename" +%s)
local last_build=$(awk -v file="$filename" '$1 == file {print $2}' "$timestamp_file")
if [ "$last_mod" -gt "${last_build:-0}" ]; then
return 0 # needs rebuilding
else
return 1 # does not need rebuilding
fi
}
# Define write_page function
write_page() {
local filename=$1
local title=$2
local category=$3 # Category determines if it's a post or a page
if needs_rebuilding "$filename"; then
local directory
if [ "$category" = "posts" ]; then
directory="build/posts/$(basename "$filename" .md)"
else
directory="build/$(basename "$filename" .md)"
fi
mkdir -p "$directory"
local target="${directory}/index.html"
local created=$(head -3 "$filename" | tail -1)
{
sed "s|{{TITLE}}|$title|" header.html
$MARKDOWN "$filename"
cat footer.html
} > "$target"
update_timestamp "$filename"
echo "Rebuilt: $filename"
fi
}
# Create tab separated file with filename, title
index_tsv() {
for f in "$1"/*.md; do
title=$(sed -n '/^# /{s/# //p; q}' "$f")
printf '%s\t%s\n' "$f" "${title:="No Title"}"
done
}
# Generate index.html
index_html() {
sed "s/{{TITLE}}/$header_title/" header.html
$MARKDOWN index.md
echo "
"
while read -r f title; do
link="${f%.md}/"
created=$(head -3 "$f" | tail -1)
echo "$created · $title "
done < "$1" | sort -r
echo "
"
cat footer.html
}
# Generate atom.xml
atom_xml() {
echo "
$header_title$now$git_user_name$domain,$first_commit_date:default-atom-feed"
while read -r f title; do
content=$($MARKDOWN "$f" | sed 's/&/\&/g; s/\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g')
post_link="${f%.md}"
basic_date=$(head -3 "$f" | tail -1)
published_date=$(date -d "$basic_date" -u +%Y-%m-%dT10:%M:%SZ)
echo " $title$content$domain/$post_link$published_date$published_date"
done < "$1"
echo ''
}
# Generate RSS
rss_xml() {
uri=$(sed -rn '/rss.xml/ s/.*href="([^"]*)".*/\1/ p' header.html)
first_commit_date=$(git log --pretty='format:%ai' . | cut -d ' ' -f1 | tail -1)
cat <$(sed -n '/^# /{s/# //p; q}' index.md)
$domain/rss.xml
Feed description here$(date -u +"%a, %d %b %Y %H:%M:%S %z")$(date -u +"%a, %d %b %Y %H:%M:%S %z")Custom RSS Generator1800
EOF
while read -r f title created; do
content=$($MARKDOWN "$f" | sed 's/&/\&/g; s/\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g')
post_link=$(echo "$f" | sed -E 's|posts/(.*).md|\1|')
basic_date=$(echo $(head -3 "$f" | tail -1))
published_date=$(date -d "$basic_date" -u +"%a, %d %b %Y %H:%M:%S %z")
cat <$title$content
$domain/$post_link
$domain/$post_link$published_date
EOF
done < "$1"
echo ''
echo ''
}
# Initialize timestamps for all Markdown files if not already done
initialize_timestamps() {
if [ ! -f "$timestamp_file" ] || [ ! -s "$timestamp_file" ]; then
echo "Initializing timestamps..."
for f in index.md posts/*.md pages/*.md; do
update_timestamp "$f"
done
echo "Timestamps initialized for all Markdown files."
fi
}
# Main operations
mkdir -p build/posts build/pages
initialize_timestamps
index_tsv posts > build/posts.tsv
index_tsv pages > build/pages.tsv
while read -r f title; do
write_page "$f" "$title" "posts"
done < build/posts.tsv
while read -r f title; do
write_page "$f" "$title" "pages"
done < build/pages.tsv
if needs_rebuilding "index.md"; then
index_html build/posts.tsv > build/index.html
echo "Rebuilt index.html due to changes in index.md"
update_timestamp "index.md"
fi
atom_xml build/posts.tsv > build/atom.xml
rss_xml build/posts.tsv > build/rss.xml
end_time=$(date +%s)
elapsed_time=$((end_time - start_time))
echo "Total time: ${elapsed_time}s"