diff --git a/download.html b/download.html index 1ba9700..be9e716 100644 --- a/download.html +++ b/download.html @@ -30,19 +30,27 @@

another.im android


+ + Get it on F-Droid + +

Fork of Conversations XMPP client with additional features

+
-

another.im iOs

+

another.im iOS


" # Don't close ul before first header + echo "

$month

" + echo "" + echo "
$template_archive_index_page
" + } 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 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 "

$template_tags_title

" + echo "" + echo "
$template_archive_index_page
" + } 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" +} + +# 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 + + # 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 "
$template_archive$template_tags_title$template_subscribe
" + } 3>&1 >"$contentfile" + + echo "" + + 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 ', ' ' ' +} + +# 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 +} + +# Rebuilds tag_*.html files +# if no arguments given, rebuilds all of them +# if arguments given, they should have this format: +# "FILE1 [FILE2 [...]]" "TAG1 [TAG2 [...]]" +# where FILEn are files with posts which should be used for rebuilding tags, +# and TAGn are names of tags which should be rebuilt. +# example: +# 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) + 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" +} + +# Return the post author +# +# $1 the html file +get_post_author() { + 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 + + ls ./$prefix_tags*.html &> /dev/null + (($? != 0)) && echo "No posts yet. Use 'bb.sh post' to create one" && return + + lines="" + 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 +} + +# Displays a list of the posts +list_posts() { + ls ./*.html &> /dev/null + (($? != 0)) && echo "No posts yet. Use 'bb.sh post' to create one" && return + + 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 "#" +} + +# Generate the feed file +make_rss() { + echo -n "Making RSS " + + 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 "" + + mv "$rssfile" "$blog_feed" + chmod 644 "$blog_feed" +} + +# generate headers, footers, etc +create_includes() { + { + 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 $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" +} + +# 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 + + # 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 " + + 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") + + 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") + + 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: $0 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 open $0 in a code editor and read the header and comments" +} + +# 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 +} + +# Detects if GNU date is installed +date_version_detect() { + date --version >/dev/null 2>&1 + if (($? != 0)); then + # date utility is BSD. Test if gdate is installed + if gdate --version >/dev/null 2>&1 ; then + date() { + gdate "$@" + } + else + # BSD date + 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 +# Encapsulated on its own function for readability purposes +# +# $1 command to run +# $2 file name of a draft to continue editing (optional) +do_main() { + # Detect if using BSD date or GNU date + date_version_detect + # Load default configuration, then override settings with the config file + global_variables + [[ -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 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 == 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 + + # 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 + + [[ $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 + delete_includes +} + + +# +# MAIN +# Do not change anything here. If you want to modify the code, edit do_main() +# +do_main "$@" + +# vim: set shiftwidth=4 tabstop=4 expandtab: