commit
28e9a51d90
|
@ -0,0 +1,2 @@
|
|||
dist/*
|
||||
!/dist/.gitkeep
|
|
@ -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.
|
|
@ -0,0 +1,19 @@
|
|||
# gemrec
|
||||
|
||||
This is a little recfile database that produces a gemlog
|
||||
|
||||
## 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`?
|
||||
|
||||
|
|
@ -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.
|
|
@ -0,0 +1,376 @@
|
|||
#!/bin/zsh
|
||||
# GEMREC!
|
||||
# It's a gemlog powered by recutils
|
||||
# author: dozens <dozens@tilde.team>
|
||||
# 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 <dozens@tilde.team>" # 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<<EOF
|
||||
# Dozens Gemlog 💎
|
||||
|
||||
One of my goals here is to make new friends and interact with people on gemini. For this reason, I also keep a gem log here to record my thoughts and to reply to other geminauts.
|
||||
EOF
|
||||
)
|
||||
|
||||
### A list item on the gemlog index page
|
||||
TMPL_INDEXITEM()(
|
||||
updated=$1
|
||||
cat<<EOF
|
||||
=> {{id}}.gmi $updated - {{title}}
|
||||
EOF
|
||||
)
|
||||
|
||||
### the gemlog index page footer
|
||||
TMPL_INDEXFOOTER=$(
|
||||
cat<<EOF
|
||||
|
||||
---
|
||||
|
||||
=> atom.xml Atom Feed
|
||||
=> gemini://tilde.town/~dozens/ Home
|
||||
EOF
|
||||
)
|
||||
|
||||
### A metadata block that goes on each gemlog page
|
||||
TMPL_METADATA()(
|
||||
cat<<EOF
|
||||
|
||||
\`\`\`metadata
|
||||
title: {{title}}
|
||||
author: $author
|
||||
url: $url/{{id}}.gmi
|
||||
created: {{created}}
|
||||
updated: {{updated}}
|
||||
tags: {{tags}}
|
||||
\`\`\`
|
||||
EOF
|
||||
)
|
||||
|
||||
### A feed item
|
||||
TMPL_FEEDITEM(){
|
||||
Timestamp=$1
|
||||
cat<<EOF
|
||||
<entry>
|
||||
<id>$url/{{id}}.gmi</id>
|
||||
<title>{{title}}</title>
|
||||
<updated>$Timestamp</updated>
|
||||
<link href='$url/{{id}}.gmi' />
|
||||
<content type="text/plain">
|
||||
<![CDATA[
|
||||
{{body}}
|
||||
]]>
|
||||
</content>
|
||||
</entry>
|
||||
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<<EOF
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<id>$url</id>
|
||||
<title>dozens gemlog</title>
|
||||
<updated>$UPDATED</updated>
|
||||
<author>
|
||||
<name>dozens</name>
|
||||
<email>dozens@tilde.team</email>
|
||||
</author>
|
||||
<link href="$url/$feed" rel="self"/>
|
||||
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++<NF){print "=> 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 "</feed>"
|
||||
)
|
||||
|
||||
### 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 <options>"
|
||||
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
|
|
@ -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 <dozens@tilde.\&team>
|
|
@ -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 <dozens@tilde.team>
|
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
Loading…
Reference in New Issue