This page permanently redirects to gemini://gemini.techrights.org/git/tr-git/Gemini/.
This page presents code associated with the module/unit named above.
=> Summary of changes
=> Back to Git index
=> Licence (AGPLv3)
#!/bin/bash yesterday=$(date --date yesterday +"%Y-%m-%d") today=$(date --date today +"%Y-%m-%d") echo "(ℹ) Planet Gemini updated. Latest complete date at gemini://gemini.techrights.org/planet/othercapsules/${yesterday}.gmi and so far today at gemini://gemini.techrights.org/planet/othercapsules/${today}.gmi with 3-day aggregate at gemini://gemini.techrights.org/planet/othercapsules/allinone.gmi" > /home/glr/ii-1.8/techrightslocal/irc.techrights.org/#techrights/in
#!/usr/bin/perl -T # 2021-01-04 # updated 2021-02-12 # XML RSS and Atom feed web scraper, # feed it URLs for feeds plus a date-time stamp # entries will be parsed and can saved in a file # local times will be converted to UTC use utf8; use Getopt::Std; use Time::ParseDate; use Time::Piece; use XML::Feed; use URI; use LWP::UserAgent; use HTTP::Response::Encoding; use HTML::TreeBuilder::XPath; binmode *STDOUT, ':utf8'; use English; use strict; use warnings; our $VERBOSE = 0; $OUTPUT_AUTOFLUSH=1; # work-arounds for 'wide character' error from wrong UTF8 binmode(STDIN, ":encoding(utf8)"); binmode(STDOUT, ":encoding(utf8)"); our %opt; getopts('ad:ho:uv', \%opt); my $script = $0; if (defined($opt{'h'})) { &usage($script); } if (defined($opt{'v'})) { $VERBOSE++; } my $output = ''; if (defined($opt{'o'})) { # XXX needs proper sanity checking for path and filename at least $output = $opt{'o'}; $output =~ s/[\0-\x1f]//g; if ($output =~ /^([-\/\w\.]+)$/) { $output = $1; } else { die("Bad path or file name: '$output'\n"); } } my $utc = 0; # treat input as a local time and convert to UTC if (defined($opt{'u'})) { $utc = 1; # treat input as UTC without conversion } # accept feed entries only after this date, default is yesterday my $sdts; if (defined($opt{'d'})) { $sdts = parsedate($opt{'d'}, GMT=>$utc); # interpret input } else { $sdts = parsedate('yesterday'); # default to yesteday } my $t = Time::Piece->strptime($sdts, '%s'); # time in epoch seconds print STDERR qq(S=$sdts\n) if ($VERBOSE); print STDERR qq(D=),$t->strftime("%a, %d %b %Y %H:%M:%S %Z"),qq(\n) if ($VERBOSE); # process feed URLs one at a time, keep track of how many there were my $count = 0; while (my $url = shift) { next if ($url =~ /^\s*#/); # skip comments print STDERR qq(\nU=$url\n) if ($VERBOSE); # get the feed and work on it my $r = &get_feed($t,$url,$output); if ($r) { $count++; } else { print STDERR qq(Could not find feed at URL: "$url"\n); } } # print qq(\n
\n\n) if ($count); exit(1) unless ($count); exit(0); sub usage { my ($script) = (@_); $script =~ s/^.*\///; print <parse(URI->new($uri)); }; if ($@) { print STDERR $@,qq(\n); print STDERR qq( Failed feed for '$uri'\n); return(0); } # move past otherwise fatal failures in parsing titles, jump to next my $feed_title; eval { $feed_title = $feed->title; }; if ($@) { print STDERR qq( Failed title for '$uri'\n); return(0); } my $feed_modified = $feed->modified; # unsupported my $feed_format = $feed->format; print STDERR qq(\tT=$feed_title\n) if ($VERBOSE); print STDERR qq(\tF=$feed_format\n) if ($VERBOSE); # feed was acquired now go through and find the URLs it contains &read_entries($t,$feed,$output); return(1); } # find URLs within a feed sub read_entries { my ($t,$feed,$output) = (@_); $t = parsedate($t); # if there is an output file set it up for writing my $out; if($output) { # choose append or overwrite mode for file my $mode = ''; if (defined($opt{'a'})) { $mode = '>>'; } else { $mode = '>'; } # open file for output in chosen mode and handling UTF-8 open($out, $mode, $output) or die("Could not open '$output' for appending: $!\n"); binmode($out, ":encoding(utf8)"); } my $count = 0; foreach my $entry ($feed->entries) { # entry time my $ft = $entry->{entry}{pubDate} || $entry->issued || $entry->modified; # entry time in seconds my $et = parsedate($ft) || 0; next unless($et =~ /^\d+$/ && $et >= $t ); # these links are sometimes redirections from proxies my ($base, $content) = &fetch_page($entry->link) or die("Missing content from '",$entry->link,"'\n"); next if ($base eq -1 || $content eq -1); next if ($base =~ /^\d+/ && $base<0); print STDERR qq(Fetched:),substr($base,0,30),qq(\n) if ($VERBOSE); my $uri = URI->new($base) or warn("Bad address, '$base', could not form URI\n"); $uri->query(undef); $uri->fragment(undef); my $site = $uri->authority; print STDERR qq(A=$site\n) if ($VERBOSE); my $o = $uri->canonical; if ($o) { $count++; if($output) { print $out $o,qq(\n); } else { print $o,qq(\n); } } print STDERR qq(\t\t),$base,qq(\n) if ($VERBOSE); } if($output) { close $out; } return(1); } sub fetch_page { my ($uri) = (@_); # this part could just as well be replaced by wget or curl via system() my $ua = LWP::UserAgent->new; $ua->agent("TechRights-Gemini-Bot/0.1"); my $request = HTTP::Request->new(GET => $uri); my $result = $ua->request($request); if ($result->is_success) { return($result->base, $result->decoded_content); } else { warn("Could not open '$uri' : ", $result->status_line, "\n"); return(-1,-1); } return(-1,-1); }
[Unit] Description=Logging for the Agate Gemini Server After=network.target After=agate.target [Service] User=root Type=simple Environment=STARTED_BY_SYSTEMD=true ExecStart=/usr/local/sbin/agate-tcpdump-logger.sh ExecReload=/bin/kill -HUP $MAINPID ExecStop=/bin/kill $MAINPID KillMode=control-group PrivateTmp=true Restart=on-failure Restart=5s [Install] WantedBy=multi-user.target Alias=gemini-logger.service
#!/usr/bin/perl # 2021-06-30 # scrape a designated wiki page and convert to gemtext use utf8; use Getopt::Std; use File::Glob ':bsd_glob'; use HTML::TreeBuilder::XPath; use HTML::Entities; use URI; binmode *STDIN, ':utf8'; # binmode *STDOUT, ':utf8'; use English; use warnings; use strict; $OUTPUT_AUTOFLUSH = 1; our %opt; my $script = $0; getopts('Chvw:', \%opt); &usage($script) if ($opt{'h'}); # iterate through any parmeters passed on the command line, # treat as file names and allow globbing my @filenames; while (my $file = shift) { if ($file eq '-') { # allow processing of STDIN push(@filenames, '-'); if($opt{'v'}) { print qq(F= *STDIN\n); } } else { my @files = bsd_glob($file); foreach my $f (@files) { push(@filenames, $f); if($opt{'v'}) { print qq(F=$f\n); } } } } my $outfile = $opt{'w'} || ''; chomp($outfile); print "1: ", $outfile,qq(\n) if($opt{'v'}); # lll ( $outfile ) = ($outfile =~ m/^([\:\"\'\/\-\_\.\(\)\p{Word}\x7f-\xff]+)$/ ); print "2: ", $outfile,qq(\n) if($opt{'v'}); # quit if no files were listed &usage($script) if($#filenames < 0); # process each file, skipping turd files, hidden files, and temp files while (my $infile = shift(@filenames)) { next if ($infile =~ m/~$/); next if ($infile =~ m/^\.\.?(?!\/)/); next if ($infile =~ m/^#/); my $result = &wiki_to_gemini($infile) || exit(1); if ($outfile) { my ($dir) = ($outfile =~ m{^(.*/)[^/]+$}); if (! -d $dir) { die("Directory '$dir' does not exist.\n"); } if (! -w $dir) { die("Directory '$dir' is not writable.\n"); } open(my $o, '>:utf8', $outfile) or die("Could not open '$outfile' for writing: $!\n"); if ($opt{'v'}) { print qq(Writing to "$outfile"\n); } print $o $result; print $o qq(\n),qq(-)x10,qq(\n); print $o qq(=>\t/\tTechrights\n); print $o qq(➮ Sharing is caring. ); print $o qq(Content is available under CC-BY-SA.); close($o); } else { print $result; print qq(\n),qq(-)x10,qq(\n); print qq(=>\t/\tTechrights\n); print qq(➮ Sharing is caring. ); print qq(Content is available under CC-BY-SA.\n); } } exit(0); sub usage { my ($script) = (@_); $script =~ s/^.*\///g; print qq(Usage: $script [-Chv] [-w file] file\n); print <new; $xhtml->implicit_tags(1); $xhtml->no_space_compacting(0); $xhtml->parse_file($input) or die("Could not parse '$file' : $!\n"); my $result = ''; my %prefix = ( 'h1' => "#\t● ", 'h2' => "##\t●● ", 'h3' => "###\t●●● ", 'h4' => "###\t●●●● ", 'h5' => "###\t●●●●● ", 'h6' => "###\t●●●●●● " ); my @content = (); for my $wiki ($xhtml->findnodes('//div[@id="bodyContent"]')) { $wiki->detach(); push(@content, $wiki); } my $post = HTML::Element->new('div'); $post->push_content(@content); if ($opt{'C'}) { print qq(Deleting TOC\n) if($opt{'v'}); for my $toc ($post->findnodes('//table[@id="toc"]')) { $toc->delete; } } for my $script ($post->findnodes('//script')) { $script->delete; } for my $div ($post->findnodes('//div/div/div')) { $div->delete; } for my $table ($post->findnodes('//table[@id="toc"]')) { $table->delete; } for my $table ($post->findnodes('//table[@class="wikitable"]')) { $table->delete; } for my $a ($post->findnodes('//a[@name and not(@href)]')) { $a->replace_with_content($a->as_text()); } foreach my $hn (1 .. 5) { # format headings $hn = qq(h$hn); for my $heading ($post->findnodes("//$hn")) { my $h ="\n"; $h .= $prefix{$hn} if (defined($prefix{$hn})); $h .= $heading->as_text."\n"; my $tmp = HTML::Element->new('~literal', 'text'=>$h); $heading->replace_with($tmp); } } for my $ul ($post->findnodes('.//ul')) { for my $li ($ul->findnodes('.//li')) { my $listitem = ''; if ($li->findnodes('text()')) { $listitem = $li->as_text; chomp($listitem); } my @anchors = (); for my $a ($li->findnodes('.//a[@href and not(ancestor::pre)]')) { my $href = $a->attr('href') || next; my $uri = URI->new($href)->canonical || next; my $text = $a->as_trimmed_text(); # normalize TR addresses if(!$uri->scheme) { $uri->scheme('http'); $uri->host('techrights.org'); } elsif($uri->scheme eq 'mailto') { next; } elsif($uri->host eq 'boycottnovell.com') { $uri->host('techrights.org'); } # mark external link or else convert TR links to Gemini if ($uri->host ne 'techrights.org') { $text = '↺ '.$text; } elsif ($uri->host eq 'techrights.org' && ! $opt{'C'}) { if($uri->path =~ m{\.pdf$}i) { $text = '↺ '.$text; } else { $uri->host('gemini.techrights.org'); $uri->scheme('gemini'); unless ($uri->path =~ m/\/$/) { my $p = $uri->path; $uri->path($p.'/'); } } } my $link = "\n=>\t".$uri->canonical."\t".$text; push(@anchors, $link); } $listitem = $listitem.join("\n", @anchors).qq(\n); my $tmp = HTML::Element->new('~literal', 'text'=>$listitem); $li->replace_with($tmp); } } for my $pp ($post->findnodes(".//p")) { my @anchors=(); for my $a ($pp->findnodes('.//a[@href and not(ancestor::pre)]')) { my $href = $a->attr('href'); print " H=$href\n" if ($opt{'v'}); next if ($href =~ m/^#/); $href =~ s/\s/%20/g; my $uri = URI->new($href)->canonical || next; my $text = $a->as_trimmed_text(); # normalize TR addresses if(!$uri->scheme) { $uri->scheme('http'); $uri->host('techrights.org'); } elsif($uri->scheme eq 'mailto') { next; } elsif($uri->host eq 'boycottnovell.com') { $uri->host('techrights.org'); } # mark external link or else convert TR links to Gemini if ($uri->host ne 'techrights.org') { $text = '↺ '.$text; } elsif ($uri->host eq 'techrights.org' && ! $opt{'C'}) { if($uri->path =~ m{\.pdf$}) { $text = '↺ '.$text; } else { $uri->host('gemini.techrights.org'); $uri->scheme('gemini'); unless ($uri->path =~ m/\/$/) { my $p = $uri->path; $uri->path($p.'/'); } } } my $link = "\n=>\t".$uri->canonical."\t".$text; push (@anchors, $link); } my $d; if($#anchors >= 0) { $d = $pp->as_text.qq(\n) .join("\n", @anchors ).qq(\n); } else { $d = $pp->as_text.qq(\n); } my $tmp = HTML::Element->new('~literal', 'text' => $d); $pp->replace_with($tmp); } for my $hr ($post->findnodes("//hr")) { my $tmp = HTML::Element->new('~literal', 'text'=>"\n"); $hr->replace_with($tmp); } $result = $post->as_XML_indented; $post->destroy; $xhtml->destroy; unless($is_stdin) { close($input); } while ($result =~ s/<[^>]+>/ /g) { 1 }; # dead tags while ($result =~ s/^\s+#/#/g) { 1 }; # fix headings while ($result =~ s/^\s+$//) { 1 }; # trailing white space while ($result =~ s/^\n\n\n/\n\n/gm) { 1 }; # vertical white space $result = decode_entities($result); return($result); }
#!/bin/sh # 2022-01-18 # try to extract gemini log info from systemd's journalctl # and convert it to gemtext since=$(ps -p $(pgrep -o agate) --no-headers -o start) d=$(date +"%F") #--until "$(date -d "$d -1 day" +'%F 23:59')" \ # set -xv journalctl -q -u agate \ --since "$(date -d "$d -1 day" +'%F 00:00')" \ | awk ' $7~/INFO/ && $11 ~/"gemini/ { sub(/^"/, "", $11) sub(/"$/, "", $11) sub(/\/index.gmi$/, "/", $11) sub(/\/feed$/, "/feed/", $11) sub(/gemini:\/\/gemini.techrights.org:1965\//, "gemini://gemini.techrights.org/", $11) url[$11]++ c++ } END { print(c " Unique Requests\n"); for (u in url) { printf("%s\t%4d\t%s\n", u,url[u],u) } }' \ | sort -k2,2nr -k3,3 \ | head -n 31 \ | awk -v s="$since" 'FNR==1 { print("# Techrights Gemini Capsule Usage\n") print("Running since " s "\n") print("## Top accessed pages yesterday:\n") } $2 { printf("=> %s\t%4d\t%s\n",$3,$2,$3) } END { print("\n=> / Techrights") printf("➮ Sharing is caring. ") printf("Content is available under CC-BY-SA.\n") }' \ > /home/gemini/gemini/stats/top-usage-yesterday.gmi
#!/bin/sh # 2021-02-15 # a template for generating the main index.gmi file PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin # set -xv d=$(date +'%F') # get formatted dates mm=$(date +"%Y/%m/index.gmi\t%B" -d "$d"); # this month # my=$(date +"%Y/%m/index.gmi\t%B" -d "$d -1 month"); # last month my=$(date --date="$(date -d $d +%Y-%m-15) -1 month" +"%Y/%m/index.gmi\t%B"); dy=$(date +"%Y/%m/%d" -d "$d -1 day"); # yesterday dd=$(date +"%Y/%m/%d" -d "$d"); # today mbn=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d"); # this month mb1=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$(date -d $d +%Y-%m-15) -1 month"); mb2=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -2 month"); mb3=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -3 month"); mb4=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -4 month"); mb5=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -5 month"); mb6=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -6 month"); mb7=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -7 month"); mb8=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -8 month"); mb9=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -9 month"); mb10=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -10 month"); mb11=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -11 month"); mb12=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -12 month"); mb13=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -13 month"); mb14=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -14 month"); mb15=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -15 month"); mb16=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -16 month"); mb17=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -17 month"); mb18=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -18 month"); mb19=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -19 month"); mb20=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -20 month"); mb21=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -21 month"); mb22=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -22 month"); mb23=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -23 month"); mb24=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -24 month"); mb25=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -25 month"); mb26=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -26 month"); mb27=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -27 month"); mb28=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -28 month"); mb29=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -29 month"); mb30=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -30 month"); mb31=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -31 month"); mb32=$(date +"bulletins/%Y/%m/index.gmi\t%Y %B" -d "$d -32 month"); tmplinks=$(mktemp --suffix "-index-links-gemini") || exit 1 tmpindex=$(mktemp --suffix "-index-idx-gemini") || exit 1 trap "rm -f -- $tmplinks; rm -f -- $tmpindex;" EXIT set -e # find the index files for those dates and extract the links # find /home/gemini/gemini \ # -type f \ # \( -path "*/$dy/index.gmi" -o -path "*/$dd/index.gmi" \) \ # -exec sed -nre '/Whole Month/,${/Whole Month/d;p}' {} \; \ # | sort -r \ # > $tmplinks # # find /home/gemini/gemini/202? \ # -mindepth 3 -maxdepth 3 -type f -name index.gmi -print \ # | sort -r \ # | head -n 3 \ # | xargs awk '$1=="=>"\ # &&$2~/^.[0-9]{4}.[0-9]{2}.[0-9]{2}.[[:alnum:]]{2}/' \ find /home/gemini/gemini/202? \ -mindepth 3 -maxdepth 3 -type f -name index.gmi -print \ | sort -r \ | head -n 3 \ | xargs perl -a -n -e \ '$F[1]=~m{/[0-9]{4}/[0-9]{2}/[0-9]{2}/\w+} && print' \ > $tmplinks # cat -n $tmp cat << EOF > $tmpindex Welcome to Techrights, the Gemini Capsule! ⛬ We also have a Web proxy at http://gemini.techrights.org/ # Overview => /intro/ Introduction (ℹ) => /about/ About this capsule ⌂ => /archives.gmi Capsule archives § => /irc.gmi Contact us (IRC) 📧 => /logo/logo.png Site logo (if your Gemini client supports that) # Articles from Techrights (GemText) ## Latest Articles in Techrights $(cat $tmplinks) • Please note the above might be slightly out of date, they are synched from HTTP every 3 hours ⟳ Next update at approximately $(TZ=UTC date -d "+3 hours" +"%H:%M UTC"). ## Monthly Archives => $(echo $mm) 🕮 => $(echo $my) 🕮 => /archive/ Older (2006 to present) 📚 # Additional Sections ## Organised Information => /wiki/ Techrights wiki ▤ ## Code => /git/ Techrights git G ## Videos => /latest-videos/ Latest Techrights videos ◉ => /videos/ All Techrights videos ◉ ## Capsule Stats => stats/index.gmi Statistics for this month 🗠 ## Syndication => /feed.xml RSS/XML ♲ => /planet/ Planet Gemini ♲ ### Gemini Feeds (GemText) => /feed/ Feed as GemText ♲ => /daily-feed/ Daily Feeds ♲ ## IPFS (Decentralised) => /ipfs/ IPFS Archive 🗜 ## Bulletins from Techrights (Plain Text) => $(echo -n $mbn), $(echo $mbn | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb1), $(echo $mb1 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb2), $(echo $mb2 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb3), $(echo $mb3 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb4), $(echo $mb4 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb5), $(echo $mb5 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb6), $(echo $mb6 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb7), $(echo $mb7 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb8), $(echo $mb8 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb9), $(echo $mb9 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb10), $(echo $mb10 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb11), $(echo $mb11 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb12), $(echo $mb12 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb13), $(echo $mb13 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb14), $(echo $mb14 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb15), $(echo $mb15 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb16), $(echo $mb16 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb17), $(echo $mb17 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb18), $(echo $mb18 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb19), $(echo $mb19 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb20), $(echo $mb20 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb21), $(echo $mb21 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb22), $(echo $mb22 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb23), $(echo $mb23 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb24), $(echo $mb24 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb25), $(echo $mb25 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb26), $(echo $mb26 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb27), $(echo $mb27 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb28), $(echo $mb28 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb29), $(echo $mb29 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb30), $(echo $mb30 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb31), $(echo $mb31 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 => $(echo -n $mb32), $(echo $mb32 | cut -c1-18 \ | sed 's|bulletins|/home/gemini/gemini|' \ | xargs du -sh | cut -f1) 🖃 • The World Wide Web 🗺 always contains the latest bulletins • Sizes at the top are for all bulletins (for a given month) combined ### ➮ Sharing is caring. Content is available under CC-BY-SA. ⟲ EOF cat $tmpindex rm -f -- $tmplinks rm -f -- $tmpindex trap - exit exit
#!/usr/bin/perl # 2021-02-22 # surveys the designated directory for articles # groups them by day in daily summaries for each day, then # creates a feed of recent articles # creates another feed of recent daily summaries use utf8; use Getopt::Std; use File::Glob ':bsd_glob'; use Path::Iterator::Rule; # libpath-iterator-rule-perl use POSIX qw(strftime); use Date::Calc qw(Add_Delta_Days Month_to_Text); use strict; use warnings; our %opt; getopts('A:v', \%opt); print qq(Verbose mode\n) if ($opt{'v'}); # iterate through any parmeters passed on the command line, # treat as file names and allow globbing my @filenames; while (my $file = shift) { my @files = bsd_glob($file); foreach my $f (@files) { if (-d $f && -w $f) { push(@filenames, $f); } else { warn("'$f' is not a directory and/or not writable.\n"); } } } if ($#filenames < 0) { print qq(Example:\n); my ($script) = ($0 =~ m{([^/]+)$}); print qq($script /home/foobar/\n); exit(1); } print qq(Paths:\n\t),join("\n\t",@filenames),qq(\n) if ($opt{'v'}); # prepare a search through the file system my $rule = Path::Iterator::Rule->new; $rule->name("*.gmi"); $rule->min_depth(4); $rule->max_depth(6); # $rule->contents_match(qr/^#+\s+/); # this rule does not match correctly # find the sought after file names my @files = $rule->all( @filenames ); print qq(Files:\n\t),join("\n\t",@files),qq(\n) if ($opt{'v'}); # collect titles and file names from the found issues/numbers and volumes our %issue = (); for my $f ( @files ) { $f =~ s{//} {/}g; print qq(Found: $f\n) if ($opt{'v'}); if (my ( $base, $year, $month, $day, $issue ) = ($f =~ m{^(.*)/(\d{4})/(\d{2})/(\d{2})/(.*)/(\w+\.gmi)$})) { my $title = &process_file($f); my $gindex = "/$year/$month/$day/index.gmi"; my $gfile = "/$year/$month/$day/$issue/index.gmi"; my $link = "=>\t$gfile\t$month/$day $title"; print " /$year/$month/$day/$issue/\n" if ($opt{'v'}); push (@{$issue{$gindex}{'links'}}, $link); $issue{$gindex}{'base'} = $base; } } &daily_summaries(); &monthly_summaries(); if($opt{'A'}) { my ($archive) = ($opt{'A'} =~ /^([\w\/\_\-]+)$/); if($archive) { print qq(Archive = $archive\n) if ($opt{'v'}); &grand_archive($archive); } } exit(0); sub process_file { my ($file) = (@_); my $title = ''; open(my $article, '<:encoding(UTF-8)', $file) or die("Could not open file '$file' for reading: $!\n"); while (my $line = <$article>) { if ($line =~ m/^#+\s+(.*)$/) { # skip plain dates next if($line =~ m/^\#+\s+\S+\s+\d{2}\.\d{2}/); chomp($line); ($title) = ($line=~m/^\#+\s+\S+\s+(.*)$/); last; } } close($article); return($title||''); } sub daily_summaries { # daily summaries my @key = sort keys %issue; for my $k (@key) { my $base = $issue{$k}{'base'}; my $out; open ($out, ">:utf8", "$base$k") or warn("Could not open file '$base$k' for output: error: $!\n"); my ($title) = ($k =~ m/^(.*)index.gmi$/); my ($month) = ($title =~ m/^\/(.*)\/\d+\/$/); print $out qq(#\tTechRights\t$title\n\n); print $out qq(=>\t/index.gmi\tTechrights\n); print $out qq(=>\t../index.gmi\tThe Whole Month $month\n\n); for my $link(@{$issue{$k}{'links'}}) { print $out qq($link\n); } print $out qq(\n); close($out); } # save the latest data as a sort of feed my $k = $key[$#key]; my $base = $issue{$k}{'base'}; $base =~ s|\/$||; my $feed = "$base/feed/"; unless (-e $feed) { mkdir($feed,0755) or die("Could not create directory '$feed': $!\n"); } elsif (! -d $feed) { die("Not a directory: '$feed' \n"); } elsif (! -w $feed) { die("Cannot write to directory '$feed'\n"); } my $out; open ($out, ">:utf8", $feed.'index.gmi') or die("Could not open file '".$base.$feed. "index.gmi' for output: error: $!\n"); # my ($title) = ($k =~ m/^(.*)index.gmi$/); my ($month) = ($title =~ m/^\/(.*)\/\d+\/$/); # iso-8601 format $title =~ s|^/||; $title =~ s|/$||; $title =~ s|/|-|g; my $latest = $title; print $out qq(#\tTechrights\n\n); print $out qq(#\tDaily Feed of Recent Articles as of $title\n\n); print $out qq(=>\t/index.gmi\tTechrights\n\n); # add the current day's links for my $link(@{$issue{$k}{'links'}}) { $link =~ s|\b\d{2}/\d{2}\s+||; $link =~ s|^(=>\s*\S+)(\s+)|$1$2$title |; print $out qq($link\n); } print $out qq(\n); # add the previous day's links too $k = $key[$#key-1]; ($title) = ($k =~ m/^(.*)index.gmi$/); # iso-8601 format $title =~ s|^/||; $title =~ s|/$||; $title =~ s|/|-|g; for my $link(@{$issue{$k}{'links'}}) { $link =~ s|\b\d{2}/\d{2}\s+||; $link =~ s|^(=>\s*\S+)(\s+)|$1$2$title |; print $out qq($link\n); } print $out qq(\n=>\t/$month/index.gmi\tThe Whole Month $month\n\n); # or for GMT formatted appropriately for your locale: my $updatednow = strftime "Last updated %F %H:%M UTC\n", gmtime; print $out $updatednow; close($out); # feed of daily summaries $feed = $base.'/daily-feed/index.gmi'; open ($out, ">:utf8", $feed) or die("Daily-feed: Could not open file '".$feed ."' for output: error: $!\n"); print $out qq(#\tTechrights\n\n); print $out qq(#\tFeed of Recent Daily Summaries\n\n); print $out qq(=>\t/index.gmi\tTechrights\n\n); my ($y, $m, $d) = split(/-/, $latest); for my $i (0 .. 10) { my ($dy, $dm, $dd) = Add_Delta_Days($y, $m, $d, -$i); my $index = sprintf("/%04d/%02d/%02d/index.gmi", $dy,$dm,$dd); if (-f $base.$index) { printf $out ("=> %s\t%04d-%02d-%02d\n", $index,$dy,$dm,$dd); } } print $out qq(\n).$updatednow; close($out); return(1); } sub monthly_summaries { # monthly summaries my %volume = (); for my $k (sort keys %issue) { my $base = $issue{$k}{'base'}; # K=/2021/01/01/index.gmi my ($title) = ($k =~ m/^(\/\d{4}\/\d{2}\/)/); my ($month) = ($title); my ($year) = ($month =~ m/^(\d{4})\//); next unless ($month); $volume{$month}{'title'} = $title; $volume{$month}{'base'} = $base; for my $link(@{$issue{$k}{'links'}}) { push(@{$volume{$month}{'links'}}, $link); } } for my $m (sort keys %volume) { my $title = $volume{$m}{'title'}; my $base = $volume{$m}{'base'}; my ($year,$month) = ( $title =~ m/^\/(\d{4})\/(\d{2})/); my $out; open ($out, ">:utf8", "$base$m"."index.gmi") or warn("Could not open file '$base$m' for output: error: $!\n"); print $out qq(#\tTechrights\t$title\n\n); print $out qq(=>\t/index.gmi\tTechrights\n\n\n); # print $out qq(=>\t../index.gmi\tThe Whole Year $year\n\n); my $count = 0; for my $link (@{$volume{$m}{'links'}}) { print $out qq($link\n); $count++; print $out qq(\n) unless ($count % 5); print $out qq(\n) unless ($count % 10); } # append navigation for next and previous months, if they exits my $next_month = $month+1>12 ? 1 : $month+1; my $next_year = $next_month < $month ? $year+1 : $year; my $prev_month = $month-1<1 ? 12 : $month-1; my $prev_year = $prev_month > $month ? $year-1 : $year; # next and previous keys to look for my $next_key = sprintf("/%04d/%02d/", $next_year, $next_month); my $prev_key = sprintf("/%04d/%02d/", $prev_year, $prev_month); if(defined($volume{$next_key}) or defined($volume{$prev_key})){ print $out qq(\n),qq(-)x10,qq(\n); if(defined($volume{$next_key})){ print $out qq(=>\t),$next_key,qq(index.gmi\tNext Month\n); } if(defined($volume{$prev_key})){ print $out qq(=>\t),$prev_key,qq(index.gmi\tPrevious Month\n); } } close($out); } } sub grand_archive { my ($archive) = (@_); my $latest_year=0; my %volume = (); for my $k (sort keys %issue) { my ($year,$month) = ($k =~ m/^\/(\d{4})\/(\d{2})\//); next unless ($month); $volume{$year}{$month}++; $latest_year=$year if ($year > $latest_year); } my $out; my $f = "$archive/index.gmi"; unless(-e $archive) { # ought to be made recursive mkdir($archive,0755) or die("Could not create directory '$archive': $!\n"); } open ($out, ">:utf8", "$f") or die("Could not open file '$f' for output: error: $!\n"); print $out qq(#\tArchive of All Articles as of $latest_year\n\n); print $out qq(=>\t/\t ↩ back to Techrights (Main Index)\n); for my $y (reverse sort keys %volume) { print $out qq(\n# $y\n\n); for my $m (reverse sort keys %{$volume{$y}}) { my $month = Month_to_Text($m,1); print $out qq(=> /$y/$m/\t$month $y\n); } } close($out); }
#!/bin/sh # 2021-09-13 # update read-only git archive PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # set -x set -e test -d /home/gemini/gemini/git test -w /home/gemini/gemini/git if test -d /home/gemini/gemini/git/tr-git; then cd /home/gemini/gemini/git/tr-git git fetch --all git reset --hard git pull else cd /home/gemini/gemini/git git clone ssh://tr-git-read-only/home/git/tr-git/ git pull fi # reassemble pages cd /home/gemini/gemini/git/tr-git # to be sure # git pull echo "# Latest Git Commits" > ~/gemini/git/change/index.gmi echo "\n## Latest Change" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git show --format='--8<---[ %H ] | [ %aD ]----' * >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "## Two Changes Ago" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git show HEAD~2 --format='--8<---[ %H ] | [ %aD ]----' * >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "## Three Changes Ago" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git show HEAD~3 --format='--8<---[ %H ] | [ %aD ]----' * >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "## Four Changes Ago" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git show HEAD~4 --format='--8<---[ %H ] | [ %aD ]----' * >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "## Five Changes Ago" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git show HEAD~5 --format='--8<---[ %H ] | [ %aD ]----' * >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "\n# Files changed in the past week" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git diff --stat @{7.days.ago} >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "\n# Older Commits (Latest Shown First)" >> ~/gemini/git/change/index.gmi echo "\n\`\`\`" >> ~/gemini/git/change/index.gmi git log --all --decorate --oneline --graph >> ~/gemini/git/change/index.gmi echo "\`\`\`\n" >> ~/gemini/git/change/index.gmi echo "=> / back to Techrights (Main Index)" >> ~/gemini/git/change/index.gmi echo "# List of Files (Self-Hosted Git)" > ~/gemini/git/files/index.gmi echo "\`\`\`" >> ~/gemini/git/files/index.gmi git ls-tree --full-tree -r --name-only HEAD >> ~/gemini/git/files/index.gmi echo "\`\`\`\n" >> ~/gemini/git/files/index.gmi echo "=> / back to Techrights (Main Index)" >> ~/gemini/git/files/index.gmi echo "\n# Git browser\n" > Desktop-Utils/index.gmi echo "=> /git/ Back to index\n" >> Desktop-Utils/index.gmi find Desktop-Utils/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> Desktop-Utils/index.gmi echo "# Git browser"\n > Gemini/index.gmi echo "=> /git/ Back to index\n" >> Gemini/index.gmi find Gemini/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> Gemini/index.gmi echo "# Git browser"\n > IPFS/index.gmi echo "=> /git/ Back to index\n" >> IPFS/index.gmi find IPFS/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n' \ >> IPFS/index.gmi echo "# Git browser"\n > IRC/index.gmi echo "=> /git/ Back to index\n" >> IRC/index.gmi find IRC/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> IRC/index.gmi echo "# Git browser"\n > Links/index.gmi echo "=> /git/ Back to index\n" >> Links/index.gmi find Links/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> Links/index.gmi echo "# Git browser"\n > sbin/index.gmi echo "=> /git/ Back to index\n" >> sbin/index.gmi find sbin/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> sbin/index.gmi echo "# Git browser"\n > Unit-files/index.gmi echo "=> /git/ Back to index\n" >> Unit-files/index.gmi find Unit-files/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> Unit-files/index.gmi echo "# Git browser"\n > sbin-tm/index.gmi echo "=> /git/ Back to index\n" >> sbin-tm/index.gmi find sbin-tm/ -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> sbin-tm/index.gmi exit 0
#!/usr/bin/sh # SHELL=/usr/bin/sh # export PATH=$PATH:/home/gemini/bin # openssl s_client -quiet -crlf \ # -servername skyjake.fi \ # -connect skyjake.fi:1965 \ # | awk '{ print "response: " $0 }' #gemini://skyjake.fi/~Cosmos/ #openssl s_client -quiet -crlf \ #-servername skyjake.fi \ #-connect skyjake.fi:1965 \ #| awk '{ print "response: " $0 }' #gemini://skyjake.fi/~Cosmos/ openssl s_client -quiet -crlf \ -servername skyjake.fi \ -connect skyjake.fi:1965 \ | awk '{ print "" $0 }' > /tmp/cosmos gemini://skyjake.fi/~Cosmos/
#!/usr/bin/perl # 2021-07-03 # read a hard-coded RSS feed and extract the URLs for changed # wikipages, if they were changed on or after the designated date use utf8; use Getopt::Std; use Time::ParseDate; use Time::Piece; use XML::Feed; use URI; use strict; use warnings; my $script = $0; our $VERBOSE = 0; # work-arounds for 'wide character' error from wrong UTF8 binmode(STDIN, ":encoding(utf8)"); binmode(STDOUT, ":encoding(utf8)"); our %opt; getopts('d:huv', \%opt); if (defined($opt{'h'})) { &usage($script); } if (defined($opt{'v'})) { $VERBOSE++; } my $url ="http://techrights.org/wiki/index.php?title=Special:RecentChanges&feed=rss"; my $utc = 0; # treat input as a local time and convert to UTC if (defined($opt{'u'})) { $utc = 1; # treat input as UTC without conversion } my $sdts; if (defined($opt{'d'})) { $sdts = parsedate($opt{'d'}, GMT=>$utc); } else { $sdts = parsedate('yesterday'); } print STDERR qq(S=$sdts\n) if ($VERBOSE); my $t = Time::Piece->strptime($sdts, '%s'); print STDERR qq(D=),$t->strftime("%a, %d %b %Y %H:%M:%S %Z"),qq(\n) if ($VERBOSE); my @urls = &get_feed_urls($t, $url); print join("\n", @urls),qq(\n); exit(0); sub usage { my ($script) = (@_); $script =~ s/^.*\///; print <parse(URI->new($uri)); }; if ($@) { print STDERR $@,qq(\n); print STDERR qq( Failed feed for '$uri'\n); return(0); } my $count = 0; foreach my $entry ($feed->entries) { # print STDERR Dumper($entry),qq(\n\n) # if($VERBOSE); # entry time my $ft = $entry->{entry}{pubDate} || $entry->issued || $entry->modified; # entry time in seconds my $et = parsedate($ft) || 0; next unless($et =~ /^\d+$/ && $et >= $t ); my $link = URI->new($entry->link); my %keywords = $link->query_form(); my $new_uri = URI->new(); $new_uri->scheme($link->scheme); $new_uri->host($link->host); $new_uri->path($link->path); $new_uri->query('title='.$keywords{'title'}); push(@urls, $new_uri->canonical) if (defined($link)); } @urls = &unique(@urls); return(@urls) } sub unique { my (@urls) = (@_); my %link; foreach my $u (@urls) { $link{$u}++; } my @links=(); foreach my $l (sort keys %link) { push(@links, $l); } return(@links); }
#!/bin/sh # 2021-09-13 # update read-only git archive PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # set -x set -e documentroot=/home/gemini/techrights.org test -d ${documentroot}/git test -w ${documentroot}/git if test -d ${documentroot}/git/tr-git; then cd ${documentroot}/git/tr-git/ git fetch --all git reset --hard git pull else cd ${documentroot}/git/ git clone /home/git/tr-git/ git pull fi # reassemble pages cd ${documentroot}/git/tr-git # to be sure # git pull echo "# Latest Git Commits" > ${documentroot}/git/change/index.gmi echo "\n## Latest Change" >> ${documentroot}/git/change/index.gmi echo "\n\`\`\`" >> ${documentroot}/git/change/index.gmi git show --format='--8<---[ %H ] | [ %aD ]----' * >> ${documentroot}/git/change/index.gmi echo "\`\`\`\n" >> ${documentroot}/git/change/index.gmi echo "## Two Changes Ago" >> ${documentroot}/git/change/index.gmi c=1 while [ $c -lt 5 ]; do echo "\n\`\`\`" \ >> ${documentroot}/git/change/index.gmi git show HEAD~1 \ --format='--8<---[ %H ] | [ %aD ]----' * \ >> ${documentroot}/git/change/index.gmi echo "\`\`\`\n" \ >> ${documentroot}/git/change/index.gmi c=$(($c + 1)) done echo "\n# Files changed in the past week" \ >> ${documentroot}/git/change/index.gmi echo "\n\`\`\`" \ >> ${documentroot}/git/change/index.gmi git diff --stat @{7.days.ago} \ >> ${documentroot}/git/change/index.gmi echo "\`\`\`\n" \ >> ${documentroot}/git/change/index.gmi echo "\n=> / back to Techrights (Main Index)" \ >> ${documentroot}/git/change/index.gmi echo "\n# Older Commits (Latest Shown First)" \ > ${documentroot}/git/all_changes/index.gmi echo "\n\`\`\`" \ >> ${documentroot}/git/all_changes/index.gmi git log --all --decorate --stat --graph \ | grep -v 'Author:' \ >> ${documentroot}/git/all_changes/index.gmi echo "\`\`\`\n" \ >> ${documentroot}/git/all_changes/index.gmi echo "\n=> / back to Techrights (Main Index)" \ >> ${documentroot}/git/all_changes/index.gmi echo "# List of Files (Self-Hosted Git)" \ > ${documentroot}/git/files/index.gmi echo "\`\`\`" \ >> ${documentroot}/git/files/index.gmi git ls-tree --full-tree -r --name-only HEAD \ >> ${documentroot}/git/files/index.gmi echo "\`\`\`\n" \ >> ${documentroot}/git/files/index.gmi echo "=> / back to Techrights (Main Index)" \ >> ${documentroot}/git/files/index.gmi for d in */ ; do echo "# Git browser: $d" > "$d"/index.gmi echo "This page presents code associated with the module/unit named above." >> "$d"/index.gmi echo "=> /git/all_changes/ Summary of changes" >> "$d"/index.gmi echo "=> /git/ Back to Git index" >> "$d"/index.gmi echo "=> /git/agplv3/ Licence (AGPLv3)" >> "$d"/index.gmi find "$d" -type f -not -name index.gmi \ -printf '## %p\n\n```\n' \ -exec cat {} \; \ -printf '\n```\n'\ >> "$d"index.gmi echo "=> / Back to main index" >> "$d"/index.gmi test -d "$d"/changes/ || mkdir -p "$d"/changes/ echo "Latest changes in $d (latest first)" > "$d"/changes/index.gmi echo "=> /git/ Back to Git index" >> "$d"/changes/index.gmi git log "$d" \ | sed -e '/Author/d' \ -e 's/commit /# Commit identifier /' \ -e 's/Date:/##Time of change: /' \ >> "$d"/changes/index.gmi echo "=> / Back to main index" >> "$d"/changes/index.gmi done exit 0
#!/bin/sh PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin amfora= '~/amfora_1.7.2_linux_64-bit' while true; do $amfora gemini.techrights.org & p=$! sleep 120 $amfora simplynews.metalune.xyz/theguardian.com & p=$(echo "$! $p") sleep 120 $amfora gemini://gemini.bortzmeyer.org/software/lupa/stats.gmi & p=$(echo "$! $p") sleep 120 kill $p done exit 0
#!/usr/bin/perl # read TR's gemtext files and guess at building an RSS feed from them use Getopt::Std; use File::Find; use Date::Parse; use Date::Calc qw( Add_Delta_Days Gmtime ); use Time::Local; use XML::Feed; use DateTime; use English; use strict; use warnings; our %opt; getopts('d:ho:r:v', \%opt); my $script = $0; $script =~ s|^.*\/||; &usage($script) if ($opt{'h'}); my $path = shift; if (! defined($path) || ! -d $path) { &usage($script, 1); } our $date; if ($opt{'d'}) { $date = str2time($opt{'d'}, 'UTC') || &usage($script, 2); } else { print "Date missing. Assuming yesterday.\n"; my ($year,$month,$day) = Gmtime(); ($year,$month,$day) = Add_Delta_Days($year,$month,$day, -1); print "$year, $month, $day\n"; $month = $month - 1; $year = $year - 1900; $date = timegm( 0, 0, 0, $day, $month, $year) } if (! defined($opt{'r'}) && ! -d $opt{'r'}) { &usage($script, 4); } my ($output); if (defined($opt{'o'})) { # XXX needs proper sanity checking for path and filename at least $output = $opt{'o'}; $output =~ s/[\0-\x1f]//g; if ($output =~ /^([-\/\w\.]+)$/) { $output = $1; } else { die("Bad path or file name: '$output'\n"); } } else { $output = '/dev/stdout'; } our @retrieved_files; File::Find::find({wanted => \&wanted}, $path); my @files = @retrieved_files; if ($opt{'v'}) { print "Files:\n", join("\n",@files),"\n"; } my %metadata = &read_files(@files); my $feed = XML::Feed->new('RSS'); $feed->title('Techrights Gemini Feed'); $feed->modified(DateTime->now(time_zone=> 'UTC')); $feed->link('gemini://gemini.techrights.org/feed.rss'); $feed->language('en'); $feed->description('Techrights Gemini feed'); # $feed->ttl(1440); for my $f (sort keys %metadata) { my $r = "^$opt{'r'}"; my $p = $f; my $u = "gemini://gemini.techrights.org/"; $p =~ s/$r/$u/; $p =~ s|(?from_epoch(epoch=>$time, time_zone=>"UTC"); $title =~ s/^[#\s●]+//; my $entry = XML::Feed::Entry->new(); $entry->link($p); $entry->title($title); $entry->modified($time); $feed->add_entry($entry); } if ($output eq '/dev/stdout') { print $feed->as_xml; } elsif ($output) { open(my $out, ">", $output) or die("Could not open '$output' for writing: $!\n"); binmode($out, ':encoding(utf8)'); print $out $feed->as_xml; close($out); } exit(0); sub usage { my ($script, $reason) = (@_); if ($reason == 1 ) { print "Missing path to GemText files\n"; } elsif ($reason == 2 ) { print "Bad date or date format.\n"; } elsif ($reason == 3) { print "Date missing\n"; } elsif ($reason == 4) { print "Document root (base) missing\n"; print "use the -r option to set it\n"; } print "\n"; print "Usage: \n"; print "$script [options] -r documentroot path\n"; print " -d starting date, defaults to yesterday\n"; print " -o path to output file, defaults to stdout\n"; print " -r document root for the Gemini server. required\n"; print " -v verbose output\n"; print " -h help - this output\n"; exit(0); } sub wanted { my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks); # print "D=$File::Find::name\n"; if ((($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = lstat($_)) && -f $File::Find::name && m/\.gmi$/ && $mtime >= $date) { push(@retrieved_files, $File::Find::name); # print"$File::Find::name\n"; } } sub read_files { my (@files) = (@files); my %md =(); for my $file (@files) { open(my $fh, "<", $file) or die("Could not open '$file' : $!\n"); my $title = ''; my $count = 0; while (my $line = <$fh>) { chomp($line); if ($line =~ m/^#/ && $count++) { my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev, $size,$atime,$mtime) = stat($fh); $title = $line; $md{$file}{'title'} = $title; $md{$file}{'time'} = $mtime; last; } } close($fh); } return(%md); }
#!/bin/sh # # Initial edits 2021-02-27 # Improvements for scaling 2021-09-09 (RS) PATH=/usr/bin:/bin:/home/gemini/bin capsule='/home/gemini' RED='\033[0;31m' # Set some colours to help separate output visually AMBER='\033[0;33m' YELLOW='\033[1;33m' GREEN='\033[0;32m' BLUE='\033[0;34m' NC='\033[0m' # No color alertthreshold=1000 # How many requests per 10 minutes (by default) are considered 'too much' dt=$(date +"%F %H:%M %Z") # now d=$(date -d "$dt" +"%F") # today dt=$(date -d "$dt") # reformat now lockfile="/tmp/lockfile-$(basename $0)" trap "rm -f -- $lockfile;" EXIT if [ "${FLOCK}" != "$lockfile" ]; then if flock -en "$lockfile" -c date; then exec env FLOCK="$lockfile" flock -en "$lockfile" "$0" "$@" else echo "Already Locked. Aborting." >&2 exit 1 fi else echo Locking fi echo ' 🅶🅴🅼🅸🅽🅸 🅳🅳🅾🆂 🅿🆁🅾🆃🅴🅲🆃🅸🅾🅽' # Yup, just DDOS Protection (alert and response) printf "${GREEN}" systemctl status agate | grep Active printf "${NC}\n" printf "${AMBER}██████████████████████${NC} TOP REQUESTS ${AMBER}█████████████████████████████████████████▉▊▋${NC}\n" set -e # limit to just latest 1,000 in each file as logs have grown very large tail -n1000 $capsule/logs/gemini-log-* \ | awk '$3 {a[$3]++} END{ for (b in a) {print a[b],b}}' OFS="\t" \ | sort -k1,1n -k2,2 | tail -n6 printf "${RED}██████████████████████${NC} LATEST 100 ${RED}███████████████████████████████████████████▉▊▋${NC}\n" tail -n100 $capsule/logs/gemini-log-$d.log \ | awk '$3 {a[$3]++} END{ for (b in a) {print a[b],b}}' OFS="\t" \ | sort -k1,1n -k2,2 | tail -n4 TOTAL=$(wc -l < $capsule/logs/gemini-log-$d.log) LASTTOTAL=$(cat $capsule/last-total.txt) sum=$(( $TOTAL - $LASTTOTAL )) # Get the diff if [ $sum -gt $alertthreshold ] # If too drastic an increase then printf "${RED}" echo -n $sum echo " new requests in 10 minutes. Check logs." # Verbose printf "${NC}\n" echo '' echo " Consider running: sudo iptables -I INPUT -i wlan0 -s {OFFENDER_IP}/24 -j DROP" # Only suggest, do not run (yet) echo ${TOTAL} > $capsule/last-total.txt # Update tally so as to not suppress the next run printf "${RED}" cat $capsule/logo.txt printf "${NC}\n" exit 2 # Sound the system bell fi echo ${TOTAL} > $capsule/last-total.txt # FOR ALL DAYS: # HOSTS=$(cat $capsule/logs/gemini-log-* | awk '$3 {a[$3]++} END{ for (b in a) {print a[b],b}}' OFS="\t" \ # | sort -k1,1n -k2,2 | wc -l) # For current day only HOSTS=$(cat $capsule/logs/gemini-log-$d.log \ | awk '$3 {a[$3]++} END{ for (b in a) {print a[b],b}}' OFS="\t" \ | sort -k1,1n -k2,2 | wc -l) # HOSTS=off # turn off the above for extra speed printf "${YELLOW}█████████████${NC} ${TOTAL} total requests and ${HOSTS} known hosts ${YELLOW}█████████████████▉▊▋${NC}\n" echo -n $sum echo " requests since last run (usually 10 minutes ago)." echo -n 'Alert threshold (system bell): ' echo -n $alertthreshold echo ' or higher' # printf "${RED}____________________________________________________________${NC}\n" echo printf " ${GREEN}Latest 20 requests${NC} (updated <10 mins ago)\n\n" tail -n20 $capsule/logs/gemini-log-$d.log \ | sed -E -e 's/[^ ]+ //; s/ / ⃪ /;' echo _________________________________________________________ printf "${BLUE}" cat $capsule/logo.txt echo _________________________________________________________ # wc -l $capsule/logs/gemini-log-* | cut -b1-7,38-47 # wc -l $capsule/logs/gemini-log-* | cut -d/ -f1,5- | sed 's/ \/gemini-log//' | sed 's/.log//'| sed s/'-'/' reqs '/ | sed s/'2021-'/' | 2021-'/ | sed s/'-'/' \/ '/ | sed s/'-'/' \/ '/ wc -l $capsule/logs/gemini-log-* \ | sed -e 's#/.*-log-#reqs | #; s#-# / #g; s#\.log$##;' \ printf "${NC}\n" Gemini=$(wc -l $capsule/logs/gemini-* | tail -n1) Pages=$(find $capsule/gemini -name '*.gmi' | wc -l) Gemactive=$(/usr/sbin/service agate status | grep Active) echo "# Techrights Gemini Capsule Stats" > $capsule/gemini/stats/index.gmi echo "## Gemini requests since start of month: $Gemini " >> $capsule/gemini/stats/index.gmi echo "## Total pages in capsule: $Pages " >> $capsule/gemini/stats/index.gmi echo "## Uptime (daemon): $Gemactive " >> $capsule/gemini/stats/index.gmi # create page echo "## Top accessed pages yesterday (highest number first):\n" >> $capsule/gemini/stats/index.gmi cat $capsule/logs/top-yesterday.log >> $capsule/gemini/stats/index.gmi echo "## Detailed (number of pages, by date) \n • Please note that all logs are deleted at end of each month (completely, permanently)" >> $capsule/gemini/stats/index.gmi echo "" >> $capsule/gemini/stats/index.gmi echo " Page requests ── Date" >> $capsule/gemini/stats/index.gmi echo " ↧ ────────────── ↧" >> $capsule/gemini/stats/index.gmi echo "┌────────────────────────────────┐" >> $capsule/gemini/stats/index.gmi # wc -l $capsule/logs/gemini-log-* | cut -b1-8,39-47 >> $capsule/gemini/stats/index.gmi # send to capsule too # wc -l $capsule/logs/gemini-log-* | cut -d/ -f0,5- | sed 's/ \/gemini-log//' | sed 's/.log//'| sed s/'-'/' reqs '/ | sed s/'2021-'/' | 2021-'/ | sed s/'-'/' \/ '/ | sed s/'-'/' \/ '/ >> $capsule/gemini/stats/index.gmi wc -l $capsule/logs/gemini-log-* \ | sed -e 's#/.*-log-#reqs | #; s#-# / #g; s#\.log$##;' \ >> $capsule/gemini/stats/index.gmi echo " ──────────────────────────────── " >> $capsule/gemini/stats/index.gmi echo '## Daily Stats Archive' >> $capsule/gemini/stats/index.gmi # Each year another block will need to be added below for the past years y=$(date -d "$d -1 year" +"%Y") echo "### $y Archive" >> $capsule/gemini/stats/index.gmi echo "=> $y.gmi All days ($y)" >> $capsule/gemini/stats/index.gmi echo "# $y Stats Archive" > $capsule/gemini/stats/$y.gmi find /home/gemini/gemini/stats/ \ -type f \ -name "stats-$y*.gmi" \ -exec basename {} \; \ | sort \ | sed -r -e 's/([0-9]{4}-[0-9]{2}-[0-9]{2})\.gmi/\1.gmi \1/; s/^/=> /' \ -e '/01-01.*/i ### January ㋀' \ -e '/02-01.*/i ### February ㋁' \ -e '/03-01.*/i ### March ㋂' \ -e '/04-01.*/i ### April ㋃' \ -e '/05-01.*/i ### May ㋄' \ -e '/06-01.*/i ### June ㋅' \ -e '/07-01.*/i ### July ㋆' \ -e '/08-01.*/i ### August ㋇' \ -e '/09-01.*/i ### September ㋈' \ -e '/10-01.*/i ### October ㋉' \ -e '/11-01.*/i ### November ㋊' \ -e '/12-01.*/i ### December ㋋' \ >> $capsule/gemini/stats/$y.gmi y=$(date -d "$d -2 year" +"%Y") echo "### $y Archive" >> $capsule/gemini/stats/index.gmi echo "=> $y.gmi All days ($y)" >> $capsule/gemini/stats/index.gmi echo "# $y Stats Archive" > $capsule/gemini/stats/$y.gmi find /home/gemini/gemini/stats/ \ -type f \ -name "stats-$y*.gmi" \ -exec basename {} \; \ | sort \ | sed -r -e 's/([0-9]{4}-[0-9]{2}-[0-9]{2})\.gmi/\1.gmi \1/; s/^/=> /' \ -e '/01-01.*/i ### January ㋀' \ -e '/02-01.*/i ### February ㋁' \ -e '/03-01.*/i ### March ㋂' \ -e '/04-01.*/i ### April ㋃' \ -e '/05-01.*/i ### May ㋄' \ -e '/06-01.*/i ### June ㋅' \ -e '/07-01.*/i ### July ㋆' \ -e '/08-01.*/i ### August ㋇' \ -e '/09-01.*/i ### September ㋈' \ -e '/10-01.*/i ### October ㋉' \ -e '/11-01.*/i ### November ㋊' \ -e '/12-01.*/i ### December ㋋' \ >> $capsule/gemini/stats/$y.gmi echo '### This Year' >> $capsule/gemini/stats/index.gmi y=$(date -d "$d" +"%Y") find /home/gemini/gemini/stats/ \ -type f \ -name "stats-$y*.gmi" \ -exec basename {} \; \ | sort \ | sed -r -e 's/([0-9]{4}-[0-9]{2}-[0-9]{2})\.gmi/\1.gmi \1/; s/^/=> /' \ -e '/01-01.*/i ### January ㋀' \ -e '/02-01.*/i ### February ㋁' \ -e '/03-01.*/i ### March ㋂' \ -e '/04-01.*/i ### April ㋃' \ -e '/05-01.*/i ### May ㋄' \ -e '/06-01.*/i ### June ㋅' \ -e '/07-01.*/i ### July ㋆' \ -e '/08-01.*/i ### August ㋇' \ -e '/09-01.*/i ### September ㋈' \ -e '/10-01.*/i ### October ㋉' \ -e '/11-01.*/i ### November ㋊' \ -e '/12-01.*/i ### December ㋋' \ >> $capsule/gemini/stats/index.gmi echo '• No personally-identifying data is in these pages. The raw logs get deleted.' >> $capsule/gemini/stats/index.gmi echo " ──────────────────────────────── \n \n=> / back to Techrights (Main Index)" >> $capsule/gemini/stats/index.gmi echo -n "🅶🅴🅼🅸🅽🅸 Page last updated at " >> $capsule/gemini/stats/index.gmi echo $dt >> $capsule/gemini/stats/index.gmi wget --quiet --tries=22 --retry-on-http-error=500,503 \ -O $capsule/gemini/chat/irc.gmi http://techrights.org/irc/log.gmi \ && sleep 6 \ && mv --backup -f \ $capsule/gemini/chat/irc.gmi $capsule/gemini/chat/index.gmi \ || gemini-ping-roy.sh bright # cat $capsule/techrights-logo-colour.txt echo Unlocking exit 0
Welcome to Techrights Archives, static section of the capsule => / Back to index # Techrights Archives ## Popular Sections => /epo/ EPO Articles ▤ => /linuxfoundation/ Linux Foundation ▤ => /gatesfoundation/ Gates Foundation ▤ => /wiki/ Techrights wiki ▤ => /chat/ Latest chat logs for #techrights (updated every 10 minutes) ▤ # Full Archives => /archive/ Monthly Archives of Articles => /videos/ Techrights videos ◉ => stats/index.gmi Statistics for this month 🗠 => /git/ Techrights git G ## Techrights IRC Archives => irc/index.gmi ㏒ - IRC logs for #techrights => social/index.gmi ㏒ - IRC logs for #boycottnovell-social => techbytes/index.gmi ㏒ - IRC logs for #techbytes => boycottnovell/index.gmi ㏒ - IRC logs for #boycottnovell ## Techrights Site Archives => /ipfs/ IPFS Archive 🗜 => /bulletins/ Techrights Bulletins 🖃 • Plain Text Bulletins are included, but may be hard to get over IPFS due to their size • The World Wide Web 🗺 site always contains the latest Techrights bulletins ## Techrights Syndication => /feed.xml RSS/XML ♲ => /planet/ Planet Gemini ♲ => /feed/ Feed as GemText ♲ => /daily-feed/ Daily Feeds ♲ => /logo/logo.png Site logo (if your Gemini client supports that) ### ➮ Sharing is caring. Content is available under CC-BY-SA. ⟲
#!/usr/bin/perl -T # 2021-07-05 # main script to launch two helper scripts: # a) gemini-get-and-convert-wiki-get-rss.pl - read URLs from RSS # b) gemini-get-and-convert-wiki-from-html.pl - convert from specific HTML to Gemini # then feed the output from a into b and save as a file use Time::ParseDate; use Date::Calc qw(Localtime); use URI; use File::Path qw(make_path); use Getopt::Std; use URI::Escape; use utf8; use warnings; use strict; our %opt; getopts('d:hUv', \%opt); my $date = $opt{'d'} || 'now -2 days'; $date = &iso_8601_date($date); die() unless($date); my $destination = '/home/gemini/gemini/wiki'; $ENV{'PATH'} = '/home/gemini/bin:/usr/local/bin:/usr/bin:/bin'; my @urls = &read_rss_feed($date); foreach my $url (@urls) { my $uri = URI->new($url)->canonical; my %query = $uri->query_form(); my $title = $query{'title'}; next if ($title =~ m/\.\./); my $outdir = join('/',$destination,$title); print qq(outdir = $outdir\n) if $opt{'v'}; &convert_html_to_gemini($uri, $outdir); } &write_index unless($opt{'U'}); exit(0); sub iso_8601_date { my ($date) = (@_); my $seconds = parsedate($date); my ($year,$month,$day) = Localtime($seconds); $date = sprintf("%04d-%02d-%02d", $year,$month,$day); return($date); } sub read_rss_feed { my ($date) = (@_); my $feed_source = "gemini-get-and-convert-wiki-get-rss.pl"; next unless($date =~ m/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/); print qq(Date = $date\n) if ($opt{'v'}); open(my $fh, "-|", $feed_source, "-d", $date) or die("Could not open feed source \"$feed_source\": $!\n"); my @urls; while (my $url = <$fh>) { chomp($url); print qq(URL = $url\n) if ($opt{'v'}); push(@urls, $url); } close($fh); return(@urls); } sub convert_html_to_gemini { my ($uri, $outdir) = (@_); unless (-e $outdir) { make_path($outdir, {mode=>0755}); } unless (-w $outdir) { print STDERR qq(Cannot write to "$outdir"\n); return(0); } ($uri) = uri_unescape($uri); my $outfile = join('/', $outdir, 'index.gmi'); # ($outfile) =~ ($outfile =~ m/^([^\x00-\x20]+)$/g); print qq(\tO = $outfile\n) if ($opt{'v'}); my @doc = (); $uri = uri_escape($uri,"\x20\x22\x27\x60"); ($uri) = ($uri =~ m/^([^\x00-\x20]+)$/); open(my $html, '-|', "curl", "-s", "$uri") or die("Cannot open 'curl'\n"); while(my $line = <$html>) { push(@doc, $line); } close($html); print qq(\tOO = $outfile\n) if($opt{'v'}); open($html,'|-',"gemini-get-and-convert-wiki-from-html.pl", "-w", "$outfile", "-") or die("Cannot open converter\n"); foreach my $line (@doc) { print $html $line; } close($html); return(1); } sub write_index { my $path = '/home/gemini/gemini/wiki'; my $base = '/wiki'; opendir(my $dir, $path) or die("Could not read '$path': $!\n"); my @dirs=(); while (readdir($dir)) { my $d = $_; next unless(-d "$path/$d"); next if ($d =~ m/^\.+/); push(@dirs, $_); } closedir($dir); open(my $o, ">", "$path/index.gmi") or die("Could not open \"$path/index.gmi\" for writing: $!\n"); print $o qq(# Techrights Wiki mirror\n\n); print $o qq(=>\tgemini://gemini.techrights.org/\tTechrights\n\n); foreach my $d (sort @dirs) { my $dd = $d; $dd =~ s/_/ /g; print $o qq(=>\t$base/$d/\t$dd\n); } print $o qq(\n### ➮ Sharing is caring. ); print $o qq(Content is available under CC-BY-SA. ⟲ \n); close($o); }
#/bin/sh # 2021-09-15 # runs as 'pi' PATH=/usr/bin:/bin awk ' $5~/^agate/ { if($11~/favicon\.txt/) { next; } sub(/^"/,"",$11); sub(/"$/,"",$11); sub(/index\.gmi$/,"",$11); sub("^gemini://gemini.techrights.org:1965/", "gemini://gemini.techrights.org/",$11); if($11!~/\/$/) { $11=$11 "/"; } if($11=="/") { $11="gemini://gemini.techrights.org/"; } a[$11]++ c++ } END { print(c " Unique Requests\n"); for(u in a) { print(a[u],u) } }' OFS="\t" /var/log/syslog.1 \ | sort -k1,1nr -k2,2 \ | head -n 31 \ | awk ' NR==2 { print("\nRequests\tPage") } NR>1 { print("=> ", $2, $0 " ⇛") } NR<2 { print; } ' OFS="\t" \ > /home/gemini/logs/top-yesterday.log echo -n 'Accessed over HTTP/S gateway: '>> /home/gemini/logs/top-yesterday.log wc -l /var/log/nginx/access.log.1 | cut -f 1 -d ' ' >> /home/gemini/logs/top-yesterday.log exit 0
#!/usr/bin/perl # 2021-09-17 # update latest video gallery page use HTML::TreeBuilder::XPath; use File::Basename; use JSON; print "# Latest Techrights Videos\n\n"; print "Most recent shown first (the list below is limited to past 7 days)\n\n"; my %videos = &xhtml_video_links('-'); my %metadata = &fetch_metadata(%videos); foreach my $key (sort {$a<=>$b} keys %metadata) { print "=> "; print $metadata{$key}{'link'}," "; print "↺ "; printf ("%2d ",$key); if (exists($metadata{$key}{'title'})) { print $metadata{$key}{'title'}; if(exists($metadata{$key}{'date'})){ print " (",$metadata{$key}{'date'},")"; } } else { print $metadata{$key}{'file'}; } print "\n"; } print "\n=> /videos/ Show videos archive\n"; print "=> / Back to homepage\n"; exit(0); sub xhtml_video_links{ my ($file)= (@_); my $is_stdin = 0; my $input; if ($file eq '-') { $input = *STDIN; $is_stdin++; } else { # force input to be read in as UTF-8 open ($input, "<:utf8", $file) or die("Could not open file '$file' : error: $!\n"); } my $xhtml = HTML::TreeBuilder::XPath->new; $xhtml->implicit_tags(1); $xhtml->no_space_compacting(0); $xhtml->parse_file($input) or die("Could not parse '$file' : $!\n"); my %videos = (); my $listpos = 0; # reset position at 0 for my $l ($xhtml->findnodes_as_strings('//a[@target="video"]/@href') ) { my $link = qq(http://techrights.org/videos/).$l; my $vid = basename($link); $listpos++; $videos{$listpos}{'link'} = $link; $videos{$listpos}{'file'} = $vid; } $xhtml->destroy; unless($is_stdin) { close($input); } return(%videos); } sub fetch_metadata() { my (%metadata) = (@_); foreach my $listpos (keys %metadata) { my @cmd = ("ffprobe", "-v", "panic", "-of", "json", "-show_format", $metadata{$listpos}{'link'}); open(my $json, "-|", @cmd) or die("Could not open pipe '@cmd' : $!\m"); my @text = (); while (my $j = <$json>) { push (@text, $j); } close($json); my $t = join("", @text); my $d = decode_json(join("",@text)); # print Dumper($d),"\n"; if ($d->{'format'}->{'tags'}->{'title'}) { $metadata{$listpos}{'title'} = $d->{'format'}->{'tags'}->{'title'}; } if ($d->{'format'}->{'tags'}->{'DATE'}) { $metadata{$listpos}{'date'} = $d->{'format'}->{'tags'}->{'DATE'}; } # print $metadata{$listpos}{'link'},"\n"; # print $metadata{$listpos}{'file'},"\n\n"; } return(%metadata); }
#!/bin/sh # 2021-02-15 Update TR Gemini site from TR HTTP RSS # # fetch the TR RSS feed with the first script # (gemini-fetch-urls-from-rss.pl) # fetch the linked web pages with the second, # (gemini-fetch-web-page.pl) # which internally calls a third script # (gemini-parse-html-to-gemini.pl) # that third script converts the page from HTML to Gemini # and places the result in the file system hierarchy # then if successful, rebuild the Gemini indexes using a fourth script # (gemini-main-index-template.sh) PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin # override environment variables set incorrectly by the SSH client export LANG="en_GB.UTF-8" export LC_ALL="en_GB.UTF-8" export LC_TIME="en_GB.UTF-8" export LC_MONETARY="en_GB.UTF-8" export LC_ADDRESS="en_GB.UTF-8" export LC_TELEPHONE="en_GB.UTF-8" export LC_NAME="en_GB.UTF-8" export LC_MEASUREMENT="en_GB.UTF-8" export LC_IDENTIFICATION="en_GB.UTF-8" export LC_NUMERIC="en_GB.UTF-8" export LC_PAPER="en_GB.UTF-8" lockfile="/tmp/lockfile-$(basename $0)" if [ "${FLOCK}" != "$lockfile" ]; then if flock -en "$lockfile" -c date; then exec env FLOCK="$lockfile" flock -en "$lockfile" \ -c "$0" "$@" else echo "Already Locked. Aborting." >&2 exit 4 fi else true # echo Locking fi sudo /usr/local/sbin/tc-shaper-v2021-Nov.sh tmpfeeds=$(mktemp --suffix "-cron-gemini") || exit 1 trap "rm -f -- $lockfile; rm -f -- $tmplinks; rm -f -- $tmpindex;" EXIT set -e yyyy=$(date +"%Y"); count=5 while ! timeout 200 gemini-fetch-urls-from-rss.pl http://techrights.org/feed/ \ > ${tmpfeeds} do count=$((${count}-1)) if [ ${count} -eq 0 ] then exit 2 fi sleep 5 done for u in $(grep http ${tmpfeeds}); do count=5 while ! timeout 200 gemini-fetch-web-page.pl \ -g -p -b /home/gemini/gemini/ ${u} do count=$((${count}-1)) if [ ${count} -eq 0 ] then exit 3 fi sleep 5 done done timeout 600 gemini-inventory.pl -A /home/gemini/gemini/archive/ \ /home/gemini/gemini/ \ && gemini-main-index-template.sh > /home/gemini/gemini/index.gmi # gemini-inventory.pl /home/gemini/gemini/2021 works, too, but # truncates the archive, if used gemini-bulletin-irc-update.sh # let's wait for the site to update its index (as it does # every 5 minutes) and then retrieve the list in case # a new video was posted (note that the file of the video # gets uploaded well before a post gets published, so sleep() # might be spurious) sleep 25 gemini-latest-videos.sh rm -f -- ${lockfile} rm -f -- ${tmpfeeds} trap - exit sudo /usr/local/sbin/tc-shaper-v2.sh exit 0
#!/bin/sh # 2021-09013 PATH=/usr/bin:/bin cd /home/gemini/gemini find 2??? \ -maxdepth 0 \ -type d \ -exec sh -c "(echo '# Techrights {}\n'; ls -d {}/?? | \ sed -re 's|^.*/||; s|(.*)|=> \1/ \1|') \ > {}/index.gmi" \; exit 0
=> gemini://sbg.one/gemfeed/atom.xml => gemini://lab6.com/atom.xml => gemini://basnja.ru/atom.xml => gemini://makeworld.gq/gemlog/atom.xml => gemini://si3t.ch/log/atom.xml => gemini://alexschroeder.ch:1965/do/blog/atom => gemini://capsule.theparanoidtimes.org/posts/atom.xml => gemini://ainent.xyz/gemlog/index.gmi => gemini://l-ipa.net/atom.xml => gemini://gemini.susa.net/atom.xml => gemini://tilde.team/~sumpygump/gemlog/atom.xml => gemini://heathens.club/~palm93/the_woods/ => gemini://hoseki.iensu.me/atom.xml => gemini://six10.pw => gemini://9til.de/users/~julienxx/atom.xml => gemini://thfr.info/index.gmi => gemini://pachapunk.space/atom.xml => gemini://etam-software.eu/ => gemini://freeshell.de/gemlog/atom.xml => gemini://envs.net/~vee/pikkulog/atom.xml => gemini://bobignou.red/atom.xml => gemini://acidic.website/musings/atom.xml => gemini://edwardtefft.com/atom.xml => gemini://mizik.eu/feed.xml => gemini://miso.town/atom.xml => gemini://jdj.golf/gemlog/atom.xml => gemini://cap.swan.quest/p/atom.xml => gemini://amami.city/~xdefrag/atom.xml => gemini://knijn.srht.site/posts/atom.xml => gemini://gemlog.blue/users/cariboudatascience/ => gemini://aprates.dev/log/atom.xml => gemini://misterbanal.net/atom.xml => gemini://skyjake.fi/gemlog/atom.xml => gemini://idf.looting.uk/capslog/atom.xml => gemini://dira.cc/gemlog/atom.xml => gemini://ebc.li/atom.xml => gemini://tanelorn.city/~bouncepaw/gemlog/feed.rss => gemini://benj.smol.pub/atom.xml => gemini://smcttl.flounder.online/gemlog/atom.xml => gemini://gemini.circumlunar.space/users/solderpunk/pikkulog/atom.xml => gemini://reisub.nsupdate.info/test/atom.xml => gemini://rosenzweig.io/gemlog/atom.xml => gemini://xhrpb.com/feed.xml => gemini://drewdevault.com/feed.xml => gemini://envs.net/~vee/gemlog/atom.xml => gemini://sylvaindurand.org/rss.xml => gemini://tanso.net/atom.xml => gemini://random-projects.net/feed.atom => gemini://www.underworld.fr/atom.xml => gemini://sylvaindurand.org/feed.xml => gemini://cee64.us/feed.gmi => gemini://tracciabi.li/whiterabbit/index.gmi => gemini://gluonspace.com/gemlog/atom.xml => gemini://rtr.kalayaan.xyz/blog.gmi/atom.xml => gemini://roughcustomers.com => gemini://makeworld.space/gemlog/atom.xml => gemini://taoetc.org/ => gemini://rootkey.co.uk/posts/atom.xml => gemini://gemini.ctrl-c.club/~nehrman/gemlog/atom.xml => gemini://shit.cx/atom.xml => gemini://deblan.io/feed.xml => gemini://c3d2.de/news-atom.xml => gemini://celehner.com/feed.xml => gemini://ondollo.com/~/zert:7C:8E:F5/atom.gem => gemini://gemini.circumlunar.space/users/acdw/atom.xml => gemini://laika.lk/atom.xml => gemini://725.be/index.gmi => gemini://www.demorrow.net/atom.xml => gemini://republic.circumlunar.space/users/crdpa/blog/atom.xml => gemini://muscar.eu/feeds/feed.atom.xml => gemini://gemini.circumlunar.space/~adiabatic/atom.xml => gemini://beyondneolithic.life/atom.xml => gemini://phreedom.club/~tolstoevsky/glog/atom.xml => gemini://gemini.mat.services/atom.xml => gemini://gemini.bbbhltz.space/gemlog/atom.xml => gemini://tilde.club/~lewiscowper/gemlog/atom.xml => gemini://posixcafe.org/blogs/feed.atom => gemini://shuhao.srht.site/posts/atom.xml => gemini://gnuser.land/gemlog/atom.xml => gemini://gemlog.blue/users/NetCandide/ => gemini://spool-five.com/gemlog/index.gmi => gemini://c3po.aljadra.xyz/blog.gmi => gemini://talon.computer/log/atom.xml => gemini://nader.pm/atom.xml => gemini://c3po.aljadra.xyz/atom.xml => gemini://gemini.ucant.org/gemlog/atom.xml => gemini://sylvaindurand.org/atom.xml => gemini://low-key.me/gemlog/atom.xml => gemini://gem.johanbove.info/gemlog/atom.xml => gemini://tilde.pink/~emily/atom.xml => gemini://taoetc.org/feed.gmi => gemini://gemini.circumlunar.space/users/alchemist/gemlog/atom.xml => gemini://warmedal.se/~bjorn/atom.xml => gemini://ruario.flounder.online/gemlog/atom.xml => gemini://blog.schmidhuberj.de/atom.xml => gemini://tilde.team/~ivanruvalcaba/glog/atom.xml => gemini://tilde.team/~easeout/glog/atom.xml => gemini://koyu.space/blu256/atom.xml => gemini://gem.vectorpoem.com/projects_log.gmi => gemini://perso.pw/blog/rss.xml
#!/bin/bash HEIGHT=15 WIDTH=40 CHOICE_HEIGHT=4 BACKTITLE="DDOS observer" TITLE="Gemini @ Techrights" MENU="Choose refresh/recheck interval:" OPTIONS=(1 "Every 1 minute" 2 "Every 10 minutes (recommended, sound/beep suppressed)" 3 "Every 30 minutes" ) CHOICE=$(dialog --clear \ --backtitle "$BACKTITLE" \ --title "$TITLE" \ --menu "$MENU" \ $HEIGHT $WIDTH $CHOICE_HEIGHT \ "${OPTIONS[@]}" \ 2>&1 >/dev/tty) clear case $CHOICE in 1) echo "You chose Option 1" watch -b -c -n 60 ~gemini/bin/show-new-visitors-count.sh ;; 2) echo "You chose Option 2" watch -c -n 600 ~gemini/bin/show-new-visitors-count.sh ;; 3) echo "You chose Option 3" watch -b -c -n 1800 ~gemini/bin/show-new-visitors-count.sh ;; esac # watch -b -c -n 600 ~gemini/bin/show-new-visitors-count.sh
=> gemini://mozz.us/journal/atom.xml => gemini://midnight.pub/feed.xml => gemini://gemini.circumlunar.space/users/solderpunk/gemlog/atom.xml => gemini://gemini.circumlunar.space/~solderpunk/hitenheroes/posts/atom.xml => gemini://gemini.circumlunar.space/~solderpunk/gemlog/atom.xml => gemini://gemini.circumlunar.space/~solderpunk/cornedbeef/atom.xml => gemini://republic.circumlunar.space/users/flexibeast/gemlog/atom.xml => gemini://gemini.circumlunar.space/~ew/feed.xml => gemini://drewdevault.com/feed.xml => gemini://treeprophet.flounder.online/gemlog/atom.xml => gemini://mothbaby.flounder.online/gemlog/atom.xml => gemini://cetacean.club/journal/atom.xml => gemini://hannuhartikainen.fi/twinlog/atom.xml => gemini://gemini.jayeless.net/gemlog/atom.xml => gemini://idiomdrottning.org/atom.xml => gemini://going-flying.com/~mernisse/atom.xml => gemini://breadpunk.club/~bagel/atom.xml => gemini://nytpu.com/flightlog/atom.xml => gemini://nytpu.com/gemlog/atom.xml => gemini://avalos.me/gemlog/atom.xml => gemini://rawtext.club/~mieum/prose/atom.xml => gemini://breadpunk.club/~snickerdoodles/recipes/atom.xml => gemini://rawtext.club/~mieum/relog/atom.xml => gemini://rawtext.club/~mieum/poems/atom.xml => gemini://gemini.sensorstation.co/atom.xml => gemini://envs.net/~kyrenaios/atom.xml => gemini://tilde.team/~easeout/glog/atom.xml => gemini://gemini.conman.org/boston.atom => gemini://carcosa.net/send-the-nukes/atom.xml => gemini://carcosa.net/journal/atom.xml => gemini://yam655.com/recent-feed.xml => gemini://envs.net/~negatethis/atom.xml => gemini://upyum.com/journal/feed.atom => gemini://1436.ninja/gemlog/gemlog.atom => gemini://80h.dev/glog/atom.xml => gemini://80h.dev/~int/glog/atom.xml => gemini://9til.de/users/~julienxx/atom.xml => gemini://caracolito.mooo.com/~sejo/atom.xml => gemini://tilde.team/~emilis/atom.xml => gemini://republic.circumlunar.space/users/joneworlds/atom.xml => gemini://rosenzweig.io/gemlog/atom.xml => gemini://breadpunk.club/~bakersdozen/gemlog/atom.xml => gemini://calcuode.com/gemlog/atom.xml => gemini://salejandro.me/gemlog/atom.xml => gemini://gemini.circumlunar.space/users/solderpunk/pikkulog/atom.xml => gemini://warmedal.se/~bjorn/atom.xml => gemini://gemini.circumlunar.space/~solderpunk/pikkulog/atom.xml => gemini://hedy.flounder.online/gemlog/atom.xml => gemini://antiphasis.flounder.online/gemlog/atom.xml => gemini://asp.flounder.online/gemlog/atom.xml => gemini://jfh.me/atom.xml => gemini://ecs.d2evs.net/feed.xml => gemini://chartjunk.flounder.online/gemlog/atom.xml => gemini://enteka.flounder.online/gemlog/atom.xml => gemini://gem.acdw.net/do/atom => gemini://gem.acdw.net/do/rss => gemini://gem.acdw.net/do/all/atom => gemini://going-flying.com/thoughts/atom.xml => gemini://tilde.team/~ivanruvalcaba/glog/atom.xml => gemini://gemini.ctrl-c.club/~nehrman/gemlog/atom.xml => gemini://gemini.circumlunar.space/users/adiabatic/atom.xml => gemini://rawtext.club/~tolstoevsky/glog/atom.xml => gemini://rawtext.club/~verkaro/glog//atom.xml => gemini://tilde.club/~lewiscowper/gemlog/atom.xml => gemini://gemini.circumlunar.space/users/parker/archives/atom.xml => gemini://gemini.circumlunar.space/users/parker/gacme/atom.xml => gemini://gemini.circumlunar.space/~swiftmandolin/gemlog/atom.xml => gemini://tilde.team/~sumpygump/gemlog/atom.xml => gemini://l-3.space/atom.xml => gemini://republic.circumlunar.space/users/itsdave/atom.xml => gemini://republic.circumlunar.space/~itsdave/noc/atom.xml => gemini://republic.circumlunar.space/~itsdave/atom.xml => gemini://republic.circumlunar.space/users/luminar/atom_feed.xml => gemini://rwv.io/src/atom.xml => gemini://rwv.io/atom.xml => gemini://m040601.flounder.online/gemlog/atom.xml => gemini://testuser.flounder.online/atom.xml => gemini://testuser.flounder.online/myfeed.xml => gemini://thelovebug.flounder.online/gemlog/atom.xml => gemini://zettelkastensystem.flounder.online/gemlog/atom.xml => gemini://gem.acdw.net/code/do/atom => gemini://gem.acdw.net/code/do/rss => gemini://gem.acdw.net/food/do/atom => gemini://gem.acdw.net/food/do/rss => gemini://gem.acdw.net/life/do/atom => gemini://gem.acdw.net/life/do/rss => gemini://gem.acdw.net/made/do/atom => gemini://gem.acdw.net/made/do/rss => gemini://gem.acdw.net/pub/do/atom => gemini://gem.acdw.net/pub/do/rss => gemini://gem.acdw.net/text/do/atom => gemini://gem.acdw.net/text/do/rss => gemini://gemini.susa.net/atom.xml => gemini://pulham.info/atom.xml => gemini://mrnd.xyz/log/atom.xml => gemini://her.esy.fun/gem-atom.xml => gemini://celehner.com/feed.xml => gemini://gemini.circumlunar.space/~solderpunk/3albums/atom.xml => gemini://otrn.org/atom.xml => gemini://acidic.website/musings/atom.xml => gemini://gemini.thegonz.net/glog/atom.xml => gemini://samsai.eu/gemlog/atom.xml => gemini://apintandaparma.club/~ajc/log/atom.xml => gemini://sunshinegardens.org/~xj9/feed.atom => gemini://envs.net/~lrb/gemlog/atom.xml => gemini://perplexing.space/atom.xml => gemini://gemini.circumlunar.space/~adiabatic/atom.xml => gemini://apintandaparma.club/~ajft/phlog/atom.xml => gemini://gempaper.strangled.net/notes/atom.xml => gemini://republic.circumlunar.space/users/dbane/gemlog/atom.xml => gemini://tilde.pink/~lucymoth/gemlog/atom.xml => gemini://aoalmeida.com/feed.xml => gemini://shit.cx/atom.xml => gemini://tilde.team/~emilis/feed.xml => gemini://gsthnz.com/posts/atom.xml => gemini://skyjake.fi/gemlog/atom.xml => gemini://emii.gay/en/emi-overshares/atom.xml => gemini://republic.circumlunar.space/~luminar/atom_feed.xml => gemini://drsudo.com/gemlog/atom.xml => gemini://gemini.ucant.org/gemlog/atom.xml => gemini://gemini.iosa.it/gemlog/atom.xml => gemini://freeside.wntrmute.net/log/index.rss => gemini://orx57.flounder.online/gemlog/atom.xml => gemini://rawtext.club/~mieum/music/atom.xml => gemini://rawtext.club/~ecliptik/_posts/feed.xml => gemini://mnmnm.flounder.online/gemlog/atom.xml => gemini://kujiu.org/blog/atom.xml => gemini://nerv-project.eu/blog/atom.xml => gemini://gmi.karl.berlin/atom.xml => gemini://tposs.flounder.online/gemlog/atom.xml => gemini://gemini.lottalinuxlinks.com/posts/feed.xml => gemini://nader.pm/atom.xml => gemini://dsfadsfgafgf.flounder.online/gemlog/atom.xml => gemini://space.fqserv.eu/gemlog/atom.xml => gemini://moddedbear.xyz/logs/atom.xml => gemini://lightspeed.flounder.online/gemlog/atom.xml => gemini://shtirlic.flounder.online/gemlog/atom.xml => gemini://makeworld.space/users/~atyrfingerprints/gemlog/atom.xml => gemini://makeworld.space/gemlog/atom.xml => gemini://phreedom.club//atom.xml => gemini://jochen.flounder.online/gemlog/atom.xml => gemini://lycopersica.flounder.online/gemlog/atom.xml => gemini://rasputin.selfip.net/atom.xml => gemini://space.fqserv.eu/tanka/atom.xml => gemini://thmslld.flounder.online/gemlog/atom.xml => gemini://moribundo.flounder.online/gemlog/atom.xml => gemini://gemini.cyberbot.space/gemlog/atom.xml => gemini://breadpunk.club/~proof/atom.xml => gemini://breadpunk.club/~snickerdoodles/mouthfuls/atom.xml => gemini://riqtare.flounder.online/gemlog/atom.xml => gemini://przemek.flounder.online/gemlog/atom.xml => gemini://szczezuja.flounder.online/gemlog/atom.xml => gemini://votih.flounder.online/gemlog/atom.xml => gemini://cosmic.voyage/atom.xml => gemini://random-projects.net/feed.atom => gemini://muppet.flounder.online/gemlog/atom.xml => gemini://scifirenegade.flounder.online/gemlog/atom.xml => gemini://etam-software.eu/blog/feed.xml => gemini://adnano.co/atom.xml => gemini://edwardtefft.com/atom.xml => gemini://t-900.flounder.online/gemlog/atom.xml => gemini://sunbance.flounder.online/gemlog/atom.xml => gemini://jlk.flounder.online/gemlog/atom.xml => gemini://capsule.usebox.net/gemlog/atom.xml => gemini://filter.id.au/gemlog/atom.xml => gemini://tilde.pink/~emily/atom.xml => gemini://senders.io/feed/atom.xml => gemini://senders.io/gemlog/feed/atom.xml => gemini://1436.ninja/phlog.atom => gemini://flume.space/atom.xml => gemini://wirthslaw.flounder.online/gemlog/atom.xml => gemini://pwshnotes.flounder.online/gemlog/atom.xml => gemini://bonehead.flounder.online/gemlog/atom.xml => gemini://luke.flounder.online/gemlog/atom.xml => gemini://gemini.grappling.ca/gemlog/atom.xml => gemini://fungihirn.flounder.online/gemlog/atom.xml => gemini://mederle.de/feed-de => gemini://mederle.de/feed-en => gemini://heathens.club/~palm93/atom.xml => gemini://tilde.team/~ivanruvalcaba/blog/atom.xml => gemini://tilde.club/~liamvhogan/blog/atom.xml => gemini://soviet.circumlunar.space/markov/schismatrix-notes/atom.xml => gemini://phreedom.club/~tolstoevsky/glog/atom.xml => gemini://tilde.pink/~monerulo/atom.xml => gemini://posixcafe.org/blogs/feed.atom => gemini://posixcafe.org/vocaloid/feed.atom => gemini://gemini.mcgillij.dev/atom.xml => gemini://gemini.bunburya.eu/gemlog/posts/atom.xml => gemini://ew.srht.site/feed.xml => gemini://dantes.flounder.online/gemlog/atom.xml => gemini://my32.flounder.online/gemlog/atom.xml => gemini://si3t.ch/log/atom.xml => gemini://gemini.circumlunar.space/~alchemist/gemlog/atom.xml => gemini://blog.snowfrost.garden/atom.xml => gemini://www.underworld.fr/blog/atom.xml => gemini://envs.net/~vee/gemlog/atom.xml => gemini://gem.rmgr.dev/blog/atom.xml => gemini://inconsistentuniverse.space/atom.xml => gemini://s.tymo.name/log/atom.xml => gemini://envs.net/~vee/pikkulog/atom.xml => gemini://gem.pwarren.id.au/gemlog/atom.xml => gemini://rawtext.club/~mieum/dallok/atom.xml => gemini://qd.discordian.de/entries/atom.xml => gemini://tilde.pink/~hektor/atom.xml => gemini://caolan.uk/atom.xml => gemini://gemini.astropirados.space/gemlog/atom.xml => gemini://www.underworld.fr/atom.xml => gemini://g.dumke.me/log/atom.xml => gemini://rek2.hispagatos.org/posts/atom.xml => gemini://gemini.ctrl-c.club/~axeflayer/atom.xml => gemini://bi-rabittoh.flounder.online/gemlog/atom.xml => gemini://axiomatika.flounder.online/gemlog/atom.xml => gemini://cdaniels.net/feed_http.rss => gemini://cdaniels.net/feed_http.atom => gemini://cdaniels.net/feed_gmi.rss => gemini://cdaniels.net/feed_gmi.atom => gemini://buetow.org/gemfeed/atom.xml => gemini://gemini.cyberbot.space/smolzine/atom.xml => gemini://0gitnick.flounder.online/atom.xml => gemini://nicksphere.com/atom.xml => gemini://crystal.flounder.online/gemlog/atom.xml => gemini://ilogique.flounder.online/gemlog/atom.xml => gemini://renedarioherrera.flounder.online/gemlog/atom.xml => gemini://thek3nger.flounder.online/gemlog/atom.xml => gemini://breadpunk.club/~snickerdoodles/meta/atom.xml => gemini://figbert.com/log/atom.xml => gemini://szczezuja.space/gemlog/atom.xml => gemini://birabittoh.smol.pub/atom.xml => gemini://ocramoi.flounder.online/gemlog/atom.xml => gemini://corstar.flounder.online/gemlog/atom.xml => gemini://freeshell.de/gemlog/atom.xml => gemini://degrowther.smol.pub/atom.xml => gemini://starbreaker.smol.pub/atom.xml => gemini://edim.flounder.online/gemlog/atom.xml => gemini://gnuser.land/gemlog/atom.xml => gemini://thwidge.flounder.online/gemlog/atom.xml => gemini://ghostglyph.flounder.online/gemlog/atom.xml => gemini://tilde.cafe/~hedy/feed.xml => gemini://gemini.marmaladefoo.com/cgi-bin/atom-feed.cgi?lukee => gemini://mieum.smol.pub/atom.xml => gemini://hedy.tilde.cafe/feed.xml => gemini://gemini.spam.works/users/emery/atom.feed => gemini://memex.smol.pub/atom.xml => gemini://compudanzas.net/atom.xml => gemini://euromancer.flounder.online/gemlog/atom.xml => gemini://0x80.org/gemlog/atom.xml => gemini://hedy.smol.pub/atom.xml => gemini://reisub.nsupdate.info/fabianbonetti/atom.xml => gemini://cobaltblue.flounder.online/gemlog/atom.xml => gemini://erifnella.flounder.online/gemlog/atom.xml => gemini://tilde.team/~supernova/gemlog/atom.xml => gemini://rawtext.club/~mieum/atom.xml => gemini://blog.locrian.zone/atom.xml => gemini://snonux.de/gemfeed/atom.xml => gemini://hugeping.ru/atom.xml => gemini://melyanna.flounder.online/gemlog/atom.xml => gemini://miguelmurca.flounder.online/gemlog/atom.xml => gemini://november.smol.pub/atom.xml => gemini://cowface.online/gemlog/atom.xml => gemini://fawn.garden/log/atom.xml => gemini://tilde.team/~g1n/blog/feed.rss => gemini://subphase.xyz/users/flow/gemlog/atom.xml => gemini://twh.flounder.online/gemlog/atom.xml => gemini://jayeless.flounder.online/gemlog/atom.xml => gemini://devinprater.flounder.online/gemlog/atom.xml => gemini://alsd.eu/it/feed.xml => gemini://alsd.eu/en/feed.xml => gemini://bleyble.com/users/quokka/atom.xml => gemini://dimension.sh/~nikdoof/logs/atom.xml => gemini://tilde.team/~blumenkiste/atom.xml => gemini://thelambdalab.xyz/atom.xml => gemini://matthewhall.xyz/gemlog/atom.xml => gemini://karmanyaah.malhotra.cc/gemlog/atom.xml => gemini://gmi.bacardi55.io/gemlog/atom.xml => gemini://gem.keazilla.net/atom.xml => gemini://gemini.alexandrevicente.net/atom.xml => gemini://dira.cc/gemlog/atom.xml => gemini://aperalesf.flounder.online/gemlog/atom.xml => gemini://nickj.flounder.online/gemlog/atom.xml => gemini://reisub.nsupdate.info/planetalibre/atom.xml => gemini://dustypenguin.flounder.online/gemlog/atom.xml => gemini://g.mikf.pl/gemlog/atom.xml => gemini://mkf.flounder.online/gemlog/atom.xml => gemini://monika.flounder.online/gemlog/atom.xml => gemini://kota.nz/atom.xml => gemini://mischk.flounder.online/gemlog/atom.xml => gemini://epi.benthic.zone/atom.xml => gemini://byzoni.org/gemlog/atom.xml => gemini://orkney.flounder.online/gemlog/atom.xml => gemini://isoraqathedh.pollux.casa/atom.xml => gemini://hugeping.ru/micro/atom.xml => gemini://danihopera.flounder.online/gemlog/atom.xml => gemini://niedzwiedzinski.cyou/feed.xml => gemini://hugeping.tk/micro/atom.xml => gemini://miso.town/atom.xml => gemini://m15o.smol.pub/atom.xml => gemini://ichthys.tilde.cafe/atom.xml => gemini://marginalia.nu/log/feed.xml => gemini://envs.net/~anonyth/atom.xml => gemini://sev.flounder.online/gemlog/atom.xml => gemini://ataraxia.flounder.online/gemlog/atom.xml => gemini://privacy.flounder.online/gemlog/atom.xml => gemini://gemini.panda-roux.dev/log/feed.xml => gemini://foobucket.xyz/gemlog/atom.xml => gemini://warmedal.se/~antenna/atom.xml => gemini://maren.flounder.online/gemlog/atom.xml => gemini://eaplmx.smol.pub/atom.xml => gemini://envs.net/~armen/gemlog/atom.xml => gemini://mieum.smol.space/atom.xml => gemini://phreedom.club/atom.xml => gemini://blog.datapulp.de/atom.xml => gemini://datapulp.smol.pub/atom.xml => gemini://aprates.dev/log/atom.xml => gemini://alexwennerberg.com/gemlog/atom.xml => gemini://alex.flounder.online/gemlog/atom.xml => gemini://text.eapl.mx/atom.xml => gemini://jsreed5.org/feeds/log.xml => gemini://jsreed5.org/feeds/math.xml => gemini://jsreed5.org/feeds/changelog.xml => gemini://soviet.circumlunar.space/wholesomedonut/gemlog/atom.xml => gemini://drafts.cyclexo.com/gemlog/atom.xml => gemini://s0.is/projects/atom.xml => gemini://tilde.cafe/~ichthys/atom.xml => gemini://iceworks.cc/z/atom.xml => gemini://vy.binarylab.eu/gemlog/atom.xml => gemini://officialdonut.smol.pub/atom.xml => gemini://viridian.flounder.online/gemlog/atom.xml => gemini://hajime.4teri.de/dotfiles/atom.xml => gemini://gemini.ctrl-c.club/~nristen/gemlog/atom.xml => gemini://aprates.dev/pt-br/log/atom.xml => gemini://stacksmith.flounder.online/gemlog/atom.xml => gemini://blekksprut.net/nikki/atom.xml => gemini://breadpunk.club/~snickerdoodles/atom.xml => gemini://josias.dev/gemlog/feed.xml => gemini://szczezuja.space/git/scripts/atom.xml => gemini://szczezuja.space/git/gmidiff/atom.xml => gemini://tilde.team/~tomasino/atom.xml => gemini://beyondneolithic.life/atom.xml => gemini://lertsenem.com/atom.xml => gemini://tilde.town/~nihilazo/atom.xml => gemini://moonrockcenter.flounder.online/gemlog/atom.xml => gemini://gemini.bvnf.space/blog.rss => gemini://ichi.smol.pub/atom.xml => gemini://sequel.space/bubble/K1gTCL2PVZJN7ZZ1VPFp98/atom.xml => gemini://sequel.space/bubble/ViPx8vf3YSCUisLSKW1rzT/atom.xml => gemini://sequel.space/bubble/PVnyeuvYXKkA18UFFC6ZZy/atom.xml => gemini://sequel.space/bubble/GgZW37jjdLk4JPSeie7tCW/atom.xml => gemini://sequel.space/bubble/CWYmF993GKX94aSwufXU5y/atom.xml => gemini://sequel.space/bubble/Xg2Zdu3nYdSDMKD6qBiYM3/atom.xml => gemini://sequel.space/bubble/9NmeAJSkwGTHtoS3Xr1rw2/atom.xml => gemini://sequel.space/bubble/H6ognLcBjqQSa6MhbuDGKN/atom.xml => gemini://sequel.space/bubble/GLTatsSbmzzejurBzJ5dHS/atom.xml => gemini://sequel.space/bubble/7h3uWLuZbgzvB99d4rdnPC/atom.xml => gemini://sequel.space/bubble/TTToQ7FsbQGqw23SYzQ5un/atom.xml => gemini://sequel.space/bubble/HngiQfQ9cAQChi5ghRTcAF/atom.xml => gemini://sequel.space/bubble/9octt9FwLbbVumUkpjUgZP/atom.xml => gemini://sequel.space/bubble/Xm395CWNAT8fbUAt8dmVQr/atom.xml => gemini://sequel.space/bubble/Azs3YBJ78ytjuFgzf5KyHV/atom.xml => gemini://sequel.space/bubble/5Z3SGnuJEJND3tsR9iBrgM/atom.xml => gemini://sequel.space/bubble/JUQwKFrE8qKWH265BdYp3U/atom.xml => gemini://sequel.space/bubble/6EyhnusCdAV5MseoLFU9o1/atom.xml => gemini://sequel.space/bubble/JguD5Ws1tDvvfJrbKN7TGW/atom.xml => gemini://sequel.space/bubble/NXP4oChaEPJpd5rSkRPsk1/atom.xml => gemini://sequel.space/bubble/RnA2gV1Lcj6nFvdHRxRoYp/atom.xml => gemini://sbg.one/SandboxGeneral/atom.xml => gemini://gemini.circumlunar.space:1965/users/adiabatic/atom.xml => gemini://auragem.space/devlog/atom.xml => gemini://ax.flounder.online/gemlog/atom.xml => gemini://galaxyhub.uk/articles/atom.xml => gemini://gemini.circumlunar.space:1965/~solderpunk/gemlog/atom.xml => gemini://gem.acdw.net:1965/do/atom => gemini://gem.acdw.net:1965/do/rss => gemini://gem.acdw.net:1965/do/all/atom => gemini://gem.acdw.net:1965/code/do/atom => gemini://gem.acdw.net:1965/code/do/rss => gemini://gem.acdw.net:1965/food/do/atom => gemini://gem.acdw.net:1965/food/do/rss => gemini://gem.acdw.net:1965/life/do/atom => gemini://gem.acdw.net:1965/life/do/rss => gemini://gem.acdw.net:1965/made/do/atom => gemini://gem.acdw.net:1965/made/do/rss => gemini://gem.acdw.net:1965/pub/do/atom => gemini://gem.acdw.net:1965/pub/do/rss => gemini://gem.acdw.net:1965/text/do/atom => gemini://gem.acdw.net:1965/text/do/rss => gemini://gemini.circumlunar.space:1965/users/parker/archives/atom.xml => gemini://gemini.circumlunar.space:1965/users/parker/gacme/atom.xml => gemini://gemini.circumlunar.space:1965/users/rbasile/blog/feed.atom => gemini://gemini.circumlunar.space:1965/users/solderpunk/gemlog/atom.xml => gemini://gemini.circumlunar.space:1965/users/solderpunk/pikkulog/atom.xml => gemini://mizik.eu/feed.xml => gemini://rawtext.club:1965/~mieum/atom.xml => gemini://rawtext.club:1965/~mieum/poems/atom.xml => gemini://rawtext.club:1965/~mieum/prose/atom.xml => gemini://rawtext.club:1965/~mieum/relog/atom.xml => gemini://rawtext.club:1965/~mieum/music/atom.xml => gemini://gemini.thegonz.net:1965/glog/atom.xml => gemini://soviet.circumlunar.space:1965/wholesomedonut/gemlog/atom.xml => gemini://mozz.us:1965/journal/atom.xml => gemini://hannuhartikainen.fi:1965/twinlog/atom.xml => gemini://80h.dev:1965/glog/atom.xml => gemini://80h.dev:1965/~int/glog/atom.xml => gemini://exul.flounder.online/gemlog/atom.xml => gemini://latte.flounder.online/gemlog/atom.xml => gemini://pkill9.flounder.online/gemlog/atom.xml => gemini://sequel.space/bubble/XxLSRdjrZmctoE3CUmpnd2/atom.xml => gemini://sequel.space/bubble/VPxAbFt11WndPpYh1svnVS/atom.xml => gemini://sequel.space/bubble/V3pHHE5npaGdZ5cv88qMVq/atom.xml => gemini://inthetrees.flounder.online/gemlog/atom.xml => gemini://jordir.flounder.online/gemlog/atom.xml => gemini://ivanruvalcaba.cf/atom.xml => gemini://gemini.cyberbot.space:1965/gemlog/atom.xml => gemini://gemini.cyberbot.space:1965/smolzine/atom.xml => gemini://freeside.wntrmute.net:1965/log/index.rss => gemini://gemini.ucant.org:1965/gemlog/atom.xml => gemini://szczezuja.flounder.online/git/scripts/atom.xml => gemini://szczezuja.flounder.online/git/gmidiff/atom.xml => gemini://sjo.smol.pub/atom.xml => gemini://lyk.so/feed.atom => gemini://g.moi.lc/atom.xml => gemini://unixcat.coffee/gemlog/atom.xml => gemini://unixcat.coffee/recipes/atom.xml => gemini://armen138.flounder.online/gemlog/atom.xml => gemini://nicksphere.ch/atom.xml => gemini://frogs.flounder.online/gemlog/atom.xml => gemini://johnstephens.flounder.online/gemlog/atom.xml => gemini://stuserw.smol.pub/atom.xml => gemini://tilde.team/~konomo/atom.xml => gemini://blekksprut.net/日常鑑賞/atom.xml => gemini://bogart.flounder.online/gemlog/atom.xml => gemini://ruario.flounder.online/gemlog/atom.xml => gemini://lantashifiles.com/gemlog/entries/atom.xml => gemini://sotiris.papatheodorou.xyz/gemlog/atom.xml => gemini://vk3.wtf/gemlog/atom.xml => gemini://karabas.flounder.online/gemlog/atom.xml => gemini://sixohthree.com/atom.xml => gemini://bitdweller.flounder.online/gemlog/atom.xml => gemini://jdj.golf/gemlog/atom.xml => gemini://spxtr.net/atom.xml => gemini://yretek.com/atom.xml => gemini://gemini.ctrl-c.club/~pipe/atom.xml => gemini://low-key.me/gemlog/atom.xml => gemini://rasputin.selfip.net:1965/atom.xml => gemini://moddedbear.xyz:1965/logs/atom.xml => gemini://spool-five.com/gemlog/atom.xml => gemini://jfh.me:1965/atom.xml => gemini://going-flying.com:1965/thoughts/atom.xml => gemini://199.247.10.62/users/~julienxx/atom.xml => gemini://amadeus.flounder.online/gemlog/atom.xml => gemini://tentree.flounder.online/gemlog/atom.xml => gemini://hoseki.iensu.me/atom.xml => gemini://freeshell.de:1965/gemlog/atom.xml => gemini://koyu.space/blu256/atom.xml => gemini://dvd.flounder.online/feed.xml => gemini://sysnull.info/blog/atom.xml => gemini://www.groovestomp.com/gemlog/atom.xml => gemini://www.groovestomp.com/poetry/atom.xml => gemini://sequel.space/bubble/UcDBktgT6fVzeg7mhzSMMU/atom.xml => gemini://smol.pub/atom.xml => gemini://megymagy.flounder.online/gemlog/atom.xml => gemini://parsley.smol.pub/atom.xml => gemini://pietro.flounder.online/gemlog/atom.xml => gemini://sillylaird.flounder.online/gemlog/atom.xml => gemini://winter.flounder.online/gemlog/atom.xml => gemini://asciibene.flounder.online/gemlog/atom.xml => gemini://parsley.farm/atom.xml => gemini://cetacean.club:1965/journal/atom.xml => gemini://gluonspace.com/gemlog/atom.xml => gemini://kujiu.eu/blog/atom.xml => gemini://www.snonux.de/gemfeed/atom.xml => gemini://www.buetow.org/gemfeed/atom.xml => gemini://sequel.space/bubble/7nHibfwwMvZQvdt1LAA4P3/atom.xml => gemini://ruario.flounder.online/journal-atom.xml => gemini://text.adventuregameclub.com/atom.xml => gemini://foo.zone/gemfeed/atom.xml => gemini://www.foo.zone/gemfeed/atom.xml => gemini://gemini.circumlunar.space/news/atom.xml => gemini://gemini.circumlunar.space:1965/news/atom.xml => gemini://buetow.org:1965/gemfeed/atom.xml => gemini://nytpu.com:1965/flightlog/atom.xml => gemini://compudanzas.net:1965/atom.xml => gemini://alsd.eu:1965/it/feed.xml => gemini://calcuode.com:1965/gemlog/atom.xml => gemini://hedy.tilde.cafe:1965/feed.xml => gemini://salejandro.me:1965/gemlog/atom.xml => gemini://alsd.eu:1965/en/feed.xml => gemini://breadpunk.club:1965/~bakersdozen/gemlog/atom.xml => gemini://etam-software.eu:1965/blog/feed.xml => gemini://blog.schmidhuberj.de/atom.xml => gemini://tilde.team:1965/~konomo/atom.xml => gemini://tilde.pink:1965/~monerulo/atom.xml => gemini://dira.cc:1965/gemlog/atom.xml => gemini://corscada.uk/gemlog/atom.xml => gemini://bvnf.space/blog.rss => gemini://dns.eric.jetzt/gemlog/atom.xml => gemini://knijn.ga/posts/atom.xml => gemini://dctrud.randomroad.net/gemlog/atom.xml => gemini://cipay.ca/atom.xml => gemini://sanelkukic.smol.pub/atom.xml => gemini://costas.dev/posts/atom.xml => gemini://kayvr.com/gemlog/feed.xml => gemini://rawtext.club:1965/~verkaro/glog//atom.xml => gemini://sequel.space/bubble/8XvescodwwhNVjLVhV2HcP/atom.xml => gemini://dctrud.randomroad.net:1965/gemlog/atom.xml => gemini://cjc.im/feed.xml => gemini://mysidard.com/gemlog/public/atom.xml => gemini://colincogle.name/blog/atom.xml => gemini://evenstar.flounder.online/gemlog/atom.xml => gemini://saurabh.flounder.online/gemlog/atom.xml => gemini://tilde.club/~kerobaros/glog//atom.xml => gemini://hashtagueule.fr/atom.xml => gemini://armitage.flounder.online/gemlog/atom.xml => gemini://r2aze.observer/atom.xml => gemini://head.baselab.org/gemlog/atom.xml => gemini://0gitnick.flounder.online:1965/atom.xml => gemini://birabittoh.smol.pub:1965/atom.xml => gemini://blekksprut.net:1965/nikki/atom.xml => gemini://byzoni.org:1965/gemlog/atom.xml => gemini://capsule.usebox.net:1965/gemlog/atom.xml => gemini://causa-arcana.com:1965/blog/feed.xml => gemini://cdaniels.net:1965/feed_http.rss => gemini://cdaniels.net:1965/feed_http.atom => gemini://cdaniels.net:1965/feed_gmi.rss => gemini://cdaniels.net:1965/feed_gmi.atom => gemini://celehner.com:1965/feed.xml => gemini://cipay.ca:1965/atom.xml => gemini://dvd.flounder.online:1965/feed.xml => gemini://edwardtefft.com:1965/atom.xml => gemini://epi.benthic.zone:1965/atom.xml => gemini://g.dumke.me:1965/log/atom.xml => gemini://gluonspace.com:1965/gemlog/atom.xml => gemini://gmi.karl.berlin:1965/atom.xml => gemini://gsthnz.com:1965/posts/atom.xml => gemini://isoraqathedh.pollux.casa:1965/atom.xml => gemini://josias.dev:1965/gemlog/feed.xml => gemini://karmanyaah.malhotra.cc:1965/gemlog/atom.xml => gemini://makeworld.space:1965/gemlog/atom.xml => gemini://mysidard.com:1965/gemlog/public/atom.xml => gemini://nicksphere.com:1965/atom.xml => gemini://november.smol.pub:1965/atom.xml => gemini://nytpu.com:1965/gemlog/atom.xml => gemini://olivescout.flounder.online/gemlog/atom.xml => gemini://perplexing.space:1965/atom.xml => gemini://pulham.info:1965/atom.xml => gemini://rfmpie.smol.pub/atom.xml => gemini://ruario.flounder.online:1965/journal-atom.xml => gemini://rwv.io:1965/src/atom.xml => gemini://sixohthree.com:1965/atom.xml => gemini://testuser.flounder.online:1965/atom.xml => gemini://testuser.flounder.online:1965/myfeed.xml => gemini://thelambdalab.xyz:1965/atom.xml => gemini://unbinding.flounder.online/gemlog/atom.xml => gemini://vk3.wtf:1965/gemlog/atom.xml => gemini://yvngwytch840.flounder.online/gemlog/atom.xml => gemini://crash.smol.pub/atom.xml => gemini://longform.flounder.online/gemlog/atom.xml => gemini://binarycat.flounder.online/gemlog/atom.xml => gemini://malinfreeborn.com/gen/atom.xml => gemini://nafmusings.xyz/atom.xml => gemini://causa-arcana.com/blog/feed.xml => gemini://gemini.conman.org:1965/boston.atom => gemini://vectorprime.deszaras.xyz:1965/passages/atom.xml => gemini://kirill.zholnay.name/gemfeed/atom.xml => gemini://ttrpgs.org/all/atom.xml => gemini://seydaneen.nahtgards.de/leuchtturm/dwemerartefakte/gemini-circumlunar-space/news/atom.xml => gemini://gemini.locrian.zone/gemini/news/atom.xml => gemini://gemini.locrian.zone:1965/gemini/news/atom.xml => gemini://gemini.circumlunar.space/users/rbasile/blog/feed.atom => gemini://cap.swan.quest/p/atom.xml => gemini://rawtext.club:1965/~mieum/dallok/atom.xml # CAPCOM: => gemini://voidcruiser.nl => gemini://station.martinrue.com/martin/4c5f8b1291a049319033ad1c33aa373d => gemini://g.xn--nck.club/feed.xml => gemini://mozz.us/journal/atom.xml => gemini://gemlog.blue/users/futagoza/1619481193.gmi => gemini://monmac.flounder.online => gemini://gem.acdw.net/do/rss => gemini://otrn.org/atom.xml => gemini://mrnd.xyz/log/atom.xml => gemini://freeshell.de/gemlog/atom.xml => gemini://nuclear.discrust.pl => gemini://posixcafe.org/blogs/feed.atom => gemini://republic.circumlunar.space/users/dbane/gemlog/atom.xml => gemini://overeducated-redneck.net/glog/atom.xml => gemini://nalie.art => gemini://midnight.pub/feed.xml => gemini://decelerationist.net/feed.xml => gemini://gemini.bvnf.space/blog.rss => gemini://t-900.flounder.online/gemlog/atom.xml => gemini://calcuode.com/gemlog/atom.xml => gemini://calmwaters.xyz => gemini://six10.pw => gemini://sotiris.papatheodorou.xyz/gemlog/atom.xml => gemini://gemini.susa.net/atom.xml => gemini://gem.informethique.org/recettes/atom.xml => gemini://om.gay/redacted/gmi.atom => gemini://foo.zone/gemfeed/atom.xml => gemini://thesudorm.com/atom.xml => gemini://gem.rmgr.dev/blog/atom.xml => gemini://luke.flounder.online/gemlog/atom.xml => gemini://gemini.ctrl-c.club/~stack/gemlog/ => gemini://gemini.kevinronceray.com/atom.xml => gemini://hannuhartikainen.fi/twinlog/atom.xml => gemini://fortunebot.crabdance.com/feed/atom.xml => gemini://rawtext.club/~tolstoevsky/glog/atom.xml => gemini://tilde.team/~remyabel/atom.xml => gemini://ybad.name/log/feed.atom => gemini://soviet.circumlunar.space/~hektor/atom.xml => gemini://xj-ix.luxe:1969/feed.atom => gemini://pietro.flounder.online/gemlog => gemini://soviet.circumlunar.space/wholesomedonut/gemlog/atom.xml => gemini://jlk.flounder.online/gemlog/ => gemini://l-3.space/atom.xml => gemini://cdaniels.net/feed_gmi.atom => gemini://republic.circumlunar.space/users/crdpa/blog/atom.xml => gemini://bcn08012.ddns.net/atom.xml => gemini://blog.hispagatos.org => gemini://gemini.marmaladefoo.com/cgi-bin/atom-feed.cgi?lukee => gemini://simbly.me/posts/atom.xml => gemini://idf.looting.uk/capslog/atom.xml => gemini://oberdada.pollux.casa/gemlog.gmi => gemini://tilde.club/~lewiscowper/gemlog/atom.xml => gemini://gemlog.blue/users/cariboudatascience/1613780342.gmi => gemini://avalos.me/gemlog/atom.xml => gemini://inconsistentuniverse.space/atom.xml => gemini://carcosa.net/journal/atom.xml => gemini://tilde.team/~steve/atom.xml => gemini://www.demorrow.net/atom.xml => gemini://republic.circumlunar.space/crdpa/blog/atom.xml => gemini://skyjake.fi/gemlog/atom.xml => gemini://wirthslaw.flounder.online/gemlog/atom.xml => gemini://gemini.maxxk.me/atom.xml => gemini://sdf.org/atom.xml => gemini://rawtext.club/~ploum/atom.xml => gemini://benj.smol.pub/atom.xml => gemini://l-ipa.net/atom.xml => gemini://gemini.go350.com/atom.xml => gemini://subphase.xyz/users/flow/gemlog/atom.xml => gemini://gemlog.blue/users/cariboudatascience/ => gemini://mikelynch.org/index.gmi => gemini://gemini.strahinja.org/blog/rss.xml => gemini://quasivoid.net/gemlog/atom.xml => gemini://alsd.eu/en/feed.xml => gemini://hugeping.tk/atom.xml => gemini://ondollo.com/~/zert:7C:8E:F5/atom.gem => gemini://g.dumke.me/log/atom.xml => gemini://tilde.team/~easeout/glog/atom.xml => gemini://gemini.bbbhltz.space/gemlog/atom.xml => gemini://tilde.team/~ivanruvalcaba/glog/atom.xml => gemini://alexschroeder.ch:1965/do/blog/atom => gemini://starbreaker.org/atom.xml => gemini://blog.snowfrost.garden/atom.xml => gemini://blog.schmidhuberj.de/atom.xml => gemini://cadadr.space/blag.gmi => gemini://gemini.ctrl-c.club/~lettuce => gemini://bbs.archaicbinary.net/atom.xml => gemini://snowcode.ovh/rss.xml => gemini://ainent.xyz/gemlog/index.gmi => gemini://phreedom.club/~tolstoevsky/glog/atom.xml => gemini://gems.geminet.org/avr/atom.xml => gemini://0x80.org/gemlog/atom.xml => gemini://gemini.rawles.net/blog/atom.xml => gemini://josias.dev/gemlog/feed.xml => gemini://sbg.one/SandboxGeneral/atom.xml => gemini://gemini.freeradical.zone/log/ => gemini://gem.iwritethe.codes/posts/atom.xml => gemini://dira.cc/gemlog/atom.xml => gemini://figbert.com/log/atom.xml => gemini://lantashifiles.com/gemlog/entries/atom.xml => gemini://sl1200.dystopic.world/feed.gmi
# 2021-02-16 All these scripts are very specific to Techright's structure. Though ideas and components might be reusable elsewhere with modification. Each involves /lots/ of scraping and are therefore inherently brittle. They are run twice a day via a shell script in cron: $ crontab -l | grep -E -v '^#' 01 */3 * * * /home/gemini/bin/gemini-cron-updater.sh That script contains the work flow for all the steps needed to keep the Gemini site up to date. So reading it would be the place to start. # gemini-fetch-urls-from-rss.pl This gets an RSS feed and extracts the date. RPiOIS has a quirk in regards to /dev/stdout ownership, so that part needs repair. However, the -w option works. This script is standalone but can pipe data to another script or pass it via a file. Probably this ought to be redone to use wget instead. Example: ./gemini-fetch-urls-from-rss.pl http://techrights.org/feed/ Example: ./gemini-fetch-urls-from-rss.pl -d 2021-02-12 http://techrights.org/feed/ Example: ./gemini-fetch-urls-from-rss.pl -w tr.urls.txt -d 2021-02-12 \ http://techrights.org/feed/ # gemini-fetch-web-page.pl Reads in a URL and fetches them using wget. wget is more flexible than CPAN's LWP. This script is not standalone, it calls the next script, gemini-parse-html-to-gemini.pl using a temporary file to pass the data. It has the option to convert some of the links to Gemini links. Example: cat ~/bin/feeds.tr.2021.txt \ | xargs ~/bin/gemini-fetch-web-page.pl -g -p -v -b /home/gemini/gemini/ # gemini-parse-html-to-gemini.pl Reads a file containing XHTML and converts it to Gemini mark up, with the expectation that it conforms to the structures used at Techrights as of 2021. This is a standalone script. Example: ./gemini-parse-html-to-gemini.pl -w /dev/stdout -v sample.html # gemini-inventory.pl Traverses the file system and extracts titles from the Gemini articles. The data is used to construct daily and monthly summaries. Example: ./gemini-inventory.pl /home/gemini/gemini/2021/ ## perl modules XPath is used for most of the processing. Cwd English File::Basename File::Glob File::Path File::Temp Getopt::Std HTML::TreeBuilder::XPath HTTP::Response::Encoding LWP::UserAgent Path::Iterator::Rule POSIX Time::ParseDate Time::Piece URI utf8 XML::Feed # gemini-bulletin-irc-update.sh Creates Gemini indexes from the text bulletins. The bulletins will be read from the ~/gemini/tr_text_versioni/ directory. # gemini-cron-updater.sh A batch job to update starting by reading the RSS feed and finishing with updating the indexes and bulletins. # gemini-main-index-template.sh A template for making the 'home page' for the Gemini site
#!/bin/sh # 2021-02-22 download TR back issue articles a year at a # time and then convert them from HTML to Gemini year=$1 echo $year | sed -r '/^[0-9]{4}$/q; s/.*/0/' if [ $year -eq 0 ]; then echo "Year missing" exit 1 fi stop=$1 echo $stop | sed -r '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/q; s/.*/0/' target=/home/gemini cache=${target}/X/ log=/tmp/wget.tr.log # --- PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin test -f ${log} && rm -f ${log} # the wget loops can take from 5 to 13 hours depending on # the number of posts that year for m in $(seq --format '%02.0f' 11 12) do for d in $(seq --format '%02.0f' 1 31); do date -d "$year-$m-$d" > /dev/null || break wget \ --progress=dot \ --limit-rate=90k \ --wait=4 \ --random-wait \ --tries=22 \ --retry-on-http-error=500,503 \ --no-host-directories \ --directory-prefix=${cache} \ --recursive \ --level=3 \ --no-parent \ --accept '*.html' \ http://techrights.org/${year}/$m/$d/ \ | tee -a ${log} done done # find all the cached web pages and send them to the parser # for conversion to Gemini format; use parallel to run several # instances of the parser concurrently time \ find ${cache} \ -type f \ -name '*.html' \ -not -path '*/page/*' \ -not -path '*/feed/*' \ -print0 | \ parallel \ --null \ --jobs 6 gemini-fetch-web-page.pl \ -p -b ${target} file://{} ::: # see also: # https://www.gnu.org/software/parallel/parallel_cheat.pdf exit 0
# To protect people's privacy run near end of each month; don't delete everything for a number of reasons, including open files and spacing anomalies echo 'Log purge of the following files:' ls -la ../logs/gemini-log-2023-05* rm -f ../logs/gemini-log-2023-05-3* rm -f ../logs/gemini-log-2023-05-0* rm -f ../logs/gemini-log-2023-05-1* rm -f ../logs/gemini-log-2023-05-2* echo "C'est la vie"
#!/bin/sh # archive stats page # will need to be extended at some point to partition many pages g=/home/gemini/techrights.org d=$(date +"%Y-%m-%d") set -e cp ${g}/stats/index.gmi ${g}/stats/stats$(date -d ${d} +"-%Y-%m-%d").gmi sed -i "1s|^|$(date +"# %d %m %Y Archive\n")|" \ ${g}/stats/stats$(date -d ${d} +"-%Y-%m-%d").gmi exit 0
#!/usr/bin/perl -T # 2021-02-17 Fetches HTML from URLs and # calls another script to convert to Gemini # Alpha Version # Reads the URLs from the command line use utf8; use Getopt::Std; use Cwd qw(getcwd abs_path); use URI; use File::Path qw(make_path); use File::Basename; use File::Temp qw(tempfile); use HTML::TreeBuilder::XPath; use English; use warnings; use strict; $OUTPUT_AUTOFLUSH = 1; # untaint the $PATH $ENV{'PATH'} = '/home/gemini/bin:/usr/local/bin:/usr/bin:/bin'; # path to the next script, it will convert XHTML to Gemini and save it # my $parser = './gemini-parse-html-to-gemini.pl'; my $parser = 'gemini-parse-html-to-gemini.pl'; # command line option our %opt; getopts('b:ghmpv', \%opt); &usage if ($opt{'h'}); # set the base working directory for resulting files, # it will be created later on if necessary my $dest_path; if ($opt{'b'}) { $dest_path = $opt{'b'}; } # sanity checking of destination path unless($dest_path) { warn("Use -b to set a destination path.\n\n"); &usage; } if ($dest_path =~ m{^/?.*?(?=\.\.)}) { die("Use an absolute path.\n\n"); } elsif ($dest_path =~ m{^(/[\w\-\=\%\.\/]+)}) { $dest_path = $1; $dest_path =~ s|([^/])$|$1/|; } else { die("Wonky path: '$dest_path'\n\n"); } $dest_path = abs_path($dest_path); if( ! $dest_path){ die("Bad destination path.\n\n"); } elsif (-d $dest_path && ! -w $dest_path) { warn("Path: '$dest_path'\n"); die("Destination path is not writable: '$dest_path' \n\n"); } elsif (! -d $dest_path && ! $opt{'p'}) { warn("Path: '$dest_path'\n"); die("Destination path doesn't exist. Use -p also.\n\n"); } # process the URLs passed as command line parameters my @URL = (); foreach my $url (@ARGV) { my $uri = URI->new($url); if (defined($uri->scheme)) { if ($uri->scheme eq 'http' or $uri->scheme eq 'https' or $uri->scheme eq 'file') { push(@URL, $uri); } } } &usage if ($#URL < 0); # process each URL, one at a time foreach my $url (@URL) { if ($opt{'v'}) { print $url->canonical,qq(\n); } # get the document path from the URL my $path = $dest_path.'/'.$url->path; ( $path ) = ($path =~ m/^([\w\-\.\/\%]+)$/); # untaint while ($path =~ s|//|/|g) { 1 } my $name = ''; ($name, $path) = fileparse($path); if ($name) { $name =~ s/\.html$//; $name .= '.gmi'; ($name) = ($name =~ m/^([\w\-\.\/\%]+)$/); # untaint } else { $name = 'index.gmi'; } if($opt{'v'}) { print qq(Path = $path\n); print qq(Name = $name\n); } # use a temp file to get the XHTML over to the next script my $tmp = File::Temp->new( TEMPLATE => 'temp.XXXXX', DIR => '/tmp', SUFFIX => '.fetch.gemini.tmp', UNLINK => 1 ); my $tmpfile = $tmp->filename; -f $tmpfile && unlink($tmpfile); # clear the way for wget my $success = 0; if ($url->scheme eq 'http' or $url->scheme eq 'https') { # fetch URL and hold content in a variable $success = &fetch($url, $tmpfile); # if the page content and destination path exist, continue if ( $success && $path) { # make the target directory if called for unless(-d $path or ! $opt{'p'}) { if ($path =~ m{^(/[\w\-\=\%\.\/]+)}) { $path = $1; } make_path($path,{mode=>0755}) or die("Could not create path '$path' : $!\n"); } # parse temp file and write output to "$path$name" my @args = (); push(@args, '-g') if ($opt{'g'}); # tell it to convert links my @cmd = ($parser, @args, '-w', "$path$name", $tmpfile); system(@cmd) == 0 or die("system '@cmd' failed: $?\n"); # fetching videos is not done by default if($opt{'m'}) { print qq(Fetching videos\n) if ($opt{'v'}); $success = &extract_webm($url, $tmpfile, $path); } # close temp file, if UNLINK is set then it is deleted now close($tmp); } else { exit(1); } } elsif ($url->scheme eq 'file') { print qq(FILE:///\n) if ($opt{'v'}); $success = &fetch_file($url, $tmpfile); $path = $url->path; # hard-coded /yyyy/mm/dd/ pattern ... if($path =~ m{^.*/(\d{4}/\d{2}/\d{2}/.*)/[^/]+\.html}) { $path = $dest_path.'/'.$1; } else { exit(0); } print qq(DEST_PATH=$path\n) if ($opt{'v'}); # if the page content and destination path exist, continue if ( $success && $path) { # make the target directory if called for unless(-d $path or ! $opt{'p'}) { if ($path =~ m{^(/[\w\-\=\%\.\/]+)}) { $path = $1; } make_path($path,{mode=>0755}) or die("Could not create path '$path' : $!\n"); } # parse temp file and write output to "$path$name" my @args = (); push(@args, '-g') if ($opt{'g'}); # tell it to convert links my @cmd = ($parser, @args, '-w', "$path/$name", $tmpfile); print qq(CMD=@cmd\n) if($opt{'v'}); system(@cmd) == 0 or die("system '@cmd' failed: $?\n"); # fetching videos is not done # close temp file, if UNLINK is set then it is deleted now close($tmp); } else { exit(1); } } } exit(0); sub usage { print qq(Fetch web pages (from TechRights) for conversion to Gemini\n); $0 =~ s/^.*\///; print qq($0: [-hbmpv] URL [URL...]\n); print qq( -h print this help text\n); print qq( -b base working directory, default is current\n); print qq( -m also fetch and store videos, default is not to\n); print qq( -p create destination directories\n); print qq( -v increase message verbosity\n); exit(1); } sub fetch_file { my ( $uri, $filename ) = ( @_ ); my $path = $uri->path; # works only with absolute paths print qq(SRC FILE=$path\n) if ($opt{'v'}); unless(-f $path && -r $path){ warn("File '$path' does not exist or is unreadable!\n"); return(0); } my $result = system('cp', $path, $filename); if($result) { die("File copy failed,\n"); } return(1); } sub fetch { my ( $uri, $filename ) = ( @_ ); # wget is more flexible than LWP, # especially with large files like the videos my @args=( '--quiet', '--user-agent=TechRights-Gemini-Bot/0.1', '--no-directories', '--no-clobber', '--retry-on-http-error=500,503', '--tries=25', '--waitretry=8', "--output-document=$filename" ); my $url = $uri->canonical; print qq(URI Canonical = ), $url,qq(\n) if ($opt{'v'}); $url =~ s/\#.*$//; $url =~ s/\?.*$//; unless (( $url ) = ( $url =~ m/^([\w\.\-\%\/\:]+)$/ )) { print qq(WrongURL = $uri->canonical\n); return(0); } print qq(Fetching $url\n) if ($opt{'v'}); my @cmd = ('wget', @args, $url); my $result = system(@cmd); if($result == 256) { warn("File '$filename' already exists!\n"); } elsif ($result) { die("system '@cmd' failed: $?\n"); } return(1); } sub extract_webm { my ($base, $tmpfile, $path) = (@_); my $xhtml = HTML::TreeBuilder::XPath->new; $xhtml->implicit_tags(1); $xhtml->no_space_compacting(0); $xhtml->parse_file($tmpfile); my %videos = (); my %ok_hosts = ( 'www.techrights.org' => 1, 'techrights.org' => 1, ); for my $a ($xhtml->findnodes('//a[contains(@href,".webm")]')) { my $url = URI->new($a->attr('href')); $url = $url->abs($base); # convert relative links if (defined($url->host) && $ok_hosts{$url->host}) { $videos{$url->canonical} = $url; } } foreach my $vurl (sort values %videos) { # get the document path from the URL my $path = $dest_path.'/'.$vurl->path; ( $path ) = ($path =~ m/^([\w\-\.\/\%]+)$/); # untaint while ($path =~ s|//|/|g) { 1 } my $name = ''; ($name, $path) = fileparse($path); if ($name =~ m/\.webm/) { ($name) = ($name =~ m/^([\w\-\.\/\%]+)$/); # untaint } else { return(0); } if (! -d $path and $opt{'p'}) { if ($path =~ m{^(/[\w\-\=\%\.\/]+)}) { $path = $1; } make_path($path,{mode=>0755}) or die("Could not create path '$path' : $!\n"); } elsif (! -d $path) { die("Path '$path' is missing!\n"); } &fetch($vurl, "$path$name"); } }
#!/bin/bash # 2021-02-14 CreateGemini indexes for various IRC logs # for History see Git archive # p=/home/gemini/techrights.org; # path to working directory limit=5; # cycle back this many months # ##### # main body of program PATH=/usr/local/bin:/usr/bin:/bin set -e cd $p now=$(date +"%Y-%m-%d") # construct Gemini indexes for Bulletins m=0 while test $m -lt $limit do dd=$(date +"%Y-%m" -d "$now -$m month") bb=$(date +"%Y/%m" -d "$now -$m month") test -e ./bulletins/$bb/ || mkdir -p ./bulletins/$bb/ cp ~gemini/bulletin-menu.txt ./bulletins/$bb/index.gmi find ./tr_text_version -name "techrights-$dd*" -print | sort \ | sed -re 's|^\.([^-]+)-(.*).txt|=> \1-\2.txt Techrights \2|;' \ >> ./bulletins/$bb/index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> ./bulletins/$bb/index.gmi cat ~gemini/logo.txt >> ./bulletins/$bb/index.gmi m=$((m+1)) done # construct Gemini indexes for IRC logs m=0 while test $m -lt $limit do mm=$(date +"%m" -d "$now -$m month") yy=$(date +"%y" -d "$now -$m month") yyyy=$(date +"%Y" -d "$now -$m month") test -e ./irc/$yyyy/$mm/ || mkdir -p ./irc/$yyyy/$mm/ cp ~gemini/irc-menu.txt ./irc/$yyyy/$mm/index.gmi echo '## GemText Version' >> ./irc/$yyyy/$mm/index.gmi find ./irc-gmi -name "*irc*techrights*$mm$yy.gmi" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Gemini/GemText IRC Logs for Techrights $yyyy-$mm-\2|" \ >> ./irc/$yyyy/$mm/index.gmi echo '## Plain Text Version' >> ./irc/$yyyy/$mm/index.gmi find ./tr_text_version -name "*irc*techrights*$mm$yy.txt" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Plain Text IRC Logs for Techrights $yyyy-$mm-\2|" \ >> ./irc/$yyyy/$mm/index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> ./irc/$yyyy/$mm/index.gmi cat ~gemini/logo.txt >> ./irc/$yyyy/$mm/index.gmi m=$((m+1)) done # construct Gemini indexes for TR Social IRC logs m=0 while test $m -lt $limit do mm=$(date +"%m" -d "$now -$m month") yy=$(date +"%y" -d "$now -$m month") yyyy=$(date +"%Y" -d "$now -$m month") test -e ./social/$yyyy/$mm/ || mkdir -p ./social/$yyyy/$mm/ cp ~gemini/irc-menu.txt ./social/$yyyy/$mm/index.gmi echo '## GemText Version' >> ./social/$yyyy/$mm/index.gmi find ./irc-gmi -name "*social*$mm$yy.gmi" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Gemini/GemText IRC Logs for Techrights Social $yyyy-$mm-\2|" \ >> ./social/$yyyy/$mm/index.gmi echo '## Plain Text Version' >> ./social/$yyyy/$mm/index.gmi find ./tr_text_version -name "*social*$mm$yy.txt" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Plain Text IRC Logs for Techrights Social $yyyy-$mm-\2|" \ >> ./social/$yyyy/$mm/index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> ./social/$yyyy/$mm/index.gmi cat ~gemini/logo.txt >> ./social/$yyyy/$mm/index.gmi m=$((m+1)) done # construct Gemini indexes for TR TechBytes IRC logs m=0 while test $m -lt $limit do mm=$(date +"%m" -d "$now -$m month") yy=$(date +"%y" -d "$now -$m month") yyyy=$(date +"%Y" -d "$now -$m month") test -e ./techbytes/$yyyy/$mm/ || mkdir -p ./techbytes/$yyyy/$mm/ cp ~gemini/irc-menu.txt ./techbytes/$yyyy/$mm/index.gmi echo '## GemText Version' >> ./techbytes/$yyyy/$mm/index.gmi find ./irc-gmi -name "*techbytes*$mm$yy.gmi" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Gemini/GemText IRC Logs for Techrights TechBytes $yyyy-$mm-\2|" \ >> ./techbytes/$yyyy/$mm/index.gmi echo '## Plain Text Version' >> ./techbytes/$yyyy/$mm/index.gmi find ./tr_text_version -name "*techbytes*$mm$yy.txt" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Plain Text IRC Logs for Techrights TechBytes $yyyy-$mm-\2|" \ >> ./techbytes/$yyyy/$mm/index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> ./techbytes/$yyyy/$mm/index.gmi cat ~gemini/logo.txt >> ./techbytes/$yyyy/$mm/index.gmi m=$((m+1)) done # construct Gemini indexes for TR BoycottNovell IRC logs m=0 while test $m -lt $limit do mm=$(date +"%m" -d "$now -$m month") yy=$(date +"%y" -d "$now -$m month") yyyy=$(date +"%Y" -d "$now -$m month") test -e ./boycottnovell/$yyyy/$mm/ || mkdir -p ./boycottnovell/$yyyy/$mm/ cp ~gemini/irc-menu.txt ./boycottnovell/$yyyy/$mm/index.gmi # find ./tr_text_version -name "irc-log-*$mm$yy.txt" -print \ echo '## GemText Version' >> ./boycottnovell/$yyyy/$mm/index.gmi find ./irc-gmi -regextype posix-basic \ -regex ".*/irc-log-[0-9]\{2\}$mm$yy.gmi\$" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Gemini/GemText IRC Logs for Techrights BoycottNovell $yyyy-$mm-\2|" \ >> ./boycottnovell/$yyyy/$mm/index.gmi echo '## Plain Text Version' >> ./boycottnovell/$yyyy/$mm/index.gmi find ./tr_text_version -regextype posix-basic \ -regex ".*/irc-log-[0-9]\{2\}$mm$yy.txt\$" -print \ | sort \ | sed -r -e "s|^\.(.*)-(..)(.*)$|=> \1-\2\3 Plain Text IRC Logs for Techrights BoycottNovell $yyyy-$mm-\2|" \ >> ./boycottnovell/$yyyy/$mm/index.gmi date -u +"%nUpdated %F %H:%M UTC%n" \ >> ./boycottnovell/$yyyy/$mm/index.gmi cat ~gemini/logo.txt \ >> ./boycottnovell/$yyyy/$mm/index.gmi m=$((m+1)) done cd $p/irc/ cp ~gemini/irc-menu.txt index.gmi echo '## Logs for #techrights at irc.techrights.org' >> index.gmi echo >> index.gmi find . -mindepth 2 -maxdepth 2 -type d \ | sort -r \ | cut -b 3-100 \ | while read -r line; do \ echo -n "=> $line/index.gmi " & sed "s/\/index.gmi//" \ <<< "$line" done >> index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> index.gmi cat ~gemini/logo.txt >> index.gmi cd $p/social/ cp ~gemini/irc-menu.txt index.gmi echo '## Logs for #boycottnovell-social at irc.techrights.org' >> index.gmi echo >> index.gmi find . -mindepth 2 -maxdepth 2 -type d \ | sort -r \ | cut -b 3-100 \ | while read -r line; do \ echo -n "=> $line/index.gmi " & sed "s/\/index.gmi//" \ <<< "$line" done >> index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> index.gmi cat ~gemini/logo.txt >> index.gmi cd $p/techbytes/ cp ~gemini/irc-menu.txt index.gmi echo '## Logs for #techbytes at irc.techrights.org' >> index.gmi echo >> index.gmi find . -mindepth 2 -maxdepth 2 -type d \ | sort -r \ | cut -b 3-100 \ | while read -r line; do \ echo -n "=> $line/index.gmi " & sed "s/\/index.gmi//" \ <<< "$line" done >> index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> index.gmi cat ~gemini/logo.txt >> index.gmi cd $p/boycottnovell/ cp ~gemini/irc-menu.txt index.gmi echo '## Logs for #boycottnovell at irc.techrights.org' >> index.gmi echo >> index.gmi find . -mindepth 2 -maxdepth 2 -type d \ | sort -r \ | cut -b 3-100 \ | while read -r line; do \ echo -n "=> $line/index.gmi " & sed "s/\/index.gmi//" \ <<< "$line" done >> index.gmi date -u +"%nUpdated %F %H:%M UTC%n" >> index.gmi cat ~gemini/logo.txt >> index.gmi exit 0
#!/bin/sh PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin # percent signs are processed in crontabs so this wrapper is needed gemini-make-feed.pl \ -r /home/gemini/gemini \ -o /home/gemini/gemini/feed.xml \ /home/gemini/gemini/$(date +"%Y/%m")/ \ > /home/gemini/logs/make-feed.log exit 0
Welcome to Techrights IRC section => / Back to index # IRC Introduction Techrights has its own IRC network. => about/ To access our network see details in this page # IRC Logs in Techrights => chat/index.gmi ▢ - Latest chat logs for #techrights (updated every 5-10 minutes) ### Techrights Archive => irc/index.gmi ㏒ - Logs for #techrights ### Social Archive => social/index.gmi ㏒ - Logs for #boycottnovell-social ### Techbytes Archive => techbytes/index.gmi ㏒ - Logs for #techbytes ### BoycottNovell Archive => boycottnovell/index.gmi ㏒ - Logs for #boycottnovell => /logo/logo.png Site logo (if your Gemini client supports that) ### ➮ Sharing is caring. Content is available under CC-BY-SA. ⟲
#!/bin/sh # 2022-01-22 PATH=/usr/sbin:/usr/bin:/sbin:/bin today=$(date +"%F") echo '\n----------------------------------------------------------------' \ >> /home/gemini/logs/gemini-log-${today}.log date +"Restarting logging at %F %T%n" \ >> /home/gemini/logs/gemini-log-${today}.log # use wlan0 below if the server uses Wi-Fi stdbuf -oL tcpdump -ttttqpli eth0 'inbound and port 1965 and not src net 192.168.4.0/24 and tcp[tcpflags] & tcp-syn != 0' \ | perl -a -n -e ' $|=1; # autoflush buffer $d=$F[0]; $t=$F[1]; $h=$F[3]; $t=~s/\.[0-9]+$//; $h=~s/\.\d+$//; # print STDERR qq($d $t $h\n); print qq($d $t $h\n); ' \ >> /home/gemini/logs/gemini-log-${today}.log exit 0
#!/bin/sh # 2021-02-27 PATH=/usr/bin:/bin set -e awk '$3 {a[$3]++} END{ for (b in a) {print a[b],b}}' OFS="\t" \ /home/gemini/logs/gemini-log-$(date +"%F").log \ | sort -k1,1n -k2,2 exit 0
#!/bin/sh PATH=/usr/sbin:/usr/bin:/sbin:/bin now=$(date +"%F") echo '----------------------------------------------------------------------------' >> /home/gemini/logs/gemini-log-${now}.log echo -n 'Restarting logging at ' >> /home/gemini/logs/gemini-log-${now}.log date >> /home/gemini/logs/gemini-log-${now}.log echo '' >> /home/gemini/logs/gemini-log-${now}.log tcpdump \ -q \ -p \ -l \ -tttt \ -i wlan0 \ 'not src net 192.168.1.0/24 and dst net 192.168.1.0/24 and tcp[tcpflags] & (tcp-syn) != 0 and port 1965' \ | awk '{ sub(/\.[0-9]+$/,"",$2); \ sub(/\.[0-9]+$/,"",$4); \ print $1, $2, $4; \ fflush();\ }' >> /home/gemini/logs/gemini-log-${now}.log
[Unit] Description=Use tcpdump to log contavts to the Gemini server After=network.target [Service] User=root Type=exec ExecStart=/usr/local/sbin/tcpdump-logger.sh ExecReload=/bin/kill -HUP $MAINPID KillMode=control-group Restart=on-failure RestartPreventExitStatus=255 RestartSec=5s [Install] WantedBy=multi-user.target
#!/bin/sh # 2021-02-13 # 2021-02-27 updated # tail -n 100 -f log.txt \ # | grep -v host81 \ # | grep -v roibng \ # | grep -v '\-\-' # host81-154-168-60.range81-154.btce:44808 <= 0b 739b 462b 924B # [2021-02-26 04:29:59] v2202102141844143923.supersrv.de:53510 <= 0b 0b 266b 1.30KB PATH=/usr/bin:/bin # tail -f /home/gemini/logs/gemini-$(date +"%F").log \ # exit 0 tail -n 500 -f /home/gemini/logs/gemini-log-$(date +"%F").log \ | awk '($5!="0b" || $6!="0b" || $7!="0b" || $8!="0b") \ && $3!~/roibng/ \ && $3!~/btce/ \ && $3~/[a-z0-9]/ { \ sub(/:.*$/, "", $3); \ print $1 " " $2, $3; \ }'
#!/bin/sh # update latest video gallery page PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin d=/var/www/techrights.org/htdocs g=/home/gemini/techrights.org cat $d/videos/index.html | tr-gemini-latest-videos.pl > $g/videos/index.gmi exit 0
#!/bin/sh # archive stats page # will need to be extended at some point to partition many pages cp /home/gemini/gemini/stats/index.gmi /home/gemini/gemini/stats/stats$(date +"-%Y-%m-%d").gmi && sed -i "1s|^|$(date +"# %d %m %Y Archive\n")|" /home/gemini/gemini/stats/stats$(date +"-%Y-%m-%d").gmi
#!/bin/sh # 2020-12-25 PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin if test "x$1" = "xbright"; then timeout 9 run-blinkt.py flashed_bar 250 255 255 0.0001 else timeout 9 run-blinkt.py flashed_bar 250 128 128 0.0001 fi exit 0
#!/bin/sh # 2021-09-17 # update latest video gallery page PATH=/home/gemini/bin:/usr/local/bin:/usr/bin:/bin sudo /usr/local/sbin/tc-shaper-v2021-Nov.sh wget -qO- --tries=21 --waitretry=10 http://techrights.org/videos/ \ | gemini-latest-videos.pl > ~/gemini/latest-videos/index.gmi sudo /usr/local/sbin/tc-shaper-v2.sh exit 0
#!/bin/sh # 2021-10-09 PATH=/usr/local/bin:/usr/bin:/bin d=/home/gemini/techrights.org/git/sloc.gmi s=/home/gemini/techrights.org/git/tr-git/ echo "# SLOC stats $(date +'%F')\n" > ${d} echo "Source Lines Of Code (SLOC) it not a useful metric and provideded \ only for amusement.\n" >> ${d} sloccount ${s} 2>/dev/null \ | sed -n -r -e ' /^SLOC/,/^$/ {s/^SLOC./# SLOC /; s/SLOC-/ &/;p}; /^Totals/,/^$/ {s/^Totals/# &/;p}; /^Total / {p;q}' \ >> ${d} cat << EOT >> ${d} ## Licence GNU Affero General Public License (AGPLv3) unless stated otherwise, e.g. Public Domain => / back to Techrights (Main Index) EOT
#!/usr/bin/perl # 2021-09-17 # update latest video gallery page use HTML::TreeBuilder::XPath; use File::Basename; use JSON; print "# Latest Techrights Videos\n\n"; print "Most recent shown first (the list below is limited to past 7 days)\n\n"; my %videos = &xhtml_video_links('-'); my %metadata = &fetch_metadata(%videos); foreach my $key (sort {$a<=>$b} keys %metadata) { print "=> "; print $metadata{$key}{'link'}," "; print "↺ "; printf ("%2d ",$key); if (exists($metadata{$key}{'title'})) { print $metadata{$key}{'title'}; if(exists($metadata{$key}{'date'})){ print " (",$metadata{$key}{'date'},")"; } } else { print $metadata{$key}{'file'}; } print "\n"; } print "\n=> /videos/ Show videos archive\n"; print "=> / Back to homepage\n"; exit(0); sub xhtml_video_links{ my ($file)= (@_); my $is_stdin = 0; my $input; if ($file eq '-') { $input = *STDIN; $is_stdin++; } else { # force input to be read in as UTF-8 open ($input, "<:utf8", $file) or die("Could not open file '$file' : error: $!\n"); } my $xhtml = HTML::TreeBuilder::XPath->new; $xhtml->implicit_tags(1); $xhtml->no_space_compacting(0); $xhtml->parse_file($input) or die("Could not parse '$file' : $!\n"); my %videos = (); my $listpos = 0; # reset position at 0 for my $l ($xhtml->findnodes_as_strings('//a[@target="video"]/@href') ) { my $link = qq(http://techrights.org/videos/).$l; my $vid = basename($link); $listpos++; $videos{$listpos}{'link'} = $link; $videos{$listpos}{'file'} = $vid; } $xhtml->destroy; unless($is_stdin) { close($input); } return(%videos); } sub fetch_metadata() { my (%metadata) = (@_); foreach my $listpos (keys %metadata) { my @cmd = ("ffprobe", "-v", "panic", "-of", "json", "-show_format", $metadata{$listpos}{'link'}); open(my $json, "-|", @cmd) or die("Could not open pipe '@cmd' : $!\m"); my @text = (); while (my $j = <$json>) { push (@text, $j); } close($json); my $t = join("", @text); my $d = decode_json(join("",@text)); # print Dumper($d),"\n"; if ($d->{'format'}->{'tags'}->{'title'}) { $metadata{$listpos}{'title'} = $d->{'format'}->{'tags'}->{'title'}; } if ($d->{'format'}->{'tags'}->{'DATE'}) { $metadata{$listpos}{'date'} = $d->{'format'}->{'tags'}->{'DATE'}; } # print $metadata{$listpos}{'link'},"\n"; # print $metadata{$listpos}{'file'},"\n\n"; } return(%metadata); }
#!/usr/bin/perl # 2021-01-11 read HTML from a file and convert it to Gemini # not-generic, for TR only # 2021-02-21 Proof-of-concept prototype # not suitable for production use utf8; use Getopt::Std; use File::Glob ':bsd_glob'; use HTML::TreeBuilder::XPath; use URI; binmode *STDOUT, ':utf8'; use English; use warnings; use strict; $OUTPUT_AUTOFLUSH = 1; our %opt; getopts('ghmvw:', \%opt); &usage if ($opt{'h'}); # iterate through any parmeters passed on the command line, # treat as file names and allow globbing my @filenames; while (my $file = shift) { my @files = bsd_glob($file); foreach my $f (@files) { push(@filenames, $f); if($opt{'v'}) { print qq(F=$f\n); } } } my $outfile = $opt{'w'} || ''; ( $outfile ) = ( $outfile =~ m/^([\w\-\.\/]+)$/ ); # quit if no files were listed &usage if($#filenames < 0); # process each file, skipping turd files, hidden files, and temp files while (my $infile = shift(@filenames)) { next if ($infile =~ m/~$/); next if ($infile =~ m/^\.\.?(?!\/)/); next if ($infile =~ m/^#/); my $result = &xhtml_to_gemini($infile) || exit(1); if ($outfile) { my ($dir) = ($outfile =~ m{^(.*/)[^/]+$}); if (! -d $dir) { die("Directory '$dir' does not exist.\n"); } if (! -w $dir) { die("Directory '$dir' is not writable.\n"); } open(my $o, '>:utf8', $outfile) or die("Could not open '$outfile' for writing: $!\n"); if ($opt{'v'}) { print qq(Writing to "$outfile"\n); } print $o $result; print $o qq(\n),qq(-)x10,qq(\n); print $o qq(=>\t/\tTechrights\n); print $o qq(➮ Sharing is caring. ); print $o qq(Content is available under CC-BY-SA.); close($o); } else { print $result; print qq(\n),qq(-)x10,qq(\n); print qq(=>\t/\tTechrights\n); print qq(➮ Sharing is caring. ); print qq(Content is available under CC-BY-SA.\n); } } exit(0); sub usage { print qq(Read pages via files or else stdin and convert them\n); print qq(from XHTML to Gemini.\n); $0 =~ s/^.*\///; print qq($0: xhtml_file [xhtml_file...]\n); print qq( -g convert internal links to Gemini\n); print qq( -m convert internal video links, default not to\n); print qq( -w file save output to the given file\n); print qq( -h this help message\n); print qq( -v increase verbosity and debugging info\n); exit(1); } sub xhtml_to_gemini{ my ($file)= (@_); # force input to be read in as UTF-8 my $input; open ($input, "<:utf8", $file) or die("Could not open file '$file' : error: $!\n"); # parse UTF-8 my $xhtml = HTML::TreeBuilder::XPath->new; $xhtml->implicit_tags(1); $xhtml->no_space_compacting(0); $xhtml->parse_file($input) or die("Could not parse '$file' : $!\n"); my $result = ''; if (my $l = $xhtml->findnodes_as_string('//h2/a') ) { # this pattern is weird if($l =~ m/>Links\D+\d+\D\d+\D\d+\D/) { print qq(DAILY LINKS\n) if ($opt{'v'}); $result = &daily_links_page($xhtml); } elsif($l =~ m/>Leftover Links/) { print qq(LEFTOVER LINKS\n) if ($opt{'v'}); $result = &daily_links_page($xhtml); } elsif($l =~ m/>Gemini Links/) { print qq(GEMINI LINKS\n) if ($opt{'v'}); $result = &daily_links_page($xhtml); } else { print qq(NORMAL PAGES\n) if ($opt{'v'}); $result = &normal_page($xhtml); } } $xhtml->destroy; close($input); return($result); } sub normal_page { my ($xhtml) = (@_); my %prefix = ( 'h1' => "# ● ", 'h2' => "## ●● ", 'h3' => "### ●●● ", 'h4' => "### ●●●● ", 'h5' => "### ●●●● ", 'h6' => "### ●●●● ", ); if ($opt{'g'}) { $xhtml = &links2gemini($xhtml); } # print qq(Parsing file\n); my $result; for my $post ($xhtml->findnodes('//div[contains(@class,"post")]')){ # print STDERR "parsing post\n"; foreach my $hn (1 .. 5) { # format headings $hn = qq(h$hn); for my $heading ($post->findnodes(".//$hn")) { my $h = ""; if (defined($prefix{$hn})) { $h .= $prefix{$hn}; } $h = qq(\n\n).$h.$heading->as_text.qq(\n\n); my $tmp = HTML::Element->new('~literal'); $tmp->push_content($h); $heading->replace_with($tmp); } } for my $pq ($post->findnodes('.//span[@class="pullQuote"]')){ my $text = $pq->as_text; $text =~ s/\s+/ /gm; $text =~ s/\n+/ /gm; my $tmp = HTML::Element->new('span'); $tmp->push_content("\n\n> " . $text . "\n\n"); $pq->replace_with($tmp); } for my $pp ($post->findnodes('./p[@class="meta"]')) { # keep the text but ditch the hyperlinks my $text = $pp->as_text; $text =~ s/\s+/ /gm; $text =~ s/\n+/ /gm; my $tmp = HTML::Element->new('p'); $tmp->push_content($text); $pp->replace_with($tmp); } for my $ol ($post->findnodes('./ol')) { my $item = 1; for my $li ($ol->findnodes('./li')) { my $href =''; my $new_li = HTML::Element->new('~literal'); $new_li->push_content($li->as_text."\n"); for my $a ($li->findnodes('./a')) { my $href = $a->attr('href'); $href=~ s{https?://techrights.org(/\d{1,4}/\d{1,2}/\d{1,2}/)} {$1}x; $href=~ s{gemini://gemini.techrights.org(/\d{1,4}/\d{1,2}/\d{1,2}/)} {$1}x; $href=~ s/\s/%20/g; next if ($href=~ m/^#/); next if ($href=~ m/\.jpe?g$/); next if ($href=~ m/\.png$/); next if ($href=~ m/\.gif$/); $new_li->push_content("\n=>\t".$href."\t". $item++." ".$a->as_text."\n"); } $li->replace_with($new_li); } } for my $ul ($post->findnodes('./ul[@class="irc-gemini"]')) { for my $li ($ul->findnodes('./li')) { my $href =''; my $new_li = HTML::Element->new('li'); $new_li->push_content($li->as_text."\n"); for my $a ($li->findnodes('./a')) { $href = $a->attr('href'); # because the direcories on Gemini and WWW are different, # the path must change so that Gemini can point # to gemtext instead of plain text if( $href=~ s{^(gemini://gemini.techrights.org)/tr_text_version/} {$1/irc-gmi/}x ) { $href =~ s{/(irc-log[^/]+)\.txt$} {/$1.gmi}x; $a->delete_content(); $a->push_content($href); } $new_li->push_content("\n=>\t".$href."\t ". $a->as_text."\n"); } $li->replace_with($new_li); } } for my $quote ($post->findnodes('./blockquote')){ $quote->unshift_content("\n> "); $quote->push_content("\n> "); for my $pp ($quote->findnodes("./p")) { $pp->unshift_content("\n> \n> "); } # treat pre within a blockquote as a blockquote for my $pp ($quote->findnodes("./pre")) { my $text = $pp->as_text; $text =~ s/\n/\n> /gm; my $tmp = HTML::Element->new('~literal'); $tmp->push_content($text); $pp->replace_with($tmp); } } for my $pre ($post->findnodes('./pre')){ my $text = $pre->as_text; chomp($text); $text = '``` ' . $text; $text =~ s/\n/\n``` /gm; my $tmp = HTML::Element->new('~literal'); $tmp->push_content($text.qq(\n\n)); $pre->replace_with($tmp); } for my $pp ($post->findnodes("./p")) { # kludge: HTML5 video element is not recognized by parser next unless ($pp->as_text =~ m/Video download link/ || $pp->as_text =~ m/Reprinted/); my @anchors=(); for my $a ($pp->findnodes('.//a[@href]')) { my $href = $a->attr('href'); next if ($href =~ m/^#/); $href =~ s/\s/%20/g; my $t = $a->as_text; if(0 && $opt{'m'}) { # convert video link to gemini local, # presumably it was already downloaded by now $href =~ s{^https?://techrights.org/} {gemini://gemini.techrights.org}x; } else { # don't convert the video link, leave it alone # $href =~ s{^https?://techrights.org/} {/}x; $t = '↺ '.$t; } push (@anchors, "=>\t".$href."\t".$t); } my $d; if($#anchors >= 0) { $d = $pp->as_text.qq(\n\n) .join("\n", @anchors ).qq(\n\n); } else { $d = $pp->as_text.qq(\n\n); } my $tmp = HTML::Element->new('~literal', 'text' => $d); $pp->replace_with($tmp); } for my $br ($post->findnodes("./br")) { my $tmp = HTML::Element->new('~literal', 'text' => "\n\n"); $br->replace_with($tmp); } for my $pp ($post->findnodes("./p")) { my @anchors=(); for my $a ($pp->findnodes('.//a[@href]')) { my $href = $a->attr('href'); $href=~ s{https?://techrights.org(/\d{1,4}/\d{1,2}/\d{1,2}/)} {$1}x; $href=~ s{gemini://gemini.techrights.org(/\d{1,4}/\d{1,2}/\d{1,2}/)} {$1}x; $href=~ s/\s/%20/g; if(my ($img) = $a->findnodes('.//img')) { my $alt = $img->attr('alt') || 'unknown'; # lll $a->detach_content; $a->push_content('Image: '.$alt); } next if ($href=~ m/^#/); next if ($href=~ m/\.jpe?g$/); next if ($href=~ m/\.png$/); next if ($href=~ m/\.gif$/); unless($href=~m/^gemini/ || $href=~m/^\//) { $href = $href.' ↺'; } push (@anchors, "=>\t".$href." ".$a->as_text); } for my $img ($pp->findnodes('./img[@alt]')) { my $alt = $img->attr('alt') || 'unknown'; chomp($alt); $img->detach_content; $img->push_content('> Image: '.$alt."\n\n"); } my $p; if($#anchors >= 0) { $p = $pp->as_text.qq(\n\n). join("\n", @anchors ).qq(\n\n); } else { $p = $pp->as_text.qq(\n\n); } my $tmp = HTML::Element->new('~literal', 'text' => $p); $pp->replace_with($tmp); } for my $node ($post->findnodes('./*')){ my $n = $node->as_text.qq(\n\n); my $tmp = HTML::Element->new('~literal', 'text' => $n); $node->replace_with($tmp); } # suppress warnings for $post->as_XML line local $SIG{__WARN__} = sub { # here we get the warning my $warning = shift; if ($warning =~ m{join or string at /usr/share/perl5/HTML/Element.pm line 1184.}x) { return(1); } }; $result = $post->as_XML; local $SIG{__WARN__}; $post->delete(); $result =~ s/<[^>]+>//g; while ( $result =~ s/\n\n\n/\n\n/gm ) { 1; } last; } $xhtml->delete; return($result); } sub daily_links_page { ( my $xhtml ) = ( @_ ); # Daily Links use a difficult 1990-style structure instead of CSS :( # they're very hard to parse my $result = ''; if ($opt{'g'}) { $xhtml = &links2gemini($xhtml); } my $tmp = HTML::Element->new('~literal'); $tmp->push_content("\n"); for my $toc ($xhtml->findnodes('//div[contains(@id,"contents")]')) { $toc->replace_with($tmp); } for my $post ($xhtml->findnodes('//div[@class="post"]')){ for my $pp ($post->findnodes('./p[@class="gemini"]')) { # delete blurb promoting gemini $pp->delete; } for my $pp ($post->findnodes('./p[@class="meta"]')) { # keep the text but ditch the hyperlinks my $text = $pp->as_text; $text =~ s/\s+/ /gm; $text =~ s/\n+/ /gm; my $tmp = HTML::Element->new('p'); $tmp->push_content($text); $pp->replace_with($tmp); } for my $h1 ($post->findnodes('./h1')) { # page date from H1 my $n = $h1->as_text.qq(\n\n); my $tmp = HTML::Element->new('~literal'); $tmp->push_content("\n#\t● $n"); $h1->replace_with($tmp); last; } for my $h2 ($post->findnodes('./h2')) { # page title from H2 my $n = $h2->as_text.qq(\n\n); my $tmp = HTML::Element->new('~literal'); $tmp->push_content("\n#\t● $n"); $h2->replace_with($tmp); last; } for my $ul ($post->findnodes('./div/ul')) { # deal with the nested, unorderedd lists by flattening them $ul = &ul(0, $ul); } $result = $post->as_text; $post->delete(); while ( $result =~ s/\n\n\n/\n\n/gm ) { 1; } last; } return($result); } sub ul { my ($depth, $ul) = ( @_ ); $depth++; for my $h3 ($ul->findnodes('./li/h3')) { my $new_h3 = HTML::Element->new('~literal'); $new_h3->push_content( "\n##\t".$h3->as_text."\n\n" ); $h3->replace_with($new_h3); } for my $u ($ul->findnodes('./li/ul')) { $u = &ul($depth, $u); } my $new_li = HTML::Element->new('~literal'); for my $l ($ul->findnodes('./li[not(.//ul)]')) { for my $h5 ($l->findnodes('./h5')) { my $new_h5 = HTML::Element->new('~literal'); my $href =''; my $title = $h5->as_text; for my $a ($h5->findnodes('./a')) { $href = $a->attr('href'); $new_li->push_content("\n=>\t".$href."\t↺ ".$title."\n\n"); } } for my $q ($l->findnodes('./blockquote')) { my $new_q = HTML::Element->new('~literal'); for my $p ($q->findnodes('./p')) { $new_li->push_content( "*\t".$p->as_text."\n\n" ); } } $l->replace_with($new_li); } return($ul); } sub links2gemini { my ($xhtml) = (@_); # convert TR http and https links to gemini for my $anchor ($xhtml->findnodes('//a[@href]')) { my $href = $anchor->attr('href'); if ($href!~m/^http/) { next; } elsif ($href=~m/\.webm$/) { next; } $href =~ s{/wiki/index\.php/} {/wiki/}; my $url = URI->new($href); # not all schemes support 'host' objects, thus the sequence matters if (($url->scheme eq 'http' || $url->scheme eq 'https') && $url->host =~ m/techrights\.org$/ ) { $url->host('gemini.techrights.org'); $url->scheme('gemini'); $anchor->attr('href' => $url->canonical); } } return ($xhtml); }
#!/usr/bin/perl -T # 2202-02-04 # shell equivalent: # echo -ne "gemini://gemini.techrights.org:1965/\r\n\r\n" \ # | openssl s_client -connect "gemini.techrights.org:1965" \ # -servername "gemini.techrights.org" -quiet -ign_eof use 5.32.1; # state() requires 5.010 or later # break requires 5.1.0 or later use IO::Socket::SSL; # libio-socket-ssl-perl # use HTML::Entities; # libhtml-parser-perl use CGI::Fast; # libcgi-fast-perl use CGI qw( :standard ); # use CGI::Carp qw( fatalsToBrowser ); # Remove for production use use strict; use warnings; use English qw( -no_match_vars ); $CGI::POST_MAX = 1024 * 1024 * 10; # max 10MB posts # binmode *STDOUT, ':utf8'; # binmode *STDIN, ':utf8'; my $socket_name = "/run/nginx/nginx.gemini.proxy.0.sock"; my $socket_path = "/run/nginx/"; # destroy any pre-existing socket -S $socket_name && unlink $socket_name; umask 007; $ENV{FCGI_SOCKET_PATH} = $socket_name; $ENV{FCGI_LISTEN_QUEUE} = 50; my $url; while (my $query = CGI::Fast->new) { print qq(Content-type: text/html\n\n); &print_head; print qq(\n); # for my $e (sort keys %ENV) { # print qq($e : $ENV{$e}\n); return(1); } sub status { my ($status) =(@_); $status = int($status); state %code = ( 10 => 'INPUT', 11 => 'SENSITIVE INPUT', 20 => 'SUCCESS', 30 => 'REDIRECT - TEMPORARY', 31 => 'REDIRECT - PERMANENT', 40 => 'TEMPORARY FAILURE', 41 => 'SERVER UNAVAILABLE', 42 => 'CGI ERROR', 43 => 'PROXY ERROR', 44 => 'SLOW DOWN', 50 => 'PERMANENT FAILURE', 51 => 'NOT FOUND', 52 => 'GONE', 53 => 'PROXY REQUEST REFUSED', 59 => 'BAD REQUEST', 60 => 'CLIENT CERTIFICATE REQUIRED', 61 => 'CERTIFICATE NOT AUTHORISED', 62 => 'CERTIFICATE NOT VALID', ); return(exists($code{$status}) ? $code{$status} : 'UNKNOWN' ); } sub sanitize { my ($url) = (@_); $url =~ s/\s+//gm; $url =~ s|/index.gmi$|/|; $url =~ s|(?
\n); # } # for my $p ($query->param) { # print qq($p ),$query->param($p),qq(
\n); # } my $action = $query->param('action') || 0; my $url = $query->param('url') || 0; $url = &sanitize($url); if ($url) { my ($status, @p) = ('',''); my $count = 3; while ($count--) { ($status, @p ) = &fetch_gemini($url); my $meta; ($status, $meta) = ($status =~ m/^([0-9]{2})\s+(.*)$/); if ($status =~ /^3/) { $url = &sanitize($meta); next; } else { last; } } my $proxy = "/proxy"; print qq(); #override alignment print qq([Status code $status | ),&status($status), qq(]
\n); print qq(
\n); my $http = $url; $http =~ s|/index.gmi$|/|; $http =~ s|(?the original in the official Web site 🢡
\n); print qq(It may also have images and/or videos.); } print qq(Note: this is only a proxy (Gemini→HTTP) gateway. ); print qq(We highly recommend using proper ); print qq(Gemini client software ); print qq(instead.
\n); &gemtext_to_xhtml($proxy, $url, @p); } else { &print_form; } &print_tail; } exit(0); sub fetch_gemini { my ($url) = (@_); # simple client my $cl = IO::Socket::SSL->new( PeerHost=>"gemini.techrights.org", PeerPort=>1965, Timeout=>2, Proto => 'tcp', # SSL_ca_path => '/home/pi/Certs/', SSL_ca_file => '/home/gemini/bin/Gemini-Proxy/Cert-Cache/gemini.tecrights.org.pem', SSL_hostname => "gemini.techrights.org", SSL_verify_mode => SSL_VERIFY_PEER, # overriden by next line ... # SSL_verify_mode => SSL_VERIFY_NONE, # unsafe kludge ) or die("Failed to connect: $!, '$SSL_ERROR'\n"); print $cl $url,"\r\n\r\n"; my @page = (); my $status = <$cl>; my $tmp = <$cl>; while (my $line = <$cl> ){ push(@page,$line); } close($cl); return($status, @page); } sub gemtext_to_xhtml { my ($proxy, $url, @page) = (@_); my ($path ) = ( $url =~ m{^.*//[^/]+(.*)$} ); print qq(\n); while (my $line = shift @page) { chomp($line); if (! $line) { # $line ="\x{a0}"; # non-breaking space $line =" "; # non-breaking space } else { $line =~ s/\&/\&/gm; $line =~ s/\</gm; } if ($line =~ m/^#\s/) { print qq(\n); return(1); } sub print_head { print qq(\n); print qq(\n); print qq(\n); print qq( \n); print qq($line
\n); } elsif ($line =~ m/^##\s/) { print qq($line
\n); } elsif ($line =~ m/^###\s/) { print qq($line
\n); } elsif ($line =~ m/^=>\s/) { my ($link, $text) = ("", ""); if (($link, $text ) = ($line =~ m/^=>\s+(\S+)\s+(.*)$/)) { 1; } elsif (($link) = ($line =~ m/^=>\s+(\S+)/)) { 1; } else { 0; } if ($link =~ m{^/} ) { $link = "gemini://gemini.techrights.org/$link"; } elsif( $link !~ m{^\w+\://?} ) { $link = "gemini://gemini.techrights.org/$path$link"; } if( ! defined($text) ) { $text = $link; } $link =~ s|(?$text \n); } else { print qq(\n); } } elsif ($line =~ m/^>\s/) { $line =~ s/^>\s+//; print qq($line\n); } elsif ($line =~ m/^\*\s/) { $line =~ s/^\*\s+//; print qq(● $line
\n); } elsif ($line =~ m/^\`\`\`/) { print qq(\n); while (my $l = shift @page) { if ($l =~ m/^\`\`\`/) { last; } $l =~ s/\</g; print $l,"\n"; } print qq(\n); } else { print qq($line
\n); } } print qq(Gemini Proxy for Techrights \n); print qq( \n); print qq(\n); return(1); } sub print_tail { print qq( \n\n); return(1); } sub print_form { print qq(
User-agent: * Disallow: /proxy
## # You should look at the following URL's in order to grasp a solid understanding # of Nginx configuration files in order to fully unleash the power of Nginx. # https://www.nginx.com/resources/wiki/start/ # https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/ # https://wiki.debian.org/Nginx/DirectoryStructure # # In most cases, administrators will remove this file from sites-enabled/ and # leave it as reference inside of sites-available where it will continue to be # updated by the nginx packaging team. # # This file will automatically load configuration files provided by other # applications, such as Drupal or Wordpress. These applications will be made # available underneath a path with that package name, such as /drupal8. # # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. ## # Default server configuration # server { listen 80; # listen [::]:80 default_server; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name _; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } location /proxy { fastcgi_pass unix:/var/run/nginx/nginx.gemini.proxy.0.sock; fastcgi_param SCRIPT_FILENAME /usr/local/bin/gemini-proxy.pl; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; include fastcgi_params; deny 20.34.0.0/15; # bing 病 deny 20.36.0.0/14; # bing 病 deny 20.40.0.0/13; # bing 病 deny 20.48.0.0/12; # bing 病 deny 20.64.0.0/10; # bing 病 deny 20.128.0.0/16; # bing 病 deny 23.96.0.0/13; # bing 病 deny 34.64.0.0/10; # googlebot deny 40.74.0.0/15; # bing 病 deny 40.76.0.0/14; # bing 病 deny 40.80.0.0/12; # bing 病 deny 40.96.0.0/12; # bing 病 deny 40.124.0.0/16; # bing 病 deny 40.112.0.0/13; # bing 病 deny 40.120.0.0/14; # bing 病 deny 40.125.0.0/17; # bing 病 deny 52.84.0.0/14; # bing 病 deny 52.88.0.0/13; # bing 病 deny 52.136.0.0/13; # ddg / bing 病 deny 52.132.0.0/14; # ddg / bing 病 deny 52.145.0.0/16; # bing 病 deny 52.146.0.0/15; # bing 病 deny 52.148.0.0/14; # bing 病 deny 52.152.0.0/13; # bing 病 deny 52.160.0.0/11; # bing 病 deny 157.56.0.0/14; # bing 病 deny 157.54.0.0/15; # bing 病 deny 157.60.0.0/16; # bing 病 deny 207.46.0.0/16; # bing 病 deny 37.252.64.0/19; deny 66.249.64.0/19; # google bot deny 116.128.0.0/10; # baidu deny 162.142.125.0/24; # censys deny 185.250.240.0/24; deny 208.80.192.0/21; deny 77.88.0.0/18; # yandex deny 93.158.128.0/18; # yandex } location = / { return 301 http://gemini.techrights.org/proxy?url=gemini://gemini.techrights.org/; } } server { listen 443 ssl; # listen [::]:443 ssl; include snippets/self-signed.conf; include snippets/ssl-params.conf; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name _; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } location /proxy { fastcgi_pass unix:/var/run/nginx/nginx.gemini.proxy.0.sock; fastcgi_param SCRIPT_FILENAME /usr/local/bin/gemini-proxy.pl; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; include fastcgi_params; } location = / { return 301 https://gemini.techrights.org/proxy?url=gemini://gemini.techrights.org/; } } # Virtual Host configuration for example.com # # You can move that to a different file under sites-available/ and symlink that # to sites-enabled/ to enable it. # #server { # listen 80; # listen [::]:80; # # server_name example.com; # # root /var/www/example.com; # index index.html; # # location / { # try_files $uri $uri/ =404; # } #}
-----BEGIN CERTIFICATE----- MIIBVTCB+6ADAgECAgEqMAoGCCqGSM49BAMCMCAxHjAcBgNVBAMMFWdlbWluaS50 ZWNocmlnaHRzLm9yZzAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAwMFow IDEeMBwGA1UEAwwVZ2VtaW5pLnRlY2hyaWdodHMub3JnMFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAEI0o5Lnz2dDrRtj/G7fbTQQlIij6iJxkw6B6pFd19Bk+PoPxy sVjC81ORc8h14HbDD8NBDWIL0SdPtzcYNT/A+aMkMCIwIAYDVR0RBBkwF4IVZ2Vt aW5pLnRlY2hyaWdodHMub3JnMAoGCCqGSM49BAMCA0kAMEYCIQDCs7jcvilZocLT lsvT9algZT2z6s1UHJ2VPffKIh2B2wIhAOuiE2nhxYijTimG+YM4xMH4bNIKA6Be wJ8hAedbybAt -----END CERTIFICATE-----
[Unit] Description=Gemini Proxy Service After=network.target After=nginx.target [Service] Type=simple User=gemprox PermissionsStartOnly=true ExecStartPre=-/bin/mkdir -p /run/nginx/ ExecStartPre=/bin/chmod g=rwxs /run/nginx/ ExecStartPre=/bin/chown www-data:gemprox /run/nginx/ ExecStart=/usr/local/bin/gemini-proxy.pl # or always, on-abort, etc Restart=on-failure Nice=5 [Install] WantedBy=multi-user.target
#!/bin/bash # Initial 2022-03-06 # Last updated 2022-03-18 set -v -x # PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin # Get key dates first daybeforeyesterday=$(date --date "2 days ago" +"%Y-%m-%d") yesterday=$(date --date yesterday +"%Y-%m-%d") today=$(date --date today +"%Y-%m-%d") ################################## # Start main page of Planet echo "# Planet Gemini" > ~/gemini/planet/index.gmi echo "Welcome to Planet Gemini. This is where we aggregate sources to help us identify new material in gopher:// and gemini:// space." >> ~/gemini/planet/index.gmi echo "## Get added" >> ~/gemini/planet/index.gmi echo "Contact us if you want yours to be added too." >> ~/gemini/planet/index.gmi echo "=> /about Contacting us" >> ~/gemini/planet/index.gmi echo "=> / Go back to Techrights (Main Index)" >> ~/gemini/planet/index.gmi echo "# New/Updated So Far Today and Yesterday" >> ~/gemini/planet/index.gmi echo "=> /planet/latest Latest Items" >> ~/gemini/planet/index.gmi ################################## # Update the page with latest posts in the Planet (to use prior snapshot, not upcoming) echo "# Latest Posts/Articles Across Geminispace" > ~/gemini/planet/latest/index.gmi echo "This page aggregates posts found for the current day and prior day. It's typically updated every 3 hours." >> ~/gemini/planet/latest/index.gmi cat ~/gemini/planet/othercapsules/${today}.gmi >> ~/gemini/planet/latest/index.gmi cat ~/gemini/planet/othercapsules/${yesterday}.gmi >> ~/gemini/planet/latest/index.gmi echo "____________________________________________________" >> ~/gemini/planet/latest/index.gmi echo "=> / Go back to Techrights (Main Index)" >> ~/gemini/planet/latest/index.gmi echo "=> /planet Planet (Full)" >> ~/gemini/planet/latest/index.gmi echo -n "Last update cycle ended " >> ~/gemini/planet/latest/index.gmi date --date today "+%A, %B %d, %Y at %H:%M" >> ~/gemini/planet/latest/index.gmi ################################## # Now go back to main Planet page echo "## More Dates" >> ~/gemini/planet/index.gmi echo "=> /planet/othercapsules Older Dates (Archive)" >> ~/gemini/planet/index.gmi echo "=> /planet/othercapsules/allinone.gmi All in one, past 3 days combined, fused and compacted" >> ~/gemini/planet/index.gmi echo "=> /planet/othercapsules/new.gmi New (added since last update cycle)" >> ~/gemini/planet/index.gmi echo "## Updates" >> ~/gemini/planet/index.gmi echo -n "Last update cycle started " >> ~/gemini/planet/index.gmi date --date today "+%A, %B %d, %Y at %H:%M" >> ~/gemini/planet/index.gmi echo "Page updated every 3 hours ⦼" >> ~/gemini/planet/index.gmi echo "## Sources" >> ~/gemini/planet/index.gmi echo "Some suggested feeds (for syndication) are listed below." >> ~/gemini/planet/index.gmi echo "=> /git/tr-git/Gemini/gemini-feeds.gmi List of feeds" >> ~/gemini/planet/index.gmi echo "=> /git/tr-git/Gemini/gemini-capcom.gmi More active feeds" >> ~/gemini/planet/index.gmi echo "# Full Lists (Item Listing, Undated)" >> ~/gemini/planet/index.gmi echo "Pertinent capsules followed by list of lists, credit added where it is due" >> ~/gemini/planet/index.gmi # Note: dirty hacks below, might be worth tidying up in the future # echo -ne "gemini://gemini.techrights.org/feed.xml\r\n\r\n" | openssl s_client -servername gemini.techrights.org -quiet -ign_eof -connect gemini.techrights.org:1965 | sed -e '1{/^[0-9][0-9]/d}' | xmlstarlet sel -E utf-8 -T -t -m '//item' -o '=> ' -v './link' -o " " -v './title' -n >> ~/gemini/planet/index.gmi echo "## mieum" >> ~/gemini/planet/index.gmi (echo "gemini://rawtext.club/~mieum/poems/atom.xml"; sleep 1) \ | openssl s_client -connect rawtext.club:1965 \ | grep -e title -e link \ | tac \ | sed "s/ //" \ | sed "s/<\/title>//" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" >> ~/gemini/planet/index.gmi echo "## 🅰🆅🅰🅻🅾🆂.🅼🅴" >> ~/gemini/planet/index.gmi echo -ne "gemini://avalos.me/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername avalos.me -quiet -ign_eof -connect avalos.me:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s///" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🆂🅸🆇🅾🅷🆃🅷🆁🅴🅴.🅲🅾🅼" >> ~/gemini/planet/index.gmi echo -ne "gemini://sixohthree.com:1965/atom.xml\r\n\r\n" \ | openssl s_client -servername sixohthree.com -quiet -ign_eof -connect sixohthree.com:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f4-4 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🆅🅺3.🆆🆃🅵 " >> ~/gemini/planet/index.gmi echo -ne "gemini://vk3.wtf:1965/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername vk3.wtf -quiet -ign_eof -connect vk3.wtf:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🆃🅷🅴🅻🅰🅼🅱🅳🅰🅻🅰🅱.🆇🆈🆉 " >> ~/gemini/planet/index.gmi echo -ne "gemini://thelambdalab.xyz:1965/atom.xml\r\n\r\n" \ | openssl s_client -servername thelambdalab.xyz -quiet -ign_eof -connect thelambdalab.xyz:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".txt" >> ~/gemini/planet/index.gmi # OFFLINE JULY 2022: # echo "## 🅳🆁🅴🆆🅳🅴🆅🅰🆄🅻🆃.🅲🅾🅼" >> ~/gemini/planet/index.gmi # echo -ne "gemini://drewdevault.com/feed.xml\r\n\r\n" \ # | openssl s_client -servername drewdevault.com -quiet -ign_eof -connect drewdevault.com:1965 \ # | grep -e title -e link \ # | tac \ # | sed "s//=> /" \ # | cut --d="\"" -f2-2 \ # | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ # | sed "s/ //" \ # | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ # | grep "=>" \ # | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## Tux Machines">> ~/gemini/planet/index.gmi echo -ne "gemini://gemini.tuxmachines.org/feed.xml\r\n\r\n" \ | openssl s_client -servername gemini.tuxmachines.org -quiet -ign_eof -connect gemini.tuxmachines.org:1965 \ | grep -e title -e link \ | sed "s//=> /" \ | cut --d="\"" -f4-4 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅼🅾🅳🅳🅴🅳🅱🅴🅰🆁.🆇🆈🆉">> ~/gemini/planet/index.gmi echo -ne "gemini://moddedbear.xyz/logs/atom.xml\r\n\r\n" \ | openssl s_client -servername moddedbear.xyz -quiet -ign_eof -connect moddedbear.xyz:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//; s/<\/link>//" \ | sed "s/ //" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi # echo "## nader.pm">> ~/gemini/planet/index.gmi # echo -ne "gemini://nader.pm/atom.xml\r\n\r\n" | openssl s_client -servername nader.pm -quiet -ign_eof -connect nader.pm:1965 | grep -e title -e link | tac | sed "s//=> /" | cut --d="\"" -f2-2 | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" | sed "s/gemini:/=> gemini:/" | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' | grep "=>" | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅶🅴🅼🅸🅽🅸.🅸🅾🆂🅰.🅸🆃">> ~/gemini/planet/index.gmi echo -ne "gemini://gemini.iosa.it/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername gemini.iosa.it -quiet -ign_eof -connect gemini.iosa.it:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅲🅰🅻🅲🆄🅾🅳🅴.🅲🅾🅼">> ~/gemini/planet/index.gmi echo -ne "gemini://calcuode.com/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername calcuode.com -quiet -ign_eof -connect calcuode.com:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi ### Inactive May 2022, hence commented out ### echo "## jfh.me">> ~/gemini/planet/index.gmi ### echo -ne "gemini://jfh.me/atom.xml\r\n\r\n" \ ### | openssl s_client -servername jfh.me -quiet -ign_eof -connect jfh.me:1965 \ ### | grep -e title -e link \ ### | tac \ ### | sed "s//=> /" \ ### | cut --d="\"" -f2-2 \ ### | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ ### | sed "s/gemini:/=> gemini:/" \ ### | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ ### | grep "=>" \ ### | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅶🅰🅻🅰🆇🆈🅷🆄🅱.🆄🅺">> ~/gemini/planet/index.gmi echo -ne "gemini://galaxyhub.uk/articles/atom.xml\r\n\r\n" \ | openssl s_client -servername galaxyhub.uk -quiet -ign_eof -connect galaxyhub.uk:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi # echo "## gemini://cosmic.voyage">> ~/gemini/planet/index.gmi # echo -ne "gemini://cosmic.voyage/atom.xml\r\n\r\n" | openssl s_client -servername cosmic.voyage -quiet -ign_eof -connect cosmic.voyage:1965 | grep -e title -e link | tac | sed "s//=> /" | cut --d="\"" -f2-2 | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" | sed "s/gemini:/=> gemini:/" | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' | grep "=>" | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅶🅴🅼🅸🅽🅸.🆄🅲🅰🅽🆃.🅾🆁🅶">> ~/gemini/planet/index.gmi echo -ne "gemini://gemini.ucant.org/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername gemini.ucant.org -quiet -ign_eof -connect gemini.ucant.org:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅻🅾🆃🆃🅰🅻🅸🅽🆄🆇🅻🅸🅽🅺🆂.🅲🅾🅼">> ~/gemini/planet/index.gmi echo -ne "gemini://gemini.lottalinuxlinks.com/posts/feed.xml\r\n\r\n" \ | openssl s_client -servername gemini.lottalinuxlinks.com -quiet -ign_eof -connect gemini.lottalinuxlinks.com:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep -v "id>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅰🅿.🆂🆆🅰🅽.🆀🆄🅴🆂🆃">> ~/gemini/planet/index.gmi echo -ne "gemini://cap.swan.quest/p/atom.xml\r\n\r\n" \ | openssl s_client -servername cap.swan.quest -quiet -ign_eof -connect cap.swan.quest:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi echo "## 🅽🆈🆃🅿🆄.🅲🅾🅼" >> ~/gemini/planet/index.gmi echo -ne "gemini://nytpu.com:1965/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername nytpu.com -quiet -ign_eof -connect nytpu.com:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="'" -f4-4 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/\/\//=> gemini:\/\//" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi ################################## # Start imports section/s echo "# Imported by nytpu.com">> ~/gemini/planet/index.gmi echo "Credit due (original):" >> ~/gemini/planet/index.gmi echo "=> gemini://nytpu.com/feed.gmi Alex" >> ~/gemini/planet/index.gmi echo -ne "gemini://nytpu.com/feed.gmi\r\n\r\n" \ | openssl s_client -servername nytpu.com -quiet -ign_eof -connect nytpu.com:1965 \ | sed -n '/##/,$p' >> ~/gemini/planet/index.gmi ################################## # Add/chain CAPCOM echo "# Imported via CAPCOM">> ~/gemini/planet/index.gmi echo "Credit due (original):" >> ~/gemini/planet/index.gmi echo "=> gemini://gemini.circumlunar.space/capcom/ CAPCOM" >> ~/gemini/planet/index.gmi echo -ne "gemini://gemini.circumlunar.space/capcom/\r\n\r\n" \ | openssl s_client -servername gemini.circumlunar.space -quiet -ign_eof -connect gemini.circumlunar.space:1965 \ | sed -n '/Aggregating 100/,$p' >> ~/gemini/planet/index.gmi ################################## # Add/chain Spacewalk echo "# Imported via Spacewalk">> ~/gemini/planet/index.gmi echo "Credit due (original):" >> ~/gemini/planet/index.gmi echo "=> gemini://rawtext.club/~sloum/spacewalk.gmi Spacewalk" >> ~/gemini/planet/index.gmi # echo "\`\`\`" >> ~/gemini/planet/index.gmi echo -ne "gemini://rawtext.club/~sloum/spacewalk.gmi\r\n\r\n" \ | openssl s_client -servername rawtext.club -quiet -ign_eof -connect rawtext.club:1965 \ | sed -n '/Oldest/,$p' >> ~/gemini/planet/index.gmi ################################## # Add/chain Skyjake echo "# Imported via Skyjake">> ~/gemini/planet/index.gmi echo "Credit due (original):" >> ~/gemini/planet/index.gmi echo "=> gemini://skyjake.fi/~Cosmos/ Skyjake" >> ~/gemini/planet/index.gmi # openssl s_client -quiet -crlf \ # -servername skyjake.fi \ # -connect skyjake.fi:1965 \ # | awk '{ print "response: " $0 }' gemini://skyjake.fi/~Cosmos/ | # openssl s_client -quiet -crlf \ # -servername skyjake.fi \ # -connect skyjake.fi:1965 \ #| awk '{ print "response: " $0 }' #gemini://skyjake.fi/~Cosmos/ | sed -n '/202/,$p' >> ~/gemini/planet/index.gmi # Temporary workaround below because the capsule acts weird mv ~/Downloads/~Cosmos.gmi /tmp/cosmos cat /tmp/cosmos | sed -n '/202/,$p' >> ~/gemini/planet/index.gmi # sh ~/bin/gemini-get-cosmo.sh ################################## # Add/chain Warmedal echo "# Imported via Warmedal">> ~/gemini/planet/index.gmi echo "Credit due (original):" >> ~/gemini/planet/index.gmi echo "=> gemini://warmedal.se/~antenna/index.gmi Warmedal" >> ~/gemini/planet/index.gmi echo "" >> ~/gemini/planet/index.gmi echo -ne "gemini://warmedal.se/~antenna/index.gmi\r\n\r\n" \ | openssl s_client -servername warmedal.se -quiet -ign_eof -connect warmedal.se:1965 \ | sed -n '/202/,$p' >> ~/gemini/planet/index.gmi ################################## # Add/chain Calcuode echo "# Imported via Calcuode">> ~/gemini/planet/index.gmi echo "Credit due (original):" >> ~/gemini/planet/index.gmi echo "=> gemini://calcuode.com/gmisub-aggregate.gmi Calcuode" >> ~/gemini/planet/index.gmi echo -ne "gemini://calcuode.com/gmisub-aggregate.gmi\r\n\r\n" \ | openssl s_client -servername calcuode.com -quiet -ign_eof -connect calcuode.com:1965 \ | sed -n '/Entries/,$p' >> ~/gemini/planet/index.gmi echo '________________________________________________' >> ~/gemini/planet/index.gmi echo -n 'Last updated ' >> ~/gemini/planet/index.gmi date --date today "+%A, %B %d, %Y at %H:%M" >> ~/gemini/planet/index.gmi echo "=> / Go back to Techrights (Main Index)" >> ~/gemini/planet/index.gmi ################################## # Now update the archives # We limits the scope of the scanner to imported sections echo -n "## News for " > ~/gemini/planet/othercapsules/${yesterday}.gmi echo ${yesterday} >> ~/gemini/planet/othercapsules/${yesterday}.gmi sed -n '/# Imported/,$p' ~/gemini/planet/index.gmi \ | sed -n -e "/${yesterday}/,/${daybeforeyesterday}/p" \ | sort -u -k2,2 \ | grep -v " 2020-" \ | grep -v " 2021-" \ | sort -k3,3 \ | grep "=>" >> ~/gemini/planet/othercapsules/${yesterday}.gmi # Consider adding sed 's/gopher:\/\//gopher:\/\/ [Gopher Link]/' or similar if many gopher links exist or need culling echo -n "## News for " > ~/gemini/planet/othercapsules/${today}.gmi echo ${today} >> ~/gemini/planet/othercapsules/${today}.gmi sed -n '/# Imported/,$p' ~/gemini/planet/index.gmi \ | sed -n -e "/${today}/,/${yesterday}/p" \ | sort -u -k2,2 \ | grep -v " 2020-" \ | grep -v " 2021-" \ | sort -k3,3 \ | grep "=>" >> ~/gemini/planet/othercapsules/${today}.gmi # All in one, past 3 days combined, fused and compacted cp ~/gemini/planet/othercapsules/allinone.gmi ~/gemini/planet/othercapsules/allinone-last.gmi echo "# 3-day Outline for Geminispace" > ~/gemini/planet/othercapsules/allinone.gmi cat ~/gemini/planet/othercapsules/${today}.gmi \ ~/gemini/planet/othercapsules/${yesterday}.gmi \ ~/gemini/planet/othercapsules/${daybeforeyesterday}.gmi \ | uniq \ | grep -v "News for 20" \ | sort -u -k2,2 \ | sort -r -k3,3 >> ~/gemini/planet/othercapsules/allinone.gmi echo '____________‿︵‿︵ʚ˚̣̣̣͙ɞ・❉・ ʚ˚̣̣̣͙ɞ‿︵‿︵_________' >> ~/gemini/planet/othercapsules/allinone.gmi echo -n 'Last updated ' >> ~/gemini/planet/othercapsules/allinone.gmi date --date today "+%A, %B %d, %Y at %H:%M" >> ~/gemini/planet/othercapsules/allinone.gmi echo "=> /planet/othercapsules/new.gmi Latest updates, sorted by time" >> ~/gemini/planet/othercapsules/allinone.gmi echo "=> / Go back to Techrights (Main Index)" >> ~/gemini/planet/othercapsules/allinone.gmi # Start the page afresh at first 3 hours of the day (assumes update cycles no greater than # 3 hours apart case $(date +%H:%M) in (0[0]:*) echo "# New in Gemini (Since Last Time or Update Cycle)" > ~/gemini/planet/othercapsules/new.gmi;; (*) echo " ‿︵•‿︵•‿︵•‿︵" >> ~/gemini/planet/othercapsules/new.gmi;; esac # Show differences in the direction of the "new" version, annul the "old" one aging away diff ~/gemini/planet/othercapsules/allinone.gmi ~/gemini/planet/othercapsules/allinone-last.gmi \ | egrep '^[d<]' \ | cut -c3-256 >> ~/gemini/planet/othercapsules/new.gmi # Start assembling the archives echo "# Gemini Archive" > ~/gemini/planet/othercapsules/index.gmi echo "Select any of the dates below. Those show all the Geminispace updates visible to us." >> ~/gemini/planet/othercapsules/index.gmi # Process starts of month specially find /home/gemini/gemini/planet/othercapsules/ \ -type f \ -name "2*" \ -exec basename {} \; \ | sort \ | sed -r -e 's/([0-9]{4}-[0-9]{2}-[0-9]{2})\.gmi/\1.gmi \1/; s/^/=> /' \ -e '/01-01.*/i ### January ㋀' \ -e '/02-01.*/i ### February ㋁' \ -e '/03-01.*/i ### March ㋂' \ -e '/04-01.*/i ### April ㋃' \ -e '/05-01.*/i ### May ㋄' \ -e '/06-01.*/i ### June ㋅' \ -e '/07-01.*/i ### July ㋆' \ -e '/08-01.*/i ### August ㋇' \ -e '/09-01.*/i ### September ㋈' \ -e '/10-01.*/i ### October ㋉' \ -e '/11-01.*/i ### November ㋊' \ -e '/12-01.*/i ### December ㋋' \ >> ~/gemini/planet/othercapsules/index.gmi echo -n 'Last updated ' >> ~/gemini/planet/othercapsules/index.gmi date --date today "+%A, %B %d, %Y at %H:%M" >> ~/gemini/planet/othercapsules/index.gmi echo "=> / Go back to Techrights (Main Index)" >> ~/gemini/planet/othercapsules/index.gmi # Finish gracefully exit 0 ################################## # Note/stale below # ------- # echo -ne "gemini://gemini.jayeless.net/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername gemini.jayeless.net -quiet -ign_eof -connect gemini.jayeless.net:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep ".gmi" >> ~/gemini/planet/index.gmi # echo -ne "gemini://gemini.jayeless.net/gemlog/atom.xml\r\n\r\n" \ | openssl s_client -servername gemini.jayeless.net -quiet -ign_eof -connect gemini.jayeless.net:1965 \ | sed -e '1{/^[0-9][0-9]/d}' \ | xmlstarlet sel -E utf-8 -T -t -m '//item' -o '=> ' -v './link' -o " " -v './title' -n # ------ # echo -ne "gemini://midnight.pub/feed.xml\r\n\r\n" \ | openssl s_client -servername midnight.pub -quiet -ign_eof -connect midnight.pub:1965 \ | grep -e title -e link \ | tac \ | sed "s//=> /" \ | cut --d="\"" -f2-2 \ | sed -e "s/ //" -e "s/<\/title>//" -e "s/<\/link>//" \ | sed "s/gemini:/=> gemini:/" \ | sed -e :a -e N -e '$!ba' -e 's/gmi\n/gmi /g' \ | grep "=>" \ | grep "posts" # echo -ne "gemini://midnight.pub/feed.xml\r\n\r\n" \ | openssl s_client -servername midnight.pub -quiet -ign_eof -connect midnight.pub:1965 \ | sed -e '1{/^[0-9][0-9]/d}' \ | xmlstarlet sel -E utf-8 -T -t -m '//item' -o '=> ' -v './link' -o " " -v './title' -n # ------
=> Back to main index This content has been proxied by September (ba2dc).Proxy Information
text/gemini;lang=en-GB