sbrs

Simple blog and RSS system
git clone git://git.christosmarg.xyz/sbrs.git
Log | Files | Refs | README | LICENSE

commit 0dcdac2814dbb4f7e7f862402c2c8a21e5342be6
parent 12d1542a19b66b3a7498a7d7f1125c728f05f97a
Author: Christos Margiolis <christos@margiolis.net>
Date:   Sat, 24 Oct 2020 04:44:29 +0300

changed name

Diffstat:
MMakefile | 2+-
MREADME.md | 10+++++-----
Dautoblog | 196-------------------------------------------------------------------------------
Dautoblog.1 | 75---------------------------------------------------------------------------
Asbrs | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asbrs.1 | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 277 insertions(+), 277 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ # See LICENSE file for copyright and license details. -BIN = autoblog +BIN = sbrs VERSION = 0.1 DIST = ${BIN}-${VERSION} MAN1 = ${BIN}.1 diff --git a/README.md b/README.md @@ -1,10 +1,10 @@ -# autoblog +# sbrs A small and simple blog and RSS shell script written in POSIX shell. ## Features -`autoblog` can do the following: +`sbrs` can do the following: * Define a `blog` directory where all blog posts will be stored. * Set up a seperate `HTML` blog page with CSS styling of your choosing. @@ -21,7 +21,7 @@ be installed in `usr/local/bin/`. You can change the install path by editing the `BIN_DIR` variable in the `Makefile`. ```shell -$ cd path/to/autoblog/ +$ cd path/to/sbrs/ $ sudo make install ``` @@ -40,12 +40,12 @@ The following files have to exist * `template.html` * `styles.css` -Inside the `autoblog` script, change the `website` and `author` variables +Inside the `sbrs` script, change the `website` and `author` variables to your website's URL and your name and make sure the rest of the variables are properly set to match your website's structure. By default, all blog posts are stored in `blog/`. -`autoblog` will search for `<!--BLOG-->` inside `index.html`, +`sbrs` will search for `<!--BLOG-->` inside `index.html`, `blogindex.html` and `rss.xml` in order to put the blog post listings and RSS feed below it. diff --git a/autoblog b/autoblog @@ -1,196 +0,0 @@ -#!/bin/sh -# See LICENSE file for copyright and license details. - -website="https://christosmarg.xyz" -author="Christos Margiolis" -blogdir="blog" -draftdir=".drafts" -blogindex="blogindex.html" -index="index.html" -rssfile="rss.xml" -template="template.html" -[ -z "$EDITOR" ] && EDITOR="vim" - -main() { - missing_check - case $1 in - -n*) newpost ;; - -p*) listposts $draftdir && publish ;; - -e*) listposts $draftdir && $EDITOR $draftdir/$blogpost.html ;; - -v*) listposts $draftdir && view ;; - -t*) listposts $draftdir && delete $draftdir ;; - -r*) listposts $blogdir && $EDITOR $blogdir/$blogpost.html ;; - -c*) listposts $blogdir && title_change ;; - -o*) listposts $blogdir && $BROWSER $blogdir/$blogpost.html ;; - -d*) listposts $blogdir && delete $blogdir ;; - -l*) listposts $blogdir ;; - *) usage ;; - esac -} - -list() { - find $1 -type f ! -name '*final*' 2> /dev/null | awk -F/ '{print $NF}' -} - -listposts() { - #TODO: 10 doesn't work for some reason. fix. - printf "Listing posts in %s (total: %d)\n" "$1" "$(list $1 | wc -l)" - nposts=$(expr $(list $1 | wc -l)) - list $1 | nl - [ $nposts -eq 0 ] && echo "No posts available in $1" && exit - read -erp "Choose a post to by number: " num \ - && [ -z "$(echo $num | grep -E "^[1-9]+$")" ] \ - || [ $(expr $num) -gt $nposts ] || [ -z "$num" ] \ - && echo "No post selected." && exit - blogpost=$(list $1 | nl | grep -w "$num" | awk '{print $2}') - blogpost=$(basename -s ".html" $blogpost) -} - -newpost() { - mkdir -p $draftdir - read -erp "Title: " title && [ -z "$title" ] && - echo "Please specify a title." && exit - blogpost=$( - echo "$title" | iconv -cf UTF-8 -t ASCII//TRANSLIT | \ - tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' - ) - [ -f "$blogdir/$blogpost.html" ] && echo "File exists already." && exit - $EDITOR "$draftdir/$blogpost.html" - sed "s/TITLE/$title/g;s/HEADER/$title/g;s/AUTHOR/$author/g;" $template \ - > $draftdir/$blogpost.final.html -} - -confirm_action() { - read -erp "$1" confirm && [ "$confirm" = "$2" ] || exit -} - -psed() { - sed -i.orig "$@" && rm *.orig $blogdir/*.orig 2> /dev/null -} - -title_get() { - grep "<title>" $1 | sed "s/<title>//;s/<\/title>//;s/ *//;" -} - -publish() { - confirm_action "Publish post (y/N)? " "y" - title=$(title_get $draftdir/$blogpost.final.html) - psed "s/^/\ \ \ \ \ \ \ \ /" $draftdir/$blogpost.html # bad? - psed "/<\!--BLOG-->/r $draftdir/$blogpost.html" $draftdir/$blogpost.final.html - sed "s/</\&lt;/g;s/>/\&gt;/g;" "$draftdir/$blogpost.html" > $draftdir/$blogpost.xml - cp $draftdir/$blogpost.final.html $blogdir && - mv $blogdir/$blogpost.final.html $blogdir/$blogpost.html - - printf "\t\t\t\t<li>%s &ndash; <a href=\"%s\">%s</a></li>\n" \ - "$(date '+%Y %b %d')" "$blogdir/$blogpost.html" "$title" | \ - expand -t4 > $draftdir/$blogpost.final-htmlentry - - printf "<item>\n\t<title>%s</title>\n\t<guid>%s</guid>\n\t<pubDate>%s</pubDate>\n\t<description>\n\t\t%s\n \t</description>\n</item>\n" "$title" "$website/$blogdir/$blogpost.html" "$(date '+%a, %d %b %Y')" "$(cat $draftdir/$blogpost.xml)" | expand -t4 > $draftdir/$blogpost.final-rssentry - - # using || because of psed - blogindex_update - psed "/<\!--BLOG $(date '+%B %Y')-->/r $draftdir/$blogpost.final-htmlentry" $blogindex || - echo "Blogindex... done." - psed "/<\!--BLOG-->/r $draftdir/$blogpost.final-htmlentry" $index || echo "Index... done" - psed "/<\!--BLOG-->/r $draftdir/$blogpost.final-rssentry" $rssfile || echo "RSS... done" - remove_last_index_entry || echo "Removing last entry from index file... done" - remove_contents $draftdir && echo "Cleaning up .drafts... done" - echo "Published $blogpost." -} - -#TODO: i dont like how this looks... -blogindex_update() { - dateid=$(date '+%b %Y' | sed 's/\ //' | tr '[:upper:]' '[:lower:]') - if [ -z "$(grep "$dateid" $blogindex)" ]; then - datename=$(date '+%B %Y') - monthheader=$( - printf "\\ -<h2 id=\"%s\">%s<\/h2> \\ -<ul> \\ -\t<\!--BLOG %s--> \\ -<\/ul>" \ - "$dateid" "$datename" "$datename" | sed 's/^/\t\t\t/' | expand -t4 - ) - - psed "/<\!--BLOG-->/a $monthheader" $blogindex - fi -} - -remove_last_index_entry() { - indexentries=$(sed "1,/<\!--BLOG-->/d" $index | grep "<li>") && - [ $(expr $(echo "$indexentries" | wc -l)) -gt 7 ] && - lastentry=$(echo "$indexentries" | tail -2 | head -1) && - psed "s|$lastentry||;" $index -} - -delete() { - confirm_action "Are you sure you want to delete \"$blogpost\" (y/N)? " "y" - if [ "$1" = "$blogdir" ]; then - psed "/$blogpost/d" $index $blogindex - # TODO: make portable - gsed -ni "/<item>/{ :loop; N; s/<\\/item>/&/; T loop; s/$blogpost/&/; T keep; d }; :keep; p" $rssfile - fi - remove_contents $1 && echo "Removed $blogpost." -} - -remove_contents() { - ls $1 | grep -x "$blogpost\...*" | sed "s/^/$1\//" | xargs rm -} - -view() { - cat $draftdir/$blogpost.final.html > $draftdir/$blogpost.final-view.html - title=$(title_get $draftdir/$blogpost.final-view.html) - psed "/<\!--BLOG-->/r $draftdir/$blogpost.html" $draftdir/$blogpost.final-view.html - $BROWSER $draftdir/$blogpost.final-view.html -} - -title_change() { - read -erp "Give post a new title: " newtitle && \ - confirm_action "Are you sure (y/N)? " "y" - oldtitle=$(title_get $blogdir/$blogpost.html) - newtitle_fmt=$( - echo "$newtitle" | iconv -cf UTF-8 -t ASCII//TRANSLIT | \ - tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' - ) - [ -f "$blogdir/$newtitle_fmt.html" ] && echo "File exists already." && exit - - psed "s/$blogpost/$newtitle_fmt/g;s/$oldtitle/$newtitle/g" \ - $blogdir/$blogpost.html $index $blogindex $rssfile && - mv $blogdir/$blogpost.html $blogdir/$newtitle_fmt.html && - echo "Title changed successfully: $oldtitle -> $newtitle" -} - -err() { - echo "$1 file is missing. . ." - missing=true -} - -missing_check() { - missing=false - [ -f "$template" ] || err $template - [ -f "$index" ] || err $index - [ -f "$rssfile" ] || err $rssfile - [ -f "$blogindex" ] || err $blogindex - [ "$missing" = "true" ] && exit - - [ ! -d "$blogdir" ] && - confirm_action "Blog directory doesn't exist. Intialize it here (y/n)? " "y" && - mkdir -pv $blogdir -} - -usage() { - printf "Usage: autoblog [OPTION]\n\n" - printf "Options:\n" - printf " -n\t\tNew post\n" - printf " -p\t\tPublish draft post\n" - printf " -e\t\tEdit draft post\n" - printf " -v\t\tView draft post in browser\n" - printf " -t\t\tDelete draft post\n" - printf " -r\t\tRevise published post\n" - printf " -c\t\tChange title\n" - printf " -o\t\tView published post in browser\n" - printf " -d\t\tDelete published post\n" - printf " -l\t\tList all published posts\n" -} - -main "$1" diff --git a/autoblog.1 b/autoblog.1 @@ -1,75 +0,0 @@ -.Dd autoblog\-VERSION -.Dt AUTOBLOG 1 -.Os -.Sh NAME -.Nm autoblog -.Nd automatic blog and RSS system -.Sh SYNOPSIS -.Nm -.Op Fl n Ar new post -.Op Fl p Ar publish draft -.Op Fl e Ar edit draft -.Op Fl v Ar view draft -.Op Fl t Ar delete draft -.Op Fl r Ar revise published -.Op Fl c Ar change title -.Op Fl o Ar view published -.Op Fl d Ar delete published -.Op Fl l Ar list all published -.Sh DESCRIPTION -.Nm -generates a blog post page and RSS feed. -.Sh OPTIONS -The options are as follows: -.Bl -tag -width Ds -.It Fl n Ar new post -Prompt the user to write a new blog post in HTML -.It Fl p Ar publish draft -Publish one of the posts stored in the .drafts directory. -.It Fl e Ar edit draft -Edit one of the posts stored in the .drafts directory. -.It Fl v Ar view draft -View one of the posts stored in the .drafts directory. -.It Fl t Ar delete draft -Delete one of the posts stored in the .drafts directory. -.It Fl r Ar revise published -Revise a published post stored in the blog directory. -.It Fl c Ar change title -Change a published post's title. -.It Fl o Ar view published -View a published post stored in the blog directory on your default browser. -.It Fl d Ar delete published -Delete a published post stored in the blog directory. -.It Fl l Ar list all published -List all posts stored in the blog directory. -.El -.Pp -Only one option at a time can be used. -.Sh USAGE -.Pp -Run the script inside your website's main directory and edit the website and author -to match your own information. Make sure that the rest of the variables are properly -set to match your website's structure. By default, all blog posts are stored in blog/. -.Sh REQUIREMENTS -.Pp -The following files have to exist in the same directory -.Nm -is called: -.Bl -tag -width Ds -.It index.html -Main page. -.It blogindex.html -Blog page index. -.It template.html -A template file that will be used to format the blog post. -The TITLE, HEADER and AUTHOR fields must exist and be left as is. -.It rss.xml -The RSS feed. -.El -.Pp -.Nm -will search for <!--BLOG--> inside index.html and rss.xml -in order to put the blog post listings and RSS feed respectively. Inside blogindex.html -however, it will search for <!--BLOG [Month Year]--> (e.g <!--BLOG January 1800->). -.Sh AUTHORS -.An Christos Margiolis Aq Mt christos@christosmarg.xyz diff --git a/sbrs b/sbrs @@ -0,0 +1,196 @@ +#!/bin/sh +# See LICENSE file for copyright and license details. + +website="https://christosmarg.xyz" +author="Christos Margiolis" +blogdir="blog" +draftdir=".drafts" +blogindex="blogindex.html" +index="index.html" +rssfile="rss.xml" +template="template.html" +[ -z "$EDITOR" ] && EDITOR="vim" + +main() { + missing_check + case $1 in + -n*) newpost ;; + -p*) listposts $draftdir && publish ;; + -e*) listposts $draftdir && $EDITOR $draftdir/$blogpost.html ;; + -v*) listposts $draftdir && view ;; + -t*) listposts $draftdir && delete $draftdir ;; + -r*) listposts $blogdir && $EDITOR $blogdir/$blogpost.html ;; + -c*) listposts $blogdir && title_change ;; + -o*) listposts $blogdir && $BROWSER $blogdir/$blogpost.html ;; + -d*) listposts $blogdir && delete $blogdir ;; + -l*) listposts $blogdir ;; + *) usage ;; + esac +} + +# TODO: list only html maybe +list() { + find $1 -type f ! -name '*final*' 2> /dev/null | awk -F/ '{print $NF}' +} + +listposts() { + #TODO: 10 doesn't work for some reason. fix. + printf "Listing posts in %s (total: %d)\n" "$1" "$(list $1 | wc -l)" + nposts=$(expr $(list $1 | wc -l)) + list $1 | nl + [ $nposts -eq 0 ] && echo "No posts available in $1" && exit + read -erp "Choose a post to by number: " num \ + && [ -z "$(echo $num | grep -E "^[1-9]+$")" ] \ + || [ $(expr $num) -gt $nposts ] || [ -z "$num" ] \ + && echo "No post selected." && exit + blogpost=$(list $1 | nl | grep -w "$num" | awk '{print $2}') + blogpost=$(basename -s ".html" $blogpost) +} + +newpost() { + mkdir -p $draftdir + read -erp "Title: " title && [ -z "$title" ] && + echo "Please specify a title." && exit + blogpost=$(title_fmt "$title") + [ -f "$blogdir/$blogpost.html" ] && echo "File exists already." && exit + $EDITOR "$draftdir/$blogpost.html" + sed "s/TITLE/$title/g;s/HEADER/$title/g;s/AUTHOR/$author/g;" $template \ + > $draftdir/$blogpost.final.html +} + +confirm_action() { + read -erp "$1" confirm && [ "$confirm" = "$2" ] || exit +} + +psed() { + sed -i.orig "$@" && rm *.orig $blogdir/*.orig 2> /dev/null +} + +title_fmt() { + echo "$1" | iconv -cf UTF-8 -t ASCII//TRANSLIT | \ + tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' +} + +title_get() { + grep "<title>" $1 | sed "s/<title>//;s/<\/title>//;s/ *//;" +} + +publish() { + confirm_action "Publish post (y/N)? " "y" + title=$(title_get $draftdir/$blogpost.final.html) + psed "s/^/\ \ \ \ \ \ \ \ /" $draftdir/$blogpost.html # bad? + psed "/<\!--BLOG-->/r $draftdir/$blogpost.html" $draftdir/$blogpost.final.html + sed "s/</\&lt;/g;s/>/\&gt;/g;" "$draftdir/$blogpost.html" > $draftdir/$blogpost.xml + cp $draftdir/$blogpost.final.html $blogdir && + mv $blogdir/$blogpost.final.html $blogdir/$blogpost.html + + printf "\t\t\t\t<li>%s &ndash; <a href=\"%s\">%s</a></li>\n" \ + "$(date '+%Y %b %d')" "$blogdir/$blogpost.html" "$title" | \ + expand -t4 > $draftdir/$blogpost.final-htmlentry + + printf "<item>\n\t<title>%s</title>\n\t<guid>%s</guid>\n\t<pubDate>%s</pubDate>\n\t<description>\n\t\t%s\n \t</description>\n</item>\n" "$title" "$website/$blogdir/$blogpost.html" "$(date '+%a, %d %b %Y')" "$(cat $draftdir/$blogpost.xml)" | expand -t4 > $draftdir/$blogpost.final-rssentry + + # using || because of psed + blogindex_update + psed "/<\!--BLOG $(date '+%B %Y')-->/r $draftdir/$blogpost.final-htmlentry" $blogindex || + echo "Blogindex... done." + psed "/<\!--BLOG-->/r $draftdir/$blogpost.final-htmlentry" $index || echo "Index... done" + psed "/<\!--BLOG-->/r $draftdir/$blogpost.final-rssentry" $rssfile || echo "RSS... done" + remove_last_index_entry || echo "Removing last entry from index file... done" + remove_contents $draftdir && echo "Cleaning up .drafts... done" + echo "Published $blogpost." +} + +#TODO: i dont like how this looks... +blogindex_update() { + dateid=$(date '+%b %Y' | sed 's/\ //' | tr '[:upper:]' '[:lower:]') + if [ -z "$(grep "$dateid" $blogindex)" ]; then + datename=$(date '+%B %Y') + monthheader=$( + printf "\\ +<h2 id=\"%s\">%s<\/h2> \\ +<ul> \\ +\t<\!--BLOG %s--> \\ +<\/ul>" \ + "$dateid" "$datename" "$datename" | sed 's/^/\t\t\t/' | expand -t4 + ) + + psed "/<\!--BLOG-->/a $monthheader" $blogindex + fi +} + +remove_last_index_entry() { + indexentries=$(sed "1,/<\!--BLOG-->/d" $index | grep "<li>") && + [ $(expr $(echo "$indexentries" | wc -l)) -gt 7 ] && + lastentry=$(echo "$indexentries" | tail -2 | head -1) && + psed "s|$lastentry||;" $index +} + +delete() { + confirm_action "Are you sure you want to delete \"$blogpost\" (y/N)? " "y" + if [ "$1" = "$blogdir" ]; then + psed "/$blogpost/d" $index $blogindex + # TODO: make portable + gsed -ni "/<item>/{ :loop; N; s/<\\/item>/&/; T loop; s/$blogpost/&/; T keep; d }; :keep; p" $rssfile + fi + remove_contents $1 && echo "Removed $blogpost." +} + +remove_contents() { + ls $1 | grep -x "$blogpost\...*" | sed "s/^/$1\//" | xargs rm +} + +view() { + cat $draftdir/$blogpost.final.html > $draftdir/$blogpost.final-view.html + title=$(title_get $draftdir/$blogpost.final-view.html) + psed "/<\!--BLOG-->/r $draftdir/$blogpost.html" $draftdir/$blogpost.final-view.html + $BROWSER $draftdir/$blogpost.final-view.html +} + +title_change() { + read -erp "Give post a new title: " newtitle && \ + confirm_action "Are you sure (y/N)? " "y" + oldtitle=$(title_get $blogdir/$blogpost.html) + newtitle_fmt=$(title_fmt "$newtitle") + [ -f "$blogdir/$newtitle_fmt.html" ] && echo "File exists already." && exit + + psed "s/$blogpost/$newtitle_fmt/g;s/$oldtitle/$newtitle/g" \ + $blogdir/$blogpost.html $index $blogindex $rssfile && + mv $blogdir/$blogpost.html $blogdir/$newtitle_fmt.html && + echo "Title changed successfully: $oldtitle -> $newtitle" +} + +err() { + echo "$1 file is missing. . ." + missing=true +} + +missing_check() { + missing=false + [ -f "$template" ] || err $template + [ -f "$index" ] || err $index + [ -f "$rssfile" ] || err $rssfile + [ -f "$blogindex" ] || err $blogindex + [ "$missing" = "true" ] && exit + + [ ! -d "$blogdir" ] && + confirm_action "Blog directory doesn't exist. Intialize it here (y/n)? " "y" && + mkdir -pv $blogdir +} + +usage() { + printf "Usage: sbrs [OPTION]\n\n" + printf "Options:\n" + printf " -n\t\tNew post\n" + printf " -p\t\tPublish draft post\n" + printf " -e\t\tEdit draft post\n" + printf " -v\t\tView draft post in browser\n" + printf " -t\t\tDelete draft post\n" + printf " -r\t\tRevise published post\n" + printf " -c\t\tChange title\n" + printf " -o\t\tView published post in browser\n" + printf " -d\t\tDelete published post\n" + printf " -l\t\tList all published posts\n" +} + +main "$1" diff --git a/sbrs.1 b/sbrs.1 @@ -0,0 +1,75 @@ +.Dd sbrs\-VERSION +.Dt SBRS 1 +.Os +.Sh NAME +.Nm sbrs +.Nd simple blog and RSS system +.Sh SYNOPSIS +.Nm +.Op Fl n Ar new post +.Op Fl p Ar publish draft +.Op Fl e Ar edit draft +.Op Fl v Ar view draft +.Op Fl t Ar delete draft +.Op Fl r Ar revise published +.Op Fl c Ar change title +.Op Fl o Ar view published +.Op Fl d Ar delete published +.Op Fl l Ar list all published +.Sh DESCRIPTION +.Nm +generates a blog post page and RSS feed. +.Sh OPTIONS +The options are as follows: +.Bl -tag -width Ds +.It Fl n Ar new post +Prompt the user to write a new blog post in HTML +.It Fl p Ar publish draft +Publish one of the posts stored in the .drafts directory. +.It Fl e Ar edit draft +Edit one of the posts stored in the .drafts directory. +.It Fl v Ar view draft +View one of the posts stored in the .drafts directory. +.It Fl t Ar delete draft +Delete one of the posts stored in the .drafts directory. +.It Fl r Ar revise published +Revise a published post stored in the blog directory. +.It Fl c Ar change title +Change a published post's title. +.It Fl o Ar view published +View a published post stored in the blog directory on your default browser. +.It Fl d Ar delete published +Delete a published post stored in the blog directory. +.It Fl l Ar list all published +List all posts stored in the blog directory. +.El +.Pp +Only one option at a time can be used. +.Sh USAGE +.Pp +Run the script inside your website's main directory and edit the website and author +to match your own information. Make sure that the rest of the variables are properly +set to match your website's structure. By default, all blog posts are stored in blog/. +.Sh REQUIREMENTS +.Pp +The following files have to exist in the same directory +.Nm +is called: +.Bl -tag -width Ds +.It index.html +Main page. +.It blogindex.html +Blog page index. +.It template.html +A template file that will be used to format the blog post. +The TITLE, HEADER and AUTHOR fields must exist and be left as is. +.It rss.xml +The RSS feed. +.El +.Pp +.Nm +will search for <!--BLOG--> inside index.html and rss.xml +in order to put the blog post listings and RSS feed respectively. Inside blogindex.html +however, it will search for <!--BLOG [Month Year]--> (e.g <!--BLOG January 1800->). +.Sh AUTHORS +.An Christos Margiolis Aq Mt christos@christosmarg.xyz