Apparently there’s a Lobsters Blog Carnival opens in a new tab all about the software & other projects you made for one singular person: yourself. I figured it would be a good excuse to finally talk about the thing that I made a while back for a very silly purpose and how it sorta spiraled out of control.
I made a Chrome extension for my sharefeed
Yup. I made myself a little Chrome extension that makes it easier for me to grab the metadata I need for sharefeed posts. It looks like this:
A screenshot of my sharefeed extension. The extension popout is titled "new sharefeed entry". here are single-line text input fields for the URL, title, and author of the article. There are also date input fields for the date the article was published and the date the article was accessed. There is a multi-line text input field for the note attached to the entry. A "generate" button generates the JSON for the entry in the "generated JSON" field, which is grayed out to indicate you cannot edit it, only copy and paste. In this screenshot, just the URL and date accessed fields are filled in.
Each attribute I need for an entry is included in a very minimal form with barely any styling. The URL and Date Accessed fields are automatically filled by grabbing the current URL and the current date respectively. The “generate” button generates the JSON needed to add the entry to the sharefeed, as the sharefeed is built from a JSON file.
If this was all this was, it would be pretty dumb… but there’s another trick up its sleeve. If you use the extension on specific websites, the metadata of the site is automatically filled into the form, making it so the only field you have to fill out is the note field! In fact, I just added support for it to Lobsters:
Another screenshot of my sharefeed extension. This time, all of the fields have been automatically filled in, save for the note field.
Now, creating a sharefeed entry is as easy as writing up a little blurb and clicking a button:
One last screenshot of my sharefeed extension showing what the generated JSON object for this entry would look like with a custom note finally filled in.
So wait, how does this work?
Most of the time, the metadata information is found by scraping the page for specific elements that contain the data we need.
First, we look for an “identifier”, or an element that lets us know what page we are on. For Lobsers, the main div element of the entry is given a class named story_liner, so if we can find that, we know we are on a Lobsters page. From there, we can find the title of the article from the anchor element with the u-url class and the author of the article from the anchor element with the u-author class.
Getting the published date of the article is slightly trickier. There is a <time> element within the “byline” div element that contains the “2 days ago” text. Thankfully, the actual datetime string we need for our purposes is handily included as an attribute of the time element, so all I need to do is get that datetime attribute in my code. It’s formatted a little weird, but it still works for my purposes.
A screenshot of the Lobsters entry used as an example in this blog post. The main header of the page is enclosed in a blue box labeled "div.story_liner". The title of the article is enclosed in a green box labeled "a.u-url". The author name in the byline is underlined in yellow and labeled "a.u-author". The fuzzy publish date in the byline is underlined in hot pink and labeled "time". This element has an attribute called "datetime" which contains the actual timestamp marking when the article was published.
Since I made my extension in JavaScript, here’s the full code of how the Lobsers integration is implemented:
// lobste.rs byline elements
const lobstersIdentElem = document.querySelector('div.story_liner');
if (lobstersIdentElem) {
entry.title = document.querySelector('a.u-url').textContent;
entry.author = document.querySelector('a.u-author').textContent;
const datetime = document.querySelector('div.byline').querySelector('time').getAttribute('datetime');
entry.publishedDate = new Date(datetime).toISOString().replace('Z', '');
}
Why did you make this?
I really like the idea of the sharefeed — a way to share articles, blogs, and other interesting documents on the Information Superhighway™ without much effort… but there is still some effort involved. There’s some effort I can’t reduce right now without massive restructuing (tl;dr: Dockerifying my website was kind of a bad idea), but some of it I can reduce to make it easier to actually use the thing I made for myself (…specifically to be low-effort lol).
This extension makes it a lot easier to draft sharefeed entries. I don’t need to write the JSON myself; the extension writes it for me. I don’t need to fill in all of the info from the website; the extension does it for me (on supported websites). All I need to do is copy and paste the JSON into my sharefeed file and I’m good to go!
…however, I still wanted this to do more…
The rabbit hole
I wanted this extension to eventually be able to publish sharefeed entries directly, so I didn’t even have to go through the rigmarole of adding the entry to the sharefeed file, making a new git commit and pushing it, and then dealing with deploying the new version fo the website… all of that could be taken care of through CI/CD and other shenanigans. Thankfully, there already exists a light protocol for submitting posts to a server: Micropub. opens in a new tab There’s even a browser extension for Micropub called Omnibear opens in a new tab that proves I can add a Micropub implementation to my sharefeed extension! While Micropub generally uses the h-entry opens in a new tab Microformat for its posts, for sharefeed entries, it makes more sense to me to use h-cite opens in a new tab as a basis, as it contains everything I need and not really anything I don’t. Here’s what the previous sharefeed entry would look like as an h-cite element in HTML:
<div class="h-cite">
<time class="dt-published">2025-09-25 04:48:30</time>
<time class="dt-accessed">2025-09-27 13:45:54</time>
<span class="p-author h-card">veqq</span>
<cite><a class="u-url p-name" href="https://lobste.rs/s/p3wmty/step_right_up_lobsters_blog_carnival">¡Step right up to the Lobsters! Blog! Carnival</a></cite>
<span class="p-content">A community event within the link aggregation website Lobsters asking users to write a blog post about a piece of software or other project they made for themselves. The inspiration for a blog post I am writing right now!</span>
</div>
If we translate into a JSON object, it looks suspicously like the sharefeed format we already had:
{
"dt-published": "2025-09-25 04:48:30",
"dt-accessed": "2025-09-27 13:45:54",
"p-author": "veqq",
"u-url": "https://lobste.rs/s/p3wmty/step_right_up_lobsters_blog_carnival",
"p-name": "¡Step right up to the Lobsters! Blog! Carnival",
"p-content": "A community event within the link aggregation website Lobsters asking users to write a blog post about a piece of software or other project they made for themselves. The inspiration for a blog post I am writing right now!"
}
So, we’ve got it all figured out! Just add a Micropub client to the extension, and we can publish sharefeed entries whenever we want!
…wait… where are we pushing sharefeed entries to?
The backend is, of course, the hard part
A Micropub client isn’t very useful if we don’t have a server to submit entries to. The easiest way to implement this would be to make it a part of my website. Astro has a bunch of useful RESTful API tools that makes an implementation like this really easy! …however, there are a couple of problems with this method.
With Micropub, OAuth2 authentication is required as part of the spec. During testing, I can cheat and just use a shared secret passed between the two, but in actual production, I would need to make an OAuth2 app that is implemented on the server-side… which is a little too complicated to shove into my website right now, even if I offload that stuff onto my Authentik server.
The main reason why I can’t just implement this in my website has to do with Astro itself: the only way to update the content directories within Astro’s contentlayer is to rebuild the entire site. This makes sense, considering Astro is mostly focused on statically generating its content, but it does mean any sharefeed updates requires the entire website to be updated, and thus the Docker image my site runs on to be rebuilt… which is a biiiiig oof moment.
The best way to fix this is to decouple the website’s content from the Astro contentlayer entirely, instead relying on RESTful API calls between the Astro website and a content management service to index and receive MDX content for rendering with Astro’s MDX pipeline. Of course, the problem with this method is that most content management programs are too heavy and/or not flexible enough to add Micropub support… so I would have to make the entire service myself, from scratch, probably on something like express.js opens in a new tab or hono. opens in a new tab I’ve actually gotten pretty far on an express.js implementation, but it’s definitely a lot of work that overwhelms me very quickly.
With that, I’ve reconsiled with the fact that this particular expansion is something I need to put on hold, at least until my cloud infrastructure is in a better place. Right now, I’m working on moving from Docker compose to Kubernetes to be able to work with multiple different VPS instances, so hopefully that will make implementing CI/CD for my website a little easier? I really hope????? please.
Despite everything, it still kinda fucks
I’m still really proud of this little Chrome extension. Even without the Micropub expansion, it just works and is feature-complete (there isn’t really anything else I need to add other than support for auto-fill on more websites). I finally made something that I can pretty much call “done” (for now), and it makes me feel very accomplished. I’m almost always halway home to Malamaroo: opens in a new tab I start projects easily, but I almost never finish them. While this project isn’t completely finished, it is at a state at which I can call it finished. Same with my blog — if I wanted to, I could just keep writing blog posts and journal entries for years and never once touch the infrastructure of my site and it will all just work. These projects are proof that, if I come with the right mindset and work ethic, I can actually make it home. I just need to remember that my rocketship needs fuel, not Christmas ornaments.
You can find my sharefeed extension on my personal Forgejo, opens in a new tab and while I don’t plan on putting it in the Chrome Web Store any time soon, you can always run it as a local extension like I am doing right now. I don’t really know why you would use it, as it is explicitly an extension only made for me, but if you do find a use for it, feel free to let me know! opens in a new tab
See y’all in December, I guess.