commit af2c64ede63e635d1672c1460efe457c58314503 Author: dozens Date: Sat Aug 10 22:30:31 2024 -0600 ✨ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b01c4d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist/* +!/dist/.gitkeep diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c38ef89 --- /dev/null +++ b/LICENSE @@ -0,0 +1,17 @@ +Copyright 2020 + +We're no strangers to love. You know the rules and so do I. A full +commitment's what I'm thinking of. You wouldn't get this from any other +guy. I just wanna tell you how I'm feeling. Gotta make you understand: + +1. Never gonna give you up +2. Never gonna let you down +3. Never gonna run around and desert you +4. Never gonna make you cry +5. Never gonna say goodbye +6. Never gonna tell a lie and hurt you + +WE'VE KNOWN EACH OTHER FOR SO LONG. YOUR HEART'S BEEN ACHING BUT YOU'RE +TOO SHY TO SAY IT. INSIDE WE BOTH KNOW WHAT'S BEEN GOING ON. WE KNOW THE +GAME AND WE'RE GONNA PLAY IT. AND IF YOU ASK ME HOW I'M FEELING. DON'T +TELL ME YOU'RE TOO BLIND TO SEE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cacf555 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# gemrec + +This is a little recfile database that produces a gemlog + +## GETTING STARTED + +1. read the man page (`gemrec.1`). + or `gemlog.1.scd` which is the scdoc[1] source file, + which is markdown (kinda) that generates the manpage. + +2. read `gemrec`. + you'll need to edit some stuff in there anyway. + the globals and the templates. + +[1] https://git.sr.ht/~sircmpwn/scdoc/ + +## REQUIREMENTS + +- GNU recutils 1.9 +- awk version 20240311 +- and other stuff too + +## INSTALL + +1. copy `gemrec` somewhere in your path. + maybe `~/bin`? + +2. copy `gemrec.1` to where your man pages are. + maybe `ls /usr/local/share/man/man1`? + + diff --git a/db/db.rec b/db/db.rec new file mode 100644 index 0000000..cdc2d3f --- /dev/null +++ b/db/db.rec @@ -0,0 +1,20 @@ +%rec: gemlog +%doc: a gemlog entry +%key: id +%type: id int +%auto: id created updated +%sort: id +%type: created,updated date +%type: title,tags line +%type: flags enum draft published unlisted +%unique: title +%mandatory: id title created updated body +%allowed: id title created updated tags flags body + +id: 1 +title: First Impressions of Gemini +updated: 2024-08-10T18:18:40-06:00 +created: 2020-06-14T00:00:00-06:00 +tags: gemini +flags: published +body: Boy oh boy, it's hecking cool! I can't believe it. diff --git a/dist/.gitkeep b/dist/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/gemrec b/gemrec new file mode 100755 index 0000000..2fccb27 --- /dev/null +++ b/gemrec @@ -0,0 +1,376 @@ +#!/bin/zsh +# GEMREC! +# It's a gemlog powered by recutils +# author: dozens +# created: 2024-08-10 +# updated: 2024-08-10 +# version: Albatross.0 + +############# +## GLOBALS ## +############# + +url="gemini://tilde.town/~dozens/gemlog" # where is your gemlog deployed +author="dozens " # used basically just for metadata +db="db/db.rec" # the database file +outdir="dist" # build directory +feed="atom.xml" # name of your gemlog feed +remote="tilde:public_gemini" # where to upload your gemlog? + +############### +## TEMPLATES ## +############### +# Templates are near the top of the file +# instead of near where they are used +# so you don't have to go searching so hard +# if/when you want to change them :) + +### Header of the gemlog index page +TMPL_INDEXHEADER=$( +cat< {{id}}.gmi $updated - {{title}} +EOF +) + +### the gemlog index page footer +TMPL_INDEXFOOTER=$( +cat< atom.xml Atom Feed +=> gemini://tilde.town/~dozens/ Home +EOF +) + +### A metadata block that goes on each gemlog page +TMPL_METADATA()( +cat< + $url/{{id}}.gmi + {{title}} + $Timestamp + + + + + +EOF +} + +### Header for the feed +TMPL_FEEDHEADER=$( +# feed updated always equals the updated field +# of the most recently updated log page +UPDATED=$(recsel $db -P updated -C | sort | tail -n 1) +cat< + + $url + dozens gemlog + $UPDATED + + dozens + dozens@tilde.team + + +EOF +) + +################ +## BUILD FUNS ## +################ + +### Build gemlogs +Build_gemlogs()( + Do_build()( + echo "Building $id.." + exec > $outdir/$id.gmi + echo "#" $(recsel $db -e id=$id -P title) "\n" + recsel $db -e id=$id -P body + echo "\n:wq\n" + echo "Thoughts? Comments? Let me know at dozens@tilde.team" + echo "\nTags:" + recsel $db -P tags -e id=$id \ + | awk '{while(i++ tags/" $i ".gmi " $i}}' + echo "=> tags/index.gmi All tags" + recsel $db -e id=$id | recfmt "$(TMPL_METADATA)" + ) + for id in $(recsel $db -e 'flags="published"' -P id) + do + if [ ! -f $outdir/$id.gmi ] + then + touch $outdir/$id.gmi && Do_build + else + file_updated=$(stat -f "%m" $outdir/$id.gmi) + rec_updated=$(recsel $db -P updated -e id=$id) + rec_epoch=$(gdate -d"$rec_updated" +'%s') + if [ $file_updated -lt $rec_epoch ] + then + Do_build + else + echo "Skipping $id" + fi + fi + done +) + +### build gemlog index +Build_gemindex()( + exec > $outdir/index.gmi + printf "%s\n\n" $TMPL_INDEXHEADER + for id in $(recsel $db -e 'flags="published"' -P id | sort -nr) + do + _date=$(gdate -d"$(recsel $db -e id=$id -P updated)" +'%Y-%m-%d') + recsel $db -e id=$id | recfmt "$(TMPL_INDEXITEM $_date)" + echo + done + echo $TMPL_INDEXFOOTER +) + +### Build feed +Build_feed()( + exec > $outdir/$feed + echo $TMPL_FEEDHEADER + ids=$(recsel db/db.rec -e 'flags="published"' -P id -C) + for id in $ids + do + dateorig=$(recsel $db -e id=$id -P updated) + datenew=$(gdate -Iseconds -d"$dateorig") + recsel $db -e id=$id | recfmt "$(TMPL_FEEDITEM $datenew)" + done + echo "" +) + +### Build tag index +Build_tagindex()( + if [ ! -d $outdir/tags ] + then + mkdir -r $outdir/tags + fi + exec > $outdir/tags/index.gmi + echo "# Tags" + recsel $db -p id,title,tags | recfmt "{{id}} {{tags}} + " | awk ' + { + for(i=2;i<=NF;i++){ + tags[$i]=tags[$i] " " $1; + } + } + END { + for (t in tags) { + print t tags[t] + } + }'| sort | awk -v url="$url" -v db="$db" ' + { + printf "\n## %s\n",$1 + for(i=2;i<=NF;i++){ + cmd="recsel " db " -P title -e id=" $i + cmd | getline title + close(cmd) + printf "=> %s/%s.gmi %s\n", + url,$i,title + } + print "" + }' +) + +### build tag pages +Build_tagpages()( +# be warned this is terribly hacky +recsel $db -p id,title,tags \ +| recfmt '{{tags}}@@{{id}}@{{title}} +' | awk -v outdir="$outdir" '{ + split($0,a,"@@") + taglist=a[1] + id_and_title=a[2] + split(id_and_title,b,"@") + id=b[1] + title=b[2] + split(taglist,tags," ") + for (t in tags) { + tagdict[tags[t]] = (length(tagdict[tags[t]])==0) ? tagdict[tags[t]]=id_and_title : tagdict[tags[t]] "@@" id_and_title + } + } + END { + for (t in tagdict) { + cmd="echo \"# " t "\\n\" > " outdir "/tags/" t ".gmi" + system(cmd) + split(tagdict[t],parts,"@@") + for (part in parts) { + split(parts[part],a,"@") + id=a[1];title=a[2] + link="echo \"=> ../" id ".gmi " title "\" >> " outdir "/tags/" t ".gmi" + system(link) + } + link="echo \"\n=> index.gmi All tags\" >> " outdir "/tags/" t ".gmi" + system(link) + } + } +' +) + +################## +## EDITING FUNS ## +################## + +### create new gemlog +Edit_newlog()( +read -p "Title?> " Title +tmp=$(mktemp) +$EDITOR "$tmp" +Body=$(< "$tmp") +rm $tmp +read -p "[p]ublish or [d]raft?> " Flags +read -p "tags?> " Tags +case "$Flags" in + "d") Flags="draft";; + "p") Flags="published";; + *) echo "Unknown type!"; exit 1;; +esac +recins --verbose db/db.rec -t gemlog \ + -f title -v "$Title" \ + -f flags -v "$Flags" \ + -f tags -v "$Tags" \ + -f body -v "$Body" +created="recsel db/db.rec -e 'title=\"$Title\"' -P id" +echo "Created $(eval $created)" +) + +### update existing gemlog +Edit_updatelog()( +recsel $db -p id,flags,title | recfmt "{{id}}. [{{flags}}] {{title}} +" +printf "Enter a number to edit: " +read myid +grep -w -q $myid <(recsel $db -P id -C) +if [ ! "$?" = 0 ] +then + echo "\nERROR: id does not exist, try again\n" + Edit_updatelog +else + tmpmeta=$(mktemp) + tmpbody=$(mktemp) + recsel $db -e id=$myid -p title,tags,flags > $tmpmeta + recsel $db -e id=$myid -P body > $tmpbody + $EDITOR "$tmpmeta" + $EDITOR "$tmpbody" + Meta=$(< "$tmpmeta") + Body=$(< "$tmpbody") + recset --verbose $db -e id=$myid -f body -s $Body + awk -v db="$db" -v id="$myid" ' + BEGIN {FS=": "} + { + for(i=2;i<=NF;i++){ + if(length(rec[$1]) == 0){ + rec[$1] = $i + } else { + rec[$1] = " " $i + } + } + } + END { + for(r in rec){ + cmd = "recset " db " -e id=" id " -f " r " -s \"" rec[r] "\"" + print time + system(cmd) + } + "gdate -Iseconds" | getline time + cmd = "recset " db " -e id=" id " -f updated -s \"" time "\"" + system(cmd) + } + ' $tmpmeta + rm $tmpmeta + rm $tmpbody +fi +) + +########### +## TASKS ## +########### + +### copy static assets to out dir +Task_copyassets()( +rsync -vurp static/* $outdir +) +### upload log to remote server +Task_upload()( +rsync -azP --exclude=.git dist/* $remote +) + +########## +## MAIN ## +########## + +### Show help +Show_help()( +echo "Usage: gemrec " +echo "Options:" +echo " b|build: [f|feed t|tags g|gem|gemlog] defaults to all" +echo " n|new: create a new post" +echo " u|update: update an existing post" +echo " s|static: copy static files to output" +echo " u|up|upload: upload to remote server" +) + +case "$1" in + "b"|"build") + case "$2" in + "f"|"feed") + echo "Build feed" + Build_feed + ;; + "t"|"tags"|"tag") + echo "Build tags" + Build_tagindex + Build_tagpages + ;; + "g"|"gem"|"gemlog") + echo "Build gemlog" + Build_gemindex + Build_gemlogs + ;; + *) + echo "Build all" + Build_feed + Build_tagindex + Build_tagpages + Build_gemindex + Build_gemlogs + ;; + esac + ;; + "n"|"new") Edit_newlog;; + "e"|"edit") Edit_updatelog;; + "s"|"static") Task_copyassets;; + "u"|"up"|"upload") Task_upload;; + *) Show_help;; +esac diff --git a/gemrec.1 b/gemrec.1 new file mode 100644 index 0000000..dccf482 --- /dev/null +++ b/gemrec.1 @@ -0,0 +1,83 @@ +.\" Generated by scdoc 1.11.3 +.\" Complete documentation for this program is not available as a GNU info page +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.nh +.ad l +.\" Begin generated content: +.TH "GEMREC" "1" "2024-08-11" +.PP +.SH NAME +.PP +gemrec - a gemlog powered by recutils +.PP +.SH SYNOPSIS +.PP +gemrec [options] +.PP +.SH DESCRIPTION +.PP +gemrec +is a wrapper for GNU recutils +that turns a recfile database full of posts +into a gemlog.\& +.PP +Features include: +.PP +.PD 0 +.IP \(bu 4 +All posts and metadata centrally located +in a single rec database +.IP \(bu 4 +Gemlog posts, each with a metadata block and tags +.IP \(bu 4 +A gemsub compatible index of posts +.IP \(bu 4 +A page for each tag, +linking back to each tagged page, +and an index of tags +.IP \(bu 4 +An atom feed +.PD +.PP +.SH OPTIONS +.PP +.SS gemrec build|b +Buid all: feed, gemlog (and index), and tags (and index) +.PP +.SS gemrec b|build f|feed +Build feed +.PP +.SS gemrec b|build g|gemlog +Build gemlog pages that are older than the record'\&s \fIupdated\fR value.\& And the index.\& +.PP +.SS gemrec b|build t|tag|tags +Build tag pages, and the index.\& +.PP +.SS gemrec e|edit +Edit an existing post.\& +The post will be opened in $EDITOR.\& +First the editable metadata.\& +(Title, flags, tags.\&) +And then in a second editor instance, +the post body.\& +.PP +.SS gemrec n|new +Create a new post +.PP +.SS gemrec s|static +Copy static files +(images, static pages, etc) +from \fI/static\fR +to the build dir.\& +.PP +.SS gemrec u|up|upload +Upload to a remote server.\& +.PP +.SH SEE ALSO +.PP +\fIgemrec(5)\fR \fIrecsel\fR(1) \fIrecset\fR(1) +.PP +.SH AUTHORS +.PP +dozens diff --git a/gemrec.1.scd b/gemrec.1.scd new file mode 100644 index 0000000..e2bdf2b --- /dev/null +++ b/gemrec.1.scd @@ -0,0 +1,69 @@ +GEMREC(1) + +# NAME + +gemrec - a gemlog powered by recutils + +# SYNOPSIS + +gemrec [options] + +# DESCRIPTION + +gemrec +is a wrapper for GNU recutils +that turns a recfile database full of posts +into a gemlog. + +Features include: + +- All posts and metadata centrally located + in a single rec database +- Gemlog posts, each with a metadata block and tags +- A gemsub compatible index of posts +- A page for each tag, + linking back to each tagged page, + and an index of tags +- An atom feed + +# OPTIONS + +## gemrec build|b +Buid all: feed, gemlog (and index), and tags (and index) + +## gemrec b|build f|feed +Build feed + +## gemrec b|build g|gemlog +Build gemlog pages that are older than the record's _updated_ value. And the index. + +## gemrec b|build t|tag|tags +Build tag pages, and the index. + +## gemrec e|edit +Edit an existing post. +The post will be opened in $EDITOR. +First the editable metadata. +(Title, flags, tags.) +And then in a second editor instance, +the post body. + +## gemrec n|new +Create a new post + +## gemrec s|static +Copy static files +(images, static pages, etc) +from _/static_ +to the build dir. + +## gemrec u|up|upload +Upload to a remote server. + +# SEE ALSO + +_gemrec(5)_ _recsel_(1) _recset_(1) + +# AUTHORS + +dozens diff --git a/static/img/utp.png b/static/img/utp.png new file mode 100644 index 0000000..35ebf50 Binary files /dev/null and b/static/img/utp.png differ