Replied to Yes to ActivityPub, but no to Friends by Shelley Powers (Burningbird)
I decided to disable the Friends plug-in when I realized it was inserting every new feed item as a new post in my database. This could easily become unmanageable. Considering you can use a feed reader to read weblogs AND Mastodon accounts, it just didn’t seem worth the database burden.

I’ve also been messing with the Friends and ActivityPub plugins for WordPress on my blog, and I share Shelley’s concerns about the former bloating the database with feed items. You can control this somewhat by setting retention values in days or a number of posts, but you have to go into each friend’s Feeds tab and do it manually–there’s no default setting.

After reading that post, I’m also considering disabling Friends in favor of a feed reader, especially because (as Shelley also noted) there are gaps when with favorites and comment conversations bridging between WordPress and Mastodon servers. Like her, I’m not keen on installing a single-​user Mastodon instance or other fediverse server that requires managing an unfamiliar programming language.

I’m also trying to do this in tandem with a suite of IndieWeb plugins, and I’m running into an issue with my friends feed page not showing any posts when the Post Kinds plugin is activated. I really want to keep this plugin because it lets me interact better with other IndieWeb sites as well as the Bridgy POSSE/​backfeed service connecting me to other social networks.

My ideal is a personal website where I write everything, including long-​form articles, short statuses, and replies like these. Folks can then find me via a single identifiable address and then subscribe/​follow the entire firehose of content or choose subsets according to post types, topics, or tags. They’d then be able to reply or react on my site or their favored platform, which my site would collect regardless of origin, with subsequent replies and reactions getting pushed out to them. Oh, and it should work with both ActivityPub clients and servers, IndieWeb sites, and syndicate/​backfeed to other social networks either with or akin to the Bridgy service I mentioned above.

So far I haven’t seen anything that ticks all these boxes, and I’m getting itchy to write my own. Perl is my favorite programming language, so I’m looking at the Yancy CMS as a base. But I know that it would still be a hell of a project, and one of the reasons I chose WordPress for blogging was that it was well-​established and ‑supported but still easily extensible so that I could concentrate on writing instead of endlessly tweaking the engine. Unfortunately, I’m starting to fall into that trap anyway.

Quoted 5 Reasons Why Using AI to Generate Blog Posts Can Destroy Your SEO by Dave Cross (Medium)
Using artificial intelligence (AI) to generate blog posts can be bad for search engine optimization (SEO) for several reasons. First and foremost, AI-generated content is often low quality and lacks…


(reads last line)

Wait a minute…

Liked snarfed/bridgy (GitHub)
Connects your web site to social media. Likes, retweets, mentions, cross-posting, and more... - GitHub - snarfed/bridgy: 📣 Connects your web site to social media. Likes, retweets, mentions, cross...

Been wiring up this blog for IndieWeb and Bridgy is the special sauce that connects it to more siloed social networks

IKEA BLÅHAJ shark toys

IKEA’s toy BLÅHAJ shark has become a beloved Internet icon over the past several years. I thought it might be cute to write a little Perl to get info about it and even display a cuddly picture right in the terminal where I’m running the code. Maybe this will give you some ideas for your own quick web clients. Of course, you could accomplish all of these things using a pipeline of individual command-​line utilities like curl, jq, and GNU coreutilsbase64. These examples focus on Perl as the glue, though.

Warning: dodgy API ahead

I haven’t found a publicly-​documented and ‑supported official API for querying IKEA product information but others have deconstructed the company’s web site AJAX requests so we can use that instead. The alternative would be to scrape the IKEA web site directly which, although possible, would be more tedious and prone to failure should their design change. An unofficial API is also unreliable but the simpler client code is easier to change should any errors surface.

Enter the Mojolicious

My original goal was to do this in a single line issued to the perl command, and luckily the Mojolicious framework’s ojo module is tailor-​made for such things. By adding a -Mojo switch to the perl command, you get over a dozen quick single-​character functions for spinning up a quick web application or, in our case, making and interpreting web requests without a lot of ceremony. Here’s the start of my one-​line request to the IKEA API for information on their BLÅHAJ product, using ojo’s g function to perform an HTTP GET and displaying the JSON from the response body to the terminal.

$ perl -Mojo -E 'say g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->body'

This currently returns over 2,400 lines of data, so after reading it over I’ll convert the response body JSON to a Perl data structure and dump only the main product information using ojo’s r function:

$ perl -Mojo -E 'say r g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}'
  "availability" => [],
  "breathTaking" => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ),
  "colors" => [
      "hex" => "0058a3",
      "id" => 10007,
      "name" => "blue"
      "hex" => "ffffff",
      "id" => 10156,
      "name" => "white"
  "contextualImageUrl" => "",
  "currencyCode" => "USD",
  "discount" => "",
  "features" => [],
  "gprDescription" => {
    "numberOfVariants" => 0,
    "variants" => []
  "id" => 90373590,
  "itemMeasureReferenceText" => "39 \x{bc} \"",
  "itemNo" => 90373590,
  "itemNoGlobal" => 30373588,
  "itemType" => "ART",
  "lastChance" => $VAR1->{"breathTaking"},
  "mainImageAlt" => "BL\x{c5}HAJ Soft toy, shark, 39 \x{bc} \"",
  "mainImageUrl" => "",
  "name" => "BL\x{c5}HAJ",
  "onlineSellable" => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
  "pipUrl" => "",
  "price" => {
    "decimals" => 99,
    "isRegularCurrency" => $VAR1->{"breathTaking"},
    "prefix" => "\$",
    "separator" => ".",
    "suffix" => "",
    "wholeNumber" => 19
  "priceNumeral" => "19.99",
  "quickFacts" => [],
  "tag" => "NONE",
  "typeName" => "Soft toy"

If I just want the price I can do:

$ perl -Mojo -E 'say g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}->@{qw(currencyCode priceNumeral)}'

That ->@{qw(currencyCode priceNumeral)} towards the end uses the postfix reference slicing syntax introduced experimentally in Perl v5.20 and made official in v5.24. If you’re using an older perl, you’d say:

$ perl -Mojo -E 'say @{g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}}{qw(currencyCode priceNumeral)}'

I prefer the former, though, because it’s easier to read left-to-right.

But I’m not in the United States! Where’s my native currency?

You can either replace the us/en” in the URL above or use the core I18N::LangTags::Detect module added in Perl v5.8.5 if you’re really determined to be portable across different users’ locales. This is really stretching the definition of one-​liner,” though.

$ LANG=de_DE.UTF-8 perl -Mojo -MI18N::LangTags::Detect -E 'my @lang = (split /-/, I18N::LangTags::Detect::detect)[1,0]; say g("" . join("/", @lang == 2 ? @lang : ("us", "en")) . "/search-result-page", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}->@{qw(currencyCode priceNumeral)}'

Window dressing

It’s hard to envision cuddling a number, but luckily the product information returned above links to a JPEG file in the mainImageUrl key. My favorite terminal app iTerm2 can display images inline from either a file or Base64 encoded data, so adding an extra HTTP request and encoding from the core MIME::Base64 module yields:

$ perl -Mojo -MMIME::Base64 -E 'say "\c[]1337;File=inline=1;width=100%:", encode_base64(g(g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}{mainImageUrl})->body), "\cG"'

(You could just send the image URL to iTerm2’s bundled imgcat utility, but where’s the fun in that?)

$ imgcat --url `perl -Mojo -E 'print g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}{mainImageUrl}'`

But I don’t have iTerm2 or a Mac!

I got you. At the expense of a number of other dependencies, here’s a version that will work on any terminal that supports 256-​color mode with ANSI codes using Image::Term256Color from CPAN and a Unicode font with block characters. I’ll also use Term::ReadKey to size the image for the width of your window. (Again, this stretches the definition of one-​liner.”)

$ perl -Mojo -MImage::Term256Color -MTerm::ReadKey -E 'say for Image::Term256Color::convert(g(g("", form => {types => "PRODUCT", q => "BLÅHAJ"})->json->{searchResultPage}{products}{main}{items}[0]{product}{mainImageUrl})->body, {scale_x => (GetTerminalSize)[0], utf8 => 1})'

I hate Mojolicious! Can’t you just use core modules?

Fine. Here’s retrieving the product price using HTTP::Tiny and the pure-​Perl JSON parser JSON::PP, which were added to core in version 5.14.

$ perl -MHTTP::Tiny -MJSON::PP -E 'say @{decode_json(HTTP::Tiny->new->get("ÅHAJ")->{content})->{searchResultPage}{products}{main}{items}[0]{product}}{qw(currencyCode priceNumeral)}'

Fetching and displaying a picture of the huggable shark using MIME::Base64 or Image::Term256Color as above is left as an exercise to the reader.