#!/bin/sh # generate a Atom feed from a directory, recursively # using POSIX sh # AUTHOR: Case Duckworth <acdw@acdw.net> # LICENSE: MIT usage() { cat <<END $0: generate an Atom feed from directories of files INVOCATION: $0 [-h] [-c CONFIG] DIRECTORY... OPTIONS: -h show this help -c CONFIG change the CONFIG file. Default: $PWD/gemshimfeed.conf.sh END } # FEED VARIABLES FEED_TITLE=example FEED_SUBTITLE="an example" FEED_URL="https://example.com/atom.xml" SITE_URL="https://example.com" FEED_ID="${SITE_URL#*//}" FEED_AUTHOR="nobody" FEED_COPYRIGHT="(c) 2020 CC-BY-SA $FEED_AUTHOR" FEED_UPDATED=$(date -u +'%FT%TZ') # FUNCTIONS recent_files() { # recent_files DIRECTORY FIND_ARG... # list files, in order of recency # BOO: REQUIRES GNU FIND :( :( :( :( # possibly look into https://unix.stackexchange.com/questions/9247/ # for more possibilities if you don't have GNU find. dir="$1" shift find "$dir" -maxdepth 1 \ "$@" \ -not -name '.*' \ -printf '%T@\t%p\n' | sort -nr | cut -f2 } # ENTRY FUNCTIONS skip_entry() { return 1 } entry_url() { basename="${1#$DIRECTORY}" echo "$FEED_URL/$basename" } entry_title() { awk '/^#+[ ]\S/{ for(i=2;i<=NF;i++) { printf $i; if (i!=NF) printf " "; } printf "\n";exit}' "$1" } entry_summary() { return 1 } entry_author() { echo "$FEED_AUTHOR" } entry_content() { cat "$1" } entry_updated() { # requires stat(1). # probably another way. # possibly using ls(1). stat -c '%y' "$1" | awk '{ sub(/\..*/,"",$2); sub(/[0-9][0-9]/,"&:",$3); print $1"T"$2$3;}' } # ATOM FUNCTIONS atom_header() { cat <<END <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>$FEED_TITLE</title> <subtitle>$FEED_SUBTITLE</subtitle> <link href="$FEED_URL" rel="self" /> <link href="$SITE_URL" /> <id>$FEED_ID</id> <generator uri="https://git.sr.ht/~acdw/gemshimfeed" version="infinite">GemShimFeed</generator> <rights>$FEED_COPYRIGHT</rights> <updated>$FEED_UPDATED</updated> END } atom_footer() { cat <<END </feed> END } atom_entry() { # atom_entry FILE ENTRY_URL="$(entry_url "$1")" ENTRY_TITLE="$(entry_title "$1")" ENTRY_SUMMARY="$(entry_summary "$1")" ENTRY_AUTHOR="$(entry_author "$1")" ENTRY_CONTENT="$(entry_content "$1")" ENTRY_UPDATED="$(entry_updated "$1")" cat <<END <entry> <id>$ENTRY_URL</id> <link rel="alternate" href="$ENTRY_URL" /> <title>$ENTRY_TITLE</title> <summary>$ENTRY_SUMMARY</summary> <updated>$ENTRY_UPDATED</updated> <author><name>$ENTRY_AUTHOR</name></author> <content type="text"><![CDATA[$ENTRY_CONTENT]]></content> </entry> END } main() { CONFIGFILE="$PWD/gemshimfeed.conf.sh" case "$1" in -h) usage exit 0 ;; -c) CONFIGFILE="$2" shift 2 ;; esac if [ -f "CONFIGFILE" ]; then . "$CONFIGFILE" fi atom_header for DIR; do for entry in $(recent_files "$DIR" -type f); do if skip_entry "$entry"; then continue; fi atom_entry "$entry" done done atom_footer } if [ $DEBUG ]; then set -x; fi main "$@"