#!/bin/bash # ltlnx's blog updater script, rewritten 20231103 # TODO # - readme # - some sort of help on the command line # - augument sample description and markdown files # messages and errors msg() { printf "[MSG] $@\n" } die() { printf "[ERR] $@\n" && exit 1 } # config and minimal blog boilerplate create_config() { test "$1" || return 1 cat > "$1" <. vheadername="header" # The name of your footer file. Footer files are included at the bottom of all pages. # Write the footer in html starting with a closing tag like . vfootername="footer" # The markdown converter command you would be using. For pandoc, # the command would be "pandoc -f markdown -t html". vmdconvcommand="pandoc -f markdown -t html" # The URL of your site, used for generating sitemaps and RSS feeds vurl="https://example.org" ### RSS (Atom) config ### # The description of the site vdesc="All pages on the blog of $(whoami)" # The language of the site (defined by your language code, e.g. "en" for English, # with an optional region code, e.g. "zh-TW" for Chinese in Taiwan) vlang="en" # The name of the main author (an alias would suffice) vname="$(whoami)" # The copyright of your RSS file content vcopyright="ⓒ $(whoami) $(date +%Y)." # The filename of your feed file. You may leave this intact unless you had a # blog with a canonical feed URL established already. vfeedname="atom.xml" # The URL of the RSS feed. # It should look somewhat like "https:///atom.xml". vfeedurl="https://example.org/atom.xml" EOF } create_header() { test "$1" || return 1 cat > "$1" <
EOF } create_footer() { test "$1" || return 1 cat > "$1" < EOF } create_stylesheet() { test "$1" || return 1 cat > "$1" < * {margin: 0 0 0.25em 0.25em} ul, ol {padding-left: 1em} a {color: #465aa4} #header a, .links a {text-decoration: none} #sitename, .links a:hover {color: #7d6658} #header a, .links a, .tags a {padding: 0 0.1em 0 0} hr {border: 0.75px solid} figure, img, video {width: 100%; max-width: 640px} EOF } create_desc() { test "$1" || return 1 test "$2" || return 1 cat > "$1" < "$1" < "sitemap.xml" < EOF # items for item in $(find . -name "*.html" -printf "%P\n"); do # get info of markdown file it_loc="${vurl}/$item" it_lastmod="$(date -d "$(cat "$item" | grep -Po '^

.*[\_]*Last [[:alpha:]]*: \K[^\<]*' || cat "$item" | grep -o "^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}$" || date +"%Y-%m-%d")" -R)" cat >> "sitemap.xml" < $it_loc $it_lastmod EOF done # ending cat >> "sitemap.xml" < EOF cd - } # quick actions case "$1" in deploy) test "$2" || die "Please input a commit message" test "$3" && die "Please put the commit message in quotes" gensitemap cd "$vroot"/"$vdstname" || die "Either you haven't created the destination folder, or the config has wrong settings. Please check if everything is set up." git add . || die "The destination directory is not versioned by git." git commit -m "$2" git push cd - exit 0 ;; gensitemap) gensitemap exit 0 ;; serve) cd "$vroot"/"$vdstname" || exit 1 python3 -m http.server || die "Your system probably does not have Python 3 installed. Please change the line invoking python3 into your own web server command, or install Python 3." cd - exit 0 ;; esac # copy the whole source dir to destination rm -r $vroot/$vdstname/* cp -r $vroot/$vsrcname/* "$vroot/$vdstname" # kickstart the RSS feed cat > "$vroot/$vdstname/$vfeedname" < $vtitle $vurl/ $(date +%Y-%m-%dT%T%:z) $vname $vdesc $vcopyright EOF # RSS feed cumulative item generating function genrss() { if [ -n "$date" ]; then pubDate="$(date -d "$date" +%Y-%m-%dT%T%:z)" else pubDate="2020-01-01T00:00:00+08:00" fi postcontent="$(head -n 30 "$file" | grep -v "> " | sed "s|<[^>]*>||g" | sed -n '/^# /,/^.*/d; 1,/^$/p' | grep . )" cat >> "$vroot/$vdstname/$vfeedname" < $title $vurl$link/ $vname $pubDate

$postcontent EOF } # post conversion # the code is dense, yeah, I'm sorry. mkdir -p "$vroot/$vdstname/tags" find "$vroot/$vsrcname" -path "*.md" | while read -r file; do msg "Processing $file" filebn="$(basename "$file" .md)" # the title should be on the first three lines (preferably the first) # and starts with a markdown # (single hash sign) title="$(head -n 3 "$file" | grep -Po "^# \K.*$" | sed "s|<[^>]*>||g")" # for the date we support 2 schemes: # one is the date itself on one line, another is "Last : ", # with or without italic `_` marks around them. date="$(cat "$file" | grep -o "^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}$")" \ || date="$(cat "$file" | grep -Po '^[_]*Last [^:]*: \K[^\_]*')" # there may be unfortunate cases where multiple dates are found, # for which we pick the first one date="$(echo "$date" | head -n 1)" # year for categorizing year="$(echo "$date" | grep -o "[0-9]\{4\}")" # tags start with "Tags: " of "tags: ", and is comma-separated tags="$(cat "$file" | grep -Po "^[Tt]ags: \K.*" | grep -Po '(?!( ))[^,]*' | sed 's| |-|g')" test "$tags" && htmltaglist="Tags: $(printf "$tags\n" | while read -r line; do printf "$line "; done)" # just define the link as the filename, no more categorizing by year link="/$filebn.html" # duplicate filename solving if [ -f "$vroot/${vdstname}${link}" ]; then link="$(echo "$link" | sed "s|.html|-$(find "$vroot/$vdstname" -name "$filebn-[0-9]*.html" | wc -l).html|")" fi # all titles are generated as # - cat > "$vroot/${vdstname}${link}" <|$title - $vtitle|") $(cat "$file" | sed "s|^[Tt]ags: .*$|$htmltaglist|g" | $vmdconvcommand) $(cat "$vroot/$vfootername") EOF entry="- <span class=\"date\">$date</span> [$title]($link)" # throw the entry into the appropriate catalogs # throw it into the archive if it's not a sticky post if ! (echo "$file" | grep -q "$vsrcname/sticky"); then echo "$entry" >> "$vroot/$vdstname/archive.md" fi if [ -n "$tags" ]; then printf "$tags\n" | while read -r tag; do echo "$entry" >> "$vroot/$vdstname/tags/$tag.md" done fi # generate rss entry genrss done # make tag indexes into proper pages find "$vroot/$vdstname/tags" -path "*.md" | while read -r file; do filebn="$(basename "$file" .md)" title="$(echo "$filebn" | sed 's|-| |g;s|\b\(.\)|\u\1|g')" link="/tags/$filebn.html" desc="$(cat "$vroot/$vsrcname/$filebn.desc")" || desc="No description.\n" content="$(cat "$file" | sort -rn)" cat > "$vroot/${vdstname}${link}" <<EOF $(cat "$vroot/$vheadername" | sed "s|<title>|<title>$title - $vtitle|") $(printf "$desc\n\n$content\n" | $vmdconvcommand) $(cat "$vroot/$vfootername") EOF echo " [$title]($link)" >> "$vroot/$vdstname/tags/index.md" done # make tag page desc="$(cat "$vroot/$vsrcname/tags.desc")" || desc="No description.\n" tagscontent="$(cat "$vroot/$vdstname/tags/index.md")" cat > "$vroot/$vdstname/tags/index.html" <<EOF $(cat "$vroot/$vheadername" | sed "s|<title>|<title>Tags - $vtitle|") $(printf "$desc\n\n\n$(printf "$tagscontent" | sed 's/^/-/g')\n" | $vmdconvcommand) $(cat "$vroot/$vfootername") EOF # make archive page desc="$(cat "$vroot/$vsrcname/archive.desc")" || desc="No description.\n" content="$(cat "$vroot/$vdstname/archive.md" | sort -rn)" cat > "$vroot/$vdstname/archive.html" <<EOF $(cat "$vroot/$vheadername" | sed "s|<title>|<title>Archive - $vtitle|") $(printf "$desc\n\nTags:$tagscontent\n\n$content\n" | $vmdconvcommand) $(cat "$vroot/$vfootername") EOF # close RSS generation echo "</feed>" >> "$vroot/$vdstname/$vfeedname" # remove leftover files and empty directories in the destination find "$vroot/$vdstname" -path "*.md" | xargs rm || true find "$vroot/$vdstname" -path "*.desc" | xargs rm || true find "$vroot/$vdstname" -mindepth 1 -type d -empty -delete || true