Category: Blog

  • Fastest way to create Facebook events

    I’m helping the site: https://swingshoes.dk making a sign-up system for their members.

    They have many workshops and social events, that they wish to create on Facebook, since there are many users in there.

    But it’s a hassle to go to Facebook and click through the ‘Create event’-wizard every time, considering that those same information has just been inserted manually in another system. Plus also having to find a banner image and write a description that fits Facebook (with a link to the product), etc. etc.

    Solution attempt 1: Using Facebooks events API

    Facebook apparently closed their Events API in 2014 – and they’re very strict about using their API. Grrr!! Walled gardens!! Grrr!!

    Solution attempt 2: Finding vendors with custom API-permissions

    I understand that EventBrite has some further API-access, so one could try to go through them to do something automatically. But I can see that it doesn’t allow creation of events.

    I’m also kind of glad that this didn’t work, since it would have added complexity to the solution.

    Solution attempt 3: Other 3rd party solutions

    I also considered Zapier and n8n, but apparently Facebook has disallowed this.

    Solution attempt 4: Automated manual process

    So since Facebook wants to be like this, I figured: “How can I make this manual process as absolutely nice for myself as possible”. So what I did was, that I added a bunch of Claude API-magic to WordPress and added that to a meta-box on the product page. This way, I have all the fields served right there in front of me, so I just have to click a button and copy-paste fields:

    I also vibe-coded this script:

    (async () => {
      const sleep = ms => new Promise(r => setTimeout(r, ms));
      const TARGET = 500;
      const SKIP = [];
      const PRIORITY_FIRST_NAMES = [
        'Alan',
        'Aleksandra',
        'Øivind'
      ];
    
      let totalClicked = 0;
      let priorityClicked = 0;
      let randomClicked = 0;
      let skipped = 0;
      let idlePasses = 0;
    
      const scrollable = [...document.querySelectorAll('div')].find(d => {
        const style = getComputedStyle(d);
        return d.scrollHeight > d.clientHeight + 50 
          && d.clientHeight > 200 
          && (style.overflowY === 'auto' || style.overflowY === 'scroll');
      });
    
      if (!scrollable) {
        console.log('Could not find scrollable container. Try scrolling manually.');
      }
    
      // Helper: get name from a checkbox element
      const getName = (cb) => {
        const nameEl = cb.querySelector('span[dir="auto"] h2 span');
        return nameEl ? nameEl.textContent.trim() : '';
      };
    
      const getFirstName = (name) => name.split(' ')[0];
    
      const shouldSkip = (name) => SKIP.some(s => name.toLowerCase() === s.toLowerCase());
    
      const isPriority = (name) => PRIORITY_FIRST_NAMES.some(
        p => getFirstName(name).toLowerCase() === p.toLowerCase()
      );
    
      // --- Phase 1: Scroll through everything, selecting priority names ---
      console.log('--- Phase 1: Selecting priority first names ---');
      idlePasses = 0;
    
      while (idlePasses < 5) {
        const unchecked = document.querySelectorAll('div[role="checkbox"][aria-checked="false"]');
        let clickedThisRound = 0;
    
        for (const cb of unchecked) {
          const name = getName(cb);
          if (shouldSkip(name)) { skipped++; continue; }
    
          if (isPriority(name)) {
            cb.click();
            clickedThisRound++;
            totalClicked++;
            priorityClicked++;
            if (clickedThisRound % 5 === 0) await sleep(100);
          }
        }
    
        if (scrollable) scrollable.scrollTop = scrollable.scrollHeight;
    
        idlePasses = clickedThisRound === 0 ? idlePasses + 1 : 0;
        console.log(`Phase 1 — Priority selected: ${priorityClicked} | Skipped: ${skipped} (idle: ${idlePasses}/5)`);
        await sleep(1000);
      }
    
      console.log(`Phase 1 done! Selected ${priorityClicked} priority names.`);
    
      // --- Phase 2: Randomly select from remaining until TARGET ---
      console.log(`--- Phase 2: Randomly selecting until ${TARGET} total ---`);
    
      const remaining = totalClicked < TARGET ? TARGET - totalClicked : 0;
    
      if (remaining > 0) {
        // Gather all unchecked, non-skipped checkboxes
        const allUnchecked = [...document.querySelectorAll('div[role="checkbox"][aria-checked="false"]')]
          .filter(cb => !shouldSkip(getName(cb)));
    
        console.log(`Found ${allUnchecked.length} remaining unchecked followers to pick from.`);
    
        // Shuffle using Fisher-Yates
        for (let i = allUnchecked.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [allUnchecked[i], allUnchecked[j]] = [allUnchecked[j], allUnchecked[i]];
        }
    
        for (const cb of allUnchecked) {
          if (totalClicked >= TARGET) break;
          cb.click();
          totalClicked++;
          randomClicked++;
          if (randomClicked % 5 === 0) await sleep(100);
        }
      }
    
      console.log(`Done! Total: ${totalClicked} (${priorityClicked} priority + ${randomClicked} random). Skipped: ${skipped}.`);
      console.log('You can now manually review and send.');
    })();

    … which one can copy/paste into the developer console, so it automatically marks people to invite, until TARGET is reached (500). This way, it’s possible to click an audience or a group and then within seconds invite them all to the event.

    Here is the result: https://www.facebook.com/events/903885798693760/

    It’s actually fairly okay. Now it takes less than a minute to do manually.

  • RSS Reader and news habits

    Every so often, I come back to the thought: “I wish I had a better flow of reading news/content”. If I don’t stay intentional with this, I feel like I bounce around whatever is the most fun or simply the path of least resistance. I often try to create habits, to nudge me in better directions – or keep me away from poor ones.

    Such as paying for the UnDistract Chrome Extension. Or deleting my Instagram account.

    I’ve tried setting up an RSS Reader a couple of times, and each time it slips out of my habits. I remember CGP Grey once saying (paraphrasing): “When trying to implement behavioural change ‘trying harder’ is the dumbest strategy there is”.

    RSS Readers

    Feedly

    I’ve tried using Feedly a couple of times, and every time it slips out of my habits to check it. And I kept blaming myself for it. But thinking about it, it is very revolved around ‘Today’ or ‘Newest’ post and ‘Being “done” today’. That, and the fact they they are desperately trying to implement some ‘AI Features’, that I’m not interested in, makes the interface muddy and annoying.

    Reeder.

    I’m trying to use this now, to see how that goes.

    Further reading

    Challenges

    Now I have a place to post my challenges with this setup, as I come across it. If I found solutions for it, I’ll write that as well.

    Challenge #1: People posting too much

    Look at this feed here:

    I don’t know how to solve, that Simon Willison and John Gruber posts as often as they do. They drown my feed. I’m not sure, how to solve this. I saw that RSS Reeder has some ‘Filter’-feature in the paid version, that I’ll try to give a whack. But do I then categorize/filter my RSS sources based on the frequency they post stuff.

    I should try to setup some filters.

    Challenge #2: Feeling stupid

    A situation that often happen, whenever I come back to the RSS ways, is that I end up feeling stupid. When browsing the web, I don’t think about how easily digestible the news are.

    But the things I wish I was reading more, is stuff like these:

    And it’s not that light reading, that stuff.

    I should definitely try to setup some filters.

    My own attempts and tricks

    • By subscribing to my own blog, in my RSS Reader, I can see how potential other subscribers see my content.
    • I think I’ll try to be dynamic in adding and removing feeds. So if something annoys me, either try to filter it – or unsubscribe it temporarily. Hoping that I gradually improve my feed to fit my current state of mind and interest.
  • Beginning of my Blog

    When setting up my new RSS Reader, I came across this blog post: https://www.swyx.io/learn-in-public . I severely liked it. Initially, I felt it was anxiety invoking, to publicly ask and answer all my stupid questions.

    But I really like it. In this world, where we consume so much from the internet, if feels good to, in whatever shape or form, contribute back to it.

    And also, I hope that I can use the internet a little bit as my accountability partner.