diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | serve.py | 12 | ||||
-rw-r--r-- | src/atom.sh | 41 | ||||
-rw-r--r-- | src/feed.ass | 3 | ||||
-rw-r--r-- | src/feeds.md | 129 | ||||
-rw-r--r-- | src/index.sh | 59 | ||||
-rw-r--r-- | src/tmpl.html | 55 |
8 files changed, 314 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1fcb152 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..46919a4 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +.PHONY: all +all: out/index.html out/feed.ass out/feed.atom + +out/index.html: src/index.sh src/feed.ass + sh $^ > $@ + +out/feed.ass: src/feed.ass + cp $< $@ + +out/feed.atom: src/feed.ass src/atom.sh + sh src/atom.sh < $< > $@ + +out/%.html: src/%.md src/tmpl.html + pandoc --template src/tmpl.html $< -o $@ diff --git a/serve.py b/serve.py new file mode 100644 index 0000000..3a43cc4 --- /dev/null +++ b/serve.py @@ -0,0 +1,12 @@ +from http.server import * +import os +import subprocess + +class MyHandler(SimpleHTTPRequestHandler): + def send_head(self): + path = self.translate_path(self.path) + path = os.path.relpath(path) + subprocess.run(["make", path]) + return super().send_head() + +HTTPServer(("localhost", 8080), MyHandler).serve_forever() diff --git a/src/atom.sh b/src/atom.sh new file mode 100644 index 0000000..cf694b3 --- /dev/null +++ b/src/atom.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# adapted from https://git.segvallday.org/ass2atom/file/ass2atom.html +# 0BSD License - Full text at the bottom of this file + +echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +echo "<feed xmlns=\"http://www.w3.org/2005/Atom\">" +echo "<title type=\"text\">dzwdz</title>" +echo "<updated>$(date -Iseconds)</updated>" +echo "<id>urn:uuid:677e5055-07e1-43d6-bd58-fda18d3c5277</id>" + +to_atom_entry() { + while read line; do + entry_date=$(echo "$line" | cut -f1) + entry_url=$(echo "$line" | cut -f2) + entry_title=$(echo "$line" | cut -f3) + echo "<entry>" + echo "<title>$entry_title</title>" + echo "<link href=\"$entry_url\"/>" + echo "<updated>${entry_date}T00:00Z</updated>" + echo "<id>${entry_url}?${entry_date}</id>" + echo "</entry>" + done +} + +grep -e "^[^#]" | sort -r | to_atom_entry +echo '</feed>' + +# BSD Zero Clause License +# +# Copyright (c) 2023 segvallday, adapted by dzwdz +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. diff --git a/src/feed.ass b/src/feed.ass new file mode 100644 index 0000000..df1a2b0 --- /dev/null +++ b/src/feed.ass @@ -0,0 +1,3 @@ +# actually simple syndication +# https://tilde.town/~dzwdz/ass/ +2023-05-25 https://tilde.town/~dzwdz/blog/feeds.html Linear feeds are a dark pattern diff --git a/src/feeds.md b/src/feeds.md new file mode 100644 index 0000000..1ee4aff --- /dev/null +++ b/src/feeds.md @@ -0,0 +1,129 @@ +--- +title: Linear feeds are a dark pattern +date: 2023-05-25 +--- +<style> +.vis { + border: 4px currentColor solid; + max-width: 35ch; + height: 15em; + overflow: scroll; + margin: auto; + margin-top: 6em; + padding: 1em; +} +.vis .post { + border: 1px solid currentColor; + margin-top: .5em; + padding: .5ch; +} +#vis2 button, #vis2 .day p { + display:inline; +} +.day { + text-align: center; +} +#vis1 .day:not(:first-child) { + margin-top: 1em; +} +#vis2 details { + margin-top: .5em; +} +#vis2 .post { + margin-left: 2ch; +} +</style> + +I like alternative, community-owned, social media. They have the potential to be much less user-hostile, and can be more mindful of the well-being of their users. Yet, pretty much all of them still copy one of the worst features of corporate social media -- the linear feed. Let me explain. + + +<div id="vis1" class="vis" aria-hidden="true"> +<div class="day">today</div> +<div class="post">@alice: lorem ipsum</div> +<div class="post">@alice: dolor sit amet</div> +<div class="post">@bob: consectetur adipiscing elit</div> +<div class="post">@alice: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</div> +<div class="post">@carol: ut enim ad minim veniam</div> +<div class="post">@alice: quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat</div> +<div class="post">@dave: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div> +<div class="post">@eve: excepteur sint occaecat cupidatat non proident</div> +<div class="post">@bob: sunt in culpa qui officia deserunt mollit anim id est laborum</div> +<div class="day">yesterday</div> +<div class="post">@alice: lorem ipsum</div> +<div class="post">@alice: dolor sit amet</div> +<div class="post">@bob: consectetur adipiscing elit</div> +<div class="post">@alice: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</div> +</div> + +## The linear feed + +We all know the feed. You open it, you are presented with a list of posts. +You scroll down more, and, if you see a post you've already seen, you're caught up. +It actually works pretty well with a small volume of posts. +But, as you follow more frequently-posting people, you'll go past the point of being able to see every post. +If you want to ensure you see updates from rarely posting friends, your only option is to keep scrolling -- otherwise they'll get lost in the noise from more frequent posters. Not that frequent posting means that your posts are less valuable -- but, generally speaking, I'd rather see 10 posts from 10 different friends, than 10 posts from 2 friends. I use social media to keep up with people, so I want to have at least a peek at everyone's lives. + +Now, sure, algorithmic feeds can sort of balance that out. But post frequency isn't the only metric by which we choose whose posts we care about the most. If I just e.g. went to a party with a few people, I'll want to see their posts first. An algorithm won't know about that. Furthermore, it still doesn't guarantee seeing posts from my very rarely posting best friend -- so I'll still end up compulsively scrolling a lot, just out of FOMO. + + +<div id="vis2" class="vis" aria-hidden="true"> + +<div class="day"> +<button disabled>later</button> today <button>earlier</button> +</div> + +<details><summary>@alice (4 posts)</summary> +<div class="post">lorem ipsum</div> +<div class="post">dolor sit amet</div> +<div class="post">sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</div> +<div class="post">quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat</div> +</details> + +<details><summary>@bob (2 posts)</summary> +<div class="post">consectetur adipiscing elit</div> +<div class="post">sunt in culpa qui officia deserunt mollit anim id est laborum</div> +</details> + +<details><summary>@carol (1 post)</summary> +<div class="post">enim ad minim veniam</div> +</details> + +<details><summary>@dave (1 post)</summary> +<div class="post">Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div> +</details> + +<details><summary>@eve (1 post)</summary> +<div class="post">excepteur sint occaecat cupidatat non proident</div> +</details> + +</div> +## A tree of posts +Around 2 years ago, I made an experimental Mastodon client. Instead of a feed, it presented you with a page per each day, each with a list of people who posted on that day. You could expand out everyone's posts -- but everything started out collapsed. +It let you see everything at a glance. +If any of your rarely posting friends posted something, you could prioritise them. Otherwise, you could indulge in the usual shitposting of your fedi-addicted friends. + +That was a pretty simple change, but it already heavily improved my fedi experience, while also reducing the overall time I've spent on social media. However, moving past the feed let me solve other issues too -- ones I didn't even notice before! +I was already organizing the posts by day, so I started showing the last passed day by default. Thanks to this, the page only changed once per day, unless I explicitly switched to the current day. This might sound insignificant, but once again, it made fedi *way* less addictive[^daily]. I no longer had a compulsion to open up Mastodon over and over again. If I visited it once, I had no reason to open it again until the next day. + +Now, the client was jank. I still had to fall back to the official client for many basic things. Yet, I still found myself heavily preferring it. I wasn't the only one, either! A friend has admitted that using my client has really helped them manage their social media usage. I felt the same. + +[^daily]: The same trick works for other kinds of content too. I used to have a daily cronjob which fetched the front pages of various feed aggregators, and it helped me reduce their use too -- without really missing out on anything. + +### Where's the client, then? + +Sadly, I quickly ran into limitations of the Mastodon API. It very obviously wasn't designed for anything but a linear feed. I could probably come up with cursed hacks to work around the issues I ran into[^api-issues], but I decided that wasn't worth the effort. +The only real way forward would be writing my own ActivityPub server, so I decided to shelve the project. + +[^api-issues]: I'm being purposefully vague about them. I don't believe they are/were an issue with Mastodon itself -- I was trying to use it in a very much unintended way. Furthermore, I didn't work this on so long I don't remember the details, and I'm not up to date on the current state of the API. + +## Recap +Linear feeds do a horrible job of letting the user prioritise posts, encouraging mindless scrolling so as to keep up with all their friends. My own experience leads me to believe that they're one of the main reasons why social media can be so addictive. +Abandoning them lets you view the issues of social media through a new lens -- one actually useful for solving them. + +Furthermore, current alternative social media doesn't seem to do a very good job of letting one experiment with alternatives to linear feeds. I hope this will be something that improves in the future. + +That being said, I'll admit to being out of touch with the current state of the Fediverse, or the broader alternative social media sphere. I used to be a regular Mastodon user ~~even before it was cool~~, but I've stopped using it even before the influx of Twitter users -- and probably of new developers, too. Still, from what I can tell, the situation hasn't improved too much since. + +<div class="sidenote"> +**déjà vu?** An [older version](gemini://tilde.town/~dzwdz/b/feeds.gmi) of this article was published on Gemini on 2023-02-17. +</div> diff --git a/src/index.sh b/src/index.sh new file mode 100644 index 0000000..9e0dbaa --- /dev/null +++ b/src/index.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# vim: set syntax=html: +set -e +cat <<EOF +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> + <link href="https://tilde.town/~dzwdz/blog/feed.atom" type="application/atom+xml" rel="alternate"/> + <title>dzwdz</title> + <style> +body { + max-width: 40ch; + font-family: sans-serif; + line-height: 1.3; + margin: 2em auto; + padding: 0 1ch; +} + +.sidenote { + border: 1px solid currentColor; + padding: 1ch; + margin: 3em 1ch; +} + +.sidenote > * { + margin: 0; +} + +h2, h3 { + margin-bottom: 0; + margin-top: 1.5em; +} + +span { + opacity: .5; + width: 10ch; + display: inline-block; + text-align: right; +} + </style> +</head> +<body> +<div><span>irc</span> +dzwdz on {<a href="https://libera.chat">libera</a>,<a href="https://tilde.chat">tilde</a>}.chat</div> +<div><span>email</span> +dzwdz at <a href="https://disroot.org">disroot</a></div> +<div><span>feeds</span> +<a href="https://tilde.town/~dzwdz/blog/feed.atom">atom</a>, +<a href="https://tilde.town/~dzwdz/blog/feed.ass">ass</a> +</div> +<br> +EOF + +awk -F"\t" '/^2/ { + print "<div><span>", $1, "</span>", + "<a href=\"", $2, "\">", $3, "</a></div>"; +}' $1 diff --git a/src/tmpl.html b/src/tmpl.html new file mode 100644 index 0000000..7f73c4d --- /dev/null +++ b/src/tmpl.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> + <link href="https://tilde.town/~dzwdz/blog/feed.atom" type="application/atom+xml" rel="alternate"/> + <title>$pagetitle$</title> + <style> +body { + max-width: 70ch; + font-family: sans-serif; + line-height: 1.3; + margin: 2em auto; + padding: 0 1ch; +} + +.sidenote { + border: 1px solid currentColor; + padding: 1ch; + margin: 3em 1ch; +} + +.sidenote > * { + margin: 0; +} + +h2, h3 { + margin-bottom: 0; + margin-top: 1.5em; +} + +header { border-bottom: 1px solid currentColor; } +h1 { margin: 0; } +header p { + margin: 0; + margin-bottom: .5em; +} + </style> +$for(header-includes)$ + $header-includes$ +$endfor$ +</head> +<body> +<header> +<h1>$title$</h1> +<p> +$if(date)$ +published on <span class="date">$date$</span> +$endif$ +by <a href="https://tilde.town/~dzwdz/">dzwdz</a> +</p> +</header> +$body$ +</body> +</html> |