epicyon/website/EN/v1_7_0.html

1283 lines
34 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "SoftwareApplication",
"name" : "Epicyon",
"image" : "https://libreserver.org/epicyon/images/logo.png",
"url" : "https://libreserver.org/epicyon",
"author" : {
"@type" : "Person",
"name" : "Bob Mottram",
"email": "bob@libreserver.org",
"url": "https://epicyon.libreserver.org/users/bob"
},
"applicationCategory" : ["server", "instance", "software", "activitypub", "fediverse", "self-hosting", "microblog"],
"downloadUrl" : "https://libreserver.org/epicyon/epicyon.tar.gz"
}
</script>
<meta name="description" content="ActivityPub server written in Python, HTML and CSS, and suitable for self-hosting on single board computers">
<meta name="keywords" content="ActivityPub, Fediverse, Instance, Python, HTML, CSS, SmallWeb, SelfHosting, Microblog">
<meta name="author" content="Bob Mottram">
<style>
@charset "UTF-8";
:root {
--main-bg-color: #282c37;
--dropdown-bg-color: #111;
--dropdown-bg-color-hover: #333;
--main-bg-color-reply: #212c37;
--main-bg-color-dm: #222;
--main-bg-color-report: #221c27;
--main-header-color-roles: #282237;
--main-fg-color: #dddddd;
--main-link-color: #999;
--main-visited-color: #888;
--border-color: #505050;
--font-size-header: 18px;
--font-color-header: #ccc;
--font-size: 30px;
--text-entry-foreground: #ccc;
--text-entry-background: #111;
--quote-font-weight: normal;
--quote-font-size: 120%;
}
@font-face {
font-family: 'Rooters';
font-style: normal;
font-weight: normal;
font-display: block;
src: url('./fonts/Rooters.ttf') format('truetype');
}
body, html {
background-color: var(--main-bg-color);
color: var(--main-fg-color);
height: 100%;
font-family: Arial, Helvetica, sans-serif;
max-width: 80%;
min-width: 950px;
margin: 0 auto;
font-size: var(--font-size);
}
a, u {
color: var(--main-fg-color);
}
a:visited{
color: var(--main-visited-color);
font-weight: bold;
}
a:link {
color: var(--main-link-color);
font-weight: bold;
}
blockquote {
border-left: 10px;
margin: 1.5em 10px;
padding: 0.5em 10px;
font-weight: var(--quote-font-weight);
font-style: italic;
font-size: var(--quote-font-size);
quotes: "\201C""\201D""\2018""\2019";
color: lightblue;
}
.cwButton {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 26px;
padding: 2px;
cursor: pointer;
margin: 5px;
}
.cwText {
display: none;
}
.pageicon {
width: 8%;
}
.timeline-banner {
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("img/banner.png");
height: 10%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
position: relative;
}
.hero-image {
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("image.png");
height: 50%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
position: relative;
}
.hero-text {
text-align: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--font-color-header);
font-size: var(--font-size-header);
}
.new-post-text {
font-size: 24px;
padding: 4px 0;
}
.new-post-subtext {
font-size: 18px;
padding: 4px 0;
}
.highlight {
width: 2%;
}
.roles {
text-align: center;
left: 35%;
background-color: var(--main-header-color-roles);
}
.roles-inner {
padding: 10px 25px;
background-color: var(--main-bg-color);
}
.hero-text img {
border-radius: 1%;
width: 30%;
min-width: 200px;
}
.hero-text img.emoji {
width: 50px;
padding: 0 0;
margin: 0 0;
float: none;
}
.hero-text button {
border: none;
outline: 0;
display: inline-block;
padding: 10px 25px;
color: black;
background-color: #ddd;
text-align: center;
cursor: pointer;
}
.hero-text button:hover {
background-color: #555;
color: white;
}
.button {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 10%;
max-width: 100px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
}
.buttonunfollow {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 20%;
max-width: 200px;
min-width: 100px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
float: right;
}
.buttonhighlighted {
border-radius: 4px;
background-color: green;
border: none;
color: white;
text-align: center;
font-size: 18px;
padding: 10px;
width: 10%;
max-width: 100px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
}
.timelineIcon {
width: 10%;
}
.followApprove {
border-radius: 4px;
background-color: darkgreen;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 15%;
max-width: 150px;
min-width: 100px;
cursor: pointer;
margin: 0 15px;
float: right;
}
.followDeny {
border-radius: 4px;
background-color: darkred;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 15%;
max-width: 150px;
min-width: 100px;
cursor: pointer;
margin: 0 15px;
float: right;
}
.followRequestHandle {
padding: 0px 20px;
}
.button span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.5s;
}
.button span:after {
content: '\00bb';
position: absolute;
opacity: 0;
top: 0;
right: -20px;
transition: 0.5s;
}
.button:hover span {
padding-right: 25px;
}
.button:hover span:after {
opacity: 1;
right: 0;
}
.buttonselected {
border-radius: 4px;
background-color: #666;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 10%;
max-width: 100px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
}
.buttonselectedhighlighted {
border-radius: 4px;
background-color: darkgreen;
border: none;
color: white;
text-align: center;
font-size: 18px;
padding: 10px;
width: 10%;
max-width: 100px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
}
.buttonselected span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.5s;
}
.buttonselected span:after {
content: '\00bb';
position: absolute;
opacity: 0;
top: 0;
right: -20px;
transition: 0.5s;
}
.buttonselected:hover span {
padding-right: 25px;
}
.buttonselected:hover span:after {
opacity: 1;
right: 0;
}
.container {
border: 2px solid var(--border-color);
background-color: var(--main-bg-color);
border-radius: 5px;
padding: 20px;
margin: 10px 0;
}
.media {
width: 80%;
border-radius: 5px;
padding: 10px;
margin: 10px 0;
}
.message {
margin-left: 7%;
width: 90%;
}
.container p.administeredby {
font-size: 18px;
}
.container::after {
content: "";
clear: both;
display: table;
}
.container img {
float: left;
max-width: 400px;
width: 5%;
padding: 0px 7px;
margin-right: 20px;
border-radius: 10%;
}
.searchEmoji {
-ms-transform: translateY(30%);
transform: translateY(30%);
float: none;
width: 80px;
margin: 0px 10px;
padding: 0px 0px;
border-radius: 0px;
}
.container img.emoji {
float: none;
width: 50px;
margin-left: 0px;
margin-right: 0px;
padding-right: 0px;
border-radius: 0px;
}
.containericons {
padding: 0px 0px;
margin: 0px 0px;
}
.containericons img {
float: right;
max-width: 200px;
width: 6%;
border-radius: 0%;
}
.replyingto {
color: var(--main-fg-color);
}
.container img.announceOrReply {
float: none;
width: 30px;
margin: 0 0;
padding: 0 0;
border-radius: 0;
-ms-transform: translateY(25%);
transform: translateY(25%);
}
.container img.DMicon {
float: none;
width: 40px;
margin: 0 0;
padding: 0 0;
border-radius: 0;
-ms-transform: translateY(25%);
transform: translateY(25%);
}
.darker {
background-color: var(--main-bg-color-reply);
}
.dm {
background-color: var(--main-bg-color-dm);
}
.report {
border-color: #255;
background-color: var(--main-bg-color-report);
}
.container img.attachment {
max-width: 100%;
margin-left: 25%;
width: 50%;
border-radius: 10%;
}
.container img.right {
float: right;
margin-left: 0px;
margin-right:0;
padding: 0 0;
margin: 0 0;
}
.containericons img.right {
float: right;
margin-left: 20px;
margin-right: 0;
}
.time-right {
float: right;
color: #aaa;
margin: 4px 20px;
}
.post-title {
margin-top: 0px;
color: #444;
}
.share-title {
margin-top: 0px;
color: var(--main-fg-color);
}
.skill-title {
margin-left: 25%;
text-align: left;
font-size: 24px;
font-weight: bold;
color: #666;
line-height: 40px;
}
#myProgress {
float: left;
width: 70%;
background-color: #f1f1f1;
}
#myBar {
float: left;
width: 10%;
height: 30px;
background-color: #999;
}
.question {
font-size: var(--font-size);
}
input[type=radio] {
width: 32px;
}
input[type=text], select, textarea {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
margin-top: 6px;
margin-bottom: 16px;
resize: vertical;
font-size: 24px;
background-color: var(--main-bg-color-reply);
color: var(--main-fg-color);
}
input[type=number] {
width: 10%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
margin-top: 6px;
margin-bottom: 16px;
resize: vertical;
font-size: 18px;
}
.labels {
font-size: 18px;
}
input[type=submit] {
background-color: #555;
color: white;
float: right;
margin: 10px 10px;
padding: 12px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
width: 120px;
}
input.vote[type=submit] {
background-color: #555;
color: white;
float: left;
margin: 10px 10px;
padding: 12px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
width: 120px;
}
.cancelbtn {
background-color: #555;
color: white;
float: right;
margin: 10px 10px;
padding: 12px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
width: 120px;
}
.loginButton {
background-color: #2965;
color: #000;
float: none;
margin: 0px 10px;
padding: 12px 40px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 24px;
opacity: 0.7;
}
input[type=file] {
background-color: #555;
color: white;
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
}
input[type=submit]:hover {
background-color: #555;
}
.vertical-center {
max-width: 90%;
min-width: 600px;
margin: 0 auto;
padding: 5% 0px;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
margin: 10px auto;
padding: 0px 14px;
position: relative;
display: inline-block;
}
.dropdown img {
opacity: 1.0;
width: 32px;
height: 32px;
padding: 0px 16px;
-ms-transform: translateY(-10%);
transform: translateY(-10%);
}
.timeline-avatar {
margin: 10px auto;
padding: 0px 0px;
}
.search-result-text {
font-size: var(--font-size);
}
.search-result img {
width: 7%;
padding: 0px 30px;
}
.timeline-avatar img {
opacity: 1.0;
width: 8%;
height: 8%;
padding: 0px 0px;
-ms-transform: translateY(-10%);
transform: translateY(-10%);
}
.scope-desc {
font-size: 18px;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: var(--dropdown-bg-color);
min-width: 600px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
color: var(--main-fg-color);
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown-content img {
width: 32px;
height: 32px;
padding: 0px 0px;
}
/* Change color of dropdown links on hover */
.dropdown-content a:hover {background-color: var(--dropdown-bg-color-hover);}
/* Show the dropdown menu on hover */
.show {display: block;}
input[type=checkbox]
{
-ms-transform: scale(2);
-moz-transform: scale(2);
-webkit-transform: scale(2);
-o-transform: scale(2);
transform: scale(2);
padding: 10px;
margin: 10px 5px;
}
.slider {
-webkit-appearance: none;
width: 57%;
height: 25px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
float: right;
margin: 5px 0;
padding: 12px 0;
}
.slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
background: var(--main-bg-color);
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 25px;
height: 25px;
background: var(--main-bg-color);
cursor: pointer;
}
.dropbtn {
margin: 3%;
padding: 0px 14px;
position: relative;
display: inline-block;
border: none;
cursor: pointer;
}
.dropbtn img {
opacity: 1.0;
width: 3%;
height: 3%;
min-width: 40px;
padding: 0px 16px;
-ms-transform: translateY(-10%);
transform: translateY(-10%);
}
.intro {
font-size: 24px;
color: #999;
}
.matrix {
font-size: 24px;
color: #ddd;
}
.headerlink {
font-size: 30px;
color: white;
}
.siteheadermain {
font-family: 'Rooters';
font-size: 50px;
color: white;
}
.siteheader {
font-size: 30px;
color: white;
}
.subheader {
font-size: 16px;
color: white;
}
.releaseheader {
font-size: 30px;
font-weight: bold;
color: yellow;
}
.releaseheader a:link {
color: yellow;
font-weight: bold;
}
footer {
float: right;
font-size: 18px;
}
@media screen and (min-width: 400px) {
body, html {
font-size: 22px;
}
.container img {
float: left;
max-width: 400px;
width: 5%;
padding: 0px 7px;
margin-right: 20px;
border-radius: 10%;
}
.container img.emojisearch {
float: right;
max-width: 400px;
width: 8%;
padding: 0px 7px;
margin-right: 20px;
border-radius: 10%;
}
.containericons img {
float: right;
max-width: 200px;
width: 3%;
margin: 0px 1%;
border-radius: 0%;
}
.timeline-avatar img {
opacity: 1.0;
width: 8%;
height: 8%;
padding: 0px 0px;
-ms-transform: translateY(-10%);
transform: translateY(-10%);
}
.cwButton {
border-radius: 4px;
background-color: #555;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 20px;
padding: 2px;
cursor: pointer;
margin: 5px;
}
.button {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 10%;
max-width: 100px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
}
.buttonselected {
border-radius: 4px;
background-color: #666;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 10%;
max-width: 100px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
}
.pageicon {
width: 4%;
}
.time-right {
float: right;
color: #aaa;
margin: 4px 20px;
}
input[type=text], select, textarea {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
margin-top: 6px;
margin-bottom: 16px;
resize: vertical;
font-size: 24px;
background-color: var(--main-bg-color-reply);
color: var(--main-fg-color);
}
input[type=button], input[type=submit] {
background-color: #555;
color: white;
float: right;
padding: 10px;
margin: 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: var(--font-size);
width: 20%;
}
input.vote[type=submit] {
background-color: #555;
color: white;
float: left;
padding: 10px;
margin: 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: var(--font-size);
width: 20%;
}
input[type=file] {
background-color: #555;
color: white;
padding: 20px;
margin: 0px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: var(--font-size);
width: 96%;
}
.cancelbtn {
background-color: #555;
color: white;
float: right;
padding: 10px;
margin: 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: var(--font-size);
width: 20%;
}
.scope-desc {
font-size: 32px;
}
.buttonunfollow {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 18px;
padding: 10px;
width: 20%;
max-width: 200px;
min-width: 100px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
float: right;
}
.intro {
font-size: 24px;
color: #999;
}
.headerlink {
font-size: 30px;
color: white;
}
.siteheader {
font-size: 30px;
color: white;
}
footer {
float: right;
font-size: 18px;
}
}
@media screen and (max-width: 1000px) {
body, html {
font-size: 35px;
}
.container img {
float: left;
max-width: 400px;
width: 15%;
padding: 0px 7px;
margin-right: 20px;
border-radius: 10%;
}
.container img.emojisearch {
float: right;
max-width: 400px;
width: 12%;
padding: 0px 7px;
margin-right: 20px;
border-radius: 10%;
}
.containericons img {
float: right;
max-width: 200px;
width: 7%;
margin: 1% 3%;
border-radius: 0%;
}
.timeline-avatar img {
opacity: 1.0;
width: 15%;
height: 15%;
padding: 0px 0px;
-ms-transform: translateY(-10%);
transform: translateY(-10%);
}
.cwButton {
border-radius: 4px;
background-color: #555;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 32px;
padding: 2px;
cursor: pointer;
margin: 5px;
}
.button {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 32px;
padding: 10px;
width: 20%;
max-width: 400px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 15px;
}
.buttonselected {
border-radius: 4px;
background-color: #666;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 32px;
padding: 10px;
width: 20%;
max-width: 400px;
min-width: 80px;
transition: all 0.5s;
cursor: pointer;
margin: 15px;
}
.pageicon {
width: 8%;
}
.time-right {
float: right;
color: #aaa;
margin: 25px 20px;
}
input[type=text], select, textarea {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
margin-top: 6px;
margin-bottom: 16px;
resize: vertical;
font-size: 30px;
background-color: var(--main-bg-color-reply);
color: var(--main-fg-color);
}
input[type=button], input[type=submit] {
background-color: #555;
color: white;
float: right;
padding: 10px;
margin: 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 30px;
width: 20%;
}
input.vote[type=submit] {
background-color: #555;
color: white;
float: left;
padding: 10px;
margin: 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 30px;
width: 20%;
}
input[type=file] {
background-color: #555;
color: white;
padding: 20px;
margin: 0px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 30px;
width: 95.4%;
}
.cancelbtn {
background-color: #555;
color: white;
float: right;
padding: 10px;
margin: 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 30px;
width: 20%;
}
.scope-desc {
font-size: 30px;
}
.buttonunfollow {
border-radius: 4px;
background-color: #999;
border: none;
color: #FFFFFF;
text-align: center;
font-size: 30px;
padding: 10px;
width: 20%;
max-width: 200px;
min-width: 100px;
transition: all 0.5s;
cursor: pointer;
margin: 5px;
float: right;
}
.intro {
font-size: 32px;
color: #999;
}
.headerlink {
font-size: 40px;
color: white;
}
.siteheader {
font-size: 40px;
color: white;
}
footer {
float: right;
font-size: 24px;
}
}
.imageright {
float: right;
}
.shell {
margin: 30px 30px;
width: 100%;
float: left;
font-family: Courier;
background-color: black;
}
</style>
<head>
<title>Epicyon ActivityPub server release version 1.7.0</title>
</head>
<body>
<center>
<br>
<p class="siteheadermain">Epicyon release version 1.7.0</p>
<p class="siteheader">"Courageous Corgi"</p>
<p class="subheader">Jan 11th 2026</p>
</center>
<p class="intro">It has been another year of highly exciting maintenance of the project, including the following changes:</p>
<div class="flex-container">
<ul>
<li>Option to block nostr bridges</li>
<li>Added translations for content warning lists</li>
<li>Reduced length of pages list to fit mobile screens</li>
<li>Show the instance software type on each post</li>
<li>Updated LLM crawler list</li>
<li>Bug fix: referer domain (Andreas Schreiner)</li>
<li>Changed default opacity for image watermarks</li>
<li>Support for DeltaChat link within profile</li>
<li>Default Terms Of Service changed for UK regulatory compliance</li>
<li>Added latest version of <a href="https://www.brailleinstitute.org/freefont">hyperlegible font</a></li>
<li>Ability to turn off recent posts preview on profile screen</li>
<li>Changed "Twitter" terminology to "x.com"</li>
<li>Limited support for quote toots and handling quote requests</li>
<li>Added quote approval policy to posts</li>
<li>Command option to check if a url is active</li>
<li>Log media uploaded for each account</li>
<li>When an account is suspended or removed its media is also suspended or removed</li>
<li>Improve detection of whether the instance is online (internet available)</li>
<li>Do not send posts if the instance is not online</li>
<li>Improve handling of locations</li>
<li>Add address to a post (eg. for events)</li>
<li>Show address together with location map, when applicable</li>
<li>Addresses shown on calendar events</li>
<li>Ability to block nicknames with wildcards</li>
<li>Support for event categories, and display of category with map</li>
<li>Do not include seconds on event times</li>
<li>Event categories treated the same as hashtags</li>
<li>Person options screen text santitsation</li>
<li>Current actor status shown on profile screen</li>
<li>Donation and blog links shown on searched for profiles</li>
<li>Rejection of BigTech corporate domains</li>
<li>Reject script kiddie attempts to access dot files</li>
<li>Default Terms Of Service indicates no intellectual property transfer</li>
<li>More esoteric unicode sanitisation for screen readers</li>
<li>Improve content warning list for AI slop websites</li>
<li>Default Code of Conduct forbids synthetic content</li>
<li>Warning for posts which only contain a single web link</li>
<li>Updated Gitlab continuous integration script</li>
<li>Export blogs in gemini and markdown format</li>
<li>Indicate posts coming from mutuals</li>
<li>Improved text mode browser page navigation</li>
<li>Be explicit about having no AI as a feature</li>
<li>Allow markdown-style headers within posts</li>
<li>Allow gemini-style link syntax within posts</li>
<li>Support for virtual locations</li>
<li>Improved validation on post reactions</li>
</ul>
</div>
<center>
<img src="v1_7_0.webp" alt="Epicyon logo of a running dog with paw prints in the background" />
</center>
<p class="intro">
The open social web continues to evolve at a glacial pace, but at least this does make it fairly easy to keep up with. Web standards are still the best way to go, with other more adhoc ones running into difficulties. It is clearer than ever that its either the Open Web, or barbarism, with increasingly less grey area between. Anything which is too centralized or too under the control of a single company seems doomed to a horrible fate. There is something to be said for being the last robust system standing after a bunch of hasty vibecoded crap has collapsed in a steaming heap.</p>
<p class="intro">Epicyon is designed for an anticipated glorious long term future of the ActivityPub protocol. It is written in the most tedious trend-avoiding way possible, with few dependencies, no database to get corrupted, suitable for running on old hardware at minimum cost, and definitely with <b>no "AI" features gratuitously foisted in</b>. In challenging environments, it can also run from an onion or i2p address and use text mode browsers with no risk from javascript exploits. While the industrial silicon valley behemoths are busy pumping out information pollution, and sinking into the swamp of <a href="https://en.wiktionary.org/wiki/enshittification#English">enshitification</a>, the small and meek gain advantage.</p>
<p class="intro">Epicyon will always be <a href="https://en.wikipedia.org/wiki/GNU_Affero_General_Public_License">AGPL</a> licensed, to nark off the whingers. Long live the digital commons!</p>
<p class="intro">It can be downloaded as <a href="epicyon.tar.gz">a gzipped file</a>, or you can get the latest version from the <a href="https://gitlab.com/bashrc2/epicyon">git repo</a>. For installation instructions see <a href="index.html">the main page</a>. To upgrade an existing instance, make sure that you have the <i>python3-cryptography</i> package installed then do a git pull, chown and restart the daemon.</p>
</body>
<footer>
<p>By: Bob Mottram <a href="mailto:bob@libreserver.org">bob@libreserver.org</a>
<img alt="Created by a human" src="img/created_by_a_human.png">
<img alt="Hand coded" src="img/hand_coded.png"></p>
</footer>
</html>