💾 Archived View for ix.cyb.red › wiki › pikabu captured on 2023-09-28 at 15:53:11. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
a cute gemini socnet with offline capabilities
cute pages like tumblr that's easy to learn. facilitating social applications of gemini shouldn't require new additions to the protocol, but for the sake of interoperability of social gemini clients and servers we'll try to outline a set of conventions for reading and writing to the social gemspace. for the most part, this will consist of document formats and url structure. gemini social pages should not be distinguished from other kinds of gemini documents, though certain special documents will have strict format requirements.
most existing content in gemini space should be considered conformant to this spec. the few extensions proposed here provide basic pki and inter-site commuication methods with basic privacy. this document intentionally does not specify how user content is provided to the network. though, its pretty clear that gemini+social+titan is going to be the most user-friendly option.
pikabu is a zine-centric social network.
a capsule archive is built on the gemini ebook format gempub. end users and their server host are not expected to provide already-compressed archives, though social servers may generate/cache them to minimize download bandwidth for clients.
a simple script can be used to parse this standard gempub file and download the rest of the gempub archive. minor extensions to the metadata file allow clients and servers to establish coms using the pikabu server protocol.
the gist of the spec is sketched below.
Gempub files are zip archives that contain a Gempub index file (see "Gempub Index", below), a collection of text/gemini (.gmi) files, any supporting files such as images (see "Images", below), and an optional metadata file containing the title, author and any other optional fields (see "Metadata", below).
// Example with index.gmi in a sub-directory, specified by the index value in metadata.txt // .gpub contents: book_title.gpub/ metadata.txt cover.jpg book/ index.gmi chapter1.gmi chapter2.gmi chapter3.gmi images/ illustration.png // metadata.txt: title: book title gpubVersion: 1.0.0 cover: cover.jpg index: book/index.gmi
The metadata.txt file enables Gempub to act as a full e-book format by allowing the author to specify data such as a title, a cover image, copyright information, a book description, and author information.
The metadata.txt file contains key-value pairs separated by line. Values start after the first colon and are trimmed (e.g., author: Olaf Stapledon and author:Olaf Stapledon are equivalent). All values are optional apart from title and gpubVersion. Order does not matter. If no index path is specified there must be an index.gmi in the directory root.
This metadata is intended for readers to use to display a useful catalogue of multiple .gpub files and display covers for individual books. Metadata must never be used to specify flags for content rendering. Content should always be plain Gemtext. Reader applications must ignore custom parameters.
title: my-zine author: xj9 cover: path/to/cover.jpg index: path/to/index.gmi language: nah version: ???whatmeta? publishDate: 19626 license: path/to/license.txt gpubVersion: 1.0.0 pikabuBeaconUrl: gemini://sunshinegardens.org/~xj9/bin/pikabu pikabuFileInfo: crc.txt
lots of gemini clients support subscribing to feeds in this format:
# FEED TITLE DESCRIPTION ## FEED SUBTITLE => URL YYYY-MM-DD - TITLE
gemini feeds and backlinks can be used for pull-based threaded conversations.
VERY EXPERIMENTAL
a set of scripts that demo various experimental social extensions. all operations can be done using plain gemini requests.
some gemini servers allow certain routes to be access restricted based on the pubkey of the client. that's about 80% of a consent-based social network. the remaining 20% is follow requests, a UI for accepting them, and a permission-aware feed aggregator.
installing these may vary depending on your gemini server software. in the future, we may define these interfaces in a more general way.
basically, you need two things
the same pikabu command does can be used for both. just download it somewhere convenient that works with your cgi software. here, "/path/to/db" should match the environment variable PIKKABU_DB_PATH in the cgi settings. for multiple instances, try staggering the cron jobs.
15 * * * * /path/to/pikabu cron -d /path/to/db
pikkabu has a few settings, these are controlled with an indental document:
SYSOPS lain 00100010 01001110 01000010 00100010
could be combined with an "inbox" feature to provide a simple DM push service.
gemini://$target/pikabu/_follow-request?keyid=$TLS_CLIENT_HASH&uri=$SELF_URL&i=$MESSAGE
#!/usr/local/plan9/bin/rc path = (/usr/local/plan9/bin) # opts capsule_url = 'gemini://sunshinegardens.org/~xj9' dreamers_db = /srv/gemini/.cache/follow-request.db # mkdir -p $dreamers_db # script if (~ $"TLS_CLIENT_HASH '') { echo 60 id please. } if not { dreamer = $"TLS_CLIENT_SUBJECT_CN did = $"TLS_CLIENT_HASH follow_record_path = $dreamers_db/$"did.gmi if (~ $"QUERY_STRING '') { echo 10 helllllo stranger. liiiiike to leave an introducccccction'?' } if not { echo '# follow request from' $dreamer > $follow_record_path echo $"QUERY_STRING >> $follow_record_path echo 20 text/gemini echo '# request recieved!' echo iiiiiiiii hoooooooooooope yyyyyyyour note waaaas convincing '^^' echo '=>' $capsule_url 'return to capsule' echo '=>' $capsule_url/wiki/pikkulog/ pikkulog docs echo '## transcript' cat $follow_record_path echo '=> magnet:?x.bb=1312&xt=urn:sha256:'^$did^'&dn="~gemini/'^$dreamer^'"' } }
#!/usr/bin/env rc # CHAOTIC SOFTWARE : BEWARE # This is free and unencumbered software released into the public domain. # gemini://xj-ix.luxe/chaotic-software/ . ./system/lib/list.rc . ./system/lib/gemtext.rc fn parse_urls { feed_list = $1 # parse_urls FEED_LIST fn handle_to_file_name { url=$1 handle=$2 echo ($url `{echo $handle | 9 sed s,/,__,g}) } pair_fold handle_to_file_name `{ cat $feed_list \ | 9 grep '^=>' \ | 9 sed -ne 's,^=> (gemini|gopher)://(.+?) ~(.+)$,\1://\2\n\3,p' } } fn fetch_feeds { feed_list = $1 cache = $2 # fetch_feeds FEED_LIST CACHE fn cache_capsule { url=$1 handle=$2 # cache_capsule URL HANDLE ## store encoded url in record name so we can normalize the canonical feeds ## when we read them. encoded_url = `{echo -n $"url | base64 | tr -d ' ' | sed 's, ,,g'} feed_record = $"cache/^$"handle^@^$"encoded_url^.gmi echo frfr $encoded_url echo fetching url:$"url '->' id:$"feed_record >[1=2] memex gemget $"url > $"feed_record } rm $cache/*.gmi pair_fold cache_capsule `{parse_urls $feed_list} echo 'OK' >[1=2] } fn parse_feeds { # parse_gemlogs FEED... for (feed in $*) { parse_gemlog $feed } } default_cache = data/feeds/.cache default_feed_list = data/bookmarks/feeds.gmi switch ($1) { case cron shift feed_list = $1 if (~ $"feed_list '') { feed_list = $default_feed_list } cache = $2 if (~ $"cache '') { cache = $default_cache } fetch_feeds $feed_list $cache case cache shift cache = $1 if (~ $"cache '') { cache = $default_cache } 9 ls -l $cache/*.gmi case ls shift feed_list = $1 if (~ $"feed_list '') { feed_list = $default_feed_list } parse_urls $feed_list case feed shift cache = $1 if (~ $"cache '') { cache = $default_cache } parse_feeds $cache/*.gmi | 9 sort -ur +2 | 9 head -n 69 case view shift handle = $1 cache = $default_cache if (~ $"handle '') { parse_feeds $"cache/*.gmi | 9 sort -ur +2 } if not { parse_feeds $"cache/$"handle@*.gmi | 9 sort -ur +2 } case render templates/sub.tpl.rc case * echo gemsubs ls '[FEED_LIST]' >[1=2] echo gemsubs cache '[CACHE]' >[1=2] echo gemsubs cron '[FEED_LIST]' '[CACHE]'>[1=2] echo gemsubs feed '[CACHE]' >[1=2] echo gemsubs view '[HANDLE]' '[CACHE]' >[1=2] }