@PinoBatch @Rairii Unfamiliar with #SmallWeb, but fedi is federated.. we all join one of a smaller number of servers that talk to one another (like Mastodon). #Indieweb is, well, indie-- you have your site, I have mine, but we can talk to one another. The longer I hack, the more I prefer the latter.

@Rairii I'm not sure how "the social web" distinguishes fedi from #IndieWeb or Aral Balkan's #SmallWeb, which are more based on each user running their own website on their own domain.

Blogged: Why organisations should have an indieweb publication strategy (or: why ITFC should have an RSS feed) ✍️ The social media behemoths are dying, so you need a plan B for making sure you can communicate with the outside world. And that’s having an RSS feed and POSSE-ing.

🏷 #ITFC #IndieWeb #POSSE #RSS
https://www.thisdaysportion.com/posts/itfc-indieweb/

Community gardening for pop-ups and Pythons. It’s your < 10min update on the #IndieWeb community!

This Week in the IndieWeb audio edition for June 24th - 30th, 2023. https://martymcgui.re/2023/07/01/this-week-in-the-indieweb-audio-edition--june-24th---30th-2023/

This Week in the IndieWeb Audio Edition • June 24th - 30th, 2023

#podcast #IndieWeb #this-week-indieweb-podcast

Community gardening for pop-ups and Pythons. It’s your < 10min update on the #IndieWeb community!


This Week in the IndieWeb audio edition for June 24th - 30th, 2023.
https://martymcgui.re/2023/07/01/this-week-in-the-indieweb-audio-edition--june-24th---30th-2023/

Here's a short Rust program using the microformats crate that checks the presence of a webmention on a certain page, properly resolving all URLs and even scanning HTML content in entry["properties"]["content"].

use std::cell::{RefCell, Ref};
use std::rc::Rc;

use clap::Parser;
use microformats::types::PropertyValue;
use microformats::html5ever;
use microformats::html5ever::tendril::TendrilSink;

#[derive(thiserror::Error, Debug)]
enum Error {
    #[error("http request error: {0}")]
    Http(#[from] reqwest::Error),
    #[error("microformats error: {0}")]
    Microformats(#[from] microformats::Error),
    #[error("json error: {0}")]
    Json(#[from] serde_json::Error),
    #[error("url parse error: {0}")]
    UrlParse(#[from] url::ParseError),
}

#[derive(Debug)]
enum MentionType {
    Reply,
    Like,
    Repost,
    Bookmark,
    Mention
}

fn check_mention(document: impl AsRef<str>, base_url: &url::Url, link: &url::Url) -> Result<Option<MentionType>, Error> {
    // First, check the document for MF2 markup
    let document = microformats::from_html(document.as_ref(), base_url.clone())?;

    // Get an iterator of all items
    let items_iter = document.items.iter()
        .map(AsRef::as_ref)
        .map(RefCell::borrow);

    for item in items_iter {
        let props = item.properties.borrow();
        for (prop, interaction_type) in [
            ("in-reply-to", MentionType::Reply), ("like-of", MentionType::Like),
            ("bookmark-of", MentionType::Bookmark), ("repost-of", MentionType::Repost)
        ] {
            if let Some(propvals) = props.get(prop) {
                for val in propvals {
                    if let PropertyValue::Url(url) = val {
                        if url == link {
                            return Ok(Some(interaction_type))
                        }
                    }
                }
            }
        }
        // Process `content`
        if let Some(PropertyValue::Fragment(content)) = props.get("content")
            .map(Vec::as_slice)
            .unwrap_or_default()
            .first()
        {
            let root = html5ever::parse_document(html5ever::rcdom::RcDom::default(), Default::default())
                .from_utf8()
                .one(content.html.to_owned().as_bytes())
                .document;

            // This is a trick to unwrap recursion into a loop
            //
            // A list of unprocessed node is made. Then, in each
            // iteration, the list is "taken" and replaced with an
            // empty list, which is populated with nodes for the next
            // iteration of the loop.
            //
            // Empty list means all nodes were processed.
            let mut unprocessed_nodes: Vec<Rc<html5ever::rcdom::Node>> = root.children.borrow().iter().cloned().collect();
            while unprocessed_nodes.len() > 0 {
                // "Take" the list out of its memory slot, replace it with an empty list
                let nodes = std::mem::take(&mut unprocessed_nodes);
                for node in nodes.into_iter() {
                    // Add children nodes to the list for the next iteration
                    unprocessed_nodes.extend(node.children.borrow().iter().cloned());

                    if let html5ever::rcdom::NodeData::Element { ref name, ref attrs, .. } = node.data {
                        // If it's not `<a>`, skip it
                        if name.local != *"a" { continue; }
                        for attr in attrs.borrow().iter() {
                            // if it's not `<a href="...">`, skip it 
                            if attr.name.local != *"href" { continue; }
                            // Be forgiving in parsing URLs, and resolve them against the base URL
                            if let Ok(url) = base_url.join(attr.value.as_ref()) {
                                if &url == link {
                                    return Ok(Some(MentionType::Mention));
                                }
                            }
                        }
                    }
                }
            }
            
        }
    }

    Ok(None)
}

#[derive(Parser, Debug)]
#[clap(
    name = "kittybox-check-webmention",
    author = "Vika <vika@fireburn.ru>",
    version = env!("CARGO_PKG_VERSION"),
    about = "Verify an incoming webmention"
)]
struct Args {
    #[clap(value_parser)]
    url: url::Url,
    #[clap(value_parser)]
    link: url::Url
}

#[tokio::main]
async fn main() -> Result<(), self::Error> {
    let args = Args::parse();
    
    let http: reqwest::Client = {
        #[allow(unused_mut)]
        let mut builder = reqwest::Client::builder()
            .user_agent(concat!(
                env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")
            ));

        builder.build().unwrap()
    };

    let response = http.get(args.url.clone()).send().await?;
    let text = response.text().await?;
    
    if let Some(mention_type) = check_mention(text, &args.url, &args.link)? {
        println!("{:?}", mention_type);

        Ok(())
    } else {
        std::process::exit(1)
    }
}
#Kittybox #Rust #microformats2 #IndieWeb

This seems extremely cool. I am 100% here for nntp in all its glory and warts.

https://dialup.cafe/@vga256/110637361651638656 #Indieweb #retro #technology

searching for a recipe

on the limits of searching for a recipe online, the problem with search engines, the problem with subscriptions, and the futility of trying to clean up this mess.

https://alexsirac.com/searching-for-a-recipe/

#cooking #en #indieWeb #recipe #SearchEngines

indieweb carnival

Just found out about the first edition of the IndieWeb Carnival, which is for June 2023. Of course, today is July 1st and I had to find about it today.

I'll try to keep an eye on the July one and see if it inspires me!

https://alexsirac.com/indieweb-carnival/

#en #indieWeb #WritingPrompts

That Man: The Outerworlds formed the Federation because they had to. At least, that's the "official" story. A Distant Stars tale.

This story is exclusive for blog subscribers, so do subscribe to the blog to read the story* :)

* I am mirroring my #Substack content on my website as you should. #IndieWeb, baby!

#Fiction #Writing #WritingCommunity
https://firediarist.wordpress.com/2023/07/01/that-man/

To continue my thoughts on why I left the #Apple ecosystem. It's the same reason why I left #Twitter #Facebook for #Mastodon. Why I embraced #IndieWeb and now blog the POSSE/PESOS way.
I realised that Apple products, shiny and high quality as they are, was trapping me in their ecosystem. I hated having to upgrade just because they deemed my device "too old". I hate having to buy a new thingamajic when my old dongle worked just fine - just because Apple removed a port. 1/3

There are real downsides to running my website on VPS I sysadmin myself & a homegrown pile of code in JavaScript, Python, Swift, and Zsh. The code is all over the place in every sense of the phrase.

But I can personally guarantee that it'll keep working and remain available so long as I can afford the DNS and VPS fees. I can't say that about any other place I post on the internet.

Own your own space on the web. Post there. Write there. Link to it from your various accounts elsewhere. #indieweb

DECEMBER 1994 AND HOW ARNIE KATZ CHANGED MY LIFE

Remembering a long lost friend who made things seem possible for a nerdy teenage fanboy.

#Retrocomputing #retrogaming #fanzines #magazines #diy #VideoGames #industrialmusic #Developers #indiedev #indieweb

(Reposting with tags for communities who might dig it)

https://ndd.funkatron.com/december-1994-and-how-arnie-katz-changed-my-life/

Today’s #FollowFriday:

- @decius for his work on https://news.feedseer.com/, an excellent personal aggregation of one’s feed
- @pfefferle for his great and persistent work on #Fediverse / #DiSo / #IndieWeb plug-ins for #WordPress over the last decade(?) which recently landed him a job at Automattic

The potential is there, but it doesn’t do that right now. I doubt Emissary would implement (for example) the Twitter or Facebook APIs like traditional #IndieWeb POSSE — but I am aiming at additional open PROTOCOLS, with BlueSky as a potential in the future. So, yes? Kinda? If you blur the definition of “Syndicate Elsewhere” @rmdes @shoq

@benpate @scottjenson Oh, but there is no need to _host_ your reply within your reader, you simply have to be able to _write_ your response within your reader.

Eg: I use @ivory as a client for my Mastodon account and it both reads and writes to that Mastodon account (using the Mastodon-specific API?)

With #indieweb it instead could do:

- Read the content using a standard protocol like #MicroSub: https://indieweb.org/Microsub
- Write any actions / replies using #MicroPub: https://indieweb.org/Micropub

@scottjenson The worst part of most current #Fediverse implementations:

They bundle the reader part and the publishing part.

It’s like bundling Google Reader within WordPress.

Totally needless. (And something I think the #IndieWeb is getting more right with eg #MicroPub, ensuring reading, aggregation, publishing etc doesn’t have to all be in a single application / server)

I'm gonna have to do more #IndieWeb publishing my own content on my own site, aren't I. Mastodon isn't meant to be a long term stable host of content any more than Twitter is, as much as we might wish for it.

Promising sweet goodies over here, star this repo and if you're a #Go developer, reach out to @benpate

https://github.com/EmissarySocial/emissary

#indieweb #godev #golang #fediverse #activitypub