diff --git a/bb.sh b/bb.sh index 5b612dd..304b17f 100755 --- a/bb.sh +++ b/bb.sh @@ -16,172 +16,172 @@ global_config=".config" # This function will load all the variables defined here. They might be overridden # by the 'global_config' file contents global_variables() { - global_software_name="bashblog" - global_software_version="2.8" + global_software_name="bashblog" + global_software_version="2.8" - # Blog title - global_title="my tildelog" - # The typical subtitle for each blog - global_description="a blog about tildes" - # The public base URL for this blog - global_url="https://tilde.team/~$USER/blog" + # Blog title + global_title="my tildelog" + # The typical subtitle for each blog + global_description="a blog about tildes" + # The public base URL for this blog + global_url="https://tilde.team/~$USER/blog" - # Your name - global_author="~$USER" - # You can use twitter or facebook or anything for global_author_url - global_author_url="https://tilde.team/~$USER/" - # Your email - global_email="$USER@tilde.team" + # Your name + global_author="~$USER" + # You can use twitter or facebook or anything for global_author_url + global_author_url="https://tilde.team/~$USER/" + # Your email + global_email="$USER@tilde.team" - # CC by-nc-nd is a good starting point, you can change this to "©" for Copyright - global_license="CC by-nc-nd" + # CC by-nc-nd is a good starting point, you can change this to "©" for Copyright + global_license="CC by-nc-nd" - # Leave this empty (i.e. "") if you don't want to use feedburner, - # or change it to your own URL - global_feedburner="" + # Leave this empty (i.e. "") if you don't want to use feedburner, + # or change it to your own URL + global_feedburner="" - # Change this to your username if you want to use twitter for comments - global_twitter_username="" - # Set this to false for a Twitter button with share count. The cookieless version - # is just a link. - global_twitter_cookieless="true" + # Change this to your username if you want to use twitter for comments + global_twitter_username="" + # Set this to false for a Twitter button with share count. The cookieless version + # is just a link. + global_twitter_cookieless="true" - # Blog generated files - # index page of blog (it is usually good to use "index.html" here) - index_file="index.html" - number_of_index_articles="10" - # global archive - archive_index="all_posts.html" - tags_index="all_tags.html" + # Blog generated files + # index page of blog (it is usually good to use "index.html" here) + index_file="index.html" + number_of_index_articles="10" + # global archive + archive_index="all_posts.html" + tags_index="all_tags.html" - # ignore gophermap file - gophermap="gophermap" + # ignore gophermap file + gophermap="gophermap" - # ignore gemini generation script and gemini index - gemini_index="index.gmi" + # ignore gemini generation script and gemini index + gemini_index="index.gmi" - # Non blogpost files. Bashblog will ignore these. Useful for static pages and custom content - # Add them as a bash array, e.g. non_blogpost_files=("news.html" "test.html") - non_blogpost_files=() + # Non blogpost files. Bashblog will ignore these. Useful for static pages and custom content + # Add them as a bash array, e.g. non_blogpost_files=("news.html" "test.html") + non_blogpost_files=() - # feed file (rss in this case) - blog_feed="feed.rss" - number_of_feed_articles="50" - # "cut" blog entry when putting it to index page. Leave blank for full articles in front page - # i.e. include only up to first '
', or '----' in markdown - cut_do="cut" - # When cutting, cut also tags? If "no", tags will appear in index page for cut articles - cut_tags="yes" - # Regexp matching the HTML line where to do the cut - # note that slash is regexp separator so you need to prepend it with backslash - cut_line='
' - # save markdown file when posting with "bb post -m". Leave blank to discard it. - save_markdown="yes" - # prefix for tags/categories files - # please make sure that no other html file starts with this prefix - prefix_tags="tag_" - # personalized header and footer (only if you know what you're doing) - # DO NOT name them .header.html, .footer.html or they will be overwritten - # leave blank to generate them, recommended - header_file="" - footer_file="" - # extra content to add just after we open the tag - # and before the actual blog content - body_begin_file="" - # extra content to add just before we cloese ) - body_end_file="" - # CSS files to include on every page, f.ex. css_include=('main.css' 'blog.css') - # leave empty to use generated - css_include=() - # HTML files to exclude from index, f.ex. post_exclude=('imprint.html 'aboutme.html') - html_exclude=() + # feed file (rss in this case) + blog_feed="feed.rss" + number_of_feed_articles="50" + # "cut" blog entry when putting it to index page. Leave blank for full articles in front page + # i.e. include only up to first '
', or '----' in markdown + cut_do="cut" + # When cutting, cut also tags? If "no", tags will appear in index page for cut articles + cut_tags="yes" + # Regexp matching the HTML line where to do the cut + # note that slash is regexp separator so you need to prepend it with backslash + cut_line='
' + # save markdown file when posting with "bb post -m". Leave blank to discard it. + save_markdown="yes" + # prefix for tags/categories files + # please make sure that no other html file starts with this prefix + prefix_tags="tag_" + # personalized header and footer (only if you know what you're doing) + # DO NOT name them .header.html, .footer.html or they will be overwritten + # leave blank to generate them, recommended + header_file="" + footer_file="" + # extra content to add just after we open the tag + # and before the actual blog content + body_begin_file="" + # extra content to add just before we cloese ) + body_end_file="" + # CSS files to include on every page, f.ex. css_include=('main.css' 'blog.css') + # leave empty to use generated + css_include=() + # HTML files to exclude from index, f.ex. post_exclude=('imprint.html 'aboutme.html') + html_exclude=() - # Localization and i18n - # "Comments?" (used in twitter link after every post) - template_comments="comments?" - # "Read more..." (link under cut article on index page) - template_read_more="read more..." - # "View more posts" (used on bottom of index page as link to archive) - template_archive="archive" - # "All posts" (title of archive page) - template_archive_title="all posts" - # "All tags" - template_tags_title="all tags" - # "posts" (on "All tags" page, text at the end of each tag line, like "2. Music - 15 posts") - template_tags_posts="posts" - template_tags_posts_2_4="posts" # Some slavic languages use a different plural form for 2-4 items - template_tags_posts_singular="post" - # "Posts tagged" (text on a title of a page with index of one tag, like "My Blog - Posts tagged "Music"") - template_tag_title="posts tagged" - # "Tags:" (beginning of line in HTML file with list of all tags for this article) - template_tags_line_header="tags:" - # "Back to the index page" (used on archive page, it is link to blog index) - template_archive_index_page="back home" - # "Subscribe" (used on bottom of index page, it is link to RSS feed) - template_subscribe="rss" - # "Subscribe to this page..." (used as text for browser feed button that is embedded to html) - template_subscribe_browser_button="subscribe to this page..." - # "Tweet" (used as twitter text button for posting to twitter) - template_twitter_button="tweet" - template_twitter_comment="<type your comment here but please leave the URL so that other people can follow the comments>" - - # The locale to use for the dates displayed on screen - date_format="%B %d, %Y" - date_locale="C" - date_inpost="bashblog_timestamp" - # Don't change these dates - date_format_full="%a, %d %b %Y %H:%M:%S %z" - date_format_timestamp="%Y%m%d%H%M.%S" - date_allposts_header="%B %Y" + # Localization and i18n + # "Comments?" (used in twitter link after every post) + template_comments="comments?" + # "Read more..." (link under cut article on index page) + template_read_more="read more..." + # "View more posts" (used on bottom of index page as link to archive) + template_archive="archive" + # "All posts" (title of archive page) + template_archive_title="all posts" + # "All tags" + template_tags_title="all tags" + # "posts" (on "All tags" page, text at the end of each tag line, like "2. Music - 15 posts") + template_tags_posts="posts" + template_tags_posts_2_4="posts" # Some slavic languages use a different plural form for 2-4 items + template_tags_posts_singular="post" + # "Posts tagged" (text on a title of a page with index of one tag, like "My Blog - Posts tagged "Music"") + template_tag_title="posts tagged" + # "Tags:" (beginning of line in HTML file with list of all tags for this article) + template_tags_line_header="tags:" + # "Back to the index page" (used on archive page, it is link to blog index) + template_archive_index_page="back home" + # "Subscribe" (used on bottom of index page, it is link to RSS feed) + template_subscribe="rss" + # "Subscribe to this page..." (used as text for browser feed button that is embedded to html) + template_subscribe_browser_button="subscribe to this page..." + # "Tweet" (used as twitter text button for posting to twitter) + template_twitter_button="tweet" + template_twitter_comment="<type your comment here but please leave the URL so that other people can follow the comments>" - # Perform the post title -> filename conversion - # Experts only. You may need to tune the locales too - # Leave empty for no conversion, which is not recommended - # This default filter respects backwards compatibility - convert_filename="iconv -f utf-8 -t ascii//translit | sed 's/^-*//' | tr [:upper:] [:lower:] | tr ' ' '-' | tr -dc '[:alnum:]-'" + # The locale to use for the dates displayed on screen + date_format="%B %d, %Y" + date_locale="C" + date_inpost="bashblog_timestamp" + # Don't change these dates + date_format_full="%a, %d %b %Y %H:%M:%S %z" + date_format_timestamp="%Y%m%d%H%M.%S" + date_allposts_header="%B %Y" - # URL where you can view the post while it's being edited - # same as global_url by default - # You can change it to path on your computer, if you write posts locally - # before copying them to the server - preview_url="" + # Perform the post title -> filename conversion + # Experts only. You may need to tune the locales too + # Leave empty for no conversion, which is not recommended + # This default filter respects backwards compatibility + convert_filename="iconv -f utf-8 -t ascii//translit | sed 's/^-*//' | tr [:upper:] [:lower:] | tr ' ' '-' | tr -dc '[:alnum:]-'" - # Markdown location. Trying to autodetect by default. - # The invocation must support the signature 'markdown_bin in.md > out.html' - [[ -f Markdown.pl ]] && markdown_bin=./Markdown.pl || markdown_bin=$(command -v Markdown.pl 2>/dev/null || command -v markdown 2>/dev/null) + # URL where you can view the post while it's being edited + # same as global_url by default + # You can change it to path on your computer, if you write posts locally + # before copying them to the server + preview_url="" + + # Markdown location. Trying to autodetect by default. + # The invocation must support the signature 'markdown_bin in.md > out.html' + [[ -f Markdown.pl ]] && markdown_bin=./Markdown.pl || markdown_bin=$(command -v Markdown.pl 2>/dev/null || command -v markdown 2>/dev/null) } # Check for the validity of some variables # DO NOT EDIT THIS FUNCTION unless you know what you're doing global_variables_check() { - [[ $header_file == .header.html ]] && - echo "Please check your configuration. '.header.html' is not a valid value for the setting 'header_file'" && - exit - [[ $footer_file == .footer.html ]] && - echo "Please check your configuration. '.footer.html' is not a valid value for the setting 'footer_file'" && - exit + [[ $header_file == .header.html ]] && \ + echo "Please check your configuration. '.header.html' is not a valid value for the setting 'header_file'" && \ + exit + [[ $footer_file == .footer.html ]] && \ + echo "Please check your configuration. '.footer.html' is not a valid value for the setting 'footer_file'" && \ + exit } # Test if the markdown script is working correctly test_markdown() { - local m1; m1=$("$markdown_bin" <<< $'line 1\n\nline 2') - local m2; m2=$("$markdown_bin" <<< $'line 1\n\nline 2') - local c1=$'

line 1

\n\n

line 2

' - local c2=$'

line 1

\n

line 2

' - # shellcheck disable=SC2235 # must enforce order of operations - [[ -n $markdown_bin ]] && ( [[ "$m1" == "$c1" ]] || [[ "$m2" == "$c2" ]] ) + local m1; m1=$("$markdown_bin" <<< $'line 1\n\nline 2') + local m2; m2=$("$markdown_bin" <<< $'line 1\n\nline 2') + local c1=$'

line 1

\n\n

line 2

' + local c2=$'

line 1

\n

line 2

' + # shellcheck disable=SC2235 # must enforce order of operations + [[ -n $markdown_bin ]] && ( [[ "$m1" == "$c1" ]] || [[ "$m2" == "$c2" ]] ) } # Parse a Markdown file into HTML and return the generated file markdown() { - out=${1%.md}.html - while [[ -f $out ]]; do out=${out%.html}.$RANDOM.html; done - $markdown_bin "$1" > "$out" - echo "$out" + out=${1%.md}.html + while [[ -f $out ]]; do out=${out%.html}.$RANDOM.html; done + $markdown_bin "$1" > "$out" + echo "$out" } # Reads HTML file from stdin, prints its content to stdout @@ -191,15 +191,15 @@ markdown() { # note that this does not remove
line itself, # so you can see if text was cut or not get_html_file_content() { - awk "//, //{ - if (!// && !//) print - if (\"$3\" == \"cut\" && /$cut_line/){ - if (\"$2\" == \"text\") exit # no need to read further - while (getline > 0 && !//) { - if (\"$cut_tags\" == \"no\" && /^

$template_tags_line_header/ ) print - } - } - }" + awk "//, //{ + if (!// && !//) print + if (\"$3\" == \"cut\" && /$cut_line/){ + if (\"$2\" == \"text\") exit # no need to read further + while (getline > 0 && !//) { + if (\"$cut_tags\" == \"no\" && /^

$template_tags_line_header/ ) print + } + } + }" } # Edit an existing, published .html file while keeping its original timestamp @@ -215,55 +215,56 @@ get_html_file_content() { # "full" to edit full HTML, and not only text part (keeps old filename) # leave empty for default behavior (edit only text part and change name) edit() { - [[ ! -f "${1%%.*}.html" ]] && \ + [[ ! -f "${1%%.*}.html" ]] && \ printf "Can't edit post \"%s.html\", did you mean to use \"bb.sh post \"?\\n" "${1%%.*}" && exit 1 - # Original post timestamp - edit_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +"$date_format_full" ) - touch_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +"$date_format_timestamp") - tags_before=$(tags_in_post "${1%%.*}.html") - if [[ $2 == full ]]; then - $EDITOR "$1" - filename=$1 - else - if [[ ${1##*.} == md ]]; then - if test_markdown; then - echo "Markdown is not working, please edit HTML file directly." - exit - fi - # editing markdown file - $EDITOR "$1" - TMPFILE=$(markdown "$1") - filename=${1%%.*}.html - else - # Create the content file - TMPFILE=$(basename "$1").$RANDOM.html - # Title - get_post_title "$1" > "$TMPFILE" - # Post text with plaintext tags - get_html_file_content 'text' 'text' <"$1" | sed "/^

$template_tags_line_header/s|\\1|\\1|g" >> "$TMPFILE" - $EDITOR "$TMPFILE" - filename=$1 - fi - rm "$filename" - if [[ $2 == keep ]]; then - parse_file "$TMPFILE" "$edit_timestamp" "$filename" - else - parse_file "$TMPFILE" "$edit_timestamp" # this command sets $filename as the html processed file - [[ ${1##*.} == md ]] && mv "$1" "${filename%%.*}.md" 2>/dev/null - fi - rm "$TMPFILE" - fi - touch -t "$touch_timestamp" "$filename" - touch -t "$touch_timestamp" "$1" - chmod 644 "$filename" - echo "Posted $filename" - tags_after=$(tags_in_post "$filename") - relevant_tags=$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ') - if [[ -n $relevant_tags ]]; then + + # Original post timestamp + edit_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +"$date_format_full" ) + touch_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +"$date_format_timestamp") + tags_before=$(tags_in_post "${1%%.*}.html") + if [[ $2 == full ]]; then + $EDITOR "$1" + filename=$1 + else + if [[ ${1##*.} == md ]]; then + if test_markdown; then + echo "Markdown is not working, please edit HTML file directly." + exit + fi + # editing markdown file + $EDITOR "$1" + TMPFILE=$(markdown "$1") + filename=${1%%.*}.html + else + # Create the content file + TMPFILE=$(basename "$1").$RANDOM.html + # Title + get_post_title "$1" > "$TMPFILE" + # Post text with plaintext tags + get_html_file_content 'text' 'text' <"$1" | sed "/^

$template_tags_line_header/s|\\1|\\1|g" >> "$TMPFILE" + $EDITOR "$TMPFILE" + filename=$1 + fi + rm "$filename" + if [[ $2 == keep ]]; then + parse_file "$TMPFILE" "$edit_timestamp" "$filename" + else + parse_file "$TMPFILE" "$edit_timestamp" # this command sets $filename as the html processed file + [[ ${1##*.} == md ]] && mv "$1" "${filename%%.*}.md" 2>/dev/null + fi + rm "$TMPFILE" + fi + touch -t "$touch_timestamp" "$filename" + touch -t "$touch_timestamp" "$1" + chmod 644 "$filename" + echo "Posted $filename" + tags_after=$(tags_in_post "$filename") + relevant_tags=$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ') + if [[ -n $relevant_tags ]]; then # shellcheck disable=SC2086 # Intended splitting of $relevant_tags - relevant_posts="$(posts_with_tags $relevant_tags) $filename" - rebuild_tags "$relevant_posts" "$relevant_tags" - fi + relevant_posts="$(posts_with_tags $relevant_tags) $filename" + rebuild_tags "$relevant_posts" "$relevant_tags" + fi } # Create a Twitter summary (twitter "card") for the post @@ -271,41 +272,41 @@ edit() { # $1 the post file # $2 the title twitter_card() { - [[ -z $global_twitter_username ]] && return - - echo "" - echo "" - echo "" # Twitter truncates at 70 char - description=$(grep -v "^

$template_tags_line_header" "$1" | sed -e 's/<[^>]*>//g' | head -c 250 | tr '\n' ' ' | sed "s/\"/'/g") - echo "" - image=$(sed -n 's/.*" + [[ -z $global_twitter_username ]] && return + + echo "" + echo "" + echo "" # Twitter truncates at 70 char + description=$(grep -v "^

$template_tags_line_header" "$1" | sed -e 's/<[^>]*>//g' | head -c 250 | tr '\n' ' ' | sed "s/\"/'/g") + echo "" + image=$(sed -n 's/.*" } # Adds the code needed by the twitter button # # $1 the post URL twitter() { - [[ -z $global_twitter_username ]] && return + [[ -z $global_twitter_username ]] && return - if [[ $global_twitter_cookieless == true ]]; then - id=$RANDOM + if [[ $global_twitter_cookieless == true ]]; then + id=$RANDOM - search_engine="https://twitter.com/search?q=" + search_engine="https://twitter.com/search?q=" - echo "

$template_comments $template_twitter_button " - echo " 

" - return; - else - echo "

$template_comments "; - fi + echo "

$template_comments $template_twitter_button " + echo " 

" + return; + else + echo "

$template_comments "; + fi - echo "$template_twitter_button " - echo "

" + echo "$template_twitter_button " + echo "

" } # Check if the file is a 'boilerplate' (i.e. not a post) @@ -317,21 +318,21 @@ twitter() { # Return 0 (bash return value 'true') if the input file is an index, feed, etc # or 1 (bash return value 'false') if it is a blogpost is_boilerplate_file() { - name=${1#./} - # First check against user-defined non-blogpost pages - for item in "${non_blogpost_files[@]}"; do - [[ "$name" == "$item" ]] && return 0 - done + name=${1#./} + # First check against user-defined non-blogpost pages + for item in "${non_blogpost_files[@]}"; do + [[ "$name" == "$item" ]] && return 0 + done - case $name in - ( "$index_file" | "$archive_index" | "$gophermap" | "$gemini_index" | "$tags_index" | "$footer_file" | "$header_file" | "$prefix_tags"* ) - return 0 ;; - ( * ) # Check for excluded - for excl in "${html_exclude[@]}"; do - [[ $name == "$excl" ]] && return 0 - done - return 1 ;; - esac + case $name in + ( "$index_file" | "$archive_index" | "$gophermap" | "$gemini_index" | "$tags_index" | "$footer_file" | "$header_file" | "$prefix_tags"* ) + return 0 ;; + ( * ) # Check for excluded + for excl in "${html_exclude[@]}"; do + [[ $name == "$excl" ]] && return 0 + done + return 1 ;; + esac } # Adds all the bells and whistles to format the html page @@ -347,74 +348,74 @@ is_boilerplate_file() { # $5 original blog timestamp # $6 post author create_html_page() { - content=$1 - filename=$2 - index=$3 - title=$4 - timestamp=$5 - author=$6 + content=$1 + filename=$2 + index=$3 + title=$4 + timestamp=$5 + author=$6 - # Create the actual blog post - # html, head - { - cat ".header.html" - echo "$title" - twitter_card "$content" "$title" - echo "" - # stuff to add before the actual body content - [[ -n $body_begin_file ]] && cat "$body_begin_file" - # body divs - echo '
' - echo '
' - # blog title - echo '
' - cat .title.html - echo '
' # title, header, headerholder - echo '
' + # Create the actual blog post + # html, head + { + cat ".header.html" + echo "$title" + twitter_card "$content" "$title" + echo "" + # stuff to add before the actual body content + [[ -n $body_begin_file ]] && cat "$body_begin_file" + # body divs + echo '
' + echo '
' + # blog title + echo '
' + cat .title.html + echo '
' # title, header, headerholder + echo '
' - file_url=${filename#./} - file_url=${file_url%.rebuilt} # Get the correct URL when rebuilding - # one blog entry - if [[ $index == no ]]; then - echo '' # marks the beginning of the whole post - echo "

" - # remove possible

's on the title because of markdown conversion - title=${title//

/} - title=${title//<\/p>/} - echo "$title" - echo '

' - if [[ -z $timestamp ]]; then - echo "" - else - echo "" - fi - if [[ -z $timestamp ]]; then - echo -n "
$(LC_ALL=$date_locale date +"$date_format")" - else - echo -n "
$(LC_ALL=$date_locale date +"$date_format" --date="$timestamp")" - fi - [[ -n $author ]] && echo -e " — \n$author" - echo "
" - echo '' # This marks the text body, after the title, date... - fi - cat "$content" # Actual content - if [[ $index == no ]]; then - echo -e '\n' + file_url=${filename#./} + file_url=${file_url%.rebuilt} # Get the correct URL when rebuilding + # one blog entry + if [[ $index == no ]]; then + echo '' # marks the beginning of the whole post + echo "

" + # remove possible

's on the title because of markdown conversion + title=${title//

/} + title=${title//<\/p>/} + echo "$title" + echo '

' + if [[ -z $timestamp ]]; then + echo "" + else + echo "" + fi + if [[ -z $timestamp ]]; then + echo -n "
$(LC_ALL=$date_locale date +"$date_format")" + else + echo -n "
$(LC_ALL=$date_locale date +"$date_format" --date="$timestamp")" + fi + [[ -n $author ]] && echo -e " — \n$author" + echo "
" + echo '' # This marks the text body, after the title, date... + fi + cat "$content" # Actual content + if [[ $index == no ]]; then + echo -e '\n' - twitter "$global_url/$file_url" + twitter "$global_url/$file_url" - echo '' # absolute end of the post - fi + echo '' # absolute end of the post + fi - echo '
' # content + echo '
' # content - # page footer - cat .footer.html - # close divs - echo '
' # divbody and divbodyholder - [[ -n $body_end_file ]] && cat "$body_end_file" - echo '' - } > "$filename" + # page footer + cat .footer.html + # close divs + echo '
' # divbody and divbodyholder + [[ -n $body_end_file ]] && cat "$body_end_file" + echo '' + } > "$filename" } # Parse the plain text file into an html file @@ -426,274 +427,272 @@ create_html_page() { # place if destination file name is provided, i.e: # parse_file source.txt "" destination.html parse_file() { - # Read for the title and check that the filename is ok - title="" - while IFS='' read -r line; do - if [[ -z $title ]]; then - # remove extra

and

added by markdown - title=$(echo "$line" | sed 's/<\/*p>//g') - if [[ -n $3 ]]; then - filename=$3 - else - filename=$title - [[ -n $convert_filename ]] && - filename=$(echo "$title" | eval "$convert_filename") - [[ -n $filename ]] || - filename=$RANDOM # don't allow empty filenames + # Read for the title and check that the filename is ok + title="" + while IFS='' read -r line; do + if [[ -z $title ]]; then + # remove extra

and

added by markdown + title=$(echo "$line" | sed 's/<\/*p>//g') + if [[ -n $3 ]]; then + filename=$3 + else + filename=$title + [[ -n $convert_filename ]] && filename=$(echo "$title" | eval "$convert_filename") + [[ -n $filename ]] || filename=$RANDOM # don't allow empty filenames + filename=$filename.html - filename=$filename.html + # Check for duplicate file names + while [[ -f $filename ]]; do + filename=${filename%.html}$RANDOM.html + done + fi + content=$filename.tmp + # Parse possible tags + elif [[ $line == "

$template_tags_line_header"* ]]; then + tags=$(echo "$line" | cut -d ":" -f 2- | sed -e 's/<\/p>//g' -e 's/^ *//' -e 's/ *$//' -e 's/, /,/g') + IFS=, read -r -a array <<< "$tags" - # Check for duplicate file names - while [[ -f $filename ]]; do - filename=${filename%.html}$RANDOM.html - done - fi - content=$filename.tmp - # Parse possible tags - elif [[ $line == "

$template_tags_line_header"* ]]; then - tags=$(echo "$line" | cut -d ":" -f 2- | sed -e 's/<\/p>//g' -e 's/^ *//' -e 's/ *$//' -e 's/, /,/g') - IFS=, read -r -a array <<< "$tags" + echo -n "

$template_tags_line_header " >> "$content" + for item in "${array[@]}"; do + echo -n "$item, " + done | sed 's/, $/<\/p>/g' >> "$content" + else + echo "$line" >> "$content" + fi + done < "$1" - echo -n "

$template_tags_line_header " >> "$content" - for item in "${array[@]}"; do - echo -n "$item, " - done | sed 's/, $/<\/p>/g' >> "$content" - else - echo "$line" >> "$content" - fi - done < "$1" - - # Create the actual html page - create_html_page "$content" "$filename" no "$title" "$2" "$global_author" - rm "$content" + # Create the actual html page + create_html_page "$content" "$filename" no "$title" "$2" "$global_author" + rm "$content" } # Manages the creation of the text file and the parsing to html file # also the drafts write_entry() { - test_markdown && fmt=md || fmt=html - f=$2 - [[ $2 == -html ]] && fmt=html && f=$3 + test_markdown && fmt=md || fmt=html + f=$2 + [[ $2 == -html ]] && fmt=html && f=$3 - if [[ -n $f ]]; then - TMPFILE=$f - if [[ ! -f $TMPFILE ]]; then - echo "The file doesn't exist" - delete_includes - exit - fi - # guess format from TMPFILE - extension=${TMPFILE##*.} - [[ $extension == md || $extension == html ]] && fmt=$extension - # but let user override it (`bb.sh post -html file.md`) - [[ $2 == -html ]] && fmt=html - # Test if Markdown is working before re-posting a .md file - if [[ $extension == md ]]; then - if test_markdown; then - echo "Markdown is not working, please edit HTML file directly." - exit - fi - fi - else - TMPFILE=.entry-$RANDOM.$fmt - echo -e "Title on this line\n" >> "$TMPFILE" + if [[ -n $f ]]; then + TMPFILE=$f + if [[ ! -f $TMPFILE ]]; then + echo "The file doesn't exist" + delete_includes + exit + fi + # guess format from TMPFILE + extension=${TMPFILE##*.} + [[ $extension == md || $extension == html ]] && fmt=$extension + # but let user override it (`bb.sh post -html file.md`) + [[ $2 == -html ]] && fmt=html + # Test if Markdown is working before re-posting a .md file + if [[ $extension == md ]]; then + if test_markdown; then + echo "Markdown is not working, please edit HTML file directly." + exit + fi + fi + else + TMPFILE=.entry-$RANDOM.$fmt + echo -e "Title on this line\n" >> "$TMPFILE" - [[ $fmt == html ]] && cat << EOF >> "$TMPFILE" + [[ $fmt == html ]] && cat << EOF >> "$TMPFILE"

The rest of the text file is an html blog post. The process will continue as soon as you exit your editor.

$template_tags_line_header keep-this-tag-format, tags-are-optional, example

EOF - [[ $fmt == md ]] && cat << EOF >> "$TMPFILE" + + [[ $fmt == md ]] && cat << EOF >> "$TMPFILE" The rest of the text file is a **Markdown** blog post. The process will continue as soon as you exit your editor. $template_tags_line_header keep-this-tag-format, tags-are-optional, beware-with-underscores-in-markdown, example EOF - fi - chmod 600 "$TMPFILE" + fi + chmod 600 "$TMPFILE" - post_status="E" - filename="" - while [[ $post_status != "p" && $post_status != "P" ]]; do - [[ -n $filename ]] && rm "$filename" # Delete the generated html file, if any - $EDITOR "$TMPFILE" - if [[ $fmt == md ]]; then - html_from_md=$(markdown "$TMPFILE") - parse_file "$html_from_md" - rm "$html_from_md" - else - parse_file "$TMPFILE" # this command sets $filename as the html processed file - fi + post_status="E" + filename="" + while [[ $post_status != "p" && $post_status != "P" ]]; do + [[ -n $filename ]] && rm "$filename" # Delete the generated html file, if any + $EDITOR "$TMPFILE" + if [[ $fmt == md ]]; then + html_from_md=$(markdown "$TMPFILE") + parse_file "$html_from_md" + rm "$html_from_md" + else + parse_file "$TMPFILE" # this command sets $filename as the html processed file + fi - chmod 644 "$filename" - [[ -n $preview_url ]] || preview_url=$global_url - echo "To preview the entry, open $preview_url/$filename in your browser" + chmod 644 "$filename" + [[ -n $preview_url ]] || preview_url=$global_url + echo "To preview the entry, open $preview_url/$filename in your browser" - echo -n "[P]ost this entry, [E]dit again, [D]raft for later? (p/E/d) " - read -r post_status - if [[ $post_status == d || $post_status == D ]]; then - mkdir -p "drafts/" - chmod 700 "drafts/" + echo -n "[P]ost this entry, [E]dit again, [D]raft for later? (p/E/d) " + read -r post_status + if [[ $post_status == d || $post_status == D ]]; then + mkdir -p "drafts/" + chmod 700 "drafts/" - title=$(head -n 1 $TMPFILE) - [[ -n $convert_filename ]] && title=$(echo "$title" | eval "$convert_filename") - [[ -n $title ]] || title=$RANDOM + title=$(head -n 1 $TMPFILE) + [[ -n $convert_filename ]] && title=$(echo "$title" | eval "$convert_filename") + [[ -n $title ]] || title=$RANDOM - draft=drafts/$title.$fmt - mv "$TMPFILE" "$draft" - chmod 600 "$draft" - rm "$filename" - delete_includes - echo "Saved your draft as '$draft'" - exit - fi - done + draft=drafts/$title.$fmt + mv "$TMPFILE" "$draft" + chmod 600 "$draft" + rm "$filename" + delete_includes + echo "Saved your draft as '$draft'" + exit + fi + done - if [[ $fmt == md && -n $save_markdown ]]; then - mv "$TMPFILE" "${filename%%.*}.md" - else - rm "$TMPFILE" - fi - chmod 644 "$filename" - echo "Posted $filename" - relevant_tags=$(tags_in_post $filename) - if [[ -n $relevant_tags ]]; then + if [[ $fmt == md && -n $save_markdown ]]; then + mv "$TMPFILE" "${filename%%.*}.md" + else + rm "$TMPFILE" + fi + chmod 644 "$filename" + echo "Posted $filename" + relevant_tags=$(tags_in_post $filename) + if [[ -n $relevant_tags ]]; then # shellcheck disable=SC2086 # Intended splitting of $relevant_tags - relevant_posts="$(posts_with_tags $relevant_tags) $filename" - rebuild_tags "$relevant_posts" "$relevant_tags" - fi + relevant_posts="$(posts_with_tags $relevant_tags) $filename" + rebuild_tags "$relevant_posts" "$relevant_tags" + fi } # Create an index page with all the posts all_posts() { - echo -n "Creating an index page with all the posts " - contentfile=$archive_index.$RANDOM - while [[ -f $contentfile ]]; do - contentfile=$archive_index.$RANDOM - done + echo -n "Creating an index page with all the posts " + contentfile=$archive_index.$RANDOM + while [[ -f $contentfile ]]; do + contentfile=$archive_index.$RANDOM + done - { - echo "

$template_archive_title

" - prev_month="" - while IFS='' read -r i; do - is_boilerplate_file "$i" && continue - echo -n "." 1>&3 - # Month headers - month=$(LC_ALL=$date_locale date -r "$i" +"$date_allposts_header") - if [[ $month != "$prev_month" ]]; then - [[ -n $prev_month ]] && echo "" # Don't close ul before first header - echo "

$month

" - echo "" - echo "" - } 3>&1 >"$contentfile" + { + echo "

$template_archive_title

" + prev_month="" + while IFS='' read -r i; do + is_boilerplate_file "$i" && continue + echo -n "." 1>&3 + # Month headers + month=$(LC_ALL=$date_locale date -r "$i" +"$date_allposts_header") + if [[ $month != "$prev_month" ]]; then + [[ -n $prev_month ]] && echo "" # Don't close ul before first header + echo "

$month

" + echo "" + echo "" + } 3>&1 >"$contentfile" - create_html_page "$contentfile" "$archive_index.tmp" yes "$global_title — $template_archive_title" "$global_author" - mv "$archive_index.tmp" "$archive_index" - chmod 644 "$archive_index" - rm "$contentfile" + create_html_page "$contentfile" "$archive_index.tmp" yes "$global_title — $template_archive_title" "$global_author" + mv "$archive_index.tmp" "$archive_index" + chmod 644 "$archive_index" + rm "$contentfile" } # Create an index page with all the tags all_tags() { - echo -n "Creating an index page with all the tags " - contentfile=$tags_index.$RANDOM - while [[ -f $contentfile ]]; do - contentfile=$tags_index.$RANDOM - done + echo -n "Creating an index page with all the tags " + contentfile=$tags_index.$RANDOM + while [[ -f $contentfile ]]; do + contentfile=$tags_index.$RANDOM + done - { - echo "

$template_tags_title

" - echo "" + echo "" + } 3>&1 > "$contentfile" - create_html_page "$contentfile" "$tags_index.tmp" yes "$global_title — $template_tags_title" "$global_author" - mv "$tags_index.tmp" "$tags_index" - chmod 644 "$tags_index" - rm "$contentfile" + create_html_page "$contentfile" "$tags_index.tmp" yes "$global_title — $template_tags_title" "$global_author" + mv "$tags_index.tmp" "$tags_index" + chmod 644 "$tags_index" + rm "$contentfile" } # Generate the index.html with the content of the latest posts rebuild_index() { - echo -n "Rebuilding the index " - newindexfile=$index_file.$RANDOM - contentfile=$newindexfile.content - while [[ -f $newindexfile ]]; do - newindexfile=$index_file.$RANDOM - contentfile=$newindexfile.content - done + echo -n "Rebuilding the index " + newindexfile=$index_file.$RANDOM + contentfile=$newindexfile.content + while [[ -f $newindexfile ]]; do + newindexfile=$index_file.$RANDOM + contentfile=$newindexfile.content + done - # Create the content file - { - n=0 - while IFS='' read -r i; do - is_boilerplate_file "$i" && continue; - if ((n >= number_of_index_articles)); then break; fi - if [[ -n $cut_do ]]; then - get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" - else - get_html_file_content 'entry' 'entry' <"$i" - fi - echo -n "." 1>&3 - n=$(( n + 1 )) - done < <(ls -t ./*.html) # sort by date, newest first + # Create the content file + { + n=0 + while IFS='' read -r i; do + is_boilerplate_file "$i" && continue; + if ((n >= number_of_index_articles)); then break; fi + if [[ -n $cut_do ]]; then + get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" + else + get_html_file_content 'entry' 'entry' <"$i" + fi + echo -n "." 1>&3 + n=$(( n + 1 )) + done < <(ls -t ./*.html) # sort by date, newest first - feed=$blog_feed - if [[ -n $global_feedburner ]]; then feed=$global_feedburner; fi - echo "" - } 3>&1 >"$contentfile" + feed=$blog_feed + if [[ -n $global_feedburner ]]; then feed=$global_feedburner; fi + echo "" + } 3>&1 >"$contentfile" - echo "" + echo "" - create_html_page "$contentfile" "$newindexfile" yes "$global_title" "$global_author" - rm "$contentfile" - mv "$newindexfile" "$index_file" - chmod 644 "$index_file" + create_html_page "$contentfile" "$newindexfile" yes "$global_title" "$global_author" + rm "$contentfile" + mv "$newindexfile" "$index_file" + chmod 644 "$index_file" } # Finds all tags referenced in one post. # Accepts either filename as first argument, or post content at stdin # Prints one line with space-separated tags to stdout tags_in_post() { - sed -n "/^

$template_tags_line_header/{s/^

$template_tags_line_header//;s/<[^>]*>//g;s/[ ,]\+/ /g;p;}" "$1" | tr ', ' ' ' + sed -n "/^

$template_tags_line_header/{s/^

$template_tags_line_header//;s/<[^>]*>//g;s/[ ,]\+/ /g;p;}" "$1" | tr ', ' ' ' } # Finds all posts referenced in a number of tags. # Arguments are tags # Prints one line with space-separated tags to stdout posts_with_tags() { - (($# < 1)) && return - set -- "${@/#/$prefix_tags}" - set -- "${@/%/.html}" - sed -n '/^

/{s/.*href="\([^"]*\)">.*/\1/;p;}' "$@" 2> /dev/null + (($# < 1)) && return + set -- "${@/#/$prefix_tags}" + set -- "${@/%/.html}" + sed -n '/^

/{s/.*href="\([^"]*\)">.*/\1/;p;}' "$@" 2> /dev/null } # Rebuilds tag_*.html files @@ -706,387 +705,391 @@ posts_with_tags() { # rebuild_tags "one_post.html another_article.html" "example-tag another-tag" # mind the quotes! rebuild_tags() { - if (($# < 2)); then - # will process all files and tags - files=$(ls -t ./*.html) - all_tags=yes - else - # will process only given files and tags - files=$(printf '%s\n' "$1" | sort -u) + if (($# < 2)); then + # will process all files and tags + files=$(ls -t ./*.html) + all_tags=yes + else + # will process only given files and tags + files=$(printf '%s\n' "$1" | sort -u) # shellcheck disable=SC2086 # Intended splitting of $files - files=$(ls -t $files) - tags=$2 - fi - echo -n "Rebuilding tag pages " - n=0 - if [[ -n $all_tags ]]; then - rm ./"$prefix_tags"*.html &> /dev/null - else - for i in $tags; do - rm "./$prefix_tags$i.html" &> /dev/null - done - fi - # First we will process all files and create temporal tag files - # with just the content of the posts - tmpfile=tmp.$RANDOM - while [[ -f $tmpfile ]]; do tmpfile=tmp.$RANDOM; done - while IFS='' read -r i; do - is_boilerplate_file "$i" && continue; - echo -n "." - if [[ -n $cut_do ]]; then - get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" - else - get_html_file_content 'entry' 'entry' <"$i" - fi >"$tmpfile" - for tag in $(tags_in_post "$i"); do - if [[ -n $all_tags || " $tags " == *" $tag "* ]]; then - cat "$tmpfile" >> "$prefix_tags$tag".tmp.html - fi - done - done <<< "$files" - rm "$tmpfile" - # Now generate the tag files with headers, footers, etc - while IFS='' read -r i; do - tagname=${i#./"$prefix_tags"} - tagname=${tagname%.tmp.html} - create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title — $template_tag_title \"$tagname\"" "$global_author" - rm "$i" - done < <(ls -t ./"$prefix_tags"*.tmp.html 2>/dev/null) - echo + files=$(ls -t $files) + tags=$2 + fi + echo -n "Rebuilding tag pages " + n=0 + if [[ -n $all_tags ]]; then + rm ./"$prefix_tags"*.html &> /dev/null + else + for i in $tags; do + rm "./$prefix_tags$i.html" &> /dev/null + done + fi + # First we will process all files and create temporal tag files + # with just the content of the posts + tmpfile=tmp.$RANDOM + while [[ -f $tmpfile ]]; do tmpfile=tmp.$RANDOM; done + while IFS='' read -r i; do + is_boilerplate_file "$i" && continue; + echo -n "." + if [[ -n $cut_do ]]; then + get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" + else + get_html_file_content 'entry' 'entry' <"$i" + fi >"$tmpfile" + for tag in $(tags_in_post "$i"); do + if [[ -n $all_tags || " $tags " == *" $tag "* ]]; then + cat "$tmpfile" >> "$prefix_tags$tag".tmp.html + fi + done + done <<< "$files" + rm "$tmpfile" + # Now generate the tag files with headers, footers, etc + while IFS='' read -r i; do + tagname=${i#./"$prefix_tags"} + tagname=${tagname%.tmp.html} + create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title — $template_tag_title \"$tagname\"" "$global_author" + rm "$i" + done < <(ls -t ./"$prefix_tags"*.tmp.html 2>/dev/null) + echo } # Return the post title # # $1 the html file get_post_title() { - awk '/

/, /<\/a><\/h3>/{if (!/

/ && !/<\/a><\/h3>/) print}' "$1" + awk '/

/, /<\/a><\/h3>/{if (!/

/ && !/<\/a><\/h3>/) print}' "$1" } # Return the post author # # $1 the html file get_post_author() { - awk '/
.+/, //{if (!/
.+/ && !//) print}' "$1" | sed 's/<\/div>//g' + awk '/
.+/, //{if (!/
.+/ && !//) print}' "$1" | sed 's/<\/div>//g' } # Displays a list of the tags # # $2 if "-n", tags will be sorted by number of posts list_tags() { - if [[ $2 == -n ]]; then do_sort=1; else do_sort=0; fi + if [[ $2 == -n ]]; then do_sort=1; else do_sort=0; fi - if ls ./$prefix_tags*.html > /dev/null; then - echo "No posts yet. Use 'bb.sh post' to create one" && return - fi + if ls ./$prefix_tags*.html > /dev/null; then + echo "No posts yet. Use 'bb.sh post' to create one" && return + fi - lines="" + lines="" # shellcheck disable=SC2231 # Intended splitting of $prefix_tags - for i in $prefix_tags*.html; do - [[ -f "$i" ]] || break - nposts=$(grep -c "<\!-- text begin -->" "$i") - tagname=${i#"$prefix_tags"} - tagname=${tagname#.html} - ((nposts > 1)) && word=$template_tags_posts || word=$template_tags_posts_singular - line="$tagname # $nposts # $word" - lines+=$line\\n - done + for i in $prefix_tags*.html; do + [[ -f "$i" ]] || break + nposts=$(grep -c "<\!-- text begin -->" "$i") + tagname=${i#"$prefix_tags"} + tagname=${tagname#.html} + ((nposts > 1)) && word=$template_tags_posts || word=$template_tags_posts_singular + line="$tagname # $nposts # $word" + lines+=$line\\n + done - if (( do_sort == 1 )); then - echo -e "$lines" | column -t -s "#" | sort -nrk 2 - else - echo -e "$lines" | column -t -s "#" - fi + if (( do_sort == 1 )); then + echo -e "$lines" | column -t -s "#" | sort -nrk 2 + else + echo -e "$lines" | column -t -s "#" + fi } # Displays a list of the posts list_posts() { - if ls ./*.html > /dev/null; then - echo "No posts yet. Use 'bb.sh post' to create one" && return - fi + if ls ./*.html > /dev/null; then + echo "No posts yet. Use 'bb.sh post' to create one" && return + fi - lines="" - n=1 - while IFS='' read -r i; do - is_boilerplate_file "$i" && continue - line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r "$i" +"$date_format")" - lines+=$line\\n - n=$(( n + 1 )) - done < <(ls -t ./*.html) + lines="" + n=1 + while IFS='' read -r i; do + is_boilerplate_file "$i" && continue + line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r "$i" +"$date_format")" + lines+=$line\\n + n=$(( n + 1 )) + done < <(ls -t ./*.html) - echo -e "$lines" | column -t -s "#" + echo -e "$lines" | column -t -s "#" } # Generate the feed file make_rss() { - echo -n "Making RSS " + echo -n "Making RSS " - rssfile=$blog_feed.$RANDOM - while [[ -f $rssfile ]]; do rssfile=$blog_feed.$RANDOM; done + rssfile=$blog_feed.$RANDOM + while [[ -f $rssfile ]]; do rssfile=$blog_feed.$RANDOM; done - { - pubdate=$(LC_ALL=C date +"$date_format_full") - echo '' - echo '' - echo "$global_title$global_url/$index_file" - echo "$global_descriptionen" - echo "$pubdate" - echo "$pubdate" - echo "" - - n=0 - while IFS='' read -r i; do - is_boilerplate_file "$i" && continue - ((n >= number_of_feed_articles)) && break # max 10 items - echo -n "." 1>&3 - echo '' - get_post_title "$i" - echo '$global_url/${i#./}" - echo "$global_url/$i" - echo "$(get_post_author "$i")" - echo "$(LC_ALL=C date -r "$i" +"$date_format_full")" - - n=$(( n + 1 )) - done < <(ls -t ./*.html) - - echo '' - } 3>&1 >"$rssfile" - echo "" + { + pubdate=$(LC_ALL=C date +"$date_format_full") + echo '' + echo '' + echo "$global_title$global_url/$index_file" + echo "$global_descriptionen" + echo "$pubdate" + echo "$pubdate" + echo "" - mv "$rssfile" "$blog_feed" - chmod 644 "$blog_feed" + n=0 + while IFS='' read -r i; do + is_boilerplate_file "$i" && continue + ((n >= number_of_feed_articles)) && break # max 10 items + echo -n "." 1>&3 + echo '' + get_post_title "$i" + echo '$global_url/${i#./}" + echo "$global_url/$i" + echo "$(get_post_author "$i")" + echo "$(LC_ALL=C date -r "$i" +"$date_format_full")" + + n=$(( n + 1 )) + done < <(ls -t ./*.html) + + echo '' + } 3>&1 >"$rssfile" + echo "" + + mv "$rssfile" "$blog_feed" + chmod 644 "$blog_feed" } make_gophermap() { - if [ ! -d "${HOME}/public_gopher" ]; then - printf "Creating gopher hole\\n" - mkdir "${HOME}/public_gopher" - fi + if [ ! -d "${HOME}/public_gopher" ]; then + printf "Creating gopher hole\\n" + mkdir "${HOME}/public_gopher" + fi - if [ ! -L "${HOME}/public_gopher/blog" ]; then - ln -sf "${HOME}/public_html/blog/" "${HOME}/public_gopher/blog" - fi + if [ ! -L "${HOME}/public_gopher/blog" ]; then + ln -sf "${HOME}/public_html/blog/" "${HOME}/public_gopher/blog" + fi - if [ ! -f "${HOME}/public_gopher/blog/$gophermap" ]; then - cat <<- 'EOF' > "${HOME}/public_html/blog/${gophermap}" - #!/usr/bin/env sh - printf "my bashblog posts\n" - user=$(stat -c '%U' .) - for post in $(ls -t *.md); do - post=$(basename $post) - printf "0$post\t/~$user/blog/$post\ttilde.team\t70\n" - done - EOF - chmod +x "${HOME}/public_html/blog/${gophermap}" - fi - chmod 644 ./*.md + if [ ! -f "${HOME}/public_gopher/blog/$gophermap" ]; then + cat <<- 'EOF' > "${HOME}/public_html/blog/${gophermap}" + #!/usr/bin/env sh + printf "my bashblog posts\n" + user=$(stat -c '%U' .) + for post in $(ls -t *.md); do + post=$(basename $post) + printf "0$post\t/~$user/blog/$post\ttilde.team\t70\n" + done +EOF + chmod +x "${HOME}/public_html/blog/${gophermap}" + fi + chmod 644 ./*.md } make_gemini() { - if [ ! -d "${HOME}/public_gemini" ]; then - printf "Creating ~/public_gemini\\n" - mkdir "${HOME}/public_gemini" - fi + if [ ! -d "${HOME}/public_gemini" ]; then + printf "Creating ~/public_gemini\\n" + mkdir "${HOME}/public_gemini" + fi - if [ ! -L "${HOME}/public_gemini/blog" ]; then - ln -sf "${HOME}/public_html/blog/" "${HOME}/public_gemini/blog" - fi + if [ ! -L "${HOME}/public_gemini/blog" ]; then + ln -sf "${HOME}/public_html/blog/" "${HOME}/public_gemini/blog" + fi - if [ ! -f "${HOME}/public_gemini/blog/$gemini_index" ]; then - cat <<- 'EOF' > "${HOME}/public_gemini/blog/${gemini_index}" - #!/usr/bin/env sh - printf "20 text/gemini\r\n" - printf "my bashblog posts\r\n" - user=$(stat -c '%U' $0) - for post in $(ls -t /home/$user/public_gemini/blog/*.md); do - post=$(basename $post) - printf "=> /~$user/blog/$post $post\r\n" - done - EOF - chmod +x "${HOME}/public_gemini/blog/${gemini_index}" - fi + if [ ! -f "${HOME}/public_gemini/blog/$gemini_index" ]; then + cat <<- 'EOF' > "${HOME}/public_gemini/blog/${gemini_index}" + #!/usr/bin/env sh + printf "20 text/gemini\r\n" + printf "my bashblog posts\r\n" + user=$(stat -c '%U' $0) + for post in $(ls -t /home/$user/public_gemini/blog/*.md); do + post=$(basename $post) + printf "=> /~$user/blog/$post $post\r\n" + done +EOF + chmod +x "${HOME}/public_gemini/blog/${gemini_index}" + fi } # generate headers, footers, etc create_includes() { - { - echo "

$global_title

" - echo "
$global_description
" - } > ".title.html" + { + echo "

$global_title

" + echo "
$global_description
" + } > ".title.html" - if [[ -f $header_file ]]; then cp "$header_file" .header.html - else { - echo '' - echo '' - echo '' - echo '' - printf '\n' "${css_include[@]}" - if [[ -z $global_feedburner ]]; then - echo "" - else - echo "" - fi - } > ".header.html" - fi + if [[ -f $header_file ]]; then + cp "$header_file" .header.html + else + { + echo '' + echo '' + echo '' + echo '' + printf '\n' "${css_include[@]}" + if [[ -z $global_feedburner ]]; then + echo "" + else + echo "" + fi + } > ".header.html" + fi - if [[ -f $footer_file ]]; then cp "$footer_file" .footer.html - else { - protected_mail=${global_email//@/@} - protected_mail=${protected_mail//./.} - echo "
$global_license $global_author$protected_mail
" - echo 'generated with bashblog, a single bash script to easily create blogs like this one
' - } >> ".footer.html" - fi + if [[ -f $footer_file ]]; then + cp "$footer_file" .footer.html + else + { + protected_mail=${global_email//@/@} + protected_mail=${protected_mail//./.} + echo "
$global_license $global_author$protected_mail
" + echo 'generated with bashblog, a single bash script to easily create blogs like this one
' + } >> ".footer.html" + fi } # Delete the temporarily generated include files delete_includes() { - rm ".title.html" ".footer.html" ".header.html" + rm ".title.html" ".footer.html" ".header.html" } # Create the css file from scratch create_css() { - # To avoid overwriting manual changes. However it is recommended that - # this function is modified if the user changes the blog.css file - (( ${#css_include[@]} > 0 )) && return || css_include=('main.css' 'blog.css') - if [[ ! -f blog.css ]]; then - # blog.css directives will be loaded after main.css and thus will prevail - echo '#title{font-size: x-large;} - a.ablack{color:black !important;} - li{margin-bottom:8px;} - ul,ol{margin-left:24px;margin-right:24px;} - #all_posts{margin-top:24px;text-align:center;} - .subtitle{font-size:small;margin:12px 0px;} - .content p{margin-left:24px;margin-right:24px;} - h1{margin-bottom:12px !important;} - #description{font-size:large;margin-bottom:12px;} - h3{margin-top:42px;margin-bottom:8px;} - h4{margin-left:24px;margin-right:24px;} - img{max-width:100%;} - #twitter{line-height:20px;vertical-align:top;text-align:right;font-style:italic;color:#333;margin-top:24px;font-size:14px;}' > blog.css - fi + # To avoid overwriting manual changes. However it is recommended that + # this function is modified if the user changes the blog.css file + (( ${#css_include[@]} > 0 )) && return || css_include=('main.css' 'blog.css') + if [[ ! -f blog.css ]]; then + # blog.css directives will be loaded after main.css and thus will prevail + echo '#title{font-size: x-large;} + a.ablack{color:black !important;} + li{margin-bottom:8px;} + ul,ol{margin-left:24px;margin-right:24px;} + #all_posts{margin-top:24px;text-align:center;} + .subtitle{font-size:small;margin:12px 0px;} + .content p{margin-left:24px;margin-right:24px;} + h1{margin-bottom:12px !important;} + #description{font-size:large;margin-bottom:12px;} + h3{margin-top:42px;margin-bottom:8px;} + h4{margin-left:24px;margin-right:24px;} + img{max-width:100%;} + #twitter{line-height:20px;vertical-align:top;text-align:right;font-style:italic;color:#333;margin-top:24px;font-size:14px;}' > blog.css + fi - # If there is a style.css from the parent page (i.e. some landing page) - # then use it. This directive is here for compatibility with my own - # home page. Feel free to edit it out, though it doesn't hurt - if [[ -f ../style.css ]] && [[ ! -f main.css ]]; then - ln -s "../style.css" "main.css" - elif [[ ! -f main.css ]]; then - echo 'body{font-family:Georgia,"Times New Roman",Times,serif;margin:0;padding:0;background-color:#F3F3F3;} - #divbodyholder{padding:5px;background-color:#DDD;width:100%;max-width:874px;margin:24px auto;} - #divbody{border:solid 1px #ccc;background-color:#fff;padding:0px 48px 24px 48px;top:0;} - .headerholder{background-color:#f9f9f9;border-top:solid 1px #ccc;border-left:solid 1px #ccc;border-right:solid 1px #ccc;} - .header{width:100%;max-width:800px;margin:0px auto;padding-top:24px;padding-bottom:8px;} - .content{margin-bottom:5%;} - .nomargin{margin:0;} - .description{margin-top:10px;border-top:solid 1px #666;padding:10px 0;} - h3{font-size:20pt;width:100%;font-weight:bold;margin-top:32px;margin-bottom:0;} - .clear{clear:both;} - #footer{padding-top:10px;border-top:solid 1px #666;color:#333333;text-align:center;font-size:small;font-family:"Courier New","Courier",monospace;} - a{text-decoration:none;color:#003366 !important;} - a:visited{text-decoration:none;color:#336699 !important;} - blockquote{background-color:#f9f9f9;border-left:solid 4px #e9e9e9;margin-left:12px;padding:12px 12px 12px 24px;} - blockquote img{margin:12px 0px;} - blockquote iframe{margin:12px 0px;}' > main.css - fi + # If there is a style.css from the parent page (i.e. some landing page) + # then use it. This directive is here for compatibility with my own + # home page. Feel free to edit it out, though it doesn't hurt + if [[ -f ../style.css ]] && [[ ! -f main.css ]]; then + ln -s "../style.css" "main.css" + elif [[ ! -f main.css ]]; then + echo 'body{font-family:Georgia,"Times New Roman",Times,serif;margin:0;padding:0;background-color:#F3F3F3;} + #divbodyholder{padding:5px;background-color:#DDD;width:100%;max-width:874px;margin:24px auto;} + #divbody{border:solid 1px #ccc;background-color:#fff;padding:0px 48px 24px 48px;top:0;} + .headerholder{background-color:#f9f9f9;border-top:solid 1px #ccc;border-left:solid 1px #ccc;border-right:solid 1px #ccc;} + .header{width:100%;max-width:800px;margin:0px auto;padding-top:24px;padding-bottom:8px;} + .content{margin-bottom:5%;} + .nomargin{margin:0;} + .description{margin-top:10px;border-top:solid 1px #666;padding:10px 0;} + h3{font-size:20pt;width:100%;font-weight:bold;margin-top:32px;margin-bottom:0;} + .clear{clear:both;} + #footer{padding-top:10px;border-top:solid 1px #666;color:#333333;text-align:center;font-size:small;font-family:"Courier New","Courier",monospace;} + a{text-decoration:none;color:#003366 !important;} + a:visited{text-decoration:none;color:#336699 !important;} + blockquote{background-color:#f9f9f9;border-left:solid 4px #e9e9e9;margin-left:12px;padding:12px 12px 12px 24px;} + blockquote img{margin:12px 0px;} + blockquote iframe{margin:12px 0px;}' > main.css + fi } # Regenerates all the single post entries, keeping the post content but modifying # the title, html structure, etc rebuild_all_entries() { - echo -n "Rebuilding all entries " + echo -n "Rebuilding all entries " - for i in ./*.html; do - is_boilerplate_file "$i" && continue; - contentfile=.tmp.$RANDOM - while [[ -f $contentfile ]]; do contentfile=.tmp.$RANDOM; done + for i in ./*.html; do + is_boilerplate_file "$i" && continue; + contentfile=.tmp.$RANDOM + while [[ -f $contentfile ]]; do contentfile=.tmp.$RANDOM; done - echo -n "." - # Get the title and entry, and rebuild the html structure from scratch (divs, title, description...) - title=$(get_post_title "$i") + echo -n "." + # Get the title and entry, and rebuild the html structure from scratch (divs, title, description...) + title=$(get_post_title "$i") - get_html_file_content 'text' 'text' <"$i" >> "$contentfile" + get_html_file_content 'text' 'text' <"$i" >> "$contentfile" - # Read timestamp from post, if present, and sync file timestamp - timestamp=$(awk '// { print }' "$i" | cut -d '#' -f 2) - [[ -n $timestamp ]] && touch -t "$timestamp" "$i" - # Read timestamp from file in correct format for 'create_html_page' - timestamp=$(LC_ALL=C date -r "$i" +"$date_format_full") + # Read timestamp from post, if present, and sync file timestamp + timestamp=$(awk '// { print }' "$i" | cut -d '#' -f 2) + [[ -n $timestamp ]] && touch -t "$timestamp" "$i" + # Read timestamp from file in correct format for 'create_html_page' + timestamp=$(LC_ALL=C date -r "$i" +"$date_format_full") - create_html_page "$contentfile" "$i.rebuilt" no "$title" "$timestamp" "$(get_post_author "$i")" - # keep the original timestamp! - timestamp=$(LC_ALL=C date -r "$i" +"$date_format_timestamp") - mv "$i.rebuilt" "$i" - chmod 644 "$i" - touch -t "$timestamp" "$i" - rm "$contentfile" - done - echo "" + create_html_page "$contentfile" "$i.rebuilt" no "$title" "$timestamp" "$(get_post_author "$i")" + # keep the original timestamp! + timestamp=$(LC_ALL=C date -r "$i" +"$date_format_timestamp") + mv "$i.rebuilt" "$i" + chmod 644 "$i" + touch -t "$timestamp" "$i" + rm "$contentfile" + done + echo "" } # Displays the help usage() { - echo "$global_software_name v$global_software_version" - echo "usage: bb command [filename]" - echo "" - echo "Commands:" - echo " post [-html] [filename] insert a new blog post, or the filename of a draft to continue editing it" - echo " it tries to use markdown by default, and falls back to HTML if it's not available." - echo " use '-html' to override it and edit the post as HTML even when markdown is available" - echo " edit [-n|-f] [filename] edit an already published .html or .md file. **NEVER** edit manually a published .html file," - echo " always use this function as it keeps internal data and rebuilds the blog" - echo " use '-n' to give the file a new name, if title was changed" - echo " use '-f' to edit full html file, instead of just text part (also preserves name)" - echo " delete [filename] deletes the post and rebuilds the blog" - echo " rebuild regenerates all the pages and posts, preserving the content of the entries" - echo " reset deletes everything except this script. Use with a lot of caution and back up first!" - echo " list list all posts" - echo " tags [-n] list all tags in alphabetical order" - echo " use '-n' to sort list by number of posts" - echo "" - echo "for more information please see https://tilde.team/wiki/?page=tildeblogs" - echo "source here: https://tildegit.org/team/bashblog" + echo "$global_software_name v$global_software_version" + echo "usage: bb command [filename]" + echo "" + echo "Commands:" + echo " post [-html] [filename] insert a new blog post, or the filename of a draft to continue editing it" + echo " it tries to use markdown by default, and falls back to HTML if it's not available." + echo " use '-html' to override it and edit the post as HTML even when markdown is available" + echo " edit [-n|-f] [filename] edit an already published .html or .md file. **NEVER** edit manually a published .html file," + echo " always use this function as it keeps internal data and rebuilds the blog" + echo " use '-n' to give the file a new name, if title was changed" + echo " use '-f' to edit full html file, instead of just text part (also preserves name)" + echo " delete [filename] deletes the post and rebuilds the blog" + echo " rebuild regenerates all the pages and posts, preserving the content of the entries" + echo " reset deletes everything except this script. Use with a lot of caution and back up first!" + echo " list list all posts" + echo " tags [-n] list all tags in alphabetical order" + echo " use '-n' to sort list by number of posts" + echo "" + echo "for more information please see https://tilde.team/wiki/?page=tildeblogs" + echo "source here: https://tildegit.org/team/bashblog" } # Delete all generated content, leaving only this script reset() { - echo "Are you sure you want to delete all blog entries? Please write \"Yes, I am!\" " - read -r line - if [[ $line == "Yes, I am!" ]]; then - rm .*.html ./*.html ./*.css ./*.rss &> /dev/null - echo - echo "Deleted all posts, stylesheets and feeds." - echo "Kept your old '.backup.tar.gz' just in case, please delete it manually if needed." - else - echo "Phew! You dodged a bullet there. Nothing was modified." - fi + echo "Are you sure you want to delete all blog entries? Please write \"Yes, I am!\" " + read -r line + if [[ $line == "Yes, I am!" ]]; then + rm .*.html ./*.html ./*.css ./*.rss &> /dev/null + echo + echo "Deleted all posts, stylesheets and feeds." + echo "Kept your old '.backup.tar.gz' just in case, please delete it manually if needed." + else + echo "Phew! You dodged a bullet there. Nothing was modified." + fi } # Detects if GNU date is installed date_version_detect() { - if ! stat -c"%U" /dev/null >/dev/null 2>&1 ; then - # BSD environment - if command -v gdate >/dev/null 2>&1 ; then - date() { - gdate "$@" - } - else - date() { - if [[ $1 == -r ]]; then - # Fall back to using stat for 'date -r' - format=${3//+/} - stat -f "%Sm" -t "$format" "$2" - elif [[ $2 == --date* ]]; then - # convert between dates using BSD date syntax - command date -j -f "$date_format_full" "${2#--date=}" "$1" - else - # acceptable format for BSD date - command date -j "$@" - fi - } - fi - fi + if ! stat -c"%U" /dev/null >/dev/null 2>&1 ; then + # BSD environment + if command -v gdate >/dev/null 2>&1 ; then + date() { + gdate "$@" + } + else + date() { + if [[ $1 == -r ]]; then + # Fall back to using stat for 'date -r' + format=${3//+/} + stat -f "%Sm" -t "$format" "$2" + elif [[ $2 == --date* ]]; then + # convert between dates using BSD date syntax + command date -j -f "$date_format_full" "${2#--date=}" "$1" + else + # acceptable format for BSD date + command date -j "$@" + fi + } + fi + fi } # Main function @@ -1095,78 +1098,78 @@ date_version_detect() { # $1 command to run # $2 file name of a draft to continue editing (optional) do_main() { - # make sure we're in the right directory - [ "$(pwd)" != "$HOME/public_html/blog" ] && - echo "you're not in your blog directory. moving you there now" && \ - mkdir -p "$HOME/public_html/blog" && cd "$HOME/public_html/blog" || exit 1 + # make sure we're in the right directory + [ "$(pwd)" != "$HOME/public_html/blog" ] && + echo "you're not in your blog directory. moving you there now" && \ + mkdir -p "$HOME/public_html/blog" && cd "$HOME/public_html/blog" || exit 1 - # Detect if using BSD date or GNU date - date_version_detect - # Load default configuration, then override settings with the config file - global_variables - # shellcheck disable=SC1090 # variable config file - [[ -f "$global_config" ]] && source "$global_config" &> /dev/null - global_variables_check + # Detect if using BSD date or GNU date + date_version_detect + # Load default configuration, then override settings with the config file + global_variables + # shellcheck disable=SC1090 # variable config file + [[ -f "$global_config" ]] && source "$global_config" &> /dev/null + global_variables_check - # Check for $EDITOR - [[ -z $EDITOR ]] && - echo "Please set your \$EDITOR environment variable. For example, to use nano, add the line 'export EDITOR=nano' to your \$HOME/.bashrc file" && exit + # Check for $EDITOR + [[ -z $EDITOR ]] && + echo "Please set your \$EDITOR environment variable. For example, to use nano, add the line 'export EDITOR=nano' to your \$HOME/.bashrc file" && exit - # Check for validity of argument - [[ $1 != "reset" && $1 != "post" && $1 != "rebuild" && $1 != "list" && $1 != "edit" && $1 != "delete" && $1 != "tags" ]] && - usage && exit + # Check for validity of argument + [[ $1 != "reset" && $1 != "post" && $1 != "rebuild" && $1 != "list" && $1 != "edit" && $1 != "delete" && $1 != "tags" ]] && + usage && exit - [[ $1 == list ]] && - list_posts && exit + [[ $1 == list ]] && + list_posts && exit - [[ $1 == tags ]] && - list_tags "$@" && exit + [[ $1 == tags ]] && + list_tags "$@" && exit - if [[ $1 == edit ]]; then - if (($# < 2)) || [[ ! -f ${!#} ]]; then - echo "Please enter a valid .md or .html file to edit" - exit - fi - fi + if [[ $1 == edit ]]; then + if (($# < 2)) || [[ ! -f ${!#} ]]; then + echo "Please enter a valid .md or .html file to edit" + exit + fi + fi - # Test for existing html files - if ls ./*.html &> /dev/null; then - # We're going to back up just in case - tar -c -z -f ".backup.tar.gz" -- *.html && - chmod 600 ".backup.tar.gz" - elif [[ $1 == rebuild ]]; then - echo "Can't find any html files, nothing to rebuild" - exit - fi + # Test for existing html files + if ls ./*.html &> /dev/null; then + # We're going to back up just in case + tar -c -z -f ".backup.tar.gz" -- *.html && + chmod 600 ".backup.tar.gz" + elif [[ $1 == rebuild ]]; then + echo "Can't find any html files, nothing to rebuild" + exit + fi - # Keep first backup of this day containing yesterday's version of the blog - [[ ! -f .yesterday.tar.gz || $(date -r .yesterday.tar.gz +'%d') != "$(date +'%d')" ]] && - cp .backup.tar.gz .yesterday.tar.gz &> /dev/null + # Keep first backup of this day containing yesterday's version of the blog + [[ ! -f .yesterday.tar.gz || $(date -r .yesterday.tar.gz +'%d') != "$(date +'%d')" ]] && + cp .backup.tar.gz .yesterday.tar.gz &> /dev/null - [[ $1 == reset ]] && - reset && exit + [[ $1 == reset ]] && + reset && exit - create_css - create_includes - [[ $1 == post ]] && write_entry "$@" - [[ $1 == rebuild ]] && rebuild_all_entries && rebuild_tags - [[ $1 == delete ]] && rm "$2" &> /dev/null && rebuild_tags - if [[ $1 == edit ]]; then - if [[ $2 == -n ]]; then - edit "$3" - elif [[ $2 == -f ]]; then - edit "$3" full - else - edit "$2" keep - fi - fi - rebuild_index - all_posts - all_tags - make_rss - make_gophermap - make_gemini - delete_includes + create_css + create_includes + [[ $1 == post ]] && write_entry "$@" + [[ $1 == rebuild ]] && rebuild_all_entries && rebuild_tags + [[ $1 == delete ]] && rm "$2" &> /dev/null && rebuild_tags + if [[ $1 == edit ]]; then + if [[ $2 == -n ]]; then + edit "$3" + elif [[ $2 == -f ]]; then + edit "$3" full + else + edit "$2" keep + fi + fi + rebuild_index + all_posts + all_tags + make_rss + make_gophermap + make_gemini + delete_includes }