<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Aidan Maurin-Jones</title><link>https://blog.aidanmaurinjones.com/</link><description>Aidan Maurin-Jones shares tools, automations, and thoughts on whatever’s interesting this week.</description><language>en</language><atom:link href="https://blog.aidanmaurinjones.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Building a Smarter Home, One Screen at a Time</title><link>https://blog.aidanmaurinjones.com/posts/building-a-smarter-home-one-screen-at-a-time/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/building-a-smarter-home-one-screen-at-a-time/</guid><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><description><![CDATA[<p>There&rsquo;s a certain point in any Home Assistant setup where dashboards stop feeling like control panels and start feeling like compromises.</p>
<p>Too many taps. Too many menus. Too much &ldquo;smart&rdquo; layered on top of what should be instant.</p>
<p>So instead of fighting the UI, I built my own.</p>
<h3 id="the-touch-panel-that-replaced-everything">The Touch Panel That Replaced Everything</h3>
<p>At the centre of this setup is a Waveshare ESP32-S3 touchscreen running ESPHome with LVGL. No Android tablet. No iPad. No cloud dependencies. Just a purpose-built interface that does exactly what it needs to&ndash;and nothing more.</p>
<p>The entire UI is a 5×5 grid of buttons.</p>
<p>That&rsquo;s it.</p>
<p>And that&rsquo;s the point.</p>
<p>Each button maps directly to something real in the room: TVs, lights, curtains, chargers. Tap it, and it happens instantly. No animations, no loading states, no second-guessing whether the command actually went through.</p>
<p>What makes it work isn&rsquo;t just the layout&ndash;it&rsquo;s the feedback loop. Every button reflects the <em>actual</em> state from Home Assistant in real time. If a device is unavailable, the button disables itself. If something turns on elsewhere, the panel updates immediately. It&rsquo;s not a remote. It&rsquo;s a live mirror of the system.</p>
<p>There&rsquo;s no abstraction layer to fight against.</p>
<h2 id="designing-for-real-life-not-demos">Designing for Real Life, Not Demos</h2>
<p>A lot of smart home interfaces are designed like they&rsquo;re being shown off, not used.</p>
<p>This one is designed around how things actually happen:</p>
<ul>
<li>Walking into a room → tap one button</li>
<li>Going to bed → hit the alarm page</li>
<li>Leaving → glance, confirm, done</li>
</ul>
<p>The grid layout isn&rsquo;t flashy, but it&rsquo;s predictable. Muscle memory kicks in fast. After a few days, you&rsquo;re not <em>looking</em> for buttons anymore&ndash;you&rsquo;re just pressing them.</p>
<p>Even small decisions matter:</p>
<ul>
<li><strong>Large tap targets</strong> so you never miss</li>
<li><strong>Consistent placement</strong> so nothing moves around</li>
<li><strong>No scrolling, ever</strong></li>
</ul>
<p>It behaves more like a physical control panel than an app.</p>
<h3 id="the-screen-that-knows-when-to-get-out-of-the-way">The Screen That Knows When to Get Out of the Way</h3>
<p>One of the most underrated parts of this setup is what happens when you <em>don&rsquo;t</em> use it.</p>
<p>After 30 seconds of inactivity, the display shuts off. Completely. Backlight off, LVGL paused, even a subtle &ldquo;snow&rdquo; effect to prevent burn-in.</p>
<p>Touch the screen again, and it wakes instantly&ndash;right back to where you left it.</p>
<p>It&rsquo;s a small detail, but it changes how the panel feels. It&rsquo;s not constantly glowing in the background. It&rsquo;s not demanding attention. It&rsquo;s just there when you need it.</p>
<p>And gone when you don&rsquo;t.</p>
<h3 id="a-dedicated-alarm-interface-that-feels-right">A Dedicated Alarm Interface That Feels Right</h3>
<p>The second half of the project is something I&rsquo;m disproportionately proud of: a dedicated alarm page.</p>
<p>Instead of cramming alarm controls into the main UI, it gets its own space&ndash;with a layout inspired by old-school physical keypads.</p>
<p>Mode buttons on the left. Keypad on the right. Code entry front and centre.</p>
<p>It behaves exactly how you expect:</p>
<ul>
<li>Enter a code → it masks with asterisks</li>
<li>Arm/disarm → sends directly to Home Assistant</li>
<li>Alarm triggers → screen turns on automatically and switches pages</li>
</ul>
<p>There&rsquo;s even a small touch that makes a big difference: when the system is arming, the display changes to &ldquo;Arming…&rdquo; instead of sitting there blankly.</p>
<p>It feels responsive. Intentional. Alive.</p>
<h3 id="why-this-works-better-than-a-tablet">Why This Works Better Than a Tablet</h3>
<p>A tablet can do more. That&rsquo;s exactly why it&rsquo;s worse for this job.</p>
<p>This panel is:</p>
<ul>
<li><strong>Instant</strong> &ndash; no OS, no background apps, no lag</li>
<li><strong>Local-first</strong> &ndash; nothing breaks if the internet drops</li>
<li><strong>Single-purpose</strong> &ndash; no distractions, no drift</li>
<li><strong>Ridiculously efficient</strong> &ndash; barely sips power</li>
</ul>
<p>Most importantly, it removes friction.</p>
<p>You don&rsquo;t <em>think</em> about using it. You just do.</p>
<h3 id="the-real-upgrade-wasnt-hardware">The Real Upgrade Wasn&rsquo;t Hardware</h3>
<p>The hardware is nice. The ESP32-S3 is more than capable. LVGL is flexible enough to build anything you want.</p>
<p>But the real upgrade is philosophical.</p>
<p>Instead of adapting to someone else&rsquo;s idea of a smart home interface, this setup flips the equation:</p>
<p>The interface adapts to you.</p>
<p>No unnecessary features. No forced workflows. No compromises.</p>
<p>Just a grid of buttons that does exactly what you expect&ndash;every single time.</p>
<p>If anything, this project proves something simple:</p>
<p>The best smart home UI isn&rsquo;t the one with the most features.</p>
<p>It&rsquo;s the one you stop noticing entirely.</p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>There&rsquo;s a certain point in any Home Assistant setup where dashboards stop feeling like control panels and start feeling like compromises.</p>
<p>Too many taps. Too many menus. Too much &ldquo;smart&rdquo; layered on top of what should be instant.</p>
<p>So instead of fighting the UI, I built my own.</p>
<h3 id="the-touch-panel-that-replaced-everything">The Touch Panel That Replaced Everything</h3>
<p>At the centre of this setup is a Waveshare ESP32-S3 touchscreen running ESPHome with LVGL. No Android tablet. No iPad. No cloud dependencies. Just a purpose-built interface that does exactly what it needs to&ndash;and nothing more.</p>
<p>The entire UI is a 5×5 grid of buttons.</p>
<p>That&rsquo;s it.</p>
<p>And that&rsquo;s the point.</p>
<p>Each button maps directly to something real in the room: TVs, lights, curtains, chargers. Tap it, and it happens instantly. No animations, no loading states, no second-guessing whether the command actually went through.</p>
<p>What makes it work isn&rsquo;t just the layout&ndash;it&rsquo;s the feedback loop. Every button reflects the <em>actual</em> state from Home Assistant in real time. If a device is unavailable, the button disables itself. If something turns on elsewhere, the panel updates immediately. It&rsquo;s not a remote. It&rsquo;s a live mirror of the system.</p>
<p>There&rsquo;s no abstraction layer to fight against.</p>
<h2 id="designing-for-real-life-not-demos">Designing for Real Life, Not Demos</h2>
<p>A lot of smart home interfaces are designed like they&rsquo;re being shown off, not used.</p>
<p>This one is designed around how things actually happen:</p>
<ul>
<li>Walking into a room → tap one button</li>
<li>Going to bed → hit the alarm page</li>
<li>Leaving → glance, confirm, done</li>
</ul>
<p>The grid layout isn&rsquo;t flashy, but it&rsquo;s predictable. Muscle memory kicks in fast. After a few days, you&rsquo;re not <em>looking</em> for buttons anymore&ndash;you&rsquo;re just pressing them.</p>
<p>Even small decisions matter:</p>
<ul>
<li><strong>Large tap targets</strong> so you never miss</li>
<li><strong>Consistent placement</strong> so nothing moves around</li>
<li><strong>No scrolling, ever</strong></li>
</ul>
<p>It behaves more like a physical control panel than an app.</p>
<h3 id="the-screen-that-knows-when-to-get-out-of-the-way">The Screen That Knows When to Get Out of the Way</h3>
<p>One of the most underrated parts of this setup is what happens when you <em>don&rsquo;t</em> use it.</p>
<p>After 30 seconds of inactivity, the display shuts off. Completely. Backlight off, LVGL paused, even a subtle &ldquo;snow&rdquo; effect to prevent burn-in.</p>
<p>Touch the screen again, and it wakes instantly&ndash;right back to where you left it.</p>
<p>It&rsquo;s a small detail, but it changes how the panel feels. It&rsquo;s not constantly glowing in the background. It&rsquo;s not demanding attention. It&rsquo;s just there when you need it.</p>
<p>And gone when you don&rsquo;t.</p>
<h3 id="a-dedicated-alarm-interface-that-feels-right">A Dedicated Alarm Interface That Feels Right</h3>
<p>The second half of the project is something I&rsquo;m disproportionately proud of: a dedicated alarm page.</p>
<p>Instead of cramming alarm controls into the main UI, it gets its own space&ndash;with a layout inspired by old-school physical keypads.</p>
<p>Mode buttons on the left. Keypad on the right. Code entry front and centre.</p>
<p>It behaves exactly how you expect:</p>
<ul>
<li>Enter a code → it masks with asterisks</li>
<li>Arm/disarm → sends directly to Home Assistant</li>
<li>Alarm triggers → screen turns on automatically and switches pages</li>
</ul>
<p>There&rsquo;s even a small touch that makes a big difference: when the system is arming, the display changes to &ldquo;Arming…&rdquo; instead of sitting there blankly.</p>
<p>It feels responsive. Intentional. Alive.</p>
<h3 id="why-this-works-better-than-a-tablet">Why This Works Better Than a Tablet</h3>
<p>A tablet can do more. That&rsquo;s exactly why it&rsquo;s worse for this job.</p>
<p>This panel is:</p>
<ul>
<li><strong>Instant</strong> &ndash; no OS, no background apps, no lag</li>
<li><strong>Local-first</strong> &ndash; nothing breaks if the internet drops</li>
<li><strong>Single-purpose</strong> &ndash; no distractions, no drift</li>
<li><strong>Ridiculously efficient</strong> &ndash; barely sips power</li>
</ul>
<p>Most importantly, it removes friction.</p>
<p>You don&rsquo;t <em>think</em> about using it. You just do.</p>
<h3 id="the-real-upgrade-wasnt-hardware">The Real Upgrade Wasn&rsquo;t Hardware</h3>
<p>The hardware is nice. The ESP32-S3 is more than capable. LVGL is flexible enough to build anything you want.</p>
<p>But the real upgrade is philosophical.</p>
<p>Instead of adapting to someone else&rsquo;s idea of a smart home interface, this setup flips the equation:</p>
<p>The interface adapts to you.</p>
<p>No unnecessary features. No forced workflows. No compromises.</p>
<p>Just a grid of buttons that does exactly what you expect&ndash;every single time.</p>
<p>If anything, this project proves something simple:</p>
<p>The best smart home UI isn&rsquo;t the one with the most features.</p>
<p>It&rsquo;s the one you stop noticing entirely.</p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>A Remote That Finally Belongs to You</title><link>https://blog.aidanmaurinjones.com/posts/a-remote-that-finally-belongs-to-you/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/a-remote-that-finally-belongs-to-you/</guid><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><description><![CDATA[<p>Most people think of IR remotes as relics. Dumb plastic wands that exist purely to be lost in couch cushions and die at the worst possible moment.</p>
<p>But strip away the UX sins and what you&rsquo;re left with is something surprisingly powerful: instant, local, zero-latency control.</p>
<p>This ESPHome-based IR node leans into that idea hard.</p>
<p>At its core, it&rsquo;s an ESP8266 (ESP8285 board) running both a receiver and transmitter. That alone isn&rsquo;t special. What makes it interesting is how it&rsquo;s wired into Home Assistant&ndash;not as a workaround, but as a first-class control layer.</p>
<h3 id="ir-as-input-not-just-output">IR as Input, Not Just Output</h3>
<p>Most setups treat IR as a one-way street: send commands, hope for the best.</p>
<p>Here, the remote becomes a trigger device.</p>
<p>Specific NEC codes&ndash;like the colored buttons on an LG remote&ndash;are mapped directly to Home Assistant actions:</p>
<ul>
<li>Pink button → toggle TV lights</li>
<li>Green button → toggle bedroom light</li>
<li>Yellow button → toggle soundbar power</li>
<li>Blue button → toggle TV power</li>
</ul>
<p>No cloud. No polling. No delay. Press button → thing happens.</p>
<p>That&rsquo;s the entire philosophy.</p>
<p>And because it&rsquo;s ESPHome, you&rsquo;re not stuck with whatever some manufacturer thought was useful. You decide what every button means.</p>
<h3 id="the-quiet-killer-feature-ir-proxy">The Quiet Killer Feature: IR Proxy</h3>
<p>Buried in this config is something that feels like a glimpse into the future:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>    <span style="color:#f92672">infrared</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">ir_rf_proxy</span>
</span></span></code></pre></div><p>Right now, it&rsquo;s rough. Definitely not plug-and-play. But conceptually? It&rsquo;s huge.</p>
<p>This is the beginning of IR becoming network-native inside Home Assistant.</p>
<p>Instead of:</p>
<ul>
<li>Capturing codes manually</li>
<li>Writing YAML</li>
<li>Flashing firmware</li>
</ul>
<p>You eventually get:</p>
<ul>
<li>Discoverable IR devices</li>
<li>Reusable command sets</li>
<li>Shared control layers</li>
</ul>
<p>In other words, IR stops being a hack and starts acting like a real integration.</p>
<p>We&rsquo;re not fully there yet&ndash;but this is the direction.</p>
<h3 id="output-still-matters">Output Still Matters</h3>
<p>On the flip side, the transmitter side is just as important.</p>
<p>Every key TV function is exposed as a Home Assistant button:</p>
<ul>
<li>Power</li>
<li>Volume up/down</li>
<li>Mute</li>
<li>Navigation</li>
<li>Playback</li>
</ul>
<p>Which means your &ldquo;dumb&rdquo; TV is now:</p>
<ul>
<li>Scriptable</li>
<li>Automatable</li>
<li>UI-controllable</li>
<li>Fully local</li>
</ul>
<p>No app. No API. No nonsense.</p>
<p>Just raw IR, weaponized properly.</p>
<h3 id="hdmi-cec-listening-instead-of-guessing">HDMI-CEC: Listening Instead of Guessing</h3>
<p>If the IR node is about control, the HDMI-CEC node is about awareness.</p>
<p>And honestly, this is the more interesting one.</p>
<p>Because most smart home setups fake device state. They assume the TV is on because you told it to turn on.</p>
<p>This one doesn&rsquo;t assume anything.</p>
<p>It listens.</p>
<h3 id="sniffing-the-hdmi-bus">Sniffing the HDMI Bus</h3>
<p>Using an ESP32 and this <a href="https://github.com/Palakis/esphome-native-hdmi-cec">esphome-hdmi-cec component</a>, this device taps directly into the HDMI-CEC line and watches traffic in real time.</p>
<p>Not controlling (well, not primarily)&ndash;just observing.</p>
<p>With:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>    <span style="color:#f92672">promiscuous_mode</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">decode_messages</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>…it&rsquo;s basically Wireshark for your HDMI cable.</p>
<p>And from that stream, it extracts something incredibly useful:</p>
<h3 id="a-real-power-state-sensor">A Real Power State Sensor</h3>
<p>Two messages matter here:</p>
<ul>
<li>0x36 → Standby (OFF)</li>
<li>[0x90, 0x00] → Power ON</li>
</ul>
<p>That&rsquo;s it.</p>
<p>No guessing. No delays. No &ldquo;wait 10 seconds and hope.&rdquo;</p>
<p>Just:</p>
<ul>
<li>TV says it&rsquo;s off → sensor updates</li>
<li>TV says it&rsquo;s on → sensor updates</li>
</ul>
<p>Which means your automations suddenly get way smarter.</p>
<p>Lights, sound, notifications&ndash;everything can react to what&rsquo;s actually happening, not what you think is happening.</p>
<h3 id="minimal-control-maximum-precision">Minimal Control, Maximum Precision</h3>
<p>There&rsquo;s also a small but important addition:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>    <span style="color:#f92672">hdmi_cec.send</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">destination</span>: <span style="color:#ae81ff">0x0</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">data</span>: [<span style="color:#ae81ff">0x36</span>]
</span></span></code></pre></div><p>A clean, direct &ldquo;turn off everything&rdquo; broadcast.</p>
<p>No IR blasting. No aiming. No interference.</p>
<p>Just a message on the HDMI bus that every device understands.</p>
<h3 id="why-this-setup-works-so-well">Why This Setup Works So Well</h3>
<p>Individually, these projects are solid.</p>
<p>Together, they&rsquo;re kind of ridiculous&ndash;in a good way.</p>
<p>You end up with:</p>
<h3 id="ir--control-layer">IR → Control Layer</h3>
<ul>
<li>Instant input from physical remotes</li>
<li>Reliable output to &ldquo;dumb&rdquo; devices</li>
<li>Fully local, zero latency</li>
</ul>
<h3 id="hdmi-cec--state-layer">HDMI-CEC → State Layer</h3>
<ul>
<li>Real device awareness</li>
<li>No guesswork</li>
<li>Clean integration into automations</li>
</ul>
<p>And the combination solves a problem most people don&rsquo;t even realize they have:</p>
<blockquote>
<p>Smart homes are great at sending commands.</p>
</blockquote>
<blockquote>
<p>They&rsquo;re terrible at knowing what actually happened.</p>
</blockquote>
<p>This setup fixes that.</p>
<h3 id="the-bigger-picture">The Bigger Picture</h3>
<p>What&rsquo;s happening here isn&rsquo;t just &ldquo;cool ESPHome stuff.&rdquo;</p>
<p>It&rsquo;s a shift in how you think about devices.</p>
<p>Instead of asking:</p>
<blockquote>
<p>&ldquo;Does this support Home Assistant?&rdquo;</p>
</blockquote>
<p>You start asking:</p>
<blockquote>
<p>&ldquo;Can I make this support Home Assistant?&rdquo;</p>
</blockquote>
<p>IR? Yes.</p>
<p>CEC? Yes.</p>
<p>RF (soon)? Probably.</p>
<p>And suddenly, entire categories of &ldquo;dumb&rdquo; hardware become viable again&ndash;without any of the baggage of cloud apps, firmware updates, or abandoned ecosystems.</p>
<h3 id="final-thought">Final Thought</h3>
<p>There&rsquo;s something deeply satisfying about turning off your TV with a 20-year-old protocol…</p>
<p>…while a microcontroller quietly logs the event and updates your house in real time.</p>
<p>It&rsquo;s not flashy.</p>
<p>It doesn&rsquo;t need to be.</p>
<p>It just works&ndash;and more importantly, it works on your terms.</p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>Most people think of IR remotes as relics. Dumb plastic wands that exist purely to be lost in couch cushions and die at the worst possible moment.</p>
<p>But strip away the UX sins and what you&rsquo;re left with is something surprisingly powerful: instant, local, zero-latency control.</p>
<p>This ESPHome-based IR node leans into that idea hard.</p>
<p>At its core, it&rsquo;s an ESP8266 (ESP8285 board) running both a receiver and transmitter. That alone isn&rsquo;t special. What makes it interesting is how it&rsquo;s wired into Home Assistant&ndash;not as a workaround, but as a first-class control layer.</p>
<h3 id="ir-as-input-not-just-output">IR as Input, Not Just Output</h3>
<p>Most setups treat IR as a one-way street: send commands, hope for the best.</p>
<p>Here, the remote becomes a trigger device.</p>
<p>Specific NEC codes&ndash;like the colored buttons on an LG remote&ndash;are mapped directly to Home Assistant actions:</p>
<ul>
<li>Pink button → toggle TV lights</li>
<li>Green button → toggle bedroom light</li>
<li>Yellow button → toggle soundbar power</li>
<li>Blue button → toggle TV power</li>
</ul>
<p>No cloud. No polling. No delay. Press button → thing happens.</p>
<p>That&rsquo;s the entire philosophy.</p>
<p>And because it&rsquo;s ESPHome, you&rsquo;re not stuck with whatever some manufacturer thought was useful. You decide what every button means.</p>
<h3 id="the-quiet-killer-feature-ir-proxy">The Quiet Killer Feature: IR Proxy</h3>
<p>Buried in this config is something that feels like a glimpse into the future:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>    <span style="color:#f92672">infrared</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">ir_rf_proxy</span>
</span></span></code></pre></div><p>Right now, it&rsquo;s rough. Definitely not plug-and-play. But conceptually? It&rsquo;s huge.</p>
<p>This is the beginning of IR becoming network-native inside Home Assistant.</p>
<p>Instead of:</p>
<ul>
<li>Capturing codes manually</li>
<li>Writing YAML</li>
<li>Flashing firmware</li>
</ul>
<p>You eventually get:</p>
<ul>
<li>Discoverable IR devices</li>
<li>Reusable command sets</li>
<li>Shared control layers</li>
</ul>
<p>In other words, IR stops being a hack and starts acting like a real integration.</p>
<p>We&rsquo;re not fully there yet&ndash;but this is the direction.</p>
<h3 id="output-still-matters">Output Still Matters</h3>
<p>On the flip side, the transmitter side is just as important.</p>
<p>Every key TV function is exposed as a Home Assistant button:</p>
<ul>
<li>Power</li>
<li>Volume up/down</li>
<li>Mute</li>
<li>Navigation</li>
<li>Playback</li>
</ul>
<p>Which means your &ldquo;dumb&rdquo; TV is now:</p>
<ul>
<li>Scriptable</li>
<li>Automatable</li>
<li>UI-controllable</li>
<li>Fully local</li>
</ul>
<p>No app. No API. No nonsense.</p>
<p>Just raw IR, weaponized properly.</p>
<h3 id="hdmi-cec-listening-instead-of-guessing">HDMI-CEC: Listening Instead of Guessing</h3>
<p>If the IR node is about control, the HDMI-CEC node is about awareness.</p>
<p>And honestly, this is the more interesting one.</p>
<p>Because most smart home setups fake device state. They assume the TV is on because you told it to turn on.</p>
<p>This one doesn&rsquo;t assume anything.</p>
<p>It listens.</p>
<h3 id="sniffing-the-hdmi-bus">Sniffing the HDMI Bus</h3>
<p>Using an ESP32 and this <a href="https://github.com/Palakis/esphome-native-hdmi-cec">esphome-hdmi-cec component</a>, this device taps directly into the HDMI-CEC line and watches traffic in real time.</p>
<p>Not controlling (well, not primarily)&ndash;just observing.</p>
<p>With:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>    <span style="color:#f92672">promiscuous_mode</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">decode_messages</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>…it&rsquo;s basically Wireshark for your HDMI cable.</p>
<p>And from that stream, it extracts something incredibly useful:</p>
<h3 id="a-real-power-state-sensor">A Real Power State Sensor</h3>
<p>Two messages matter here:</p>
<ul>
<li>0x36 → Standby (OFF)</li>
<li>[0x90, 0x00] → Power ON</li>
</ul>
<p>That&rsquo;s it.</p>
<p>No guessing. No delays. No &ldquo;wait 10 seconds and hope.&rdquo;</p>
<p>Just:</p>
<ul>
<li>TV says it&rsquo;s off → sensor updates</li>
<li>TV says it&rsquo;s on → sensor updates</li>
</ul>
<p>Which means your automations suddenly get way smarter.</p>
<p>Lights, sound, notifications&ndash;everything can react to what&rsquo;s actually happening, not what you think is happening.</p>
<h3 id="minimal-control-maximum-precision">Minimal Control, Maximum Precision</h3>
<p>There&rsquo;s also a small but important addition:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>    <span style="color:#f92672">hdmi_cec.send</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">destination</span>: <span style="color:#ae81ff">0x0</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">data</span>: [<span style="color:#ae81ff">0x36</span>]
</span></span></code></pre></div><p>A clean, direct &ldquo;turn off everything&rdquo; broadcast.</p>
<p>No IR blasting. No aiming. No interference.</p>
<p>Just a message on the HDMI bus that every device understands.</p>
<h3 id="why-this-setup-works-so-well">Why This Setup Works So Well</h3>
<p>Individually, these projects are solid.</p>
<p>Together, they&rsquo;re kind of ridiculous&ndash;in a good way.</p>
<p>You end up with:</p>
<h3 id="ir--control-layer">IR → Control Layer</h3>
<ul>
<li>Instant input from physical remotes</li>
<li>Reliable output to &ldquo;dumb&rdquo; devices</li>
<li>Fully local, zero latency</li>
</ul>
<h3 id="hdmi-cec--state-layer">HDMI-CEC → State Layer</h3>
<ul>
<li>Real device awareness</li>
<li>No guesswork</li>
<li>Clean integration into automations</li>
</ul>
<p>And the combination solves a problem most people don&rsquo;t even realize they have:</p>
<blockquote>
<p>Smart homes are great at sending commands.</p>
</blockquote>
<blockquote>
<p>They&rsquo;re terrible at knowing what actually happened.</p>
</blockquote>
<p>This setup fixes that.</p>
<h3 id="the-bigger-picture">The Bigger Picture</h3>
<p>What&rsquo;s happening here isn&rsquo;t just &ldquo;cool ESPHome stuff.&rdquo;</p>
<p>It&rsquo;s a shift in how you think about devices.</p>
<p>Instead of asking:</p>
<blockquote>
<p>&ldquo;Does this support Home Assistant?&rdquo;</p>
</blockquote>
<p>You start asking:</p>
<blockquote>
<p>&ldquo;Can I make this support Home Assistant?&rdquo;</p>
</blockquote>
<p>IR? Yes.</p>
<p>CEC? Yes.</p>
<p>RF (soon)? Probably.</p>
<p>And suddenly, entire categories of &ldquo;dumb&rdquo; hardware become viable again&ndash;without any of the baggage of cloud apps, firmware updates, or abandoned ecosystems.</p>
<h3 id="final-thought">Final Thought</h3>
<p>There&rsquo;s something deeply satisfying about turning off your TV with a 20-year-old protocol…</p>
<p>…while a microcontroller quietly logs the event and updates your house in real time.</p>
<p>It&rsquo;s not flashy.</p>
<p>It doesn&rsquo;t need to be.</p>
<p>It just works&ndash;and more importantly, it works on your terms.</p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>A New Landing Page &amp; the Blog's New Home</title><link>https://blog.aidanmaurinjones.com/posts/a-new-landing-page--the-blogs-new-home/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/a-new-landing-page--the-blogs-new-home/</guid><pubDate>Sun, 19 Oct 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I finally have a proper home on the web — a simple, fast, no-nonsense landing page that ties
everything together at <a href="https://aidanmaurinjones.com">aidanmaurinjones.com</a>.</p>
<p>Now the <strong>landing page</strong> handles introductions while the <strong>blog</strong> lives at
<a href="https://blog.aidanmaurinjones.com">blog.aidanmaurinjones.com</a>, focused entirely on posts
and projects.</p>
<hr>
<h2 id="the-goal">The Goal</h2>
<p>I wanted something that:</p>
<ul>
<li>loads instantly</li>
<li>works entirely from static files</li>
<li>stays easy to maintain</li>
<li>feels like me — straightforward, clean, and a little nerdy around the edges</li>
</ul>
<p>No flashy animations, no bloat, no signup forms. Just a name, a short blurb, and a link to
the blog.</p>
<hr>
<h2 id="the-build">The Build</h2>
<p>The site runs on <a href="https://gohugo.io/">Hugo</a> with the <a href="https://github.com/1bl4z3r/hermit-V2">Hermit-V2</a> theme — lightweight, elegant, and fast.<br>
I kept the layout minimal: title, subtitle, one link to the blog, and a simple contact section.</p>
<p>Everything is built locally with Hugo Extended, then deployed automatically using GitHub Pages.<br>
Once the workflow was behaving, the entire site could rebuild and publish in under 30 seconds.</p>
<hr>
<h2 id="the-result">The Result</h2>
<p>What you see now is the distilled version of everything I wanted:<br>
a quiet, fast landing page that does exactly one job — introduce me and point you in the
right direction.</p>
<p>It’s clean, responsive, and entirely under my control.<br>
No third-party builders, no analytics scripts, no compromises.</p>
<hr>
<h2 id="closing-thoughts">Closing Thoughts</h2>
<p>I didn’t rebuild the blog — I just gave it a better home.<br>
The content, feeds, and archives all live on at <a href="https://blog.aidanmaurinjones.com">blog.aidanmaurinjones.com</a>;
the main domain is now a simple, focused landing page that introduces who I am and where to find my work.</p>
<p>It’s a small change that makes everything clearer and easier to manage — one site for reading,
one site for meeting.</p>
<p>→ <a href="https://aidanmaurinjones.com">aidanmaurinjones.com</a><br>
→ <a href="https://blog.aidanmaurinjones.com">blog.aidanmaurinjones.com</a></p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I finally have a proper home on the web — a simple, fast, no-nonsense landing page that ties
everything together at <a href="https://aidanmaurinjones.com">aidanmaurinjones.com</a>.</p>
<p>Now the <strong>landing page</strong> handles introductions while the <strong>blog</strong> lives at
<a href="https://blog.aidanmaurinjones.com">blog.aidanmaurinjones.com</a>, focused entirely on posts
and projects.</p>
<hr>
<h2 id="the-goal">The Goal</h2>
<p>I wanted something that:</p>
<ul>
<li>loads instantly</li>
<li>works entirely from static files</li>
<li>stays easy to maintain</li>
<li>feels like me — straightforward, clean, and a little nerdy around the edges</li>
</ul>
<p>No flashy animations, no bloat, no signup forms. Just a name, a short blurb, and a link to
the blog.</p>
<hr>
<h2 id="the-build">The Build</h2>
<p>The site runs on <a href="https://gohugo.io/">Hugo</a> with the <a href="https://github.com/1bl4z3r/hermit-V2">Hermit-V2</a> theme — lightweight, elegant, and fast.<br>
I kept the layout minimal: title, subtitle, one link to the blog, and a simple contact section.</p>
<p>Everything is built locally with Hugo Extended, then deployed automatically using GitHub Pages.<br>
Once the workflow was behaving, the entire site could rebuild and publish in under 30 seconds.</p>
<hr>
<h2 id="the-result">The Result</h2>
<p>What you see now is the distilled version of everything I wanted:<br>
a quiet, fast landing page that does exactly one job — introduce me and point you in the
right direction.</p>
<p>It’s clean, responsive, and entirely under my control.<br>
No third-party builders, no analytics scripts, no compromises.</p>
<hr>
<h2 id="closing-thoughts">Closing Thoughts</h2>
<p>I didn’t rebuild the blog — I just gave it a better home.<br>
The content, feeds, and archives all live on at <a href="https://blog.aidanmaurinjones.com">blog.aidanmaurinjones.com</a>;
the main domain is now a simple, focused landing page that introduces who I am and where to find my work.</p>
<p>It’s a small change that makes everything clearer and easier to manage — one site for reading,
one site for meeting.</p>
<p>→ <a href="https://aidanmaurinjones.com">aidanmaurinjones.com</a><br>
→ <a href="https://blog.aidanmaurinjones.com">blog.aidanmaurinjones.com</a></p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Why Obsidian Doesn’t Work for Me</title><link>https://blog.aidanmaurinjones.com/posts/why-obsidian-doesnt-work-for-me/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/why-obsidian-doesnt-work-for-me/</guid><pubDate>Fri, 03 Oct 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>Every so often, I give Obsidian another try. On paper, it sounds like the perfect tool: a
local-first, Markdown-based note-taking app that’s cross-platform, extensible, and endlessly
customizable. For many people, it really is a game changer.</p>
<p>But every time I sit down with it, I leave thinking the same thing: “huh…”</p>
<p>⸻</p>
<h3 id="the-promise-of-obsidian">The Promise of Obsidian</h3>
<p>Obsidian is marketed as a plain text knowledge base. It provides backlinks, a graph view,
and a huge plugin ecosystem that can turn Markdown into just about anything — daily journals,
task managers, or even kanban boards. For someone who wants an all-in-one workspace, it’s
fantastic.</p>
<p>⸻</p>
<h3 id="my-workflow-is-different">My Workflow Is Different</h3>
<p>The reason it doesn’t click for me is simple: my workflow is built on a different philosophy.</p>
<ul>
<li>Markdown is the source of truth. I write everything in plain .md files. No special syntax,
no hidden metadata. If I want to preview formatting, I open it in Marked 2.</li>
<li>PDF is the permanent format. When I need something shareable or archival, I export
to PDF. That’s my version of locking it down in stone.</li>
<li>Finder organizes, Alfred retrieves. Finder handles long-term storage, Alfred lets me get
to anything instantly, and Hazel keeps everything tidy in the background.</li>
<li>Automation glues it all together. Keyboard Maestro, Shortcuts, and BetterTouchTool let me
spin up templates, transform files, or publish to Hugo and Buttondown in minutes.</li>
</ul>
<p>Within this setup, I can create a new document template in 10 minutes. I am not proud of it,
but in Obsidian, I spent two hours fiddling with plugins just to get a string quoted or a
JSON array formatted consistently without any success.</p>
<p>⸻</p>
<h3 id="the-real-difference">The Real Difference</h3>
<p>What I’ve realized is that Obsidian and my stack solve different problems:</p>
<ul>
<li>Obsidian is for people who want a unified workspace where notes, tasks, and links all live
together.</li>
<li>My stack is for people who want modular tools that each do one job well and can be
connected through automation.</li>
</ul>
<p>That’s why Obsidian feels to me like the love child of MS Word and VSCode. It’s polished,
powerful, and versatile — but also too “workspace-y” for the way I prefer to work.</p>
<p>⸻</p>
<h3 id="why-thats-okay">Why That’s Okay</h3>
<p>None of this is a knock on Obsidian. It’s a great app, and I can see why it’s so widely
loved. If I needed cross-platform syncing or a personal knowledge graph, it would be near
the top of my list.</p>
<p>But for me, life revolves around Markdown as the living format and PDF as the permanent
format. BBEdit, Marked 2, Hugo, Buttondown, Alfred, Hazel, Keyboard Maestro, and Shortcuts
give me everything I need. Obsidian just doesn’t solve a problem I actually have.</p>
<p>And that’s the real takeaway: the best tool isn’t the one with the most features. It’s the
one that disappears into your workflow and feels natural every day.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/BBEdit%20Icon.jpg" alt="BBEdit app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    BBEdit
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://marked2app.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Marked%202%20Icon.jpg" alt="Marked 2 app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://marked2app.com/" target="_blank" rel="noopener">
    Marked 2
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://obsidian.md/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Obsidian%20Icon.jpg" alt="Obsidian app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://obsidian.md/" target="_blank" rel="noopener">
    Obsidian
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>Every so often, I give Obsidian another try. On paper, it sounds like the perfect tool: a
local-first, Markdown-based note-taking app that’s cross-platform, extensible, and endlessly
customizable. For many people, it really is a game changer.</p>
<p>But every time I sit down with it, I leave thinking the same thing: “huh…”</p>
<p>⸻</p>
<h3 id="the-promise-of-obsidian">The Promise of Obsidian</h3>
<p>Obsidian is marketed as a plain text knowledge base. It provides backlinks, a graph view,
and a huge plugin ecosystem that can turn Markdown into just about anything — daily journals,
task managers, or even kanban boards. For someone who wants an all-in-one workspace, it’s
fantastic.</p>
<p>⸻</p>
<h3 id="my-workflow-is-different">My Workflow Is Different</h3>
<p>The reason it doesn’t click for me is simple: my workflow is built on a different philosophy.</p>
<ul>
<li>Markdown is the source of truth. I write everything in plain .md files. No special syntax,
no hidden metadata. If I want to preview formatting, I open it in Marked 2.</li>
<li>PDF is the permanent format. When I need something shareable or archival, I export
to PDF. That’s my version of locking it down in stone.</li>
<li>Finder organizes, Alfred retrieves. Finder handles long-term storage, Alfred lets me get
to anything instantly, and Hazel keeps everything tidy in the background.</li>
<li>Automation glues it all together. Keyboard Maestro, Shortcuts, and BetterTouchTool let me
spin up templates, transform files, or publish to Hugo and Buttondown in minutes.</li>
</ul>
<p>Within this setup, I can create a new document template in 10 minutes. I am not proud of it,
but in Obsidian, I spent two hours fiddling with plugins just to get a string quoted or a
JSON array formatted consistently without any success.</p>
<p>⸻</p>
<h3 id="the-real-difference">The Real Difference</h3>
<p>What I’ve realized is that Obsidian and my stack solve different problems:</p>
<ul>
<li>Obsidian is for people who want a unified workspace where notes, tasks, and links all live
together.</li>
<li>My stack is for people who want modular tools that each do one job well and can be
connected through automation.</li>
</ul>
<p>That’s why Obsidian feels to me like the love child of MS Word and VSCode. It’s polished,
powerful, and versatile — but also too “workspace-y” for the way I prefer to work.</p>
<p>⸻</p>
<h3 id="why-thats-okay">Why That’s Okay</h3>
<p>None of this is a knock on Obsidian. It’s a great app, and I can see why it’s so widely
loved. If I needed cross-platform syncing or a personal knowledge graph, it would be near
the top of my list.</p>
<p>But for me, life revolves around Markdown as the living format and PDF as the permanent
format. BBEdit, Marked 2, Hugo, Buttondown, Alfred, Hazel, Keyboard Maestro, and Shortcuts
give me everything I need. Obsidian just doesn’t solve a problem I actually have.</p>
<p>And that’s the real takeaway: the best tool isn’t the one with the most features. It’s the
one that disappears into your workflow and feels natural every day.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/BBEdit%20Icon.jpg" alt="BBEdit app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    BBEdit
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://marked2app.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Marked%202%20Icon.jpg" alt="Marked 2 app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://marked2app.com/" target="_blank" rel="noopener">
    Marked 2
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://obsidian.md/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Obsidian%20Icon.jpg" alt="Obsidian app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://obsidian.md/" target="_blank" rel="noopener">
    Obsidian
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Automating My Newsletter Workflow: One Markdown File for Hugo and Buttondown</title><link>https://blog.aidanmaurinjones.com/posts/automating-my-newsletter-workflow-one-markdown-file-for-hugo-and-buttondown/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/automating-my-newsletter-workflow-one-markdown-file-for-hugo-and-buttondown/</guid><pubDate>Wed, 01 Oct 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I’ve been working toward a goal for years: a single place to write, and as many automated
outputs as possible. I don’t want to copy and paste, re-format, or duplicate my writing. The
same Markdown file that powers a blog post should also power a newsletter, an archive, or
whatever else I decide to publish.</p>
<p>That philosophy led me to a new Shortcut I built for my Buttondown newsletter. With it, I
can take the exact same Markdown file I use for my Hugo-based site’s Newsletter Archive page,
and publish it straight to Buttondown in one step. No duplication, no reformatting, and no
breaking my Markdown-first workflow.</p>
<p>⸻</p>
<h3 id="a-dual-purpose-draft">A Dual-Purpose Draft</h3>
<p>Every newsletter draft I write starts as a Markdown file in my Hugo project. It includes
the standard YAML front matter — title, date, tags — so it can live side-by-side with my
blog posts and generate an archive page on my site.</p>
<p>At the bottom, I’ve also standardized on a Hugo shortcode that handles things like subscribe
links and callouts.</p>
<p>The front matter makes it valid Hugo content, but Buttondown doesn’t need that metadata. Likewise,
the shortcode at the bottom is great for my archive page but doesn’t belong in an email. The
Shortcut’s job is to strip out those bits and isolate the actual content.</p>
<p>⸻</p>
<h3 id="regex-to-the-rescue">Regex to the Rescue</h3>
<p>To solve that, I leaned on regular expressions. The Shortcut matches everything after the
closing &mdash; of the YAML front matter and before the buttons-list shortcode.</p>
<p>The pattern looks like this:</p>
<pre><code>\A---[\n\s\S]*?---\s*([\n\s\S]*?)\s*\{\{\s*buttons-list\s*\}\}
</code></pre>
<p>The captured group becomes the newsletter body. Meanwhile, the Shortcut takes the filename
of the Markdown draft and uses it as the subject line. That way, one file works for both Hugo
(which uses the front matter) and Buttondown (which only needs subject + body but I hope one
day it supports front matter).</p>
<p>⸻</p>
<h3 id="publishing-via-buttondowns-api">Publishing via Buttondown’s API</h3>
<p>The final step is an API call. The Shortcut uses the Get Contents of URL action, configured with:</p>
<ul>
<li>Endpoint: <a href="https://api.buttondown.com/v1/emails">https://api.buttondown.com/v1/emails</a></li>
<li>Headers: Authorization token (pulled from a secure Shortcut)</li>
<li>Body: JSON with subject, body, and status</li>
</ul>
<p>I set status to about_to_send, which creates the email in Buttondown ready for review. If
I’m confident, I can flip this to sent and fire it off instantly.</p>
<p>⸻</p>
<h3 id="why-this-matters">Why This Matters</h3>
<p>The beauty of this setup is that I never have to write the same thing twice. My Hugo site
automatically builds out a Newsletter Archive page from the Markdown file, while this
Shortcut takes that same file and pushes it to Buttondown.</p>
<p>Plain text is the source of truth, Hugo and Buttondown are just outputs.</p>
<p>This also gives me flexibility: if I ever change services, or if I want to generate a PDF
archive, I don’t need to rewrite anything. I’ve already got everything in a neutral,
Markdown-first format that can be re-used anywhere.</p>
<p>⸻</p>
<h3 id="why-this-works-so-well">Why This Works So Well</h3>
<p>Like many of my favorite automations, this Shortcut doesn’t feel flashy — it feels inevitable. Once
you decide everything should start as Markdown, the next step is making sure the publishing
side bends around your workflow, not the other way around.</p>
<p>Shortcuts, Buttondown, and Hugo all line up perfectly here. It’s one file, two destinations,
and zero overhead. And that’s exactly the kind of automation that keeps me writing and publishing
more often.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/b08625600f25483fa55e19207d004eec" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Publish%20Newsletter%20to%20Buttondown%20%28Public%29%20Icon.jpg" alt="Publish Newsletter to Buttondown app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/b08625600f25483fa55e19207d004eec" target="_blank" rel="noopener">
    Publish Newsletter to Buttondown
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I’ve been working toward a goal for years: a single place to write, and as many automated
outputs as possible. I don’t want to copy and paste, re-format, or duplicate my writing. The
same Markdown file that powers a blog post should also power a newsletter, an archive, or
whatever else I decide to publish.</p>
<p>That philosophy led me to a new Shortcut I built for my Buttondown newsletter. With it, I
can take the exact same Markdown file I use for my Hugo-based site’s Newsletter Archive page,
and publish it straight to Buttondown in one step. No duplication, no reformatting, and no
breaking my Markdown-first workflow.</p>
<p>⸻</p>
<h3 id="a-dual-purpose-draft">A Dual-Purpose Draft</h3>
<p>Every newsletter draft I write starts as a Markdown file in my Hugo project. It includes
the standard YAML front matter — title, date, tags — so it can live side-by-side with my
blog posts and generate an archive page on my site.</p>
<p>At the bottom, I’ve also standardized on a Hugo shortcode that handles things like subscribe
links and callouts.</p>
<p>The front matter makes it valid Hugo content, but Buttondown doesn’t need that metadata. Likewise,
the shortcode at the bottom is great for my archive page but doesn’t belong in an email. The
Shortcut’s job is to strip out those bits and isolate the actual content.</p>
<p>⸻</p>
<h3 id="regex-to-the-rescue">Regex to the Rescue</h3>
<p>To solve that, I leaned on regular expressions. The Shortcut matches everything after the
closing &mdash; of the YAML front matter and before the buttons-list shortcode.</p>
<p>The pattern looks like this:</p>
<pre><code>\A---[\n\s\S]*?---\s*([\n\s\S]*?)\s*\{\{\s*buttons-list\s*\}\}
</code></pre>
<p>The captured group becomes the newsletter body. Meanwhile, the Shortcut takes the filename
of the Markdown draft and uses it as the subject line. That way, one file works for both Hugo
(which uses the front matter) and Buttondown (which only needs subject + body but I hope one
day it supports front matter).</p>
<p>⸻</p>
<h3 id="publishing-via-buttondowns-api">Publishing via Buttondown’s API</h3>
<p>The final step is an API call. The Shortcut uses the Get Contents of URL action, configured with:</p>
<ul>
<li>Endpoint: <a href="https://api.buttondown.com/v1/emails">https://api.buttondown.com/v1/emails</a></li>
<li>Headers: Authorization token (pulled from a secure Shortcut)</li>
<li>Body: JSON with subject, body, and status</li>
</ul>
<p>I set status to about_to_send, which creates the email in Buttondown ready for review. If
I’m confident, I can flip this to sent and fire it off instantly.</p>
<p>⸻</p>
<h3 id="why-this-matters">Why This Matters</h3>
<p>The beauty of this setup is that I never have to write the same thing twice. My Hugo site
automatically builds out a Newsletter Archive page from the Markdown file, while this
Shortcut takes that same file and pushes it to Buttondown.</p>
<p>Plain text is the source of truth, Hugo and Buttondown are just outputs.</p>
<p>This also gives me flexibility: if I ever change services, or if I want to generate a PDF
archive, I don’t need to rewrite anything. I’ve already got everything in a neutral,
Markdown-first format that can be re-used anywhere.</p>
<p>⸻</p>
<h3 id="why-this-works-so-well">Why This Works So Well</h3>
<p>Like many of my favorite automations, this Shortcut doesn’t feel flashy — it feels inevitable. Once
you decide everything should start as Markdown, the next step is making sure the publishing
side bends around your workflow, not the other way around.</p>
<p>Shortcuts, Buttondown, and Hugo all line up perfectly here. It’s one file, two destinations,
and zero overhead. And that’s exactly the kind of automation that keeps me writing and publishing
more often.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/b08625600f25483fa55e19207d004eec" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Publish%20Newsletter%20to%20Buttondown%20%28Public%29%20Icon.jpg" alt="Publish Newsletter to Buttondown app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/b08625600f25483fa55e19207d004eec" target="_blank" rel="noopener">
    Publish Newsletter to Buttondown
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>What's New at the Blog - Shortcuts, Automation &amp; a Dash of Humor</title><link>https://blog.aidanmaurinjones.com/newsletter/whats-new-at-the-blog---shortcuts-automation--a-dash-of-humor/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/newsletter/whats-new-at-the-blog---shortcuts-automation--a-dash-of-humor/</guid><pubDate>Mon, 29 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>Hey there,</p>
<p>I hope this finds you well and a little curious — I’ve got a fresh batch of blog posts to
share! Whether you’re into smart home automations, shortcuts that save time, or just a little
bit of silliness when dealing with spam, there’s something here for you.</p>
<p>⸻</p>
<h2 id="-whats-new">📰 What’s New</h2>
<p>Here are the recent posts you might enjoy (plus one or two you may already have seen):</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/fighting-spam-with-automation--a-shortcut-for-writing-hilarious-replies">Fighting Spam with Automation: A Shortcut for Writing Hilarious Replies</a></strong></p>
<p>Ever want to send snarky replies to spam—but without typing them out yourself? This post
walks through a Shortcut that drafts sarcastic, AI-powered responses to spam, just for the
chuckle.</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/automating-tp-link-kasa-devices-with-shortcuts/">Automating TP-Link / Kasa Devices with Shortcuts</a></strong></p>
<p>Unlock more control over your smart plugs and bulbs by integrating them with Apple Shortcuts.</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/get-this-weeks-events-a-smarter-calendar-shortcut/">Get This Week’s Events: A Smarter Calendar Shortcut</a></strong></p>
<p>Automate the process of extracting your week’s events and display them in the Apple Shortcuts
app.</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/app-store-links-made-beautiful-with-shortcuts/">App Store Links Made Beautiful with Shortcuts</a></strong></p>
<p>Turn ugly, long App Store links into clean, pretty ones (and even automate it).</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/i-could-write-this-blog-in-notepad/">I Could Write This Blog in Notepad</a></strong></p>
<p>A reflection on how simple the publishing stack really is—plain text, Markdown, GitHub Pages,
and some automation.</p>
<p>⸻</p>
<h2 id="-spotlight">✨ Spotlight</h2>
<p><strong>Fighting Spam with Automation</strong> is the kind of fun-first Shortcut project I love doing: it’s
not optimized for productivity, but it stretches the boundaries of what Shortcuts + local
AI can do. Using AppleScript + a local LM Studio model, the setup fetches an email, crafts
a witty (borderline absurd) reply, and drops it into a draft. I didn’t send it — mostly I
just laughed.  ￼</p>
<p>But beyond the jokes, there’s a deeper idea here: using Shortcuts to glue together different
systems—in this case, email, scripting, and local AI. Everything is local, everything is
private, and everything is yours to tinker with.</p>
<p>⸻</p>
<h2 id="-why-you-might-try-these">🛠️ Why You Might Try These</h2>
<p>If any of this resonates, here are some ways you could put these posts to use:</p>
<ul>
<li><strong>Make your smart home more powerful it</strong> &ndash;&gt; Automate TP-Link, SwitchBot devices via
Shortcuts + API</li>
<li><strong>Simplify blog or web publishing it</strong> &ndash;&gt; Use the “Post Buttons” or “iCloud Links it &ndash;&gt;
Share Buttons” tricks</li>
<li><strong>Tidy up link clutter it</strong> &ndash;&gt; Beautify App Store links or automate Alfred app cards</li>
<li><strong>Laugh at spam instead of regretting it</strong> &ndash;&gt; Build the “roast the spammer” Shortcut</li>
<li><strong>Understand the minimal stack behind your blog	it</strong> &ndash;&gt; Read the “I Could Write This
Blog in Notepad” piece</li>
</ul>
<p>⸻</p>
<p><strong>If you liked any of those, I’d appreciate it if you’d:</strong></p>
<ol>
<li><strong>Reply it</strong> &ndash;&gt; tell me which post you liked (or which one you’re going to try)</li>
<li><strong>Share it</strong> &ndash;&gt; forward this newsletter to a friend who loves automation</li>
<li><strong>Bookmark it</strong> &ndash;&gt; keep it somewhere you’ll revisit when you need inspiration</li>
</ol>
<p>As always, thanks for reading. I’m already brainstorming what’s next (maybe something with
HomeKit, or combining shortcuts + other tools you love). Stay tuned.</p>
<p>Cheers,</p>
<p>Aidan 👋</p>
<p><a href="https://aidanmaurinjones.com">aidanmaurinjones.com</a></p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>Hey there,</p>
<p>I hope this finds you well and a little curious — I’ve got a fresh batch of blog posts to
share! Whether you’re into smart home automations, shortcuts that save time, or just a little
bit of silliness when dealing with spam, there’s something here for you.</p>
<p>⸻</p>
<h2 id="-whats-new">📰 What’s New</h2>
<p>Here are the recent posts you might enjoy (plus one or two you may already have seen):</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/fighting-spam-with-automation--a-shortcut-for-writing-hilarious-replies">Fighting Spam with Automation: A Shortcut for Writing Hilarious Replies</a></strong></p>
<p>Ever want to send snarky replies to spam—but without typing them out yourself? This post
walks through a Shortcut that drafts sarcastic, AI-powered responses to spam, just for the
chuckle.</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/automating-tp-link-kasa-devices-with-shortcuts/">Automating TP-Link / Kasa Devices with Shortcuts</a></strong></p>
<p>Unlock more control over your smart plugs and bulbs by integrating them with Apple Shortcuts.</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/get-this-weeks-events-a-smarter-calendar-shortcut/">Get This Week’s Events: A Smarter Calendar Shortcut</a></strong></p>
<p>Automate the process of extracting your week’s events and display them in the Apple Shortcuts
app.</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/app-store-links-made-beautiful-with-shortcuts/">App Store Links Made Beautiful with Shortcuts</a></strong></p>
<p>Turn ugly, long App Store links into clean, pretty ones (and even automate it).</p>
<p>• <strong><a href="https://aidanmaurinjones.com/posts/i-could-write-this-blog-in-notepad/">I Could Write This Blog in Notepad</a></strong></p>
<p>A reflection on how simple the publishing stack really is—plain text, Markdown, GitHub Pages,
and some automation.</p>
<p>⸻</p>
<h2 id="-spotlight">✨ Spotlight</h2>
<p><strong>Fighting Spam with Automation</strong> is the kind of fun-first Shortcut project I love doing: it’s
not optimized for productivity, but it stretches the boundaries of what Shortcuts + local
AI can do. Using AppleScript + a local LM Studio model, the setup fetches an email, crafts
a witty (borderline absurd) reply, and drops it into a draft. I didn’t send it — mostly I
just laughed.  ￼</p>
<p>But beyond the jokes, there’s a deeper idea here: using Shortcuts to glue together different
systems—in this case, email, scripting, and local AI. Everything is local, everything is
private, and everything is yours to tinker with.</p>
<p>⸻</p>
<h2 id="-why-you-might-try-these">🛠️ Why You Might Try These</h2>
<p>If any of this resonates, here are some ways you could put these posts to use:</p>
<ul>
<li><strong>Make your smart home more powerful it</strong> &ndash;&gt; Automate TP-Link, SwitchBot devices via
Shortcuts + API</li>
<li><strong>Simplify blog or web publishing it</strong> &ndash;&gt; Use the “Post Buttons” or “iCloud Links it &ndash;&gt;
Share Buttons” tricks</li>
<li><strong>Tidy up link clutter it</strong> &ndash;&gt; Beautify App Store links or automate Alfred app cards</li>
<li><strong>Laugh at spam instead of regretting it</strong> &ndash;&gt; Build the “roast the spammer” Shortcut</li>
<li><strong>Understand the minimal stack behind your blog	it</strong> &ndash;&gt; Read the “I Could Write This
Blog in Notepad” piece</li>
</ul>
<p>⸻</p>
<p><strong>If you liked any of those, I’d appreciate it if you’d:</strong></p>
<ol>
<li><strong>Reply it</strong> &ndash;&gt; tell me which post you liked (or which one you’re going to try)</li>
<li><strong>Share it</strong> &ndash;&gt; forward this newsletter to a friend who loves automation</li>
<li><strong>Bookmark it</strong> &ndash;&gt; keep it somewhere you’ll revisit when you need inspiration</li>
</ol>
<p>As always, thanks for reading. I’m already brainstorming what’s next (maybe something with
HomeKit, or combining shortcuts + other tools you love). Stay tuned.</p>
<p>Cheers,</p>
<p>Aidan 👋</p>
<p><a href="https://aidanmaurinjones.com">aidanmaurinjones.com</a></p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Fighting Spam with Automation: A Shortcut for Writing Hilarious Replies</title><link>https://blog.aidanmaurinjones.com/posts/fighting-spam-with-automation--a-shortcut-for-writing-hilarious-replies/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/fighting-spam-with-automation--a-shortcut-for-writing-hilarious-replies/</guid><pubDate>Fri, 26 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the joys of Shortcuts on macOS is bending the system to your will. With a little
creativity and some AppleScript, you can pull off automations that feel both absurd and brilliant.
My latest project? A Shortcut that automatically drafts a brutally funny, sarcastic reply to
spam and junk emails—powered by a local AI model running in LM Studio.</p>
<p>It’s not practical. It’s not productive. But it’s very satisfying.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>At its core, the Shortcut is a four-part pipeline:</p>
<ol>
<li><strong>Grab the Email Contents</strong>
Using a short AppleScript snippet, the Shortcut fetches the subject, sender, and body of the
currently selected message in Apple Mail. If no message is selected, it returns a friendly
“No message selected.” To keep things stable, the Shortcut also checks if the text exceeds
LM Studio’s character limit and truncates it if necessary.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-applescript" data-lang="applescript"><span style="display:flex;"><span><span style="color:#66d9ef">tell</span> application <span style="color:#e6db74">&#34;Mail&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">set</span> selectedMessages <span style="color:#66d9ef">to</span> selection
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> selectedMessages <span style="color:#f92672">is not</span> {} <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theMessage <span style="color:#66d9ef">to</span> item <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">of</span> selectedMessages
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theSubject <span style="color:#66d9ef">to</span> subject <span style="color:#66d9ef">of</span> theMessage
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theSender <span style="color:#66d9ef">to</span> sender <span style="color:#66d9ef">of</span> theMessage
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theContent <span style="color:#66d9ef">to</span> <span style="color:#a6e22e">content</span> <span style="color:#66d9ef">of</span> theMessage
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;Subject: &#34;</span> <span style="color:#f92672">&amp;</span> theSubject <span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">linefeed</span> <span style="color:#f92672">&amp;</span> <span style="color:#e6db74">&#34;From: &#34;</span> <span style="color:#f92672">&amp;</span> theSender <span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">linefeed</span> <span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">linefeed</span> <span style="color:#f92672">&amp;</span> theContent
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;No message selected.&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">if</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> <span style="color:#66d9ef">tell</span>
</span></span></code></pre></div><ol start="2">
<li>
<p><strong>Prepare the Prompt</strong>
The Shortcut sets a variable for the LM Studio model ID (gemma-3-4b-it in my case) and builds
a carefully worded prompt. The instructions tell the model to write a “brutally funny, insult-filled
response to a spam email. Be sarcastic and creatively rude… End with an absurd, over-the-top
(but never threatening) final warning.” The result is a prompt that guides the AI into crafting
exactly the kind of unhinged reply you’d never actually send, but will absolutely laugh at.</p>
</li>
<li>
<p><strong>Send It to LM Studio</strong>
With the email contents and the prompt combined, the Shortcut makes a call to LM Studio’s
local API (http://localhost:1234/v1/chat/completions). The response is parsed as JSON, and
the draft text is extracted. Because it runs locally, there are no cloud services
involved—everything stays private.</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -X POST <span style="color:#e6db74">&#34;http://localhost:1234/v1/chat/completions&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -H <span style="color:#e6db74">&#34;Content-Type: application/json&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -d <span style="color:#e6db74">&#39;{
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &#34;model&#34;: &#34;gemma-3-4b-it&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &#34;messages&#34;: [
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;role&#34;: &#34;system&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;content&#34;: &#34;Write a brutally funny, insult-filled response to a spam email. Be 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        sarcastic and creatively rude (no slurs or hate speech). Make it clear I never 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        want to hear from them again. Reference the content of the email when possible. 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        End with an absurd, over-the-top (but never threatening) final warning, and a 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        signature that sounds unhinged yet articulate. Do Not include subject lines or 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        metadata.&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      },
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;role&#34;: &#34;user&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;content&#34;: &#34;&lt;&lt;&lt; email contents go here &gt;&gt;&gt;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    ]
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">  }&#39;</span>
</span></span></code></pre></div><ol start="4">
<li><strong>Open in Mail’s Reply Window</strong>
Finally, another AppleScript takes over: it opens a reply window to the original spam message
and drops the AI-generated draft into the compose area. From here, you can either hit send (bold!)
or just chuckle at the absurdity and close the window.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-applescript" data-lang="applescript"><span style="display:flex;"><span><span style="color:#66d9ef">on</span> run {input}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">tell</span> application <span style="color:#e6db74">&#34;Mail&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> selectedMessages <span style="color:#66d9ef">to</span> selection
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> selectedMessages <span style="color:#f92672">is not</span> {} <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">set</span> theMessage <span style="color:#66d9ef">to</span> item <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">of</span> selectedMessages
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">set</span> replyMessage <span style="color:#66d9ef">to</span> reply theMessage <span style="color:#66d9ef">with</span> opening <span style="color:#a6e22e">window</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">set</span> <span style="color:#a6e22e">content</span> <span style="color:#66d9ef">of</span> replyMessage <span style="color:#66d9ef">to</span> input
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">if</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">tell</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> run
</span></span></code></pre></div><p>⸻</p>
<h3 id="why-build-this">Why Build This?</h3>
<p>I won’t pretend this Shortcut is essential to my workflow. Nobody needs an AI-crafted insult
generator for spam. But that’s the fun of automation: sometimes it’s about play, not productivity.</p>
<p>Spam clogs our inboxes daily, and most of us simply delete it. This Shortcut flips the script,
giving you a mischievous outlet for all that frustration. Whether you actually send the replies
or just read them for a laugh, it makes the experience of dealing with spam weirdly delightful.</p>
<p>⸻</p>
<h3 id="a-perfect-example-of-local-ai--shortcuts">A Perfect Example of Local AI + Shortcuts</h3>
<p>The real story here is how easily Shortcuts can integrate with local AI tools like LM Studio. By
combining AppleScript’s system-level hooks with Shortcuts’ automation glue, you can build
workflows that feel custom-tailored to your sense of humor—or your productivity needs.</p>
<p>In this case, the Shortcut isn’t saving me time or streamlining my day. But it is showcasing
the power of running AI models locally, where latency is low, privacy is intact, and you can
experiment with ideas that wouldn’t make sense on a cloud-based service.</p>
<p>⸻</p>
<h3 id="the-result">The Result</h3>
<p>The first time I ran the Shortcut, the reply draft began with a sarcastic takedown of the
email’s fake “investment opportunity,” segued into a rant about how the spammer’s grammar
deserved jail time, and closed with a completely unhinged signature that read:</p>
<p>“Sincerely, Lord Emperor of My Inbox, Eternal Defender Against Your Nonsense.”</p>
<p>I didn’t send it. But I laughed harder than I have at an email in years. And that’s exactly
the point.</p>
<p>⸻</p>
<p><strong>Bottom line:</strong> Not every Shortcut has to be practical. Sometimes, the best ones are the ones
that bring you joy—even if that joy comes from imagining a spammer’s reaction to an AI-written
roast they’ll never actually read.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/a53cf7be25fe438d9425e73ff461f063" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Write%20Reply%20to%20Spam%20&amp;%20Junk%20Email%20Icon.jpg" alt="Write Reply to Spam &amp; Junk Email app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/a53cf7be25fe438d9425e73ff461f063" target="_blank" rel="noopener">
    Write Reply to Spam &amp; Junk Email
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create This Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://lmstudio.ai/download?os=mac" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/LM%20Studio%20Icon.jpg" alt="LM Studio app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://lmstudio.ai/download?os=mac" target="_blank" rel="noopener">
    LM Studio
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://latenightsw.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Script%20Debugger%20Icon.jpg" alt="Script Debugger app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://latenightsw.com/" target="_blank" rel="noopener">
    Script Debugger
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the joys of Shortcuts on macOS is bending the system to your will. With a little
creativity and some AppleScript, you can pull off automations that feel both absurd and brilliant.
My latest project? A Shortcut that automatically drafts a brutally funny, sarcastic reply to
spam and junk emails—powered by a local AI model running in LM Studio.</p>
<p>It’s not practical. It’s not productive. But it’s very satisfying.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>At its core, the Shortcut is a four-part pipeline:</p>
<ol>
<li><strong>Grab the Email Contents</strong>
Using a short AppleScript snippet, the Shortcut fetches the subject, sender, and body of the
currently selected message in Apple Mail. If no message is selected, it returns a friendly
“No message selected.” To keep things stable, the Shortcut also checks if the text exceeds
LM Studio’s character limit and truncates it if necessary.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-applescript" data-lang="applescript"><span style="display:flex;"><span><span style="color:#66d9ef">tell</span> application <span style="color:#e6db74">&#34;Mail&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">set</span> selectedMessages <span style="color:#66d9ef">to</span> selection
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> selectedMessages <span style="color:#f92672">is not</span> {} <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theMessage <span style="color:#66d9ef">to</span> item <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">of</span> selectedMessages
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theSubject <span style="color:#66d9ef">to</span> subject <span style="color:#66d9ef">of</span> theMessage
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theSender <span style="color:#66d9ef">to</span> sender <span style="color:#66d9ef">of</span> theMessage
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> theContent <span style="color:#66d9ef">to</span> <span style="color:#a6e22e">content</span> <span style="color:#66d9ef">of</span> theMessage
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;Subject: &#34;</span> <span style="color:#f92672">&amp;</span> theSubject <span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">linefeed</span> <span style="color:#f92672">&amp;</span> <span style="color:#e6db74">&#34;From: &#34;</span> <span style="color:#f92672">&amp;</span> theSender <span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">linefeed</span> <span style="color:#f92672">&amp;</span> <span style="color:#66d9ef">linefeed</span> <span style="color:#f92672">&amp;</span> theContent
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;No message selected.&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">if</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> <span style="color:#66d9ef">tell</span>
</span></span></code></pre></div><ol start="2">
<li>
<p><strong>Prepare the Prompt</strong>
The Shortcut sets a variable for the LM Studio model ID (gemma-3-4b-it in my case) and builds
a carefully worded prompt. The instructions tell the model to write a “brutally funny, insult-filled
response to a spam email. Be sarcastic and creatively rude… End with an absurd, over-the-top
(but never threatening) final warning.” The result is a prompt that guides the AI into crafting
exactly the kind of unhinged reply you’d never actually send, but will absolutely laugh at.</p>
</li>
<li>
<p><strong>Send It to LM Studio</strong>
With the email contents and the prompt combined, the Shortcut makes a call to LM Studio’s
local API (http://localhost:1234/v1/chat/completions). The response is parsed as JSON, and
the draft text is extracted. Because it runs locally, there are no cloud services
involved—everything stays private.</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -X POST <span style="color:#e6db74">&#34;http://localhost:1234/v1/chat/completions&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -H <span style="color:#e6db74">&#34;Content-Type: application/json&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span>  -d <span style="color:#e6db74">&#39;{
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &#34;model&#34;: &#34;gemma-3-4b-it&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    &#34;messages&#34;: [
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;role&#34;: &#34;system&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;content&#34;: &#34;Write a brutally funny, insult-filled response to a spam email. Be 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        sarcastic and creatively rude (no slurs or hate speech). Make it clear I never 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        want to hear from them again. Reference the content of the email when possible. 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        End with an absurd, over-the-top (but never threatening) final warning, and a 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        signature that sounds unhinged yet articulate. Do Not include subject lines or 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        metadata.&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      },
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      {
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;role&#34;: &#34;user&#34;,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">        &#34;content&#34;: &#34;&lt;&lt;&lt; email contents go here &gt;&gt;&gt;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      }
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    ]
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">  }&#39;</span>
</span></span></code></pre></div><ol start="4">
<li><strong>Open in Mail’s Reply Window</strong>
Finally, another AppleScript takes over: it opens a reply window to the original spam message
and drops the AI-generated draft into the compose area. From here, you can either hit send (bold!)
or just chuckle at the absurdity and close the window.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-applescript" data-lang="applescript"><span style="display:flex;"><span><span style="color:#66d9ef">on</span> run {input}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">tell</span> application <span style="color:#e6db74">&#34;Mail&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">set</span> selectedMessages <span style="color:#66d9ef">to</span> selection
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> selectedMessages <span style="color:#f92672">is not</span> {} <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">set</span> theMessage <span style="color:#66d9ef">to</span> item <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">of</span> selectedMessages
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">set</span> replyMessage <span style="color:#66d9ef">to</span> reply theMessage <span style="color:#66d9ef">with</span> opening <span style="color:#a6e22e">window</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">set</span> <span style="color:#a6e22e">content</span> <span style="color:#66d9ef">of</span> replyMessage <span style="color:#66d9ef">to</span> input
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">if</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">tell</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> run
</span></span></code></pre></div><p>⸻</p>
<h3 id="why-build-this">Why Build This?</h3>
<p>I won’t pretend this Shortcut is essential to my workflow. Nobody needs an AI-crafted insult
generator for spam. But that’s the fun of automation: sometimes it’s about play, not productivity.</p>
<p>Spam clogs our inboxes daily, and most of us simply delete it. This Shortcut flips the script,
giving you a mischievous outlet for all that frustration. Whether you actually send the replies
or just read them for a laugh, it makes the experience of dealing with spam weirdly delightful.</p>
<p>⸻</p>
<h3 id="a-perfect-example-of-local-ai--shortcuts">A Perfect Example of Local AI + Shortcuts</h3>
<p>The real story here is how easily Shortcuts can integrate with local AI tools like LM Studio. By
combining AppleScript’s system-level hooks with Shortcuts’ automation glue, you can build
workflows that feel custom-tailored to your sense of humor—or your productivity needs.</p>
<p>In this case, the Shortcut isn’t saving me time or streamlining my day. But it is showcasing
the power of running AI models locally, where latency is low, privacy is intact, and you can
experiment with ideas that wouldn’t make sense on a cloud-based service.</p>
<p>⸻</p>
<h3 id="the-result">The Result</h3>
<p>The first time I ran the Shortcut, the reply draft began with a sarcastic takedown of the
email’s fake “investment opportunity,” segued into a rant about how the spammer’s grammar
deserved jail time, and closed with a completely unhinged signature that read:</p>
<p>“Sincerely, Lord Emperor of My Inbox, Eternal Defender Against Your Nonsense.”</p>
<p>I didn’t send it. But I laughed harder than I have at an email in years. And that’s exactly
the point.</p>
<p>⸻</p>
<p><strong>Bottom line:</strong> Not every Shortcut has to be practical. Sometimes, the best ones are the ones
that bring you joy—even if that joy comes from imagining a spammer’s reaction to an AI-written
roast they’ll never actually read.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/a53cf7be25fe438d9425e73ff461f063" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Write%20Reply%20to%20Spam%20&amp;%20Junk%20Email%20Icon.jpg" alt="Write Reply to Spam &amp; Junk Email app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/a53cf7be25fe438d9425e73ff461f063" target="_blank" rel="noopener">
    Write Reply to Spam &amp; Junk Email
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create This Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://lmstudio.ai/download?os=mac" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/LM%20Studio%20Icon.jpg" alt="LM Studio app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://lmstudio.ai/download?os=mac" target="_blank" rel="noopener">
    LM Studio
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://latenightsw.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Script%20Debugger%20Icon.jpg" alt="Script Debugger app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://latenightsw.com/" target="_blank" rel="noopener">
    Script Debugger
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Get This Week’s Events: A Smarter Calendar Shortcut</title><link>https://blog.aidanmaurinjones.com/posts/get-this-weeks-events-a-smarter-calendar-shortcut/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/get-this-weeks-events-a-smarter-calendar-shortcut/</guid><pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the things I love about Shortcuts is how they let you bend the system to match your mental model of time. Apple&rsquo;s Calendar app is great at showing what&rsquo;s on your plate, but sometimes you want to zoom out and get a clear snapshot of just this week. That&rsquo;s exactly what this Shortcut, Get This Week&rsquo;s Events, does&ndash;by calculating the week&rsquo;s boundaries dynamically and pulling in only the events you care about.</p>
<hr>
<h3 id="how-it-works">How It Works</h3>
<p>The Shortcut starts by establishing today&rsquo;s date and formatting it into a value that the rest of the workflow can understand. From there, it leans on a Dictionary that acts like a custom lookup table for each day of the week. This dictionary defines offsets for both the start and end of the week depending on the current day.</p>
<p>For example:</p>
<ul>
<li>Sunday maps to {Start: 0, End: 6}</li>
<li>Monday maps to {Start: 1, End: 5}</li>
<li>Wednesday maps to {Start: 3, End: 3}</li>
</ul>
<p>This clever setup means the Shortcut doesn&rsquo;t have to assume whether your week starts on Sunday, Monday, or any other day&ndash;it adapts automatically by subtracting and adding the right number of days from the current date.</p>
<hr>
<h3 id="calculating-the-range">Calculating the Range</h3>
<p>Once the dictionary hands back the correct offsets, the Shortcut does a simple bit of date math:</p>
<ul>
<li>Subtract the &ldquo;Start&rdquo; offset from the current date to calculate the Start of Week.</li>
<li>Add the &ldquo;End&rdquo; offset to the current date to calculate the End of Week.</li>
</ul>
<p>Both results are saved into variables, which become the boundaries for the next step.</p>
<hr>
<h3 id="finding-your-events">Finding Your Events</h3>
<p>With the week&rsquo;s start and end pinned down, the Shortcut uses the Find Calendar Events action to grab only the events whose start date falls between those two values. That means whether you run this on a Tuesday or a Friday, you&rsquo;ll always get a list scoped neatly to the current week, no manual scrolling required.</p>
<hr>
<h3 id="why-this-matters">Why This Matters</h3>
<p>On the surface, it looks like a simple &ldquo;show me my week&rdquo; automation&ndash;but the beauty here is in how it generalizes. By abstracting the week&rsquo;s structure into a dictionary, you can easily tweak how you want your weeks defined. For instance, you could redefine Saturday as the end of the week or experiment with rolling five-day &ldquo;work weeks&rdquo; instead of calendar weeks.</p>
<p>This kind of flexibility is exactly why Shortcuts shines: you&rsquo;re not stuck with Apple&rsquo;s defaults&ndash;you can make the system reflect your schedule.</p>
<hr>
<h3 id="my-take">My Take</h3>
<p>I&rsquo;ve tried plenty of ways to get a weekly overview&ndash;widgets, third-party apps, even manually filtering in Calendar&ndash;but nothing beats the elegance of this Shortcut. It&rsquo;s fast, it&rsquo;s reliable, and it always gives me the right slice of time, no matter the day. It&rsquo;s a perfect example of how Shortcuts can take something that feels rigid and make it fluid again.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/7830997656894d16a2fcb3aabc8cd56c" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20This%20Week%e2%80%99s%20Events%20Icon.jpg" alt="Get This Week’s Events app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/7830997656894d16a2fcb3aabc8cd56c" target="_blank" rel="noopener">
    Get This Week’s Events
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the things I love about Shortcuts is how they let you bend the system to match your mental model of time. Apple&rsquo;s Calendar app is great at showing what&rsquo;s on your plate, but sometimes you want to zoom out and get a clear snapshot of just this week. That&rsquo;s exactly what this Shortcut, Get This Week&rsquo;s Events, does&ndash;by calculating the week&rsquo;s boundaries dynamically and pulling in only the events you care about.</p>
<hr>
<h3 id="how-it-works">How It Works</h3>
<p>The Shortcut starts by establishing today&rsquo;s date and formatting it into a value that the rest of the workflow can understand. From there, it leans on a Dictionary that acts like a custom lookup table for each day of the week. This dictionary defines offsets for both the start and end of the week depending on the current day.</p>
<p>For example:</p>
<ul>
<li>Sunday maps to {Start: 0, End: 6}</li>
<li>Monday maps to {Start: 1, End: 5}</li>
<li>Wednesday maps to {Start: 3, End: 3}</li>
</ul>
<p>This clever setup means the Shortcut doesn&rsquo;t have to assume whether your week starts on Sunday, Monday, or any other day&ndash;it adapts automatically by subtracting and adding the right number of days from the current date.</p>
<hr>
<h3 id="calculating-the-range">Calculating the Range</h3>
<p>Once the dictionary hands back the correct offsets, the Shortcut does a simple bit of date math:</p>
<ul>
<li>Subtract the &ldquo;Start&rdquo; offset from the current date to calculate the Start of Week.</li>
<li>Add the &ldquo;End&rdquo; offset to the current date to calculate the End of Week.</li>
</ul>
<p>Both results are saved into variables, which become the boundaries for the next step.</p>
<hr>
<h3 id="finding-your-events">Finding Your Events</h3>
<p>With the week&rsquo;s start and end pinned down, the Shortcut uses the Find Calendar Events action to grab only the events whose start date falls between those two values. That means whether you run this on a Tuesday or a Friday, you&rsquo;ll always get a list scoped neatly to the current week, no manual scrolling required.</p>
<hr>
<h3 id="why-this-matters">Why This Matters</h3>
<p>On the surface, it looks like a simple &ldquo;show me my week&rdquo; automation&ndash;but the beauty here is in how it generalizes. By abstracting the week&rsquo;s structure into a dictionary, you can easily tweak how you want your weeks defined. For instance, you could redefine Saturday as the end of the week or experiment with rolling five-day &ldquo;work weeks&rdquo; instead of calendar weeks.</p>
<p>This kind of flexibility is exactly why Shortcuts shines: you&rsquo;re not stuck with Apple&rsquo;s defaults&ndash;you can make the system reflect your schedule.</p>
<hr>
<h3 id="my-take">My Take</h3>
<p>I&rsquo;ve tried plenty of ways to get a weekly overview&ndash;widgets, third-party apps, even manually filtering in Calendar&ndash;but nothing beats the elegance of this Shortcut. It&rsquo;s fast, it&rsquo;s reliable, and it always gives me the right slice of time, no matter the day. It&rsquo;s a perfect example of how Shortcuts can take something that feels rigid and make it fluid again.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/7830997656894d16a2fcb3aabc8cd56c" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20This%20Week%e2%80%99s%20Events%20Icon.jpg" alt="Get This Week’s Events app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/7830997656894d16a2fcb3aabc8cd56c" target="_blank" rel="noopener">
    Get This Week’s Events
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Convert Current Date to Unix Time with Shortcuts</title><link>https://blog.aidanmaurinjones.com/posts/convert-current-date-to-unix-time-with-shortcuts/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/convert-current-date-to-unix-time-with-shortcuts/</guid><pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>Some automations are so simple that they almost feel like magic tricks. A great example of this is my Shortcut for converting any date&ndash;or just the current one&ndash;into Unix time.</p>
<p>For those unfamiliar, Unix time is a standard way of representing dates as the number of seconds since January 1, 1970, at midnight UTC. It&rsquo;s widely used in APIs, databases, and automation tools because it turns messy human dates into a single number that&rsquo;s easy for computers to understand.</p>
<hr>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>The Shortcut begins with a conditional check:</p>
<ul>
<li>If Shortcut Input has a value → use that as the date.</li>
<li>Otherwise → fall back to the current date.</li>
</ul>
<p>This flexibility means you can pass in a date from another Shortcut, an app, or a file&ndash;and it&rsquo;ll just work. If you don&rsquo;t supply anything, it defaults to &ldquo;now,&rdquo; which is handy for most uses.</p>
<p>Next, the Shortcut defines a fixed reference point:</p>
<p>1970-01-01T00:00:00Z</p>
<p>This is the start of Unix time (known as the epoch). The Shortcut parses that text into a date object.</p>
<p>Finally, it calculates the difference in seconds between the chosen date (from input or current) and the epoch date. The result is a clean integer: Unix time.</p>
<hr>
<h3 id="why-this-is-useful">Why This Is Useful</h3>
<p>I reach for this Shortcut whenever I&rsquo;m working with APIs that require timestamps or when I need a quick way to normalize dates into a standard format. It&rsquo;s especially useful in web automations, logging workflows, and even in Home Assistant setups where Unix time values can simplify comparisons.</p>
<p>What I love about this Shortcut is how it elegantly combines a few building blocks&ndash;conditional input, a static reference date, and a date difference&ndash;into a tool I use far more often than I expected. It turns a concept buried deep in programming textbooks into a tap-friendly utility.</p>
<hr>
<h3 id="try-it-yourself">Try It Yourself</h3>
<p>You can run this Shortcut as-is for an instant timestamp or pass in dates from elsewhere to convert them. Either way, you&rsquo;ll always get a precise Unix time value at the end.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/0c224e59ffa14ae7a1f285199f3b1b15" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Convert%20Current%20Date%20to%20Unix%20Time%20Icon.jpg" alt="Convert Current Date to Unix Time app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/0c224e59ffa14ae7a1f285199f3b1b15" target="_blank" rel="noopener">
    Convert Current Date to Unix Time
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>Some automations are so simple that they almost feel like magic tricks. A great example of this is my Shortcut for converting any date&ndash;or just the current one&ndash;into Unix time.</p>
<p>For those unfamiliar, Unix time is a standard way of representing dates as the number of seconds since January 1, 1970, at midnight UTC. It&rsquo;s widely used in APIs, databases, and automation tools because it turns messy human dates into a single number that&rsquo;s easy for computers to understand.</p>
<hr>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>The Shortcut begins with a conditional check:</p>
<ul>
<li>If Shortcut Input has a value → use that as the date.</li>
<li>Otherwise → fall back to the current date.</li>
</ul>
<p>This flexibility means you can pass in a date from another Shortcut, an app, or a file&ndash;and it&rsquo;ll just work. If you don&rsquo;t supply anything, it defaults to &ldquo;now,&rdquo; which is handy for most uses.</p>
<p>Next, the Shortcut defines a fixed reference point:</p>
<p>1970-01-01T00:00:00Z</p>
<p>This is the start of Unix time (known as the epoch). The Shortcut parses that text into a date object.</p>
<p>Finally, it calculates the difference in seconds between the chosen date (from input or current) and the epoch date. The result is a clean integer: Unix time.</p>
<hr>
<h3 id="why-this-is-useful">Why This Is Useful</h3>
<p>I reach for this Shortcut whenever I&rsquo;m working with APIs that require timestamps or when I need a quick way to normalize dates into a standard format. It&rsquo;s especially useful in web automations, logging workflows, and even in Home Assistant setups where Unix time values can simplify comparisons.</p>
<p>What I love about this Shortcut is how it elegantly combines a few building blocks&ndash;conditional input, a static reference date, and a date difference&ndash;into a tool I use far more often than I expected. It turns a concept buried deep in programming textbooks into a tap-friendly utility.</p>
<hr>
<h3 id="try-it-yourself">Try It Yourself</h3>
<p>You can run this Shortcut as-is for an instant timestamp or pass in dates from elsewhere to convert them. Either way, you&rsquo;ll always get a precise Unix time value at the end.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/0c224e59ffa14ae7a1f285199f3b1b15" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Convert%20Current%20Date%20to%20Unix%20Time%20Icon.jpg" alt="Convert Current Date to Unix Time app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/0c224e59ffa14ae7a1f285199f3b1b15" target="_blank" rel="noopener">
    Convert Current Date to Unix Time
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Automating TP-Link Kasa Devices with Shortcuts</title><link>https://blog.aidanmaurinjones.com/posts/automating-tp-link-kasa-devices-with-shortcuts/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/automating-tp-link-kasa-devices-with-shortcuts/</guid><pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the things I love about Shortcuts is how it can act as a bridge between apps and services
that don&rsquo;t officially support Apple&rsquo;s automation ecosystem. A perfect example of this is TP-Link&rsquo;s
Kasa line of smart plugs, switches, and bulbs. Kasa devices don&rsquo;t natively integrate with
Shortcuts&ndash;but with a little API trickery, you can bring them right into your automations.</p>
<p>Over the past week, I&rsquo;ve been experimenting with three public Shortcuts that unlock the Kasa
cloud API:</p>
<ol>
<li>
<p>Get Kasa API Token</p>
</li>
<li>
<p>Get Kasa Device Details</p>
</li>
<li>
<p>Turn On/Off Kasa Device</p>
</li>
</ol>
<p>Together, they form a powerful workflow that lets you log in to your account, retrieve all
of your devices, and control them&ndash;all without ever opening the Kasa app.</p>
<hr>
<h3 id="step-1-authenticating-with-the-kasa-cloud">Step 1: Authenticating with the Kasa Cloud</h3>
<p>Everything starts with the Get Kasa API Token Shortcut. This Shortcut asks for the email and
password tied to your Kasa account, along with a UUID (a unique identifier that mimics the
Kasa app itself). With these values, the Shortcut sends a login request to the Kasa cloud
endpoint:</p>
<pre><code>https://wap.tplinkcloud.com/
</code></pre>
<p>The response includes a temporary API token&ndash;your golden ticket for making further requests. Without
it, nothing else works. Tokens do expire occasionally (usually after an app update), but
re-running the Shortcut instantly refreshes your access.</p>
<hr>
<h3 id="step-2-retrieving-your-devices">Step 2: Retrieving Your Devices</h3>
<p>Once you have a token, the next step is to get a list of devices tied to your account. That&rsquo;s
where Get Kasa Device Details comes in.</p>
<p>This Shortcut takes your token and sends a getDeviceList request. The response is a JSON
dictionary containing all of your Kasa devices&ndash;each with a friendly name (alias), a deviceId,
and an appServerUrl (the regional server that manages the device).</p>
<p>The Shortcut loops through this dictionary, extracts the essentials, and combines them into
a clean, human-readable list. Instead of parsing raw JSON, you get something like:</p>
<pre><code>&quot;Living Room Plug&quot;: {&quot;Device ID&quot;: &quot;8006XXXXXX&quot;, &quot;App Server URL&quot;: &quot;https://use1-wap.tplinkcloud.com&quot;}
</code></pre>
<p>This is the crucial information you&rsquo;ll need to actually control the device.</p>
<hr>
<h3 id="step-3-turning-devices-on-and-off">Step 3: Turning Devices On and Off</h3>
<p>With the token, device ID, and server URL in hand, the final piece of the puzzle is Turn
On/Off Kasa Device.</p>
<p>This Shortcut first prompts you for the values you retrieved in step two, then asks you to
choose an action: On or Off. Internally, those options map to 1 and 0, which the API uses
to change the relay state.</p>
<p>The Shortcut builds a JSON request that looks like this:</p>
<pre><code>{
  &quot;method&quot;: &quot;passthrough&quot;,
  &quot;params&quot;: {
    &quot;deviceId&quot;: &quot;YOUR_DEVICE_ID&quot;,
    &quot;requestData&quot;: &quot;{\&quot;system\&quot;:{\&quot;set_relay_state\&quot;:{\&quot;state\&quot;:1}}}&quot;
  }
}
</code></pre>
<p>Send that request to the Kasa cloud, and&ndash;like magic&ndash;your smart plug or bulb responds instantly.</p>
<hr>
<h3 id="why-this-matters">Why This Matters</h3>
<p>Kasa devices are popular because they&rsquo;re inexpensive, reliable, and don&rsquo;t require a separate
hub. But until now, integrating them with Shortcuts has meant relying on Homebridge, third-party apps,
or clunky workarounds.</p>
<p>These three Shortcuts cut out the middleman. They give you direct control over your Kasa
devices from within Shortcuts, meaning you can tie them into existing automations:</p>
<ul>
<li>Turn on a desk lamp when you start a Focus mode.</li>
<li>Power cycle your router with a tap on the Home Screen.</li>
<li>Shut off everything in the house with a single command to Siri.</li>
</ul>
<hr>
<h3 id="credit-where-its-due">Credit Where It&rsquo;s Due</h3>
<p>All of this is made possible thanks to the excellent research and documentation by Joshua
Tz, who published the Kasa API details. His guide <a href="https://docs.joshuatz.com/random/tp-link-kasa/">is available here</a>
and is an invaluable resource for anyone who wants to go deeper into the API beyond what
Shortcuts can do.</p>
<hr>
<h3 id="future-improvements">Future Improvements</h3>
<p>Right now, the workflow involves some copy-paste steps&ndash;retrieving the token in one Shortcut,
then pasting it into another. With a bit of refinement, the whole process could be chained
into a single Shortcut: log in, fetch devices, pick one, and toggle it&ndash;all in one go. That&rsquo;s
the kind of polish that makes Shortcuts shine.</p>
<p>But even as-is, this trio of Shortcuts transforms Kasa devices from &ldquo;app-only&rdquo; gadgets into
fully programmable components of your Apple ecosystem. And that&rsquo;s the magic of Shortcuts:
giving you the tools to bend devices and services to your will&ndash;even when their makers don&rsquo;t.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/997094909661423e99810869f493d5ce" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20Kasa%20API%20Token%20%28Public%29%20Icon.jpg" alt="Get Kasa API Token app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/997094909661423e99810869f493d5ce" target="_blank" rel="noopener">
    Get Kasa API Token
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/56b5bf3a4abe4a6e946ba2d3ee4fc9b7" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20Kasa%20Device%20Details%20%28Public%29%20Icon.jpg" alt="Get Kasa Device Details app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/56b5bf3a4abe4a6e946ba2d3ee4fc9b7" target="_blank" rel="noopener">
    Get Kasa Device Details
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/0f8d26fecc294230bac0f1a0611bee1e" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Turn%20ON%20&amp;%20OFF%20Kasa%20Device%20%28Public%29%20Icon.jpg" alt="Turn ON &amp; OFF Kasa Device app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/0f8d26fecc294230bac0f1a0611bee1e" target="_blank" rel="noopener">
    Turn ON &amp; OFF Kasa Device
  </a>
</article>


</div>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create This Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/actions/id1586435171?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Actions%20Icon.jpg" alt="Actions app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/actions/id1586435171?uo=4" target="_blank" rel="noopener">
    Actions
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the things I love about Shortcuts is how it can act as a bridge between apps and services
that don&rsquo;t officially support Apple&rsquo;s automation ecosystem. A perfect example of this is TP-Link&rsquo;s
Kasa line of smart plugs, switches, and bulbs. Kasa devices don&rsquo;t natively integrate with
Shortcuts&ndash;but with a little API trickery, you can bring them right into your automations.</p>
<p>Over the past week, I&rsquo;ve been experimenting with three public Shortcuts that unlock the Kasa
cloud API:</p>
<ol>
<li>
<p>Get Kasa API Token</p>
</li>
<li>
<p>Get Kasa Device Details</p>
</li>
<li>
<p>Turn On/Off Kasa Device</p>
</li>
</ol>
<p>Together, they form a powerful workflow that lets you log in to your account, retrieve all
of your devices, and control them&ndash;all without ever opening the Kasa app.</p>
<hr>
<h3 id="step-1-authenticating-with-the-kasa-cloud">Step 1: Authenticating with the Kasa Cloud</h3>
<p>Everything starts with the Get Kasa API Token Shortcut. This Shortcut asks for the email and
password tied to your Kasa account, along with a UUID (a unique identifier that mimics the
Kasa app itself). With these values, the Shortcut sends a login request to the Kasa cloud
endpoint:</p>
<pre><code>https://wap.tplinkcloud.com/
</code></pre>
<p>The response includes a temporary API token&ndash;your golden ticket for making further requests. Without
it, nothing else works. Tokens do expire occasionally (usually after an app update), but
re-running the Shortcut instantly refreshes your access.</p>
<hr>
<h3 id="step-2-retrieving-your-devices">Step 2: Retrieving Your Devices</h3>
<p>Once you have a token, the next step is to get a list of devices tied to your account. That&rsquo;s
where Get Kasa Device Details comes in.</p>
<p>This Shortcut takes your token and sends a getDeviceList request. The response is a JSON
dictionary containing all of your Kasa devices&ndash;each with a friendly name (alias), a deviceId,
and an appServerUrl (the regional server that manages the device).</p>
<p>The Shortcut loops through this dictionary, extracts the essentials, and combines them into
a clean, human-readable list. Instead of parsing raw JSON, you get something like:</p>
<pre><code>&quot;Living Room Plug&quot;: {&quot;Device ID&quot;: &quot;8006XXXXXX&quot;, &quot;App Server URL&quot;: &quot;https://use1-wap.tplinkcloud.com&quot;}
</code></pre>
<p>This is the crucial information you&rsquo;ll need to actually control the device.</p>
<hr>
<h3 id="step-3-turning-devices-on-and-off">Step 3: Turning Devices On and Off</h3>
<p>With the token, device ID, and server URL in hand, the final piece of the puzzle is Turn
On/Off Kasa Device.</p>
<p>This Shortcut first prompts you for the values you retrieved in step two, then asks you to
choose an action: On or Off. Internally, those options map to 1 and 0, which the API uses
to change the relay state.</p>
<p>The Shortcut builds a JSON request that looks like this:</p>
<pre><code>{
  &quot;method&quot;: &quot;passthrough&quot;,
  &quot;params&quot;: {
    &quot;deviceId&quot;: &quot;YOUR_DEVICE_ID&quot;,
    &quot;requestData&quot;: &quot;{\&quot;system\&quot;:{\&quot;set_relay_state\&quot;:{\&quot;state\&quot;:1}}}&quot;
  }
}
</code></pre>
<p>Send that request to the Kasa cloud, and&ndash;like magic&ndash;your smart plug or bulb responds instantly.</p>
<hr>
<h3 id="why-this-matters">Why This Matters</h3>
<p>Kasa devices are popular because they&rsquo;re inexpensive, reliable, and don&rsquo;t require a separate
hub. But until now, integrating them with Shortcuts has meant relying on Homebridge, third-party apps,
or clunky workarounds.</p>
<p>These three Shortcuts cut out the middleman. They give you direct control over your Kasa
devices from within Shortcuts, meaning you can tie them into existing automations:</p>
<ul>
<li>Turn on a desk lamp when you start a Focus mode.</li>
<li>Power cycle your router with a tap on the Home Screen.</li>
<li>Shut off everything in the house with a single command to Siri.</li>
</ul>
<hr>
<h3 id="credit-where-its-due">Credit Where It&rsquo;s Due</h3>
<p>All of this is made possible thanks to the excellent research and documentation by Joshua
Tz, who published the Kasa API details. His guide <a href="https://docs.joshuatz.com/random/tp-link-kasa/">is available here</a>
and is an invaluable resource for anyone who wants to go deeper into the API beyond what
Shortcuts can do.</p>
<hr>
<h3 id="future-improvements">Future Improvements</h3>
<p>Right now, the workflow involves some copy-paste steps&ndash;retrieving the token in one Shortcut,
then pasting it into another. With a bit of refinement, the whole process could be chained
into a single Shortcut: log in, fetch devices, pick one, and toggle it&ndash;all in one go. That&rsquo;s
the kind of polish that makes Shortcuts shine.</p>
<p>But even as-is, this trio of Shortcuts transforms Kasa devices from &ldquo;app-only&rdquo; gadgets into
fully programmable components of your Apple ecosystem. And that&rsquo;s the magic of Shortcuts:
giving you the tools to bend devices and services to your will&ndash;even when their makers don&rsquo;t.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/997094909661423e99810869f493d5ce" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20Kasa%20API%20Token%20%28Public%29%20Icon.jpg" alt="Get Kasa API Token app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/997094909661423e99810869f493d5ce" target="_blank" rel="noopener">
    Get Kasa API Token
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/56b5bf3a4abe4a6e946ba2d3ee4fc9b7" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20Kasa%20Device%20Details%20%28Public%29%20Icon.jpg" alt="Get Kasa Device Details app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/56b5bf3a4abe4a6e946ba2d3ee4fc9b7" target="_blank" rel="noopener">
    Get Kasa Device Details
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/0f8d26fecc294230bac0f1a0611bee1e" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Turn%20ON%20&amp;%20OFF%20Kasa%20Device%20%28Public%29%20Icon.jpg" alt="Turn ON &amp; OFF Kasa Device app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/0f8d26fecc294230bac0f1a0611bee1e" target="_blank" rel="noopener">
    Turn ON &amp; OFF Kasa Device
  </a>
</article>


</div>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create This Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/actions/id1586435171?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Actions%20Icon.jpg" alt="Actions app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/actions/id1586435171?uo=4" target="_blank" rel="noopener">
    Actions
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Controlling SwitchBot Devices with Shortcuts and the Web API</title><link>https://blog.aidanmaurinjones.com/posts/controlling-switchbot-devices-with-shortcuts-and-the-web-api/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/controlling-switchbot-devices-with-shortcuts-and-the-web-api/</guid><pubDate>Wed, 24 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of my favorite things about Apple&rsquo;s Shortcuts app is how it can bridge the gap between hardware and cloud APIs without requiring a single line of &ldquo;real&rdquo; code. A perfect example of this is SwitchBot: a line of Bluetooth and Wi-Fi-enabled devices that can be controlled through their official app&ndash;or, with a bit of setup, entirely through Shortcuts.</p>
<p>In this post, I&rsquo;ll walk you through two Shortcuts I built: one to fetch a list of all my SwitchBot devices, and another to send commands to them. Together, they let me control my smart home directly from Siri, widgets, or automations.</p>
<hr>
<h3 id="getting-device-details">Getting Device Details</h3>
<p>The first Shortcut is a template for retrieving all registered SwitchBot devices from the company&rsquo;s cloud API.</p>
<p>It starts with a simple Text action where I paste in my API authorization key. That&rsquo;s followed by another Text action containing the endpoint URL:</p>
<pre><code>https://api.switch-bot.com/v1.0/devices/
</code></pre>
<p>The real magic happens in the Get Contents of URL action. Set to GET, this step includes a header named Authorization, pulling in the key from the earlier Text block. When the Shortcut runs, the response contains a full list of my devices and their details&ndash;device IDs, types, names, and more.</p>
<p>For me, this shortcut is especially useful when I need to look up a device ID to use in the second Shortcut.</p>
<hr>
<h3 id="sending-commands">Sending Commands</h3>
<p>The second Shortcut is where things get really interesting: sending a command to a specific device. It uses the same authorization key, but adds a few more building blocks:</p>
<ul>
<li>Device ID (so the API knows which device to target)</li>
<li>Command Type (usually &ldquo;command&rdquo;)</li>
<li>Command (for example, &ldquo;turnOn&rdquo;, &ldquo;turnOff&rdquo;, or &ldquo;toggle&rdquo;)</li>
<li>Parameter (some commands require additional values, like brightness levels or modes)</li>
</ul>
<p>The API endpoint looks like this:</p>
<pre><code>https://api.switch-bot.com/v1.0/devices/{deviceId}/commands
</code></pre>
<p>And instead of GET, this time the Shortcut uses a POST request with a JSON body. The Get Contents of URL action sends fields for commandType, command, and parameter, all filled from earlier Text actions in the Shortcut.</p>
<p>With this structure, I can turn lights on and off, start a fan, or even trigger my SwitchBot Curtain with a single tap. All without ever opening the SwitchBot app.</p>
<hr>
<h3 id="why-this-matters">Why This Matters</h3>
<p>There are countless ways to integrate SwitchBot devices with other smart home platforms, but building these Shortcuts has two big advantages:</p>
<ol>
<li>
<p>Speed &ndash; I can tie them directly into Siri, widgets, or automations. Saying &ldquo;Hey Siri, turn on the fan&rdquo; actually triggers my Shortcut, which hits the SwitchBot API in less than a second.</p>
</li>
<li>
<p>Flexibility &ndash; Since the commands are just text values, I can duplicate the Shortcut and customize it for any device and action I want, without writing code or digging through menus.</p>
</li>
</ol>
<p>For someone like me, who&rsquo;s already knee-deep in Shortcuts for other parts of my life, this setup feels natural. I can slot these actions into bigger workflows&ndash;turning on my SwitchBot devices when I leave work, or including them in a &ldquo;Good Morning&rdquo; routine alongside music and calendar events.</p>
<hr>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>Shortcuts may not be the most glamorous way to control smart home gear, but you can do it. By working directly with the SwitchBot API, these automations skip the app entirely and give me the confidence that when I tap a button, my devices respond.</p>
<p>It&rsquo;s yet another example of how Shortcuts can serve as the glue between platforms, devices, and services. And for SwitchBot users, it&rsquo;s a reminder that sometimes the simplest approach is also the most powerful.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/430120281f3c4b75a59c1bb2dbc90453" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20SwitchBot%20Devices%20Template%20%28Public%29%20Icon.jpg" alt="Get SwitchBot Devices Template app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/430120281f3c4b75a59c1bb2dbc90453" target="_blank" rel="noopener">
    Get SwitchBot Devices Template
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/7042d2acf1864db9b7b604e8ea4971ed" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Send%20Command%20to%20SwitchBot%20Template%20%28Public%29%20Icon.jpg" alt="Send Command to SwitchBot Template app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/7042d2acf1864db9b7b604e8ea4971ed" target="_blank" rel="noopener">
    Send Command to SwitchBot Template
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of my favorite things about Apple&rsquo;s Shortcuts app is how it can bridge the gap between hardware and cloud APIs without requiring a single line of &ldquo;real&rdquo; code. A perfect example of this is SwitchBot: a line of Bluetooth and Wi-Fi-enabled devices that can be controlled through their official app&ndash;or, with a bit of setup, entirely through Shortcuts.</p>
<p>In this post, I&rsquo;ll walk you through two Shortcuts I built: one to fetch a list of all my SwitchBot devices, and another to send commands to them. Together, they let me control my smart home directly from Siri, widgets, or automations.</p>
<hr>
<h3 id="getting-device-details">Getting Device Details</h3>
<p>The first Shortcut is a template for retrieving all registered SwitchBot devices from the company&rsquo;s cloud API.</p>
<p>It starts with a simple Text action where I paste in my API authorization key. That&rsquo;s followed by another Text action containing the endpoint URL:</p>
<pre><code>https://api.switch-bot.com/v1.0/devices/
</code></pre>
<p>The real magic happens in the Get Contents of URL action. Set to GET, this step includes a header named Authorization, pulling in the key from the earlier Text block. When the Shortcut runs, the response contains a full list of my devices and their details&ndash;device IDs, types, names, and more.</p>
<p>For me, this shortcut is especially useful when I need to look up a device ID to use in the second Shortcut.</p>
<hr>
<h3 id="sending-commands">Sending Commands</h3>
<p>The second Shortcut is where things get really interesting: sending a command to a specific device. It uses the same authorization key, but adds a few more building blocks:</p>
<ul>
<li>Device ID (so the API knows which device to target)</li>
<li>Command Type (usually &ldquo;command&rdquo;)</li>
<li>Command (for example, &ldquo;turnOn&rdquo;, &ldquo;turnOff&rdquo;, or &ldquo;toggle&rdquo;)</li>
<li>Parameter (some commands require additional values, like brightness levels or modes)</li>
</ul>
<p>The API endpoint looks like this:</p>
<pre><code>https://api.switch-bot.com/v1.0/devices/{deviceId}/commands
</code></pre>
<p>And instead of GET, this time the Shortcut uses a POST request with a JSON body. The Get Contents of URL action sends fields for commandType, command, and parameter, all filled from earlier Text actions in the Shortcut.</p>
<p>With this structure, I can turn lights on and off, start a fan, or even trigger my SwitchBot Curtain with a single tap. All without ever opening the SwitchBot app.</p>
<hr>
<h3 id="why-this-matters">Why This Matters</h3>
<p>There are countless ways to integrate SwitchBot devices with other smart home platforms, but building these Shortcuts has two big advantages:</p>
<ol>
<li>
<p>Speed &ndash; I can tie them directly into Siri, widgets, or automations. Saying &ldquo;Hey Siri, turn on the fan&rdquo; actually triggers my Shortcut, which hits the SwitchBot API in less than a second.</p>
</li>
<li>
<p>Flexibility &ndash; Since the commands are just text values, I can duplicate the Shortcut and customize it for any device and action I want, without writing code or digging through menus.</p>
</li>
</ol>
<p>For someone like me, who&rsquo;s already knee-deep in Shortcuts for other parts of my life, this setup feels natural. I can slot these actions into bigger workflows&ndash;turning on my SwitchBot devices when I leave work, or including them in a &ldquo;Good Morning&rdquo; routine alongside music and calendar events.</p>
<hr>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>Shortcuts may not be the most glamorous way to control smart home gear, but you can do it. By working directly with the SwitchBot API, these automations skip the app entirely and give me the confidence that when I tap a button, my devices respond.</p>
<p>It&rsquo;s yet another example of how Shortcuts can serve as the glue between platforms, devices, and services. And for SwitchBot users, it&rsquo;s a reminder that sometimes the simplest approach is also the most powerful.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/430120281f3c4b75a59c1bb2dbc90453" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Get%20SwitchBot%20Devices%20Template%20%28Public%29%20Icon.jpg" alt="Get SwitchBot Devices Template app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/430120281f3c4b75a59c1bb2dbc90453" target="_blank" rel="noopener">
    Get SwitchBot Devices Template
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/7042d2acf1864db9b7b604e8ea4971ed" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Send%20Command%20to%20SwitchBot%20Template%20%28Public%29%20Icon.jpg" alt="Send Command to SwitchBot Template app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/7042d2acf1864db9b7b604e8ea4971ed" target="_blank" rel="noopener">
    Send Command to SwitchBot Template
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Turning iCloud Shortcut Links into Share Buttons</title><link>https://blog.aidanmaurinjones.com/posts/turning-icloud-shortcut-links-into-share-buttons/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/turning-icloud-shortcut-links-into-share-buttons/</guid><pubDate>Tue, 23 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the best things about Shortcuts is that it can bridge services that were never designed
to talk to each other. The Shortcut I’ve been using lately—Share Shortcut HTML Button—is a
perfect example of that. With it, I can take any iCloud Shortcut link and instantly generate
a fully-formed Hugo shortcode that embeds the Shortcut on my blog with its name and icon, no
copy-pasting or manual uploading required.</p>
<p>⸻</p>
<h3 id="the-problem">The Problem</h3>
<p>When you share a Shortcut publicly, Apple gives you an iCloud link that looks something
like this:</p>
<p><a href="https://www.icloud.com/shortcuts/123abc">https://www.icloud.com/shortcuts/123abc</a>&hellip;</p>
<p>It works fine for sharing with friends, but when I want to add that Shortcut to my blog, I
need more than just the link. I need:</p>
<ul>
<li>The Shortcut’s proper name</li>
<li>Its icon image</li>
<li>A clean HTML/Hugo shortcode block I can drop into a Markdown file</li>
</ul>
<p>Doing all of this by hand was tedious. So I automated it.</p>
<p>⸻</p>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>The Shortcut breaks down into three key stages: fetching metadata, processing the icon, and
generating the blog card.</p>
<p><strong>Fetching Metadata</strong></p>
<p>The Shortcut starts by receiving a Shortcut iCloud link (or grabbing it from the clipboard
if none is passed in). From there:</p>
<ul>
<li>It rewrites the link into Apple’s hidden API endpoint at <a href="https://www.icloud.com/shortcuts/api/records/">https://www.icloud.com/shortcuts/api/records/</a>.</li>
<li>Using Get Contents of URL, it downloads the Shortcut’s metadata as JSON.</li>
<li>With Get Dictionary from Contents of URL, I can then pull out fields like fields.name.value
(the Shortcut’s title) and fields.icon.value.downloadURL (the actual icon).</li>
</ul>
<p><strong>Processing the Icon</strong></p>
<p>Here’s the clever part: I don’t just hotlink the icon from iCloud. Instead:</p>
<ul>
<li>I construct a GitHub API URL pointing to my site’s static/images/Shortcuts Icons folder.</li>
<li>The Shortcut checks whether a file with the same name already exists (by calling GitHub’s
API and looking for a SHA).</li>
<li>If the icon isn’t there, it downloads the image, renames it with the Shortcut’s title, and
encodes it in Base64.</li>
<li>Finally, it uploads the icon to GitHub via the API, neatly slotting it into my Hugo site’s
image folder.</li>
</ul>
<p>Now every Shortcut I publish has its own local icon, version-controlled alongside the rest
of my site.</p>
<p><strong>Generating the Blog Card</strong></p>
<p>The Shortcut assembles the code automatically, copies it to my clipboard, and I can paste
it directly into my Markdown post. No typing, no file juggling, no guesswork.</p>
<p>⸻</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>This Shortcut may sound niche, but it’s been a huge time saver for me. I publish a lot of
posts about Shortcuts, and before this, each one meant multiple minutes of repetitive work:
saving icons, renaming them, uploading them, writing out HTML. Now it’s one tap.</p>
<p>The broader lesson here is that Shortcuts isn’t limited to “personal productivity” hacks.
It’s powerful enough to serve as part of a publishing pipeline, gluing together iCloud’s
hidden APIs, GitHub’s developer endpoints, and Hugo’s templating system.</p>
<p>And that’s why I love this Shortcut: it turns Apple’s barebones sharing into a complete,
blog-ready package.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/feeec271478543b299710fb20e6bffab" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Share%20Shortcut%20HTML%20Button%20%28Public%29%20Icon.jpg" alt="Share Shortcut HTML Button app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/feeec271478543b299710fb20e6bffab" target="_blank" rel="noopener">
    Share Shortcut HTML Button
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the best things about Shortcuts is that it can bridge services that were never designed
to talk to each other. The Shortcut I’ve been using lately—Share Shortcut HTML Button—is a
perfect example of that. With it, I can take any iCloud Shortcut link and instantly generate
a fully-formed Hugo shortcode that embeds the Shortcut on my blog with its name and icon, no
copy-pasting or manual uploading required.</p>
<p>⸻</p>
<h3 id="the-problem">The Problem</h3>
<p>When you share a Shortcut publicly, Apple gives you an iCloud link that looks something
like this:</p>
<p><a href="https://www.icloud.com/shortcuts/123abc">https://www.icloud.com/shortcuts/123abc</a>&hellip;</p>
<p>It works fine for sharing with friends, but when I want to add that Shortcut to my blog, I
need more than just the link. I need:</p>
<ul>
<li>The Shortcut’s proper name</li>
<li>Its icon image</li>
<li>A clean HTML/Hugo shortcode block I can drop into a Markdown file</li>
</ul>
<p>Doing all of this by hand was tedious. So I automated it.</p>
<p>⸻</p>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>The Shortcut breaks down into three key stages: fetching metadata, processing the icon, and
generating the blog card.</p>
<p><strong>Fetching Metadata</strong></p>
<p>The Shortcut starts by receiving a Shortcut iCloud link (or grabbing it from the clipboard
if none is passed in). From there:</p>
<ul>
<li>It rewrites the link into Apple’s hidden API endpoint at <a href="https://www.icloud.com/shortcuts/api/records/">https://www.icloud.com/shortcuts/api/records/</a>.</li>
<li>Using Get Contents of URL, it downloads the Shortcut’s metadata as JSON.</li>
<li>With Get Dictionary from Contents of URL, I can then pull out fields like fields.name.value
(the Shortcut’s title) and fields.icon.value.downloadURL (the actual icon).</li>
</ul>
<p><strong>Processing the Icon</strong></p>
<p>Here’s the clever part: I don’t just hotlink the icon from iCloud. Instead:</p>
<ul>
<li>I construct a GitHub API URL pointing to my site’s static/images/Shortcuts Icons folder.</li>
<li>The Shortcut checks whether a file with the same name already exists (by calling GitHub’s
API and looking for a SHA).</li>
<li>If the icon isn’t there, it downloads the image, renames it with the Shortcut’s title, and
encodes it in Base64.</li>
<li>Finally, it uploads the icon to GitHub via the API, neatly slotting it into my Hugo site’s
image folder.</li>
</ul>
<p>Now every Shortcut I publish has its own local icon, version-controlled alongside the rest
of my site.</p>
<p><strong>Generating the Blog Card</strong></p>
<p>The Shortcut assembles the code automatically, copies it to my clipboard, and I can paste
it directly into my Markdown post. No typing, no file juggling, no guesswork.</p>
<p>⸻</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>This Shortcut may sound niche, but it’s been a huge time saver for me. I publish a lot of
posts about Shortcuts, and before this, each one meant multiple minutes of repetitive work:
saving icons, renaming them, uploading them, writing out HTML. Now it’s one tap.</p>
<p>The broader lesson here is that Shortcuts isn’t limited to “personal productivity” hacks.
It’s powerful enough to serve as part of a publishing pipeline, gluing together iCloud’s
hidden APIs, GitHub’s developer endpoints, and Hugo’s templating system.</p>
<p>And that’s why I love this Shortcut: it turns Apple’s barebones sharing into a complete,
blog-ready package.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/feeec271478543b299710fb20e6bffab" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Share%20Shortcut%20HTML%20Button%20%28Public%29%20Icon.jpg" alt="Share Shortcut HTML Button app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/feeec271478543b299710fb20e6bffab" target="_blank" rel="noopener">
    Share Shortcut HTML Button
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Share Mac App HTML Button: Automating App Cards from Alfred</title><link>https://blog.aidanmaurinjones.com/posts/share-mac-app-html-button---automating-app-cards-from-alfred/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/share-mac-app-html-button---automating-app-cards-from-alfred/</guid><pubDate>Tue, 23 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the realities of being a Mac user today is that many of the best apps you’ll discover
aren’t on the Mac App Store. Developers often prefer to sell directly, avoiding Apple’s restrictions
and revenue cut. That’s great for them (and often for us too, since it means more powerful software),
but it leaves one problem: how do you share those apps elegantly in a blog post?</p>
<p>The Mac App Store gives you a tidy preview link and icon, but direct-purchase apps don’t. That
means if I want to share an app like BBEdit or Audio Hijack, I’d normally have to dig into
the app bundle, extract the icon, save it out, rename it, upload it, then write the HTML
myself. Way too much friction.</p>
<p>So I built a Shortcut that does all of it for me. And because I run it as an Alfred File
Action, all I have to do is select the app and hit the hotkey. The Shortcut takes care of
the rest, turning any Mac app—App Store or not—into a polished HTML app card ready to paste
into my Hugo blog.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>The Shortcut is split into two halves: finding the app’s details and icon, then uploading
and generating the HTML snippet.</p>
<p><strong>Extracting the app’s icon and name</strong></p>
<p>It begins with an AppleScript that points at the selected .app bundle and looks inside its
Info.plist for the CFBundleIconFile. If that value’s missing, the script gracefully falls
back to the default AppIcon.</p>
<p>From there, it resolves the .icns file inside /Contents/Resources/, hands it back to Shortcuts,
and Shortcuts grabs the actual image. At the same time, it extracts the app’s display name so
I don’t have to type it myself later.</p>
<p><strong>Handling the upload</strong></p>
<p>With the icon in hand, the Shortcut preps the upload for GitHub. It checks if the icon is
already in my site’s /static/images/App Icons/ folder using the GitHub API. If it doesn’t
exist, the Shortcut converts the image to base64 and uploads it automatically.</p>
<p>This is especially handy for apps outside the Mac App Store, since I can’t rely on Apple’s
CDN to serve up a clean app icon for me. Once uploaded, the image is there permanently, ready
for reuse across future posts.</p>
<p><strong>Assembling the HTML card</strong></p>
<p>Finally, the Shortcut generates the Hugo shortcode I use for app cards. This snippet is copied
straight to my clipboard, so I can paste it into BBEdit alongside the rest of the post. To help
me fill in the missing link (since there’s no App Store URL), the Shortcut even runs a DuckDuckGo
search for the app’s name + “mac app.” Nine times out of ten, that surfaces the official
website instantly.</p>
<p>⸻</p>
<h3 id="why-this-shortcut-matters">Why This Shortcut Matters</h3>
<p>This automation is all about eliminating barriers. Whether the app is on the Mac App Store or
sold directly through a developer’s site, I get the same consistent app card on my blog. No
manual exporting, no renaming files, no repetitive uploads.</p>
<p>It also means I can highlight great indie apps without worrying about the extra effort. For
someone who posts often, these saved minutes add up, but more importantly, they keep me in
flow. When the tools fade into the background, the writing comes forward.</p>
<p>⸻</p>
<h3 id="alfred--shortcuts--a-perfect-match">Alfred + Shortcuts = A Perfect Match</h3>
<p>Running this Shortcut through Alfred is what makes it truly seamless. Instead of digging
through Finder or hunting down app paths manually, I just select the app in Alfred, trigger
the File Action, and let Shortcuts do the heavy lifting.</p>
<p>This combination works beautifully: Alfred is my quick-launch interface, and Shortcuts is the
automation engine in the background. Together, they make sharing Mac apps—App Store or not—as
easy as a keyboard command.</p>
<p>⸻</p>
<h3 id="the-bigger-picture">The Bigger Picture</h3>
<p>This Shortcut fits into a larger workflow where I’ve automated nearly every part of blogging,
from uploading screenshots to posting entire drafts to GitHub. Each piece removes just enough
friction to make publishing easier and more enjoyable.</p>
<p>The end result is that I can write more, share more, and showcase apps without worrying about
where they’re sold. The Mac App Store doesn’t have to be the gatekeeper for clean links and
icons anymore.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/ad57e1ca98d6430ca512e8649ffc96b8" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Share%20Mac%20App%20HTML%20Button%20%28Public%29%20Icon.jpg" alt="Share Mac App HTML Button app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/ad57e1ca98d6430ca512e8649ffc96b8" target="_blank" rel="noopener">
    Share Mac App HTML Button
  </a>
</article>

<h3 id="apps-used-to-create-this-automation">Apps Used to Create this Automation</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Alfred%205%20Icon.jpg" alt="Alfred 5 app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    Alfred 5
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://latenightsw.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Script%20Debugger%20Icon.jpg" alt="Script Debugger app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://latenightsw.com/" target="_blank" rel="noopener">
    Script Debugger
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the realities of being a Mac user today is that many of the best apps you’ll discover
aren’t on the Mac App Store. Developers often prefer to sell directly, avoiding Apple’s restrictions
and revenue cut. That’s great for them (and often for us too, since it means more powerful software),
but it leaves one problem: how do you share those apps elegantly in a blog post?</p>
<p>The Mac App Store gives you a tidy preview link and icon, but direct-purchase apps don’t. That
means if I want to share an app like BBEdit or Audio Hijack, I’d normally have to dig into
the app bundle, extract the icon, save it out, rename it, upload it, then write the HTML
myself. Way too much friction.</p>
<p>So I built a Shortcut that does all of it for me. And because I run it as an Alfred File
Action, all I have to do is select the app and hit the hotkey. The Shortcut takes care of
the rest, turning any Mac app—App Store or not—into a polished HTML app card ready to paste
into my Hugo blog.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>The Shortcut is split into two halves: finding the app’s details and icon, then uploading
and generating the HTML snippet.</p>
<p><strong>Extracting the app’s icon and name</strong></p>
<p>It begins with an AppleScript that points at the selected .app bundle and looks inside its
Info.plist for the CFBundleIconFile. If that value’s missing, the script gracefully falls
back to the default AppIcon.</p>
<p>From there, it resolves the .icns file inside /Contents/Resources/, hands it back to Shortcuts,
and Shortcuts grabs the actual image. At the same time, it extracts the app’s display name so
I don’t have to type it myself later.</p>
<p><strong>Handling the upload</strong></p>
<p>With the icon in hand, the Shortcut preps the upload for GitHub. It checks if the icon is
already in my site’s /static/images/App Icons/ folder using the GitHub API. If it doesn’t
exist, the Shortcut converts the image to base64 and uploads it automatically.</p>
<p>This is especially handy for apps outside the Mac App Store, since I can’t rely on Apple’s
CDN to serve up a clean app icon for me. Once uploaded, the image is there permanently, ready
for reuse across future posts.</p>
<p><strong>Assembling the HTML card</strong></p>
<p>Finally, the Shortcut generates the Hugo shortcode I use for app cards. This snippet is copied
straight to my clipboard, so I can paste it into BBEdit alongside the rest of the post. To help
me fill in the missing link (since there’s no App Store URL), the Shortcut even runs a DuckDuckGo
search for the app’s name + “mac app.” Nine times out of ten, that surfaces the official
website instantly.</p>
<p>⸻</p>
<h3 id="why-this-shortcut-matters">Why This Shortcut Matters</h3>
<p>This automation is all about eliminating barriers. Whether the app is on the Mac App Store or
sold directly through a developer’s site, I get the same consistent app card on my blog. No
manual exporting, no renaming files, no repetitive uploads.</p>
<p>It also means I can highlight great indie apps without worrying about the extra effort. For
someone who posts often, these saved minutes add up, but more importantly, they keep me in
flow. When the tools fade into the background, the writing comes forward.</p>
<p>⸻</p>
<h3 id="alfred--shortcuts--a-perfect-match">Alfred + Shortcuts = A Perfect Match</h3>
<p>Running this Shortcut through Alfred is what makes it truly seamless. Instead of digging
through Finder or hunting down app paths manually, I just select the app in Alfred, trigger
the File Action, and let Shortcuts do the heavy lifting.</p>
<p>This combination works beautifully: Alfred is my quick-launch interface, and Shortcuts is the
automation engine in the background. Together, they make sharing Mac apps—App Store or not—as
easy as a keyboard command.</p>
<p>⸻</p>
<h3 id="the-bigger-picture">The Bigger Picture</h3>
<p>This Shortcut fits into a larger workflow where I’ve automated nearly every part of blogging,
from uploading screenshots to posting entire drafts to GitHub. Each piece removes just enough
friction to make publishing easier and more enjoyable.</p>
<p>The end result is that I can write more, share more, and showcase apps without worrying about
where they’re sold. The Mac App Store doesn’t have to be the gatekeeper for clean links and
icons anymore.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/ad57e1ca98d6430ca512e8649ffc96b8" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Share%20Mac%20App%20HTML%20Button%20%28Public%29%20Icon.jpg" alt="Share Mac App HTML Button app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/ad57e1ca98d6430ca512e8649ffc96b8" target="_blank" rel="noopener">
    Share Mac App HTML Button
  </a>
</article>

<h3 id="apps-used-to-create-this-automation">Apps Used to Create this Automation</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Alfred%205%20Icon.jpg" alt="Alfred 5 app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    Alfred 5
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://latenightsw.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Script%20Debugger%20Icon.jpg" alt="Script Debugger app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://latenightsw.com/" target="_blank" rel="noopener">
    Script Debugger
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>App Store Links Made Beautiful with Shortcuts</title><link>https://blog.aidanmaurinjones.com/posts/app-store-links-made-beautiful-with-shortcuts/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/app-store-links-made-beautiful-with-shortcuts/</guid><pubDate>Tue, 23 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the small but constant frictions of running a blog about apps is dealing with App
Store links. Grabbing the name, copying the link, fetching an icon, turning it all into a
nicely formatted snippet—it’s not hard, but it’s repetitive. And if you do it often enough,
it’s exactly the kind of thing that cries out for automation.</p>
<p>That’s where this Shortcut comes in. Built entirely with stock Shortcuts actions, it takes
a single App Store link and spits out a polished Hugo shortcode ready to paste into a blog
post, complete with app name, link, and icon. What used to be a multi-step process is now
a single tap.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p><strong>Getting the App Store ID</strong></p>
<p>The Shortcut starts by receiving an App Store URL, either from the Share Sheet or your
clipboard. Using a quick regex ((?&lt;=id)\d+), it extracts the numeric app ID buried in the
link. That ID becomes the key for looking up everything else.</p>
<p><strong>Pulling App Metadata</strong></p>
<p>Next, Shortcuts’ built-in Find on the App Store action does the heavy lifting. It takes the
app ID and returns structured data: the app’s name, its store page, and, crucially, the artwork
URL for the icon.</p>
<p>At this point, the Shortcut already knows enough to generate a working app card, but it
goes further.</p>
<p><strong>Naming and File Prep</strong></p>
<p>The app’s name is cleaned up and stored in a variable, then URL-encoded so it can be used
safely as a filename. That ensures that even apps with spaces, dashes, or punctuation won’t
break the upload process later.</p>
<p><strong>Uploading the Icon</strong></p>
<p>Here’s where things get clever. The Shortcut builds a GitHub API request to upload the app
icon directly into the site’s repository. It grabs your personal API key, encodes the file,
and sends it off with a PUT request. If the file already exists, the Shortcut skips the upload
to avoid duplicates.</p>
<p>Behind the scenes, this means your blog’s /static/images/App Store App Icons/ folder is automatically
updated with the latest app logos—no manual dragging or renaming required.</p>
<p><strong>Assembling the Shortcode</strong></p>
<p>Finally, everything comes together in a Hugo appcard snippet:</p>
<p>This block gets copied straight to your clipboard, ready to paste into any Markdown file. The
icon path matches the uploaded file, the link points back to the store, and the name is exactly
as it appears in Apple’s listing.</p>
<p>⸻</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>This is a classic example of automation as time-saving infrastructure. Writing about apps
often involves dozens of small formatting chores that add up. By moving them into a Shortcut,
you don’t just save a few clicks—you make the whole workflow predictable, repeatable, and
error-free.</p>
<p>Better still, it’s all built with the tools Apple ships on every device. No third-party apps,
no scripting languages, no dependencies. Just Shortcuts, GitHub, and a bit of creativity.</p>
<p>⸻</p>
<h3 id="the-result">The Result</h3>
<p>Now, when inspiration strikes, I don’t have to think about sourcing icons or formatting
snippets. I just share an App Store link, run the Shortcut, and paste the finished card into
my blog post. It’s instant, it’s reliable, and it makes my site look great with zero extra
effort.</p>
<p>For a blog that lives and breathes apps, this Shortcut has become one of those invisible
automations that pays dividends every single day.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/7e33edc6ca804b259747d50c768bcf7d" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Share%20App%20Store%20App%20HTML%20Button%20%28Public%29%20Icon.jpg" alt="Share App Store App HTML Button app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/7e33edc6ca804b259747d50c768bcf7d" target="_blank" rel="noopener">
    Share App Store App HTML Button
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the small but constant frictions of running a blog about apps is dealing with App
Store links. Grabbing the name, copying the link, fetching an icon, turning it all into a
nicely formatted snippet—it’s not hard, but it’s repetitive. And if you do it often enough,
it’s exactly the kind of thing that cries out for automation.</p>
<p>That’s where this Shortcut comes in. Built entirely with stock Shortcuts actions, it takes
a single App Store link and spits out a polished Hugo shortcode ready to paste into a blog
post, complete with app name, link, and icon. What used to be a multi-step process is now
a single tap.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p><strong>Getting the App Store ID</strong></p>
<p>The Shortcut starts by receiving an App Store URL, either from the Share Sheet or your
clipboard. Using a quick regex ((?&lt;=id)\d+), it extracts the numeric app ID buried in the
link. That ID becomes the key for looking up everything else.</p>
<p><strong>Pulling App Metadata</strong></p>
<p>Next, Shortcuts’ built-in Find on the App Store action does the heavy lifting. It takes the
app ID and returns structured data: the app’s name, its store page, and, crucially, the artwork
URL for the icon.</p>
<p>At this point, the Shortcut already knows enough to generate a working app card, but it
goes further.</p>
<p><strong>Naming and File Prep</strong></p>
<p>The app’s name is cleaned up and stored in a variable, then URL-encoded so it can be used
safely as a filename. That ensures that even apps with spaces, dashes, or punctuation won’t
break the upload process later.</p>
<p><strong>Uploading the Icon</strong></p>
<p>Here’s where things get clever. The Shortcut builds a GitHub API request to upload the app
icon directly into the site’s repository. It grabs your personal API key, encodes the file,
and sends it off with a PUT request. If the file already exists, the Shortcut skips the upload
to avoid duplicates.</p>
<p>Behind the scenes, this means your blog’s /static/images/App Store App Icons/ folder is automatically
updated with the latest app logos—no manual dragging or renaming required.</p>
<p><strong>Assembling the Shortcode</strong></p>
<p>Finally, everything comes together in a Hugo appcard snippet:</p>
<p>This block gets copied straight to your clipboard, ready to paste into any Markdown file. The
icon path matches the uploaded file, the link points back to the store, and the name is exactly
as it appears in Apple’s listing.</p>
<p>⸻</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>This is a classic example of automation as time-saving infrastructure. Writing about apps
often involves dozens of small formatting chores that add up. By moving them into a Shortcut,
you don’t just save a few clicks—you make the whole workflow predictable, repeatable, and
error-free.</p>
<p>Better still, it’s all built with the tools Apple ships on every device. No third-party apps,
no scripting languages, no dependencies. Just Shortcuts, GitHub, and a bit of creativity.</p>
<p>⸻</p>
<h3 id="the-result">The Result</h3>
<p>Now, when inspiration strikes, I don’t have to think about sourcing icons or formatting
snippets. I just share an App Store link, run the Shortcut, and paste the finished card into
my blog post. It’s instant, it’s reliable, and it makes my site look great with zero extra
effort.</p>
<p>For a blog that lives and breathes apps, this Shortcut has become one of those invisible
automations that pays dividends every single day.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/7e33edc6ca804b259747d50c768bcf7d" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Share%20App%20Store%20App%20HTML%20Button%20%28Public%29%20Icon.jpg" alt="Share App Store App HTML Button app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/7e33edc6ca804b259747d50c768bcf7d" target="_blank" rel="noopener">
    Share App Store App HTML Button
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>I Could Write This Blog in Notepad</title><link>https://blog.aidanmaurinjones.com/posts/i-could-write-this-blog-in-notepad/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/i-could-write-this-blog-in-notepad/</guid><pubDate>Sun, 21 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I’ve started a lot of projects over the years, but few have clicked as quickly and completely
as my Hugo blog hosted on GitHub Pages. I can’t emphasize enough how much I love this setup.</p>
<p>Unlike platforms like Squarespace, Wix, or WordPress, I don’t have to deal with heavy
dashboards, recurring subscription fees, or bloated themes that can slow everything down. There
are no hidden limits, no proprietary lock-in, and no fear that a company will suddenly change
its pricing model or redesign the editor. My blog is lean, fast, and completely mine — built
from plain Markdown files and served directly from GitHub with almost no overhead.</p>
<hr>
<h3 id="fast-free-and-reliable">Fast, Free, and Reliable</h3>
<p>Hugo compiles my site in seconds, spitting out plain HTML that GitHub Pages serves instantly.  That’s the beauty of a <strong>static site</strong>: it’s nothing more than pre-built pages sitting on a
server, ready to be delivered the moment someone visits. There’s no database query, no
server-side code, no waiting for templates to render. The site is already fully assembled
before it ever reaches the browser, which is why it loads so quickly.</p>
<p>Contrast that with a site you’d build on Squarespace or a traditional CMS like WordPress.
Those platforms generate pages on the fly. When a reader visits, the server has to pull content
from a database, render it through a template engine, load plugins, and then send it all back.
That’s powerful, but it adds complexity and overhead — more moving parts, more chances for
something to break, and more ways for the site to slow down.</p>
<p>With Hugo and GitHub Pages, none of that exists. The entire site is already built ahead of
time on my computer, then pushed as plain HTML, CSS, and JavaScript. GitHub Pages simply
serves those files as-is. The result is a site that’s incredibly fast, nearly impossible to
break, and requires zero maintenance.</p>
<p>And because GitHub Pages is handling hosting, I get free HTTPS, rock-solid uptime, and
global distribution without ever paying a cent. That’s tough to beat.</p>
<hr>
<h3 id="version-control-built-in">Version Control Built In</h3>
<p>Because it’s GitHub, every change is automatically versioned. If I make a mistake, I can roll
back with a single command. If I want to experiment with a new design, I can branch, test, and
merge—exactly like software development, but for my writing.</p>
<hr>
<h3 id="markdown-as-the-foundation">Markdown as the Foundation</h3>
<p>The most important part, though, is that everything is <em><strong>just Markdown files</strong></em>. My posts aren’t
trapped in a database or hidden behind a proprietary editor. They’re plain text, human-readable,
and universally portable. If Hugo disappeared tomorrow, I’d still have every word I’ve written,
ready to be dropped into another system.</p>
<p>Markdown makes my blog future-proof. It’s a format that has stood the test of time, and it
gives me confidence that I’ll never lose access to my own content. I can edit posts in Drafts,
VS Code, or even Notes if I want to — the tools don’t matter, because the content is mine.</p>
<hr>
<h3 id="the-right-balance-workflow-over-design">The Right Balance: Workflow Over Design</h3>
<p>What makes this setup perfect for me is that it lets me focus on the part I actually care
about: the backend and the posting workflow. I never wanted to spend hours tweaking a front-end
or dragging blocks around to make a site look just right. With Hugo, I pick a theme once,
and that’s it. The design takes care of itself.</p>
<p>What matters to me is how I write, publish, and maintain my blog. And in that respect, Hugo +
GitHub Pages is ideal. My workflow is streamlined: write in Markdown, commit to Git, push,
and I’m done. I get all the reliability, portability, and automation I want on the backend
without having to think about the front-end at all.</p>
<hr>
<h3 id="backups-made-simple">Backups Made Simple</h3>
<p>Because my site is nothing more than a folder of Markdown files and a Git repository, backing
it up is effortless. I always have a complete copy on my computer, and duplicating it anywhere
else is as simple as syncing the folder.</p>
<p>Want a backup on an external drive? Copy the folder. Want cloud redundancy? Drop it in iCloud,
Syncthing, or any storage service I like. There’s no complex database export, no special tools,
no hoops to jump through.</p>
<p>The result is peace of mind: no matter what happens to GitHub or my computer, my blog exists
in multiple places, always under my control.</p>
<hr>
<h3 id="automation-heaven">Automation Heaven</h3>
<p>One of my favorite parts is how well this setup fits into my automation workflows. From
Shortcuts on my iPhone to custom scripts on my Mac, I can publish new posts, upload images,
or tweak site layouts without ever opening a CMS. It’s just Markdown files and Git.</p>
<hr>
<h3 id="true-ownership-of-content">True Ownership of Content</h3>
<p>That’s the real magic of this setup: ownership. My words live in my repository, under my
control. No ads. No third-party lock-in. No subscription to keep the lights on. Just a blog
I fully control, powered by the simplest possible ingredients.</p>
<hr>
<h3 id="why-it-works-for-me">Why It Works for Me</h3>
<p>There are plenty of publishing platforms out there, but Hugo + GitHub Pages hits the balance
I’ve been chasing for years. It’s fast, reliable, and deeply personal. Most importantly, it
ensures my writing will always be accessible, portable, and safely backed up.</p>
<p>The biggest win, though, is simplicity. Since my posts are just Markdown files, I don’t have
to wrestle with a visual editor, fight with formatting, or wonder if my text will look
different once it’s published. I write in plain text, add a little front matter for metadata,
and Hugo handles the rest. My words stay clean and consistent, no matter how long I’ve been
away or what app I use to write them.</p>
<p>That simplicity takes away the friction. Instead of spending energy maintaining a CMS,
updating plugins, or tweaking layouts, I can focus entirely on the thing that matters:
writing. The blog feels invisible in the best possible way — it doesn’t demand attention, it
just works.</p>
<p>Sometimes the best platform is the one that gets out of the way. For me, that’s Hugo, GitHub
Pages, and a folder full of Markdown files. It’s a setup that respects my time, my content,
and my workflow. And I’ve never enjoyed blogging more.</p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I’ve started a lot of projects over the years, but few have clicked as quickly and completely
as my Hugo blog hosted on GitHub Pages. I can’t emphasize enough how much I love this setup.</p>
<p>Unlike platforms like Squarespace, Wix, or WordPress, I don’t have to deal with heavy
dashboards, recurring subscription fees, or bloated themes that can slow everything down. There
are no hidden limits, no proprietary lock-in, and no fear that a company will suddenly change
its pricing model or redesign the editor. My blog is lean, fast, and completely mine — built
from plain Markdown files and served directly from GitHub with almost no overhead.</p>
<hr>
<h3 id="fast-free-and-reliable">Fast, Free, and Reliable</h3>
<p>Hugo compiles my site in seconds, spitting out plain HTML that GitHub Pages serves instantly.  That’s the beauty of a <strong>static site</strong>: it’s nothing more than pre-built pages sitting on a
server, ready to be delivered the moment someone visits. There’s no database query, no
server-side code, no waiting for templates to render. The site is already fully assembled
before it ever reaches the browser, which is why it loads so quickly.</p>
<p>Contrast that with a site you’d build on Squarespace or a traditional CMS like WordPress.
Those platforms generate pages on the fly. When a reader visits, the server has to pull content
from a database, render it through a template engine, load plugins, and then send it all back.
That’s powerful, but it adds complexity and overhead — more moving parts, more chances for
something to break, and more ways for the site to slow down.</p>
<p>With Hugo and GitHub Pages, none of that exists. The entire site is already built ahead of
time on my computer, then pushed as plain HTML, CSS, and JavaScript. GitHub Pages simply
serves those files as-is. The result is a site that’s incredibly fast, nearly impossible to
break, and requires zero maintenance.</p>
<p>And because GitHub Pages is handling hosting, I get free HTTPS, rock-solid uptime, and
global distribution without ever paying a cent. That’s tough to beat.</p>
<hr>
<h3 id="version-control-built-in">Version Control Built In</h3>
<p>Because it’s GitHub, every change is automatically versioned. If I make a mistake, I can roll
back with a single command. If I want to experiment with a new design, I can branch, test, and
merge—exactly like software development, but for my writing.</p>
<hr>
<h3 id="markdown-as-the-foundation">Markdown as the Foundation</h3>
<p>The most important part, though, is that everything is <em><strong>just Markdown files</strong></em>. My posts aren’t
trapped in a database or hidden behind a proprietary editor. They’re plain text, human-readable,
and universally portable. If Hugo disappeared tomorrow, I’d still have every word I’ve written,
ready to be dropped into another system.</p>
<p>Markdown makes my blog future-proof. It’s a format that has stood the test of time, and it
gives me confidence that I’ll never lose access to my own content. I can edit posts in Drafts,
VS Code, or even Notes if I want to — the tools don’t matter, because the content is mine.</p>
<hr>
<h3 id="the-right-balance-workflow-over-design">The Right Balance: Workflow Over Design</h3>
<p>What makes this setup perfect for me is that it lets me focus on the part I actually care
about: the backend and the posting workflow. I never wanted to spend hours tweaking a front-end
or dragging blocks around to make a site look just right. With Hugo, I pick a theme once,
and that’s it. The design takes care of itself.</p>
<p>What matters to me is how I write, publish, and maintain my blog. And in that respect, Hugo +
GitHub Pages is ideal. My workflow is streamlined: write in Markdown, commit to Git, push,
and I’m done. I get all the reliability, portability, and automation I want on the backend
without having to think about the front-end at all.</p>
<hr>
<h3 id="backups-made-simple">Backups Made Simple</h3>
<p>Because my site is nothing more than a folder of Markdown files and a Git repository, backing
it up is effortless. I always have a complete copy on my computer, and duplicating it anywhere
else is as simple as syncing the folder.</p>
<p>Want a backup on an external drive? Copy the folder. Want cloud redundancy? Drop it in iCloud,
Syncthing, or any storage service I like. There’s no complex database export, no special tools,
no hoops to jump through.</p>
<p>The result is peace of mind: no matter what happens to GitHub or my computer, my blog exists
in multiple places, always under my control.</p>
<hr>
<h3 id="automation-heaven">Automation Heaven</h3>
<p>One of my favorite parts is how well this setup fits into my automation workflows. From
Shortcuts on my iPhone to custom scripts on my Mac, I can publish new posts, upload images,
or tweak site layouts without ever opening a CMS. It’s just Markdown files and Git.</p>
<hr>
<h3 id="true-ownership-of-content">True Ownership of Content</h3>
<p>That’s the real magic of this setup: ownership. My words live in my repository, under my
control. No ads. No third-party lock-in. No subscription to keep the lights on. Just a blog
I fully control, powered by the simplest possible ingredients.</p>
<hr>
<h3 id="why-it-works-for-me">Why It Works for Me</h3>
<p>There are plenty of publishing platforms out there, but Hugo + GitHub Pages hits the balance
I’ve been chasing for years. It’s fast, reliable, and deeply personal. Most importantly, it
ensures my writing will always be accessible, portable, and safely backed up.</p>
<p>The biggest win, though, is simplicity. Since my posts are just Markdown files, I don’t have
to wrestle with a visual editor, fight with formatting, or wonder if my text will look
different once it’s published. I write in plain text, add a little front matter for metadata,
and Hugo handles the rest. My words stay clean and consistent, no matter how long I’ve been
away or what app I use to write them.</p>
<p>That simplicity takes away the friction. Instead of spending energy maintaining a CMS,
updating plugins, or tweaking layouts, I can focus entirely on the thing that matters:
writing. The blog feels invisible in the best possible way — it doesn’t demand attention, it
just works.</p>
<p>Sometimes the best platform is the one that gets out of the way. For me, that’s Hugo, GitHub
Pages, and a folder full of Markdown files. It’s a setup that respects my time, my content,
and my workflow. And I’ve never enjoyed blogging more.</p>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>A Hundred &amp; One Post Buttons</title><link>https://blog.aidanmaurinjones.com/posts/a-hundred--one-post-buttons/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/a-hundred--one-post-buttons/</guid><pubDate>Sun, 21 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the reasons I love this setup so much is that publishing isn&rsquo;t just simple &ndash; it&rsquo;s
fully automated with nothing more than stock Shortcuts actions on iOS and macOS. No scripts,
no extra tools. Just Shortcuts and GitHub&rsquo;s API.</p>
<p>Here&rsquo;s how it works, step by step:</p>
<hr>
<h3 id="1-take-a-markdown-file-as-input">1. Take a Markdown file as input</h3>
<p>The Shortcut starts by receiving a file &ndash; either from the Share Sheet or by prompting me
to pick one. This file is the blog post I&rsquo;ve written in plain text.</p>
<ul>
<li>Action: Receive Files from Share Sheet</li>
<li>Why: Keeps things flexible &ndash; I can run the Shortcut from Finder on my Mac, Drafts on my
iPhone, or anywhere else that can share a Markdown file.</li>
</ul>
<hr>
<h3 id="2-prepare-the-file-name">2. Prepare the file name</h3>
<p>Next, the Shortcut grabs the file&rsquo;s name, URL-encodes it (so it&rsquo;s safe for GitHub&rsquo;s API),
and saves it as Pretty File Name.</p>
<ul>
<li>Action: Get Name from Blog Post → URL Encode → Set Variable</li>
</ul>
<p>This ensures my post shows up as my-post.md inside the Hugo content/posts/ folder.</p>
<hr>
<h3 id="3-encode-the-post-content">3. Encode the post content</h3>
<p>The raw text of the file is pulled out and converted to Base64. GitHub&rsquo;s API requires files
to be sent this way.</p>
<ul>
<li>Action: Get Text from Blog Post → Encode Text with Base64</li>
</ul>
<p>Now I&rsquo;ve got my post ready in a format GitHub understands.</p>
<hr>
<h3 id="4-build-the-api-request">4. Build the API request</h3>
<p>The Shortcut constructs a URL to the right location in my repo:</p>
<pre><code>https://api.github.com/repos/&lt;username&gt;/&lt;repo&gt;/contents/content/posts/&lt;Pretty File Name&gt;.md
</code></pre>
<p>This points GitHub&rsquo;s API directly to where the Markdown file should live.</p>
<hr>
<h3 id="5-check-if-the-post-exists">5. Check if the post exists</h3>
<p>The Shortcut sends a GET request to that URL:</p>
<ul>
<li>If a file exists, GitHub&rsquo;s response includes a sha value (basically the file&rsquo;s unique ID).</li>
<li>If it doesn&rsquo;t exist, there&rsquo;s no sha.</li>
</ul>
<p>This lets the Shortcut decide whether to update an existing post or create a brand new one.</p>
<hr>
<h3 id="6-update-or-create-the-post">6. Update or create the post</h3>
<p>Depending on the result, the Shortcut runs one of two PUT requests:</p>
<ul>
<li>Update Blog Post → PUT with the sha included</li>
<li>Post New Blog Post → PUT without the sha</li>
</ul>
<p>Both requests send JSON with:</p>
<pre><code>{
  &quot;message&quot;: &quot;Posted via Shortcuts - &lt;Name of BlogPost&gt;&quot;,
  &quot;content&quot;: &quot;&lt;Base64 Encoded Markdown&gt;&quot;,
  &quot;branch&quot;: &quot;main&quot;,
  &quot;sha&quot;: &quot;&lt;if updating&gt;&quot;
}
</code></pre>
<p>GitHub commits the file to my repo, and Hugo + GitHub Pages do the rest.</p>
<hr>
<h3 id="7-done">7. Done!</h3>
<p>That&rsquo;s it. Within seconds, the post appears on my live site &ndash; no browser, no dashboard, no
manual uploads.</p>
<hr>
<h3 id="why-this-is-so-good">Why This Is So Good</h3>
<ul>
<li>Cross-platform: I use it on my Mac via Finder + Service Station, as an Alfred file action,
in BBEdit via AppleScript, and on my iPhone via Drafts. If I had an iPad, it would work there too.</li>
<li>Minimal setup: The Shortcut is just a chain of built-in actions. No scripts, no third-party
apps.</li>
<li>Future-proof: The only input it needs is a Markdown file &ndash; and that&rsquo;s the one thing my
blog will always be built on.</li>
</ul>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/d96fe2195053424793b4a4a9a3bfab33" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Post%20to%20Blog%20%28Public%29%20Icon.jpg" alt="Post to Blog app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/d96fe2195053424793b4a4a9a3bfab33" target="_blank" rel="noopener">
    Post to Blog
  </a>
</article>

<h3 id="apps-mentioned-in-this-post">Apps Mentioned in this Post</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/drafts/id1435957248?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Drafts%20Icon.jpg" alt="Drafts app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/drafts/id1435957248?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Drafts
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/service-station/id1503136033?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Service%20Station%20Icon.jpg" alt="Service Station app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/service-station/id1503136033?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Service Station
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/BBEdit%20Icon.jpg" alt="BBEdit app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    BBEdit
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Alfred%205%20Icon.jpg" alt="Alfred 5 app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    Alfred 5
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the reasons I love this setup so much is that publishing isn&rsquo;t just simple &ndash; it&rsquo;s
fully automated with nothing more than stock Shortcuts actions on iOS and macOS. No scripts,
no extra tools. Just Shortcuts and GitHub&rsquo;s API.</p>
<p>Here&rsquo;s how it works, step by step:</p>
<hr>
<h3 id="1-take-a-markdown-file-as-input">1. Take a Markdown file as input</h3>
<p>The Shortcut starts by receiving a file &ndash; either from the Share Sheet or by prompting me
to pick one. This file is the blog post I&rsquo;ve written in plain text.</p>
<ul>
<li>Action: Receive Files from Share Sheet</li>
<li>Why: Keeps things flexible &ndash; I can run the Shortcut from Finder on my Mac, Drafts on my
iPhone, or anywhere else that can share a Markdown file.</li>
</ul>
<hr>
<h3 id="2-prepare-the-file-name">2. Prepare the file name</h3>
<p>Next, the Shortcut grabs the file&rsquo;s name, URL-encodes it (so it&rsquo;s safe for GitHub&rsquo;s API),
and saves it as Pretty File Name.</p>
<ul>
<li>Action: Get Name from Blog Post → URL Encode → Set Variable</li>
</ul>
<p>This ensures my post shows up as my-post.md inside the Hugo content/posts/ folder.</p>
<hr>
<h3 id="3-encode-the-post-content">3. Encode the post content</h3>
<p>The raw text of the file is pulled out and converted to Base64. GitHub&rsquo;s API requires files
to be sent this way.</p>
<ul>
<li>Action: Get Text from Blog Post → Encode Text with Base64</li>
</ul>
<p>Now I&rsquo;ve got my post ready in a format GitHub understands.</p>
<hr>
<h3 id="4-build-the-api-request">4. Build the API request</h3>
<p>The Shortcut constructs a URL to the right location in my repo:</p>
<pre><code>https://api.github.com/repos/&lt;username&gt;/&lt;repo&gt;/contents/content/posts/&lt;Pretty File Name&gt;.md
</code></pre>
<p>This points GitHub&rsquo;s API directly to where the Markdown file should live.</p>
<hr>
<h3 id="5-check-if-the-post-exists">5. Check if the post exists</h3>
<p>The Shortcut sends a GET request to that URL:</p>
<ul>
<li>If a file exists, GitHub&rsquo;s response includes a sha value (basically the file&rsquo;s unique ID).</li>
<li>If it doesn&rsquo;t exist, there&rsquo;s no sha.</li>
</ul>
<p>This lets the Shortcut decide whether to update an existing post or create a brand new one.</p>
<hr>
<h3 id="6-update-or-create-the-post">6. Update or create the post</h3>
<p>Depending on the result, the Shortcut runs one of two PUT requests:</p>
<ul>
<li>Update Blog Post → PUT with the sha included</li>
<li>Post New Blog Post → PUT without the sha</li>
</ul>
<p>Both requests send JSON with:</p>
<pre><code>{
  &quot;message&quot;: &quot;Posted via Shortcuts - &lt;Name of BlogPost&gt;&quot;,
  &quot;content&quot;: &quot;&lt;Base64 Encoded Markdown&gt;&quot;,
  &quot;branch&quot;: &quot;main&quot;,
  &quot;sha&quot;: &quot;&lt;if updating&gt;&quot;
}
</code></pre>
<p>GitHub commits the file to my repo, and Hugo + GitHub Pages do the rest.</p>
<hr>
<h3 id="7-done">7. Done!</h3>
<p>That&rsquo;s it. Within seconds, the post appears on my live site &ndash; no browser, no dashboard, no
manual uploads.</p>
<hr>
<h3 id="why-this-is-so-good">Why This Is So Good</h3>
<ul>
<li>Cross-platform: I use it on my Mac via Finder + Service Station, as an Alfred file action,
in BBEdit via AppleScript, and on my iPhone via Drafts. If I had an iPad, it would work there too.</li>
<li>Minimal setup: The Shortcut is just a chain of built-in actions. No scripts, no third-party
apps.</li>
<li>Future-proof: The only input it needs is a Markdown file &ndash; and that&rsquo;s the one thing my
blog will always be built on.</li>
</ul>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/d96fe2195053424793b4a4a9a3bfab33" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Post%20to%20Blog%20%28Public%29%20Icon.jpg" alt="Post to Blog app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/d96fe2195053424793b4a4a9a3bfab33" target="_blank" rel="noopener">
    Post to Blog
  </a>
</article>

<h3 id="apps-mentioned-in-this-post">Apps Mentioned in this Post</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/drafts/id1435957248?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Drafts%20Icon.jpg" alt="Drafts app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/drafts/id1435957248?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Drafts
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/service-station/id1503136033?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Service%20Station%20Icon.jpg" alt="Service Station app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/service-station/id1503136033?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Service Station
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/BBEdit%20Icon.jpg" alt="BBEdit app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="http://www.barebones.com/products/bbedit/index.html" target="_blank" rel="noopener">
    BBEdit
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Alfred%205%20Icon.jpg" alt="Alfred 5 app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.alfredapp.com/" target="_blank" rel="noopener">
    Alfred 5
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Save URLs from Show Notes with Overcast and Drafts</title><link>https://blog.aidanmaurinjones.com/posts/save-urls-from-show-notes-with-overcast-and-drafts/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/save-urls-from-show-notes-with-overcast-and-drafts/</guid><pubDate>Sat, 20 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I listen to a lot of podcasts in Overcast, and more often than not, I find myself wanting
to save a link mentioned in the show notes&ndash;an app, a website, a follow-up article. Overcast
does a great job of presenting those notes, but getting the links into my notes system has
always been more work than it should be.</p>
<p>So, I built a Shortcut that solves this problem: it extracts every link from an episode&rsquo;s
show notes in Overcast and saves them neatly to Drafts.</p>
<hr>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>The Shortcut starts with Current Episode Info from Overcast, which hands me both the title
of the episode and its full show notes in raw HTML.</p>
<p>From there, I do a quick conversion dance:</p>
<ul>
<li>Make Rich Text from Show Notes HTML</li>
<li>Make Markdown from Rich Text</li>
</ul>
<p>The reason? Markdown gives me a predictable link structure that&rsquo;s easy to parse with a regex.</p>
<hr>
<h3 id="extracting-the-links">Extracting the Links</h3>
<p>With the text in Markdown, I use a Match Text action to find every link in the notes. The
Shortcut then lets me pick which ones I actually want to save. That way, I&rsquo;m not cluttering
Drafts with every single link from an episode&ndash;just the ones I care about.</p>
<hr>
<h3 id="saving-to-drafts">Saving to Drafts</h3>
<p>Here&rsquo;s the clever bit: before creating a new draft, the Shortcut searches Drafts to see if
I already have a note for that episode.</p>
<ul>
<li>If nothing exists, it creates a brand new draft with the episode title and the selected
link(s).</li>
<li>If a draft already exists, it appends the new links to it&ndash;no duplicates, no mess.</li>
</ul>
<p>The end result is a running note per episode with all the links I wanted to keep.</p>
<hr>
<h2 id="why-this-is-useful">Why This Is Useful</h2>
<p>This Shortcut saves me from the usual friction of copy-pasting URLs out of Overcast. I don&rsquo;t
have to jump between apps or worry about losing context. Everything ends up in Drafts, which
is my text inbox and the place where I process notes later.</p>
<p>It&rsquo;s a small thing, but like so many good automations, it&rsquo;s one less manual step in my day.
Now, when a host mentions a new app or service, I know I can capture the link in a couple
of taps without breaking my listening flow.</p>
<hr>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>This is exactly the kind of automation I love: lightweight, repeatable, and tuned to the way
I work. Overcast gives me the show notes, Drafts gives me the archive, and Shortcuts does
the glue work in between.</p>
<p>The next time I need to reference that obscure link from a podcast episode I heard weeks ago,
it&rsquo;ll be sitting there in Drafts, right where it belongs.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/8f82fa10d4bd469e9a11dd4d839eb04b" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Save%20URLs%20from%20Show%20Notes%20Icon.jpg" alt="Save URLs from Show Notes app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/8f82fa10d4bd469e9a11dd4d839eb04b" target="_blank" rel="noopener">
    Save URLs from Show Notes
  </a>
</article>

<h3 id="apps--tools-used-to-create-this-shortcut">Apps &amp; Tools Used to Create this Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/overcast/id888422857?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Overcast%20Icon.jpg" alt="Overcast app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/overcast/id888422857?uo=4" target="_blank" rel="noopener">
    Overcast
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/drafts/id1236254471?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Drafts%20Icon.jpg" alt="Drafts app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/drafts/id1236254471?uo=4" target="_blank" rel="noopener">
    Drafts
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I listen to a lot of podcasts in Overcast, and more often than not, I find myself wanting
to save a link mentioned in the show notes&ndash;an app, a website, a follow-up article. Overcast
does a great job of presenting those notes, but getting the links into my notes system has
always been more work than it should be.</p>
<p>So, I built a Shortcut that solves this problem: it extracts every link from an episode&rsquo;s
show notes in Overcast and saves them neatly to Drafts.</p>
<hr>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>The Shortcut starts with Current Episode Info from Overcast, which hands me both the title
of the episode and its full show notes in raw HTML.</p>
<p>From there, I do a quick conversion dance:</p>
<ul>
<li>Make Rich Text from Show Notes HTML</li>
<li>Make Markdown from Rich Text</li>
</ul>
<p>The reason? Markdown gives me a predictable link structure that&rsquo;s easy to parse with a regex.</p>
<hr>
<h3 id="extracting-the-links">Extracting the Links</h3>
<p>With the text in Markdown, I use a Match Text action to find every link in the notes. The
Shortcut then lets me pick which ones I actually want to save. That way, I&rsquo;m not cluttering
Drafts with every single link from an episode&ndash;just the ones I care about.</p>
<hr>
<h3 id="saving-to-drafts">Saving to Drafts</h3>
<p>Here&rsquo;s the clever bit: before creating a new draft, the Shortcut searches Drafts to see if
I already have a note for that episode.</p>
<ul>
<li>If nothing exists, it creates a brand new draft with the episode title and the selected
link(s).</li>
<li>If a draft already exists, it appends the new links to it&ndash;no duplicates, no mess.</li>
</ul>
<p>The end result is a running note per episode with all the links I wanted to keep.</p>
<hr>
<h2 id="why-this-is-useful">Why This Is Useful</h2>
<p>This Shortcut saves me from the usual friction of copy-pasting URLs out of Overcast. I don&rsquo;t
have to jump between apps or worry about losing context. Everything ends up in Drafts, which
is my text inbox and the place where I process notes later.</p>
<p>It&rsquo;s a small thing, but like so many good automations, it&rsquo;s one less manual step in my day.
Now, when a host mentions a new app or service, I know I can capture the link in a couple
of taps without breaking my listening flow.</p>
<hr>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>This is exactly the kind of automation I love: lightweight, repeatable, and tuned to the way
I work. Overcast gives me the show notes, Drafts gives me the archive, and Shortcuts does
the glue work in between.</p>
<p>The next time I need to reference that obscure link from a podcast episode I heard weeks ago,
it&rsquo;ll be sitting there in Drafts, right where it belongs.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/8f82fa10d4bd469e9a11dd4d839eb04b" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Save%20URLs%20from%20Show%20Notes%20Icon.jpg" alt="Save URLs from Show Notes app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/8f82fa10d4bd469e9a11dd4d839eb04b" target="_blank" rel="noopener">
    Save URLs from Show Notes
  </a>
</article>

<h3 id="apps--tools-used-to-create-this-shortcut">Apps &amp; Tools Used to Create this Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/overcast/id888422857?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Overcast%20Icon.jpg" alt="Overcast app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/overcast/id888422857?uo=4" target="_blank" rel="noopener">
    Overcast
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/drafts/id1236254471?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Drafts%20Icon.jpg" alt="Drafts app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/drafts/id1236254471?uo=4" target="_blank" rel="noopener">
    Drafts
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Open Ride Share Apps: A Beginner-Friendly Shortcut That Saves Me Money</title><link>https://blog.aidanmaurinjones.com/posts/open-ride-share-apps-a-beginner-friendly-shortcut-that-saves-me-money/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/open-ride-share-apps-a-beginner-friendly-shortcut-that-saves-me-money/</guid><pubDate>Sat, 20 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>Not every Shortcut has to be complex to be life-changing. Some of the best automations are
the simplest ones&ndash;and my new Shortcut, Open Ride Share Apps, is a perfect example. It&rsquo;s
literally just a launcher for Uber, Lyft, and Hopp. That&rsquo;s it. But in practice, it&rsquo;s saved
me both time and a surprising amount of money.</p>
<hr>
<h3 id="why-i-built-it">Why I Built It</h3>
<p>When I need a ride, I almost never know which service will be cheapest or fastest. Sometimes
Uber has the best price, sometimes Lyft does, and often Hopp beats them both. Checking each
app manually meant digging through my Home Screen or Spotlight searching&ndash;friction that often
made me default to just one app. That laziness cost me more than I realized.</p>
<hr>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>This is about as beginner-friendly as Shortcuts get. The flow is just:</p>
<ul>
<li>Open Uber</li>
<li>Open Lyft</li>
<li>Open Hopp</li>
</ul>
<p>That’s it. No menus to build, no variables to configure, no scripting required. When I run
the Shortcut, it simply opens all three apps in sequence. By the time I’m done glancing at
Uber, Lyft, and Hopp, I know which one has the best deal.</p>
<hr>
<h3 id="the-real-benefit">The Real Benefit</h3>
<p>Because this Shortcut makes it effortless to compare services, I&rsquo;ve gotten into the habit
of checking all three every time I book a ride. The result? I almost always end up picking
the cheapest option. Over time, those small savings really add up&ndash;I&rsquo;ve already saved enough
to cover multiple months of my phone bill just by avoiding surge pricing.</p>
<hr>
<h3 id="why-it-stands-out">Why It Stands Out</h3>
<p>The magic here isn&rsquo;t technical&ndash;it&rsquo;s behavioural. By lowering the friction to compare prices,
the Shortcut nudges me into making better choices. It&rsquo;s a reminder that you don&rsquo;t need advanced
automations or APIs to get value out of Shortcuts. Sometimes a handful of &ldquo;Open App&rdquo; actions
can save you more money than the most complex setups.</p>
<hr>
<p>If you&rsquo;ve been curious about building your first Shortcut but felt intimidated, start here.
It&rsquo;s dead simple, immediately useful, and might just pay for your next coffee&ndash;or your next
month of rides.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/fc023997f4684f57987fee0f4802cf39" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Open%20Ride%20Share%20Apps%20Icon.jpg" alt="Open Ride Share Apps app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/fc023997f4684f57987fee0f4802cf39" target="_blank" rel="noopener">
    Open Ride Share Apps
  </a>
</article>

<h3 id="apps-used-in-this-shortcut">Apps Used In This Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/hopp-get-a-ride/id6475395031?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Hopp:%20Get%20a%20Ride%20Icon.jpg" alt="Hopp app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/hopp-get-a-ride/id6475395031?uo=4" target="_blank" rel="noopener">
    Hopp
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/uber-request-a-ride/id368677368?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Uber%20-%20Request%20a%20ride%20Icon.jpg" alt="Uber app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/uber-request-a-ride/id368677368?uo=4" target="_blank" rel="noopener">
    Uber
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/lyft/id529379082?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Lyft%20Icon.jpg" alt="Lyft app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/lyft/id529379082?uo=4" target="_blank" rel="noopener">
    Lyft
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>Not every Shortcut has to be complex to be life-changing. Some of the best automations are
the simplest ones&ndash;and my new Shortcut, Open Ride Share Apps, is a perfect example. It&rsquo;s
literally just a launcher for Uber, Lyft, and Hopp. That&rsquo;s it. But in practice, it&rsquo;s saved
me both time and a surprising amount of money.</p>
<hr>
<h3 id="why-i-built-it">Why I Built It</h3>
<p>When I need a ride, I almost never know which service will be cheapest or fastest. Sometimes
Uber has the best price, sometimes Lyft does, and often Hopp beats them both. Checking each
app manually meant digging through my Home Screen or Spotlight searching&ndash;friction that often
made me default to just one app. That laziness cost me more than I realized.</p>
<hr>
<h3 id="how-the-shortcut-works">How the Shortcut Works</h3>
<p>This is about as beginner-friendly as Shortcuts get. The flow is just:</p>
<ul>
<li>Open Uber</li>
<li>Open Lyft</li>
<li>Open Hopp</li>
</ul>
<p>That’s it. No menus to build, no variables to configure, no scripting required. When I run
the Shortcut, it simply opens all three apps in sequence. By the time I’m done glancing at
Uber, Lyft, and Hopp, I know which one has the best deal.</p>
<hr>
<h3 id="the-real-benefit">The Real Benefit</h3>
<p>Because this Shortcut makes it effortless to compare services, I&rsquo;ve gotten into the habit
of checking all three every time I book a ride. The result? I almost always end up picking
the cheapest option. Over time, those small savings really add up&ndash;I&rsquo;ve already saved enough
to cover multiple months of my phone bill just by avoiding surge pricing.</p>
<hr>
<h3 id="why-it-stands-out">Why It Stands Out</h3>
<p>The magic here isn&rsquo;t technical&ndash;it&rsquo;s behavioural. By lowering the friction to compare prices,
the Shortcut nudges me into making better choices. It&rsquo;s a reminder that you don&rsquo;t need advanced
automations or APIs to get value out of Shortcuts. Sometimes a handful of &ldquo;Open App&rdquo; actions
can save you more money than the most complex setups.</p>
<hr>
<p>If you&rsquo;ve been curious about building your first Shortcut but felt intimidated, start here.
It&rsquo;s dead simple, immediately useful, and might just pay for your next coffee&ndash;or your next
month of rides.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/fc023997f4684f57987fee0f4802cf39" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Open%20Ride%20Share%20Apps%20Icon.jpg" alt="Open Ride Share Apps app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/fc023997f4684f57987fee0f4802cf39" target="_blank" rel="noopener">
    Open Ride Share Apps
  </a>
</article>

<h3 id="apps-used-in-this-shortcut">Apps Used In This Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/hopp-get-a-ride/id6475395031?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Hopp:%20Get%20a%20Ride%20Icon.jpg" alt="Hopp app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/hopp-get-a-ride/id6475395031?uo=4" target="_blank" rel="noopener">
    Hopp
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/uber-request-a-ride/id368677368?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Uber%20-%20Request%20a%20ride%20Icon.jpg" alt="Uber app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/uber-request-a-ride/id368677368?uo=4" target="_blank" rel="noopener">
    Uber
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/lyft/id529379082?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Lyft%20Icon.jpg" alt="Lyft app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/lyft/id529379082?uo=4" target="_blank" rel="noopener">
    Lyft
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Wikipedia Article Downloader: A Shortcut for Offline Reading</title><link>https://blog.aidanmaurinjones.com/posts/wikipedia-article-downloader--a-shortcut-for-offline-reading/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/wikipedia-article-downloader--a-shortcut-for-offline-reading/</guid><pubDate>Fri, 19 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>Sometimes the best utilities are the ones that do just one thing, quickly and well. That&rsquo;s
exactly what I had in mind when I built my <strong>Wikipedia Article Downloader</strong> Shortcut. It takes
any Wikipedia link I throw at it and instantly saves a clean PDF of the article&ndash;perfect for
offline reading, research, or archiving.</p>
<h3 id="how-it-works">How It Works</h3>
<p>I designed the Shortcut to be flexible. It accepts input either from the Share Sheet or
directly from my clipboard. That means I can grab a link from Safari, Messages, or anywhere
else and send it straight into the Shortcut without any extra steps.</p>
<p>Here&rsquo;s the flow it follows once I trigger it:</p>
<ol>
<li>
<p><strong>Extract the URL</strong> &ndash; The Shortcut pulls out the link from whatever I share or copy.</p>
</li>
<li>
<p><strong>Regex Matching</strong> &ndash; A quick regular expression finds the correct page identifier from
the Wikipedia link, so it works even if the URL has extra junk in it.</p>
</li>
<li>
<p><strong>Build the API Request</strong> &ndash; Wikipedia has a little-known REST API that can generate a
PDF version of any article. The Shortcut automatically constructs that request.</p>
</li>
<li>
<p><strong>Fetch the PDF</strong> &ndash; The API serves up the article as a PDF.</p>
</li>
<li>
<p><strong>Save to Files</strong> &ndash; Finally, the Shortcut saves the PDF wherever I choose, ready to
open in Books, Preview, or any other PDF app.</p>
</li>
</ol>
<hr>
<h3 id="why-i-find-it-useful">Why I Find It Useful</h3>
<p>Wikipedia does have a &ldquo;Download as PDF&rdquo; feature, but it&rsquo;s buried in the desktop site&rsquo;s menus
and isn&rsquo;t very friendly on mobile. With this Shortcut, I can grab a clean PDF in just a couple
of taps.</p>
<p>I use it most when I&rsquo;m traveling and don&rsquo;t want to rely on spotty internet access. It&rsquo;s
also handy when I&rsquo;m doing research and want to keep a local archive of detailed articles.</p>
<hr>
<h3 id="small-touches-i-like">Small Touches I Like</h3>
<p>A few details make the Shortcut feel smooth in practice:</p>
<ul>
<li><strong>Clipboard fallback</strong> &ndash; If I don&rsquo;t run it from the Share Sheet, it automatically checks
my clipboard for a valid link.</li>
<li><strong>Regex cleanup</strong> &ndash; It doesn&rsquo;t assume Wikipedia URLs are always clean; it handles variations.</li>
<li><strong>Automation potential</strong> &ndash; I can imagine extending it by having the PDFs saved directly
into a tagged folder in Files, or even synced into Obsidian or DEVONthink.</li>
</ul>
<hr>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>This Shortcut is a simple example of how I like to use automation: take a clunky process and
reduce it to a single tap. By leaning on Wikipedia&rsquo;s API, I get a smooth way to save articles
for offline use.</p>
<p>I&rsquo;ve already found myself reaching for it constantly, whether I&rsquo;m archiving something
interesting or putting together a reading list for later. If you rely on Wikipedia as much
as I do, this little Shortcut makes it effortless to keep what you find.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/4a7b4925023b4b6d9fb1699afd34654e" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Wikipedia%20Article%20Downloader%20Icon.jpg" alt="Wikipedia Article Downloader app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/4a7b4925023b4b6d9fb1699afd34654e" target="_blank" rel="noopener">
    Wikipedia Article Downloader
  </a>
</article>

<h3 id="apps--tools-used-to-create-this-shortcut">Apps &amp; Tools Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>Sometimes the best utilities are the ones that do just one thing, quickly and well. That&rsquo;s
exactly what I had in mind when I built my <strong>Wikipedia Article Downloader</strong> Shortcut. It takes
any Wikipedia link I throw at it and instantly saves a clean PDF of the article&ndash;perfect for
offline reading, research, or archiving.</p>
<h3 id="how-it-works">How It Works</h3>
<p>I designed the Shortcut to be flexible. It accepts input either from the Share Sheet or
directly from my clipboard. That means I can grab a link from Safari, Messages, or anywhere
else and send it straight into the Shortcut without any extra steps.</p>
<p>Here&rsquo;s the flow it follows once I trigger it:</p>
<ol>
<li>
<p><strong>Extract the URL</strong> &ndash; The Shortcut pulls out the link from whatever I share or copy.</p>
</li>
<li>
<p><strong>Regex Matching</strong> &ndash; A quick regular expression finds the correct page identifier from
the Wikipedia link, so it works even if the URL has extra junk in it.</p>
</li>
<li>
<p><strong>Build the API Request</strong> &ndash; Wikipedia has a little-known REST API that can generate a
PDF version of any article. The Shortcut automatically constructs that request.</p>
</li>
<li>
<p><strong>Fetch the PDF</strong> &ndash; The API serves up the article as a PDF.</p>
</li>
<li>
<p><strong>Save to Files</strong> &ndash; Finally, the Shortcut saves the PDF wherever I choose, ready to
open in Books, Preview, or any other PDF app.</p>
</li>
</ol>
<hr>
<h3 id="why-i-find-it-useful">Why I Find It Useful</h3>
<p>Wikipedia does have a &ldquo;Download as PDF&rdquo; feature, but it&rsquo;s buried in the desktop site&rsquo;s menus
and isn&rsquo;t very friendly on mobile. With this Shortcut, I can grab a clean PDF in just a couple
of taps.</p>
<p>I use it most when I&rsquo;m traveling and don&rsquo;t want to rely on spotty internet access. It&rsquo;s
also handy when I&rsquo;m doing research and want to keep a local archive of detailed articles.</p>
<hr>
<h3 id="small-touches-i-like">Small Touches I Like</h3>
<p>A few details make the Shortcut feel smooth in practice:</p>
<ul>
<li><strong>Clipboard fallback</strong> &ndash; If I don&rsquo;t run it from the Share Sheet, it automatically checks
my clipboard for a valid link.</li>
<li><strong>Regex cleanup</strong> &ndash; It doesn&rsquo;t assume Wikipedia URLs are always clean; it handles variations.</li>
<li><strong>Automation potential</strong> &ndash; I can imagine extending it by having the PDFs saved directly
into a tagged folder in Files, or even synced into Obsidian or DEVONthink.</li>
</ul>
<hr>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>This Shortcut is a simple example of how I like to use automation: take a clunky process and
reduce it to a single tap. By leaning on Wikipedia&rsquo;s API, I get a smooth way to save articles
for offline use.</p>
<p>I&rsquo;ve already found myself reaching for it constantly, whether I&rsquo;m archiving something
interesting or putting together a reading list for later. If you rely on Wikipedia as much
as I do, this little Shortcut makes it effortless to keep what you find.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/4a7b4925023b4b6d9fb1699afd34654e" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Wikipedia%20Article%20Downloader%20Icon.jpg" alt="Wikipedia Article Downloader app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/4a7b4925023b4b6d9fb1699afd34654e" target="_blank" rel="noopener">
    Wikipedia Article Downloader
  </a>
</article>

<h3 id="apps--tools-used-to-create-this-shortcut">Apps &amp; Tools Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1468691718?mt=12&amp;uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Wordle, But With a Twist: A Shortcut I Built That Gives You Hints</title><link>https://blog.aidanmaurinjones.com/posts/wordle-but-with-a-twist-a-shortcut-i-built-that-gives-you-hints/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/wordle-but-with-a-twist-a-shortcut-i-built-that-gives-you-hints/</guid><pubDate>Thu, 18 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I&rsquo;ve been having fun experimenting with Shortcuts, APIs, and local AI models, and recently
I built something that is kinda fun: a Shortcut that gives you a hint for the daily Wordle without
spoiling the answer.</p>
<hr>
<h3 id="how-it-works">How It Works</h3>
<p>Here&rsquo;s the flow I put together:</p>
<ol>
<li>Grab Today&rsquo;s Wordle</li>
</ol>
<p>The Shortcut starts by formatting the current date and plugging it into the New York Times&rsquo;
Wordle API (<a href="https://www.nytimes.com/svc/wordle/v2/%5Bdate%5D.json)">https://www.nytimes.com/svc/wordle/v2/[date].json)</a>. That gives me the official
solution for the day in JSON format.</p>
<ol start="2">
<li>Parse the API Response</li>
</ol>
<p>I use Shortcuts&rsquo; &ldquo;Get Dictionary from&rdquo; action to pull out the solution field &ndash; the actual
word for today&rsquo;s puzzle. Normally that would be game over, but that&rsquo;s where the next step
comes in.</p>
<ol start="3">
<li>Ask AI for a Hint</li>
</ol>
<p>Instead of showing the word, the Shortcut creates a prompt:</p>
<blockquote>
<p>&ldquo;Without telling me the word, provide a hint to what the given word is below.&rdquo;</p>
</blockquote>
<p>I pass that along with the solution to Gemma 2B v2, a small local model I&rsquo;m running. The
model generates a creative hint while keeping the answer hidden.</p>
<ol start="4">
<li>Show the Hint</li>
</ol>
<p>Finally, the Shortcut displays the hint in an alert, giving me just enough of a push without
ruining the puzzle.</p>
<hr>
<h3 id="why-i-like-it">Why I Like It</h3>
<p>What I enjoy about this Shortcut is how it combines three different things I love tinkering
with:</p>
<ul>
<li>Web data: pulling JSON directly from the NYT Wordle API.</li>
<li>Automation: using Shortcuts to parse and structure everything.</li>
<li>Local AI: letting an on-device model do the fun part of writing the hint.</li>
</ul>
<p>The result is quick, private, and surprisingly fun &ndash; every time I run it, I get a slightly
different hint for the same word.</p>
<hr>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>I wanted a way to make Wordle more approachable on the days when the word feels impossible,
without crossing into outright cheating. This Shortcut hits that sweet spot for me. It&rsquo;s a
simple automation, but it feels fresh and playful every time I use it.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/dc2aab47577a49ab9095c2f6920e60f7" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Wordle%20Hint%20Icon.jpg" alt="Wordle Hint app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/dc2aab47577a49ab9095c2f6920e60f7" target="_blank" rel="noopener">
    Wordle Hint
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create this Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/offlinellm-private-ai-chat/id6474508768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/OfflineLLM:%20Private%20AI%20Chat%20Icon.jpg" alt="OfflineLLM: Private AI Chat app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/offlinellm-private-ai-chat/id6474508768?uo=4" target="_blank" rel="noopener">
    OfflineLLM: Private AI Chat
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I&rsquo;ve been having fun experimenting with Shortcuts, APIs, and local AI models, and recently
I built something that is kinda fun: a Shortcut that gives you a hint for the daily Wordle without
spoiling the answer.</p>
<hr>
<h3 id="how-it-works">How It Works</h3>
<p>Here&rsquo;s the flow I put together:</p>
<ol>
<li>Grab Today&rsquo;s Wordle</li>
</ol>
<p>The Shortcut starts by formatting the current date and plugging it into the New York Times&rsquo;
Wordle API (<a href="https://www.nytimes.com/svc/wordle/v2/%5Bdate%5D.json)">https://www.nytimes.com/svc/wordle/v2/[date].json)</a>. That gives me the official
solution for the day in JSON format.</p>
<ol start="2">
<li>Parse the API Response</li>
</ol>
<p>I use Shortcuts&rsquo; &ldquo;Get Dictionary from&rdquo; action to pull out the solution field &ndash; the actual
word for today&rsquo;s puzzle. Normally that would be game over, but that&rsquo;s where the next step
comes in.</p>
<ol start="3">
<li>Ask AI for a Hint</li>
</ol>
<p>Instead of showing the word, the Shortcut creates a prompt:</p>
<blockquote>
<p>&ldquo;Without telling me the word, provide a hint to what the given word is below.&rdquo;</p>
</blockquote>
<p>I pass that along with the solution to Gemma 2B v2, a small local model I&rsquo;m running. The
model generates a creative hint while keeping the answer hidden.</p>
<ol start="4">
<li>Show the Hint</li>
</ol>
<p>Finally, the Shortcut displays the hint in an alert, giving me just enough of a push without
ruining the puzzle.</p>
<hr>
<h3 id="why-i-like-it">Why I Like It</h3>
<p>What I enjoy about this Shortcut is how it combines three different things I love tinkering
with:</p>
<ul>
<li>Web data: pulling JSON directly from the NYT Wordle API.</li>
<li>Automation: using Shortcuts to parse and structure everything.</li>
<li>Local AI: letting an on-device model do the fun part of writing the hint.</li>
</ul>
<p>The result is quick, private, and surprisingly fun &ndash; every time I run it, I get a slightly
different hint for the same word.</p>
<hr>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>I wanted a way to make Wordle more approachable on the days when the word feels impossible,
without crossing into outright cheating. This Shortcut hits that sweet spot for me. It&rsquo;s a
simple automation, but it feels fresh and playful every time I use it.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/dc2aab47577a49ab9095c2f6920e60f7" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Wordle%20Hint%20Icon.jpg" alt="Wordle Hint app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/dc2aab47577a49ab9095c2f6920e60f7" target="_blank" rel="noopener">
    Wordle Hint
  </a>
</article>

<h3 id="apps-used-to-create-this-shortcut">Apps Used to Create this Shortcut</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/offlinellm-private-ai-chat/id6474508768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/OfflineLLM:%20Private%20AI%20Chat%20Icon.jpg" alt="OfflineLLM: Private AI Chat app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/offlinellm-private-ai-chat/id6474508768?uo=4" target="_blank" rel="noopener">
    OfflineLLM: Private AI Chat
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Automating My City's Garbage Schedule with Shortcuts</title><link>https://blog.aidanmaurinjones.com/posts/automating-my-citys-garbage-schedule-with-shortcuts/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/automating-my-citys-garbage-schedule-with-shortcuts/</guid><pubDate>Thu, 18 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of the things I love about Shortcuts on iOS is how it can take raw, unfriendly data and
turn it into something useful and personal. I recently built a Shortcut that pulls in my city&rsquo;s
official garbage pickup calendar (published as a CSV file), processes it, and tells me exactly
what needs to go out on collection day.</p>
<p>It&rsquo;s a small thing, but it makes my life much easier.</p>
<hr>
<h2 id="how-it-works">How It Works</h2>
<p>The Shortcut really boils down to three main steps:</p>
<ol>
<li>Fetching the schedule</li>
</ol>
<p>I start with Get Contents of URL to download the CSV file the city publishes with all of the
collection dates and types. It&rsquo;s just plain text, but the formatting is predictable enough
to work with.</p>
<ol start="2">
<li>Parsing and filtering</li>
</ol>
<p>Once I split the text into individual lines, I use a filter to find the rows that match my
pickup day and today&rsquo;s date. That narrows down the entire dataset to just what I care about.</p>
<ol start="3">
<li>Turning codes into plain English</li>
</ol>
<p>The CSV doesn&rsquo;t actually spell out &ldquo;Garbage&rdquo; or &ldquo;Recycling.&rdquo; Instead, it uses numbers to
represent each type of waste. To fix this, I built a dictionary inside Shortcuts that maps
those numbers to labels (e.g., 1 = Green Bin, 2 = Garbage). A repeat loop goes through each
row, checks which items are marked T (true), and then looks up the proper label.</p>
<hr>
<h3 id="handling-multiple-bins">Handling Multiple Bins</h3>
<p>One of the tricky parts was making the results readable when more than one type of waste is
collected.</p>
<p>If there&rsquo;s only one item, the output is simple: &ldquo;Garbage.&rdquo; But if two or three bins need to
go out, I wanted it to sound natural.</p>
<p>The Shortcut counts the number of matches, and then formats them like this:</p>
<ul>
<li>Two items → &ldquo;Green Bin and Recycling&rdquo;</li>
<li>Three or more → &ldquo;Green Bin, Garbage, and Yard Waste&rdquo;</li>
</ul>
<p>It&rsquo;s a small touch, but it makes the alert feel like something I&rsquo;d actually write, not just
machine output.</p>
<hr>
<h3 id="the-end-result">The End Result</h3>
<p>When everything&rsquo;s processed, the Shortcut shows me an alert with the result. On pickup days,
I just run it and immediately know what to take to the curb:</p>
<blockquote>
<p>&ldquo;Today&rsquo;s pickup: Green Bin, Garbage, and Yard Waste.&rdquo;</p>
</blockquote>
<p>No more scrolling through PDFs, no more guessing which week is recycling week.</p>
<hr>
<h3 id="why-i-like-this-shortcut">Why I Like This Shortcut</h3>
<p>This project really highlights why I enjoy using Shortcuts:</p>
<ul>
<li>It takes local data and turns it into something that actually fits my life.</li>
<li>The automation is readable and flexible, even when dealing with messy CSV data.</li>
<li>It&rsquo;s practical&ndash;this Shortcut saves me time and prevents mistakes every week.</li>
</ul>
<hr>
<p>For now, though, it&rsquo;s already become part of my weekly routine. It&rsquo;s not flashy, but it&rsquo;s one
of those little automations that quietly makes life better&ndash;one trash day at a time.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/54eefd7b13fe4ba39e21e8ac25fc3e6d" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Toronto%20Garbage%20Schedule%20%28Public%29%20Icon.jpg" alt="Toronto Garbage Schedule app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/54eefd7b13fe4ba39e21e8ac25fc3e6d" target="_blank" rel="noopener">
    Toronto Garbage Schedule
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of the things I love about Shortcuts on iOS is how it can take raw, unfriendly data and
turn it into something useful and personal. I recently built a Shortcut that pulls in my city&rsquo;s
official garbage pickup calendar (published as a CSV file), processes it, and tells me exactly
what needs to go out on collection day.</p>
<p>It&rsquo;s a small thing, but it makes my life much easier.</p>
<hr>
<h2 id="how-it-works">How It Works</h2>
<p>The Shortcut really boils down to three main steps:</p>
<ol>
<li>Fetching the schedule</li>
</ol>
<p>I start with Get Contents of URL to download the CSV file the city publishes with all of the
collection dates and types. It&rsquo;s just plain text, but the formatting is predictable enough
to work with.</p>
<ol start="2">
<li>Parsing and filtering</li>
</ol>
<p>Once I split the text into individual lines, I use a filter to find the rows that match my
pickup day and today&rsquo;s date. That narrows down the entire dataset to just what I care about.</p>
<ol start="3">
<li>Turning codes into plain English</li>
</ol>
<p>The CSV doesn&rsquo;t actually spell out &ldquo;Garbage&rdquo; or &ldquo;Recycling.&rdquo; Instead, it uses numbers to
represent each type of waste. To fix this, I built a dictionary inside Shortcuts that maps
those numbers to labels (e.g., 1 = Green Bin, 2 = Garbage). A repeat loop goes through each
row, checks which items are marked T (true), and then looks up the proper label.</p>
<hr>
<h3 id="handling-multiple-bins">Handling Multiple Bins</h3>
<p>One of the tricky parts was making the results readable when more than one type of waste is
collected.</p>
<p>If there&rsquo;s only one item, the output is simple: &ldquo;Garbage.&rdquo; But if two or three bins need to
go out, I wanted it to sound natural.</p>
<p>The Shortcut counts the number of matches, and then formats them like this:</p>
<ul>
<li>Two items → &ldquo;Green Bin and Recycling&rdquo;</li>
<li>Three or more → &ldquo;Green Bin, Garbage, and Yard Waste&rdquo;</li>
</ul>
<p>It&rsquo;s a small touch, but it makes the alert feel like something I&rsquo;d actually write, not just
machine output.</p>
<hr>
<h3 id="the-end-result">The End Result</h3>
<p>When everything&rsquo;s processed, the Shortcut shows me an alert with the result. On pickup days,
I just run it and immediately know what to take to the curb:</p>
<blockquote>
<p>&ldquo;Today&rsquo;s pickup: Green Bin, Garbage, and Yard Waste.&rdquo;</p>
</blockquote>
<p>No more scrolling through PDFs, no more guessing which week is recycling week.</p>
<hr>
<h3 id="why-i-like-this-shortcut">Why I Like This Shortcut</h3>
<p>This project really highlights why I enjoy using Shortcuts:</p>
<ul>
<li>It takes local data and turns it into something that actually fits my life.</li>
<li>The automation is readable and flexible, even when dealing with messy CSV data.</li>
<li>It&rsquo;s practical&ndash;this Shortcut saves me time and prevents mistakes every week.</li>
</ul>
<hr>
<p>For now, though, it&rsquo;s already become part of my weekly routine. It&rsquo;s not flashy, but it&rsquo;s one
of those little automations that quietly makes life better&ndash;one trash day at a time.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/54eefd7b13fe4ba39e21e8ac25fc3e6d" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Toronto%20Garbage%20Schedule%20%28Public%29%20Icon.jpg" alt="Toronto Garbage Schedule app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/54eefd7b13fe4ba39e21e8ac25fc3e6d" target="_blank" rel="noopener">
    Toronto Garbage Schedule
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Where To Watch: A Shortcut for Finding Streaming Availability with The Movie Database</title><link>https://blog.aidanmaurinjones.com/posts/where-to-watch-a-shortcut-for-finding-streaming-availability-with-the-movie-database/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/where-to-watch-a-shortcut-for-finding-streaming-availability-with-the-movie-database/</guid><pubDate>Wed, 17 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>One of my favorite things about Shortcuts is how they can bridge the gap between scattered
web services and a smooth, native-like workflow. I built a new shortcut called Where To Watch,
which taps into The Movie Database (TMDb) API to answer a simple but constant question:
&ldquo;Where is this movie or TV show streaming?&rdquo;</p>
<p>⸻</p>
<h3 id="the-idea">The Idea</h3>
<p>The premise is straightforward: I want to type in the name of a movie or TV show, and
instantly see whether it&rsquo;s available to stream in my region. No need to scroll through
JustWatch, no extra apps, no hunting through five different services. Just one quick Shortcut
that opens Safari with the results.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>The Shortcut starts by letting me choose between Movie or TV Show. Behind the scenes, this
choice determines which TMDb endpoint it will query. For example:</p>
<ul>
<li>movie queries film titles</li>
<li>tv queries series titles</li>
</ul>
<p>Once I make a choice, the Shortcut asks me to type in the name. That query string gets
URL-encoded and sent off to TMDb&rsquo;s search API.</p>
<p>⸻</p>
<h3 id="handling-results">Handling Results</h3>
<p>TMDb often returns multiple matches (think about searching for &ldquo;Batman&rdquo;). To handle this,
the Shortcut loops through results and builds a list of title/ID pairs. I can then pick the
correct match from a clean, combined list:</p>
<pre><code>The Dark Knight : 155
Batman Begins : 272
</code></pre>
<p>If no results are found, the Shortcut gracefully shows a &ldquo;No results found :(&rdquo; message and
stops.</p>
<p>⸻</p>
<h3 id="streaming-providers">Streaming Providers</h3>
<p>Here&rsquo;s where it gets good: once I&rsquo;ve selected the right result, the Shortcut uses its TMDb
ID to fetch the watch/providers endpoint. This API call returns a region-specific breakdown
of streaming availability.</p>
<p>The Shortcut checks for my country code (CA in this case), and if providers exist, it pulls
the first available streaming link. Safari then opens directly to the movie&rsquo;s or TV Show&rsquo;s
JustWatch webpage. If nothing is available in my region, the Shortcut tells me:</p>
<blockquote>
<p>&ldquo;Unfortunately this title is not available in your region :(&rdquo;</p>
</blockquote>
<p>⸻</p>
<h3 id="why-i-love-this">Why I Love This</h3>
<p>Where To Watch has quickly become one of my most-used Shortcuts. It&rsquo;s the perfect blend of
lightweight automation and practical everyday use. Instead of juggling apps or websites, I
can now quickly search for a movie or tv show and it tells me instantly where I can watch
something&ndash;or if I need to wait until it arrives in Canada.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/cd65d16803074adb9957d512164b8f40" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Where%20To%20Watch%20%28Public%29%20Icon.jpg" alt="Where To Watch app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/cd65d16803074adb9957d512164b8f40" target="_blank" rel="noopener">
    Where To Watch
  </a>
</article>

<h3 id="apps--tools-used-to-create-this-shortcut">Apps &amp; Tools Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>One of my favorite things about Shortcuts is how they can bridge the gap between scattered
web services and a smooth, native-like workflow. I built a new shortcut called Where To Watch,
which taps into The Movie Database (TMDb) API to answer a simple but constant question:
&ldquo;Where is this movie or TV show streaming?&rdquo;</p>
<p>⸻</p>
<h3 id="the-idea">The Idea</h3>
<p>The premise is straightforward: I want to type in the name of a movie or TV show, and
instantly see whether it&rsquo;s available to stream in my region. No need to scroll through
JustWatch, no extra apps, no hunting through five different services. Just one quick Shortcut
that opens Safari with the results.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>The Shortcut starts by letting me choose between Movie or TV Show. Behind the scenes, this
choice determines which TMDb endpoint it will query. For example:</p>
<ul>
<li>movie queries film titles</li>
<li>tv queries series titles</li>
</ul>
<p>Once I make a choice, the Shortcut asks me to type in the name. That query string gets
URL-encoded and sent off to TMDb&rsquo;s search API.</p>
<p>⸻</p>
<h3 id="handling-results">Handling Results</h3>
<p>TMDb often returns multiple matches (think about searching for &ldquo;Batman&rdquo;). To handle this,
the Shortcut loops through results and builds a list of title/ID pairs. I can then pick the
correct match from a clean, combined list:</p>
<pre><code>The Dark Knight : 155
Batman Begins : 272
</code></pre>
<p>If no results are found, the Shortcut gracefully shows a &ldquo;No results found :(&rdquo; message and
stops.</p>
<p>⸻</p>
<h3 id="streaming-providers">Streaming Providers</h3>
<p>Here&rsquo;s where it gets good: once I&rsquo;ve selected the right result, the Shortcut uses its TMDb
ID to fetch the watch/providers endpoint. This API call returns a region-specific breakdown
of streaming availability.</p>
<p>The Shortcut checks for my country code (CA in this case), and if providers exist, it pulls
the first available streaming link. Safari then opens directly to the movie&rsquo;s or TV Show&rsquo;s
JustWatch webpage. If nothing is available in my region, the Shortcut tells me:</p>
<blockquote>
<p>&ldquo;Unfortunately this title is not available in your region :(&rdquo;</p>
</blockquote>
<p>⸻</p>
<h3 id="why-i-love-this">Why I Love This</h3>
<p>Where To Watch has quickly become one of my most-used Shortcuts. It&rsquo;s the perfect blend of
lightweight automation and practical everyday use. Instead of juggling apps or websites, I
can now quickly search for a movie or tv show and it tells me instantly where I can watch
something&ndash;or if I need to wait until it arrives in Canada.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/cd65d16803074adb9957d512164b8f40" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Where%20To%20Watch%20%28Public%29%20Icon.jpg" alt="Where To Watch app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/cd65d16803074adb9957d512164b8f40" target="_blank" rel="noopener">
    Where To Watch
  </a>
</article>

<h3 id="apps--tools-used-to-create-this-shortcut">Apps &amp; Tools Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Scan QR Code on Screen: A Shortcut I Built for My Mac</title><link>https://blog.aidanmaurinjones.com/posts/scan-qr-code-on-screen---a-shortcut-i-built-for-my-mac/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/scan-qr-code-on-screen---a-shortcut-i-built-for-my-mac/</guid><pubDate>Tue, 16 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I built this Shortcut because I kept running into a simple but annoying problem. Every now
and then, I’d come across a QR code on my Mac—maybe in a PDF, a presentation, or just an image
on a website. And every time, I had to pull out my iPhone to scan it. macOS doesn’t offer
a built-in way to do this, so I decided to make my own solution.</p>
<p>⸻</p>
<h3 id="the-problem-i-wanted-to-solve">The Problem I Wanted to Solve</h3>
<p>Scanning a QR code on macOS isn’t straightforward. You either have to send the image to your
iPhone or use a third-party app. Neither felt seamless. I wanted something that fit directly
into my workflow: capture the QR code on my screen, decode it, and open the link—no extra
devices or steps.</p>
<p>⸻</p>
<h3 id="how-my-shortcut-works">How My Shortcut Works</h3>
<p>I designed the Shortcut in two phases:</p>
<p><strong>Phase 1:</strong> Capturing the QR Code</p>
<ul>
<li>The Shortcut opens the Mac’s Interactive Screenshot tool, which lets me select just the
portion of the screen where the QR code is visible.</li>
<li>If I don’t actually grab anything, the Shortcut just stops cleanly. No errors, no wasted
steps.</li>
</ul>
<p><strong>Phase 2:</strong> Decoding and Opening the Link</p>
<ul>
<li>Once I’ve got the screenshot, the Shortcut sends it to the QRServer API (<a href="http://api.qrserver.com/v1/read-qr-code/)">http://api.qrserver.com/v1/read-qr-code/)</a>.</li>
<li>The API responds with the decoded content in a dictionary. I pull out symbol.1.data, which
is where the actual text or URL lives.</li>
<li>If it’s a valid URL, the Shortcut opens it immediately in Safari.</li>
<li>If there’s nothing useful, I get a simple alert: “No URL Found.”</li>
</ul>
<p>⸻</p>
<h3 id="why-i-like-this-approach">Why I Like This Approach</h3>
<p>What I like most about this Shortcut is how resilient it is. I added error checks at two
points—first to make sure an image was actually captured, and second to verify that the
decoded content is a valid URL. Both failure cases are handled gracefully.</p>
<p>It’s also a nice example of how powerful Shortcuts can be when you mix in APIs. By leaning
on QRServer, I made a feature that Apple hasn’t brought to macOS yet, and I didn’t need to
install extra apps to get there.</p>
<p>⸻</p>
<h3 id="how-i-use-it">How I Use It</h3>
<p>Now, anytime I run into a QR code on my Mac, I just trigger this Shortcut. Whether it’s a
menu, a payment link, or a download, I can scan and open it instantly without breaking my
flow.</p>
<p>It’s a small thing, but it’s one of those utilities I use often enough that I can’t imagine
not having it anymore.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/d04d8a82cfcd42fcaa1447a90f1d5e52" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Scan%20QR%20Code%20On%20Screen%20Icon.jpg" alt="Scan QR Code On Screen app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/d04d8a82cfcd42fcaa1447a90f1d5e52" target="_blank" rel="noopener">
    Scan QR Code On Screen
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I built this Shortcut because I kept running into a simple but annoying problem. Every now
and then, I’d come across a QR code on my Mac—maybe in a PDF, a presentation, or just an image
on a website. And every time, I had to pull out my iPhone to scan it. macOS doesn’t offer
a built-in way to do this, so I decided to make my own solution.</p>
<p>⸻</p>
<h3 id="the-problem-i-wanted-to-solve">The Problem I Wanted to Solve</h3>
<p>Scanning a QR code on macOS isn’t straightforward. You either have to send the image to your
iPhone or use a third-party app. Neither felt seamless. I wanted something that fit directly
into my workflow: capture the QR code on my screen, decode it, and open the link—no extra
devices or steps.</p>
<p>⸻</p>
<h3 id="how-my-shortcut-works">How My Shortcut Works</h3>
<p>I designed the Shortcut in two phases:</p>
<p><strong>Phase 1:</strong> Capturing the QR Code</p>
<ul>
<li>The Shortcut opens the Mac’s Interactive Screenshot tool, which lets me select just the
portion of the screen where the QR code is visible.</li>
<li>If I don’t actually grab anything, the Shortcut just stops cleanly. No errors, no wasted
steps.</li>
</ul>
<p><strong>Phase 2:</strong> Decoding and Opening the Link</p>
<ul>
<li>Once I’ve got the screenshot, the Shortcut sends it to the QRServer API (<a href="http://api.qrserver.com/v1/read-qr-code/)">http://api.qrserver.com/v1/read-qr-code/)</a>.</li>
<li>The API responds with the decoded content in a dictionary. I pull out symbol.1.data, which
is where the actual text or URL lives.</li>
<li>If it’s a valid URL, the Shortcut opens it immediately in Safari.</li>
<li>If there’s nothing useful, I get a simple alert: “No URL Found.”</li>
</ul>
<p>⸻</p>
<h3 id="why-i-like-this-approach">Why I Like This Approach</h3>
<p>What I like most about this Shortcut is how resilient it is. I added error checks at two
points—first to make sure an image was actually captured, and second to verify that the
decoded content is a valid URL. Both failure cases are handled gracefully.</p>
<p>It’s also a nice example of how powerful Shortcuts can be when you mix in APIs. By leaning
on QRServer, I made a feature that Apple hasn’t brought to macOS yet, and I didn’t need to
install extra apps to get there.</p>
<p>⸻</p>
<h3 id="how-i-use-it">How I Use It</h3>
<p>Now, anytime I run into a QR code on my Mac, I just trigger this Shortcut. Whether it’s a
menu, a payment link, or a download, I can scan and open it instantly without breaking my
flow.</p>
<p>It’s a small thing, but it’s one of those utilities I use often enough that I can’t imagine
not having it anymore.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/d04d8a82cfcd42fcaa1447a90f1d5e52" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Scan%20QR%20Code%20On%20Screen%20Icon.jpg" alt="Scan QR Code On Screen app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/d04d8a82cfcd42fcaa1447a90f1d5e52" target="_blank" rel="noopener">
    Scan QR Code On Screen
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<article class="app-card">
  <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
    Jayson
  </a>
</article>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Smarter MacBook Charging with Shortcuts and BetterTouchTool</title><link>https://blog.aidanmaurinjones.com/posts/smarter-macbook-charging-with-shortcuts-and-bettertouchtool/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/smarter-macbook-charging-with-shortcuts-and-bettertouchtool/</guid><pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I’ve been working on a smarter way to manage my MacBook’s charging routine. Instead of
keeping it constantly plugged in—or worse, draining too far—I built a pair of Shortcuts that
tie into Home Assistant and give me precise control over when my MacBook starts and stops
charging.</p>
<p>BetterTouchTool handles the automation side, triggering these Shortcuts when certain
conditions are met, so I don’t have to think about it. The result is a more balanced charging
cycle and less battery stress—all fully automated.</p>
<p>⸻</p>
<h3 id="the-building-blocks">The Building Blocks</h3>
<p>The setup consists of two Shortcuts:</p>
<ul>
<li>Charge MacBook: Handles turning the charger on or off depending on the battery percentage.</li>
<li>Check MacBook Charger on Login: Verifies the charger’s state when I log in or at periodic
intervals.</li>
</ul>
<p>Both Shortcuts talk to Home Assistant through its API. I store my API key and endpoint in
reusable helper Shortcuts, which makes the main flows cleaner and easier to maintain.</p>
<p>⸻</p>
<h3 id="charge-macbook">Charge MacBook</h3>
<p>This Shortcut first checks the current battery level. If it’s above 21%, it assumes charging
isn’t critical. From there, if the level hits 100%, it sends a request to Home Assistant to
switch off the charger using the /api/services/switch/turn_off endpoint.</p>
<p>If the battery is below 21%, the Shortcut flips the logic: it calls /api/services/switch/turn_on,
waits a few seconds, and then double-checks whether the MacBook actually registered as charging. If
it didn’t, I get an alert that says “Charge MacBook!!” so I can fix it manually.</p>
<p>It’s a nice mix of automation and failsafe. Most of the time, I don’t need to do anything—but
if something misfires, I get a clear prompt.</p>
<p>⸻</p>
<h3 id="check-macbook-charger-on-login">Check MacBook Charger on Login</h3>
<p>The second Shortcut adds some resilience. On login (and also every hour), BetterTouchTool
triggers it to confirm the charger’s state.</p>
<p>Here’s how it works:</p>
<ol>
<li>It checks the MacBook’s current battery percentage.</li>
<li>It queries Home Assistant for the state of the switch.macbook_charger entity.</li>
<li>If the battery is full and the switch is still on, it powers it down.</li>
<li>If the battery is at or below 21% and the charger is off, it powers it on.</li>
<li>Finally, it waits a few seconds and checks whether the MacBook is actually
charging. If not, it throws the same “Charge MacBook!!” alert.</li>
</ol>
<p>This creates a feedback loop where the system not only sends commands but also confirms
whether those commands actually worked.</p>
<p>⸻</p>
<h3 id="bettertouchtool-triggers">BetterTouchTool Triggers</h3>
<p>The final piece of the puzzle is automation via BetterTouchTool. I’ve set up triggers for:</p>
<ul>
<li>Battery drops below 21% → Run Charge MacBook.</li>
<li>Battery rises above 99% → Run Charge MacBook.</li>
<li>On screen unlock → Run Check MacBook Charger on Login.</li>
<li>Every hour → Run Check MacBook Charger on Login.</li>
</ul>
<p>This combination ensures that charging is always managed proactively, whether I’m actively
using the MacBook or not.</p>
<p>⸻</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>Apple’s built-in battery management is good, but not always predictable—and it doesn’t give
me direct control. With this Shortcuts + BetterTouchTool setup, I can enforce my own rules:
charge only when needed, stop at full, and always keep an eye on the charger’s actual state.</p>
<p>It’s a small project, but one that makes a noticeable difference in daily use. My MacBook
now charges only when it should, with BetterTouchTool quietly handling the details in the
background.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/e22b09004acf43fa882a415f3eed7cd8" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Charge%20MacBook%20Icon.jpg" alt="Charge MacBook app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/e22b09004acf43fa882a415f3eed7cd8" target="_blank" rel="noopener">
    Charge MacBook
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/62a2a4c8473342cdb2ca72df8d5e9c1b" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Check%20MacBook%20Charger%20on%20Login%20Icon.jpg" alt="Check MacBook Charger on Login app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/62a2a4c8473342cdb2ca72df8d5e9c1b" target="_blank" rel="noopener">
    Check MacBook Charger on Login
  </a>
</article>


</div>

<h3 id="apps-and-tools-used-for-this-project">Apps and Tools Used for this Project</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.home-assistant.io/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Home%20Assistant%20Icon.jpg" alt="Home Assistant app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.home-assistant.io/" target="_blank" rel="noopener">
    Home Assistant
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://folivora.ai/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/BetterTouchTool%20Icon.jpg" alt="BetterTouchTool app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://folivora.ai/" target="_blank" rel="noopener">
    BetterTouchTool
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I’ve been working on a smarter way to manage my MacBook’s charging routine. Instead of
keeping it constantly plugged in—or worse, draining too far—I built a pair of Shortcuts that
tie into Home Assistant and give me precise control over when my MacBook starts and stops
charging.</p>
<p>BetterTouchTool handles the automation side, triggering these Shortcuts when certain
conditions are met, so I don’t have to think about it. The result is a more balanced charging
cycle and less battery stress—all fully automated.</p>
<p>⸻</p>
<h3 id="the-building-blocks">The Building Blocks</h3>
<p>The setup consists of two Shortcuts:</p>
<ul>
<li>Charge MacBook: Handles turning the charger on or off depending on the battery percentage.</li>
<li>Check MacBook Charger on Login: Verifies the charger’s state when I log in or at periodic
intervals.</li>
</ul>
<p>Both Shortcuts talk to Home Assistant through its API. I store my API key and endpoint in
reusable helper Shortcuts, which makes the main flows cleaner and easier to maintain.</p>
<p>⸻</p>
<h3 id="charge-macbook">Charge MacBook</h3>
<p>This Shortcut first checks the current battery level. If it’s above 21%, it assumes charging
isn’t critical. From there, if the level hits 100%, it sends a request to Home Assistant to
switch off the charger using the /api/services/switch/turn_off endpoint.</p>
<p>If the battery is below 21%, the Shortcut flips the logic: it calls /api/services/switch/turn_on,
waits a few seconds, and then double-checks whether the MacBook actually registered as charging. If
it didn’t, I get an alert that says “Charge MacBook!!” so I can fix it manually.</p>
<p>It’s a nice mix of automation and failsafe. Most of the time, I don’t need to do anything—but
if something misfires, I get a clear prompt.</p>
<p>⸻</p>
<h3 id="check-macbook-charger-on-login">Check MacBook Charger on Login</h3>
<p>The second Shortcut adds some resilience. On login (and also every hour), BetterTouchTool
triggers it to confirm the charger’s state.</p>
<p>Here’s how it works:</p>
<ol>
<li>It checks the MacBook’s current battery percentage.</li>
<li>It queries Home Assistant for the state of the switch.macbook_charger entity.</li>
<li>If the battery is full and the switch is still on, it powers it down.</li>
<li>If the battery is at or below 21% and the charger is off, it powers it on.</li>
<li>Finally, it waits a few seconds and checks whether the MacBook is actually
charging. If not, it throws the same “Charge MacBook!!” alert.</li>
</ol>
<p>This creates a feedback loop where the system not only sends commands but also confirms
whether those commands actually worked.</p>
<p>⸻</p>
<h3 id="bettertouchtool-triggers">BetterTouchTool Triggers</h3>
<p>The final piece of the puzzle is automation via BetterTouchTool. I’ve set up triggers for:</p>
<ul>
<li>Battery drops below 21% → Run Charge MacBook.</li>
<li>Battery rises above 99% → Run Charge MacBook.</li>
<li>On screen unlock → Run Check MacBook Charger on Login.</li>
<li>Every hour → Run Check MacBook Charger on Login.</li>
</ul>
<p>This combination ensures that charging is always managed proactively, whether I’m actively
using the MacBook or not.</p>
<p>⸻</p>
<h3 id="why-it-matters">Why It Matters</h3>
<p>Apple’s built-in battery management is good, but not always predictable—and it doesn’t give
me direct control. With this Shortcuts + BetterTouchTool setup, I can enforce my own rules:
charge only when needed, stop at full, and always keep an eye on the charger’s actual state.</p>
<p>It’s a small project, but one that makes a noticeable difference in daily use. My MacBook
now charges only when it should, with BetterTouchTool quietly handling the details in the
background.</p>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/e22b09004acf43fa882a415f3eed7cd8" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Charge%20MacBook%20Icon.jpg" alt="Charge MacBook app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/e22b09004acf43fa882a415f3eed7cd8" target="_blank" rel="noopener">
    Charge MacBook
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/62a2a4c8473342cdb2ca72df8d5e9c1b" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Check%20MacBook%20Charger%20on%20Login%20Icon.jpg" alt="Check MacBook Charger on Login app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/62a2a4c8473342cdb2ca72df8d5e9c1b" target="_blank" rel="noopener">
    Check MacBook Charger on Login
  </a>
</article>


</div>

<h3 id="apps-and-tools-used-for-this-project">Apps and Tools Used for this Project</h3>
<div class="app-row">
  
<article class="app-card">
  <a class="app-card__icon" href="https://www.home-assistant.io/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/Home%20Assistant%20Icon.jpg" alt="Home Assistant app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.home-assistant.io/" target="_blank" rel="noopener">
    Home Assistant
  </a>
</article>

<article class="app-card">
  <a class="app-card__icon" href="https://folivora.ai/" target="_blank" rel="noopener">
    <img src="/images/App%20Icons/BetterTouchTool%20Icon.jpg" alt="BetterTouchTool app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://folivora.ai/" target="_blank" rel="noopener">
    BetterTouchTool
  </a>
</article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>A Raspberry Pi Stream Deck Server controlled by ESPHome</title><link>https://blog.aidanmaurinjones.com/posts/a-raspberry-pi-stream-deck-server-controlled-by-esphome/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/a-raspberry-pi-stream-deck-server-controlled-by-esphome/</guid><pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I’ve turned one of my Raspberry Pi 4s into a dedicated Stream Deck hub. It’s hooked up to
a 32-button Stream Deck that controls devices and automations in Home Assistant, which runs
on a separate machine. The Pi’s only job is to sit there, listen, and push out commands —
but if it ever hangs or I need to reboot it, I wanted a way to manage it properly without
pulling cables.</p>
<p>That’s where the ESP32 comes in. I flashed it with ESPHome and wired it straight into the
Pi’s GPIO pins so I can treat the whole setup like a real smart-home appliance: I can power
it on, shut it down safely, reboot it, and always know its current state inside Home Assistant.</p>
<p>⸻</p>
<h3 id="how-i-wired-it">How I Wired It</h3>
<p>The wiring is pretty simple. Raspberry Pi GPIO14 goes into ESP32 GPIO27, which gives me
feedback about whether the Pi is on or off. The Pi’s RUN pins are connected to ESP32 GPIO13,
so I can pulse them to power it on. For shutdown and reboot, I used GPIO26 and GPIO13 on the
Pi, wired to ESP32 pins that trigger those actions.</p>
<p>This way, the ESP32 can send commands to the Pi, and the Pi can talk back about its state.</p>
<p>⸻</p>
<h3 id="my-esphome-config">My ESPHome Config</h3>
<p>On the ESP32, I wrote an ESPHome config with a few pieces:</p>
<ul>
<li>A template switch that acts as the main power control. It checks the binary sensor to
see if the Pi is already on before trying to pulse the RUN pins.</li>
<li>A shutdown switch that pulls Pi GPIO26 high, which my shutdown script listens for.</li>
<li>A reboot button that does the same thing with GPIO13 for rebooting.</li>
<li>A binary sensor tied to GPIO14 that tells me if the Pi is running or not.</li>
</ul>
<p>Here’s the core YAML I’m running:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">switch</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">template</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Raspberry Pi Switch&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">raspberry_pi_switch</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      return id(raspberry_pi_power_state).state;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">turn_on_action</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">if</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">condition</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">lambda</span>: <span style="color:#e6db74">&#39;return !id(raspberry_pi_power_state).state;&#39;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">switch.turn_on</span>: <span style="color:#ae81ff">turn_on_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">turn_off_action</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_on</span>: <span style="color:#ae81ff">turn_off_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Turn On Raspberry Pi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO13</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">inverted</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">turn_on_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">internal</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_turn_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delay</span>: <span style="color:#ae81ff">500ms</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_off</span>: <span style="color:#ae81ff">turn_on_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Shutdown Raspberry Pi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO12</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">turn_off_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">internal</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_turn_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delay</span>: <span style="color:#ae81ff">500ms</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_off</span>: <span style="color:#ae81ff">turn_off_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Reboot Raspberry Pi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO14</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">reboot_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">internal</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_turn_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delay</span>: <span style="color:#ae81ff">500ms</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_off</span>: <span style="color:#ae81ff">reboot_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">binary_sensor</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO27</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Raspberry Pi Power State&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">raspberry_pi_power_state</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">device_class</span>: <span style="color:#ae81ff">power</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delayed_on_off</span>: <span style="color:#ae81ff">800ms</span>
</span></span></code></pre></div><p>⸻</p>
<h3 id="the-pi-side">The Pi Side</h3>
<p>On the Raspberry Pi, I wrote two tiny Python scripts. One listens on GPIO26 and calls shutdown
now, the other listens on GPIO13 and calls reboot. They just loop forever in the background,
waiting for a HIGH signal from the ESP32:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-Python" data-lang="Python"><span style="display:flex;"><span><span style="color:#75715e"># shutdown_monitor.py</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> RPi.GPIO <span style="color:#66d9ef">as</span> GPIO<span style="color:#f92672">,</span> time<span style="color:#f92672">,</span> os
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setmode(GPIO<span style="color:#f92672">.</span>BCM)
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setup(<span style="color:#ae81ff">26</span>, GPIO<span style="color:#f92672">.</span>IN, pull_up_down<span style="color:#f92672">=</span>GPIO<span style="color:#f92672">.</span>PUD_DOWN)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> GPIO<span style="color:#f92672">.</span>input(<span style="color:#ae81ff">26</span>) <span style="color:#f92672">==</span> GPIO<span style="color:#f92672">.</span>HIGH:
</span></span><span style="display:flex;"><span>        os<span style="color:#f92672">.</span>system(<span style="color:#e6db74">&#34;sudo shutdown now&#34;</span>)
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">0.5</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># reboot_pi.py</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> RPi.GPIO <span style="color:#66d9ef">as</span> GPIO<span style="color:#f92672">,</span> time<span style="color:#f92672">,</span> os
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setmode(GPIO<span style="color:#f92672">.</span>BCM)
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setup(<span style="color:#ae81ff">13</span>, GPIO<span style="color:#f92672">.</span>IN, pull_up_down<span style="color:#f92672">=</span>GPIO<span style="color:#f92672">.</span>PUD_DOWN)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> GPIO<span style="color:#f92672">.</span>input(<span style="color:#ae81ff">13</span>) <span style="color:#f92672">==</span> GPIO<span style="color:#f92672">.</span>HIGH:
</span></span><span style="display:flex;"><span>        os<span style="color:#f92672">.</span>system(<span style="color:#e6db74">&#34;sudo reboot&#34;</span>)
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">0.5</span>)
</span></span></code></pre></div><p>I wrapped both of these in simple systemd services so they start automatically on boot and
restart if they crash. That way, the Pi is always listening for signals from the ESP32.</p>
<p>⸻</p>
<h3 id="what-it-feels-like-in-practice">What It Feels Like in Practice</h3>
<p>Now, inside Home Assistant, the Pi just shows up like any other smart switch. If it’s off,
flipping the switch pulses the RUN pins and boots it up. If it’s on, flipping the switch
triggers the shutdown script and powers it down cleanly. There’s also a reboot button when I
need it. And the binary sensor tied to GPIO14 means I always know its current state.</p>
<p>The best part is how natural it feels. The Pi and Stream Deck live on my desk like a little
smart-home console, but behind the scenes it’s running with the same polish you’d expect from
a dedicated appliance. Everything is local, reliable, and integrated with the rest of my Home
Assistant setup.</p>
<p>It’s one of those projects where the wiring is simple, the software is lightweight, but the
result makes my whole setup feel more “finished.”</p>
<h3 id="apps-and-tools-used-for-this-project">Apps and Tools Used for this Project</h3>
<ul>
<li><a href="https://github.com/Patrick762/hassio-streamdeck">Stream Deck HACS Integration</a></li>
<li><a href="https://www.home-assistant.io/">Home Assistant</a></li>
<li><a href="https://esphome.io/">ESPHome - Smart Home Made Simple</a></li>
</ul>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I’ve turned one of my Raspberry Pi 4s into a dedicated Stream Deck hub. It’s hooked up to
a 32-button Stream Deck that controls devices and automations in Home Assistant, which runs
on a separate machine. The Pi’s only job is to sit there, listen, and push out commands —
but if it ever hangs or I need to reboot it, I wanted a way to manage it properly without
pulling cables.</p>
<p>That’s where the ESP32 comes in. I flashed it with ESPHome and wired it straight into the
Pi’s GPIO pins so I can treat the whole setup like a real smart-home appliance: I can power
it on, shut it down safely, reboot it, and always know its current state inside Home Assistant.</p>
<p>⸻</p>
<h3 id="how-i-wired-it">How I Wired It</h3>
<p>The wiring is pretty simple. Raspberry Pi GPIO14 goes into ESP32 GPIO27, which gives me
feedback about whether the Pi is on or off. The Pi’s RUN pins are connected to ESP32 GPIO13,
so I can pulse them to power it on. For shutdown and reboot, I used GPIO26 and GPIO13 on the
Pi, wired to ESP32 pins that trigger those actions.</p>
<p>This way, the ESP32 can send commands to the Pi, and the Pi can talk back about its state.</p>
<p>⸻</p>
<h3 id="my-esphome-config">My ESPHome Config</h3>
<p>On the ESP32, I wrote an ESPHome config with a few pieces:</p>
<ul>
<li>A template switch that acts as the main power control. It checks the binary sensor to
see if the Pi is already on before trying to pulse the RUN pins.</li>
<li>A shutdown switch that pulls Pi GPIO26 high, which my shutdown script listens for.</li>
<li>A reboot button that does the same thing with GPIO13 for rebooting.</li>
<li>A binary sensor tied to GPIO14 that tells me if the Pi is running or not.</li>
</ul>
<p>Here’s the core YAML I’m running:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">switch</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">template</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Raspberry Pi Switch&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">raspberry_pi_switch</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">lambda</span>: |-<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      return id(raspberry_pi_power_state).state;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">turn_on_action</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">if</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">condition</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">lambda</span>: <span style="color:#e6db74">&#39;return !id(raspberry_pi_power_state).state;&#39;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">then</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">switch.turn_on</span>: <span style="color:#ae81ff">turn_on_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">turn_off_action</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_on</span>: <span style="color:#ae81ff">turn_off_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Turn On Raspberry Pi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO13</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">inverted</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">turn_on_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">internal</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_turn_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delay</span>: <span style="color:#ae81ff">500ms</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_off</span>: <span style="color:#ae81ff">turn_on_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Shutdown Raspberry Pi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO12</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">turn_off_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">internal</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_turn_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delay</span>: <span style="color:#ae81ff">500ms</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_off</span>: <span style="color:#ae81ff">turn_off_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Reboot Raspberry Pi&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO14</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">reboot_pi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">internal</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">on_turn_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delay</span>: <span style="color:#ae81ff">500ms</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">switch.turn_off</span>: <span style="color:#ae81ff">reboot_pi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">binary_sensor</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">platform</span>: <span style="color:#ae81ff">gpio</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pin</span>: <span style="color:#ae81ff">GPIO27</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Raspberry Pi Power State&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">id</span>: <span style="color:#ae81ff">raspberry_pi_power_state</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">device_class</span>: <span style="color:#ae81ff">power</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">delayed_on_off</span>: <span style="color:#ae81ff">800ms</span>
</span></span></code></pre></div><p>⸻</p>
<h3 id="the-pi-side">The Pi Side</h3>
<p>On the Raspberry Pi, I wrote two tiny Python scripts. One listens on GPIO26 and calls shutdown
now, the other listens on GPIO13 and calls reboot. They just loop forever in the background,
waiting for a HIGH signal from the ESP32:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-Python" data-lang="Python"><span style="display:flex;"><span><span style="color:#75715e"># shutdown_monitor.py</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> RPi.GPIO <span style="color:#66d9ef">as</span> GPIO<span style="color:#f92672">,</span> time<span style="color:#f92672">,</span> os
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setmode(GPIO<span style="color:#f92672">.</span>BCM)
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setup(<span style="color:#ae81ff">26</span>, GPIO<span style="color:#f92672">.</span>IN, pull_up_down<span style="color:#f92672">=</span>GPIO<span style="color:#f92672">.</span>PUD_DOWN)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> GPIO<span style="color:#f92672">.</span>input(<span style="color:#ae81ff">26</span>) <span style="color:#f92672">==</span> GPIO<span style="color:#f92672">.</span>HIGH:
</span></span><span style="display:flex;"><span>        os<span style="color:#f92672">.</span>system(<span style="color:#e6db74">&#34;sudo shutdown now&#34;</span>)
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">0.5</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># reboot_pi.py</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> RPi.GPIO <span style="color:#66d9ef">as</span> GPIO<span style="color:#f92672">,</span> time<span style="color:#f92672">,</span> os
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setmode(GPIO<span style="color:#f92672">.</span>BCM)
</span></span><span style="display:flex;"><span>GPIO<span style="color:#f92672">.</span>setup(<span style="color:#ae81ff">13</span>, GPIO<span style="color:#f92672">.</span>IN, pull_up_down<span style="color:#f92672">=</span>GPIO<span style="color:#f92672">.</span>PUD_DOWN)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> GPIO<span style="color:#f92672">.</span>input(<span style="color:#ae81ff">13</span>) <span style="color:#f92672">==</span> GPIO<span style="color:#f92672">.</span>HIGH:
</span></span><span style="display:flex;"><span>        os<span style="color:#f92672">.</span>system(<span style="color:#e6db74">&#34;sudo reboot&#34;</span>)
</span></span><span style="display:flex;"><span>    time<span style="color:#f92672">.</span>sleep(<span style="color:#ae81ff">0.5</span>)
</span></span></code></pre></div><p>I wrapped both of these in simple systemd services so they start automatically on boot and
restart if they crash. That way, the Pi is always listening for signals from the ESP32.</p>
<p>⸻</p>
<h3 id="what-it-feels-like-in-practice">What It Feels Like in Practice</h3>
<p>Now, inside Home Assistant, the Pi just shows up like any other smart switch. If it’s off,
flipping the switch pulses the RUN pins and boots it up. If it’s on, flipping the switch
triggers the shutdown script and powers it down cleanly. There’s also a reboot button when I
need it. And the binary sensor tied to GPIO14 means I always know its current state.</p>
<p>The best part is how natural it feels. The Pi and Stream Deck live on my desk like a little
smart-home console, but behind the scenes it’s running with the same polish you’d expect from
a dedicated appliance. Everything is local, reliable, and integrated with the rest of my Home
Assistant setup.</p>
<p>It’s one of those projects where the wiring is simple, the software is lightweight, but the
result makes my whole setup feel more “finished.”</p>
<h3 id="apps-and-tools-used-for-this-project">Apps and Tools Used for this Project</h3>
<ul>
<li><a href="https://github.com/Patrick762/hassio-streamdeck">Stream Deck HACS Integration</a></li>
<li><a href="https://www.home-assistant.io/">Home Assistant</a></li>
<li><a href="https://esphome.io/">ESPHome - Smart Home Made Simple</a></li>
</ul>
<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>TTC Service Alerts Shortcut: Real-Time Transit Notifications Made Simple</title><link>https://blog.aidanmaurinjones.com/posts/ttc-service-alerts-shortcut-blog-post/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/ttc-service-alerts-shortcut-blog-post/</guid><pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I built this shortcut because I wanted a faster way to check TTC service alerts without digging
through the website or scrolling endlessly through apps. With one tap (or a Siri command),
I can now see all active alerts in a clean, styled view that’s easy to scan.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>At the core, my shortcut pulls live data straight from the TTC’s JSON endpoint:</p>
<p><em><em><a href="https://alerts.ttc.ca/api/alerts/list">https://alerts.ttc.ca/api/alerts/list</a></em></em></p>
<p><strong>Here’s the basic flow I set up:</strong></p>
<ul>
<li>Fetch the feed – I use <strong><em><em>Get Contents of URL</em></em></strong> to grab the JSON.</li>
<li>Parse the response – The raw data is turned into a dictionary, which makes it easy
to work with inside Shortcuts.</li>
<li>Check for active alerts – If the routes field has values, the shortcut moves forward.</li>
</ul>
<p>If not, I skip right to a “No Service Alerts at this time” message.</p>
<p>⸻</p>
<h3 id="iterating-through-alerts">Iterating Through Alerts</h3>
<p>When there are active alerts, the shortcut loops through them one by one. For each alert,
it pulls out the key pieces of info:</p>
<ul>
<li><strong><em><em>headerText</em></em></strong> for the main message</li>
<li><strong><em><em>lastUpdated</em></em></strong> for the timestamp</li>
</ul>
<p>I then format the date into something readable and wrap everything in a bit of HTML. By
setting font sizes, bolding headers, and adding dividers, the output looks more like a proper
dashboard than just plain text.</p>
<p>⸻</p>
<h3 id="the-final-output">The Final Output</h3>
<p>Once all the alerts are collected, I combine them into a single block of text, convert it
into rich text, and name it “TTC Service Alerts.” From there, I preview it in Quick Look.</p>
<p>If there aren’t any alerts, the shortcut just shows me a simple popup that says: “No Service
Alerts at this time.”</p>
<p>⸻</p>
<h3 id="why-i-made-it">Why I Made It</h3>
<p>As someone who relies on public transit, I was tired of wasting time checking for service
interruptions. This shortcut solves that problem: I get structured, up-to-date info from the
official TTC feed, formatted in a way that’s quick to read.</p>
<p>It’s a small automation, but one that makes my daily routine less stressful.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/eb224000b2e04f2cbaf85f83c99ba22e" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/TTC%20Service%20Alerts%20Icon.jpg" alt="TTC Service Alerts app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/eb224000b2e04f2cbaf85f83c99ba22e" target="_blank" rel="noopener">
    TTC Service Alerts
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I built this shortcut because I wanted a faster way to check TTC service alerts without digging
through the website or scrolling endlessly through apps. With one tap (or a Siri command),
I can now see all active alerts in a clean, styled view that’s easy to scan.</p>
<p>⸻</p>
<h3 id="how-it-works">How It Works</h3>
<p>At the core, my shortcut pulls live data straight from the TTC’s JSON endpoint:</p>
<p><em><em><a href="https://alerts.ttc.ca/api/alerts/list">https://alerts.ttc.ca/api/alerts/list</a></em></em></p>
<p><strong>Here’s the basic flow I set up:</strong></p>
<ul>
<li>Fetch the feed – I use <strong><em><em>Get Contents of URL</em></em></strong> to grab the JSON.</li>
<li>Parse the response – The raw data is turned into a dictionary, which makes it easy
to work with inside Shortcuts.</li>
<li>Check for active alerts – If the routes field has values, the shortcut moves forward.</li>
</ul>
<p>If not, I skip right to a “No Service Alerts at this time” message.</p>
<p>⸻</p>
<h3 id="iterating-through-alerts">Iterating Through Alerts</h3>
<p>When there are active alerts, the shortcut loops through them one by one. For each alert,
it pulls out the key pieces of info:</p>
<ul>
<li><strong><em><em>headerText</em></em></strong> for the main message</li>
<li><strong><em><em>lastUpdated</em></em></strong> for the timestamp</li>
</ul>
<p>I then format the date into something readable and wrap everything in a bit of HTML. By
setting font sizes, bolding headers, and adding dividers, the output looks more like a proper
dashboard than just plain text.</p>
<p>⸻</p>
<h3 id="the-final-output">The Final Output</h3>
<p>Once all the alerts are collected, I combine them into a single block of text, convert it
into rich text, and name it “TTC Service Alerts.” From there, I preview it in Quick Look.</p>
<p>If there aren’t any alerts, the shortcut just shows me a simple popup that says: “No Service
Alerts at this time.”</p>
<p>⸻</p>
<h3 id="why-i-made-it">Why I Made It</h3>
<p>As someone who relies on public transit, I was tired of wasting time checking for service
interruptions. This shortcut solves that problem: I get structured, up-to-date info from the
official TTC feed, formatted in a way that’s quick to read.</p>
<p>It’s a small automation, but one that makes my daily routine less stressful.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/eb224000b2e04f2cbaf85f83c99ba22e" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/TTC%20Service%20Alerts%20Icon.jpg" alt="TTC Service Alerts app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/eb224000b2e04f2cbaf85f83c99ba22e" target="_blank" rel="noopener">
    TTC Service Alerts
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Automating Toronto’s Beach Water Quality with Shortcuts</title><link>https://blog.aidanmaurinjones.com/posts/beach-water-quality-shortcut-blog-post/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/beach-water-quality-shortcut-blog-post/</guid><pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>This summer I wanted a faster way to check if it’s safe to swim at Toronto’s beaches. The city
publishes daily water quality results through their open data portal, but digging through JSON
feeds on a phone isn’t exactly convenient. So, I built a Shortcut that automates the whole process:
it checks for the latest update, pulls the results, and displays a clean, color-coded report in Safari.</p>
<p>⸻</p>
<h3 id="checking-for-fresh-data">Checking for Fresh Data</h3>
<p>The first thing my Shortcut does is make sure I’m not working with stale results. I format the
current date, subtract one day (since advisories usually trail by a day), and call the city’s
last_update API. From there, I grab the lastUpdate field and confirm whether it matches the date I expect.</p>
<p>If no data is available, the Shortcut stops and shows me an alert: “No recent results
found.” That way, I’m not wasting time on old advisories.</p>
<p>⸻</p>
<h3 id="fetching-the-results">Fetching the Results</h3>
<p>Once I know the data is current, I build a URL against the beach_results API. I pass both a
startDate and endDate based on the formatted date, and I also define a list of beach IDs. Right
now I have two beaches set up—IDs 8 and 9—but I can easily add more later.</p>
<p>A Repeat loop runs through each beach ID, fetching its data individually and parsing the
results. This keeps the Shortcut flexible if I want to expand it.</p>
<p>⸻</p>
<h3 id="formatting-the-data">Formatting the Data</h3>
<p>This is the part I had the most fun with. The Shortcut parses out the CollectionDate,
statusFlag, eColi count, and any advisory notes. To make the results clear at a glance,
I map:</p>
<ul>
<li>SAFE → green</li>
<li>UNSAFE → red</li>
<li>Anything else → black</li>
</ul>
<p>I then build an HTML card for each beach, using large black headers for the beach name,
medium-sized text for the collection date, and a color-coded status flag for the water
quality. Everything is wrapped in <span> elements with inline font sizes so the final
report looks neat and easy to read.</p>
<p>⸻</p>
<h3 id="displaying-the-report">Displaying the Report</h3>
<p>After the loop finishes, the Shortcut combines all of the HTML snippets into one page. It
converts that text into rich content and opens it in a Safari web view. What I end up with
is a simple dashboard that shows the latest conditions for each beach I care about.</p>
<p>If the data feed has no values for that day, I just get a quick alert instead of a blank page.</p>
<p>⸻</p>
<h3 id="why-i-built-it">Why I Built It</h3>
<p>For me, this Shortcut strikes the right balance between utility and presentation. It’s not
just dumping JSON—it’s validating freshness, parsing results for multiple beaches, and
presenting them in a way that’s useful at a glance.</p>
<p>Now, instead of digging through government websites or spreadsheets, I just run the Shortcut
and instantly see whether it’s safe to swim. It’s become part of my summer routine, and I love
how it turns raw open data into something practical and personal.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/236f3c704b1748f393eeca0244ff039b" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Toronto%20Beaches%20Water%20Quality%20%28Public%29%20Icon.jpg" alt="Toronto Beaches Water Quality app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/236f3c704b1748f393eeca0244ff039b" target="_blank" rel="noopener">
    Toronto Beaches Water Quality
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>This summer I wanted a faster way to check if it’s safe to swim at Toronto’s beaches. The city
publishes daily water quality results through their open data portal, but digging through JSON
feeds on a phone isn’t exactly convenient. So, I built a Shortcut that automates the whole process:
it checks for the latest update, pulls the results, and displays a clean, color-coded report in Safari.</p>
<p>⸻</p>
<h3 id="checking-for-fresh-data">Checking for Fresh Data</h3>
<p>The first thing my Shortcut does is make sure I’m not working with stale results. I format the
current date, subtract one day (since advisories usually trail by a day), and call the city’s
last_update API. From there, I grab the lastUpdate field and confirm whether it matches the date I expect.</p>
<p>If no data is available, the Shortcut stops and shows me an alert: “No recent results
found.” That way, I’m not wasting time on old advisories.</p>
<p>⸻</p>
<h3 id="fetching-the-results">Fetching the Results</h3>
<p>Once I know the data is current, I build a URL against the beach_results API. I pass both a
startDate and endDate based on the formatted date, and I also define a list of beach IDs. Right
now I have two beaches set up—IDs 8 and 9—but I can easily add more later.</p>
<p>A Repeat loop runs through each beach ID, fetching its data individually and parsing the
results. This keeps the Shortcut flexible if I want to expand it.</p>
<p>⸻</p>
<h3 id="formatting-the-data">Formatting the Data</h3>
<p>This is the part I had the most fun with. The Shortcut parses out the CollectionDate,
statusFlag, eColi count, and any advisory notes. To make the results clear at a glance,
I map:</p>
<ul>
<li>SAFE → green</li>
<li>UNSAFE → red</li>
<li>Anything else → black</li>
</ul>
<p>I then build an HTML card for each beach, using large black headers for the beach name,
medium-sized text for the collection date, and a color-coded status flag for the water
quality. Everything is wrapped in <span> elements with inline font sizes so the final
report looks neat and easy to read.</p>
<p>⸻</p>
<h3 id="displaying-the-report">Displaying the Report</h3>
<p>After the loop finishes, the Shortcut combines all of the HTML snippets into one page. It
converts that text into rich content and opens it in a Safari web view. What I end up with
is a simple dashboard that shows the latest conditions for each beach I care about.</p>
<p>If the data feed has no values for that day, I just get a quick alert instead of a blank page.</p>
<p>⸻</p>
<h3 id="why-i-built-it">Why I Built It</h3>
<p>For me, this Shortcut strikes the right balance between utility and presentation. It’s not
just dumping JSON—it’s validating freshness, parsing results for multiple beaches, and
presenting them in a way that’s useful at a glance.</p>
<p>Now, instead of digging through government websites or spreadsheets, I just run the Shortcut
and instantly see whether it’s safe to swim. It’s become part of my summer routine, and I love
how it turns raw open data into something practical and personal.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/236f3c704b1748f393eeca0244ff039b" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Toronto%20Beaches%20Water%20Quality%20%28Public%29%20Icon.jpg" alt="Toronto Beaches Water Quality app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/236f3c704b1748f393eeca0244ff039b" target="_blank" rel="noopener">
    Toronto Beaches Water Quality
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item><item><title>Automating Fire Ban Updates with Shortcuts</title><link>https://blog.aidanmaurinjones.com/posts/automating-fire-ban-updates-with-shortcuts/</link><guid isPermaLink="true">https://blog.aidanmaurinjones.com/posts/automating-fire-ban-updates-with-shortcuts/</guid><pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate><description><![CDATA[<p>I built a Shortcut that makes it incredibly easy to check whether there’s currently a fire
ban in Dysart et al. Instead of digging through a municipal website or scrolling a feed, I
can now get a clean, glanceable update with one tap.</p>
<p>⸻</p>
<h3 id="how-i-built-it">How I Built It</h3>
<p>The Shortcut pulls from this endpoint:</p>
<p><a href="https://www.dysartetal.ca//modules/NewsModule/services/getalertbannerfeeds.ashx">https://www.dysartetal.ca//modules/NewsModule/services/getalertbannerfeeds.ashx</a></p>
<p>That feed contains JSON data with alert banners, including fire ban notices. Here’s what
happens step by step:</p>
<ol>
<li>
<p>Fetch the feed – Using “Get Contents of URL,” the Shortcut retrieves the raw JSON.</p>
</li>
<li>
<p>Parse into a dictionary – I convert the response into a Dictionary so each item can be checked.</p>
</li>
<li>
<p>Scan for fire ban notices – A “Match Text” action looks for the string Fire Ban. If
there are matches, I know there’s an active ban.</p>
</li>
<li>
<p>Extract title and description – I loop through the items, grab the title and
description fields, and convert the HTML-rich text into plain strings.</p>
</li>
<li>
<p>Build a styled HTML card – If a ban is active, the Shortcut injects the title and
description into a block of HTML with big, bold text so it’s easy to read.</p>
</li>
<li>
<p>Display the result – The HTML card is shown in a Safari-style web view. If no fire
ban is in effect, I get a simple alert that says: “No Fire Ban Status currently available.”</p>
</li>
</ol>
<p>⸻</p>
<h3 id="why-i-use-it">Why I Use It</h3>
<p>Municipal websites aren’t always designed for quick updates, especially on a phone. With
this Shortcut, I don’t have to waste time hunting for information—I get a direct answer in seconds.</p>
<p>It’s also a great example of how I like to use Shortcuts: not for giant, flashy automations,
but for small, thoughtful utilities that make my day smoother.</p>
<p>⸻</p>
<h3 id="customizing-the-shortcut">Customizing the Shortcut</h3>
<p>Since the Shortcut outputs HTML, it’s easy to tweak the look:</p>
<ul>
<li>Change font sizes to make the text more readable.</li>
<li>Add colors—red for “ban in effect,” green for “ban lifted.”</li>
<li>Include extra fields from the feed if needed.</li>
</ul>
<p>And because it’s all built with system actions, I can extend it further: send a push notification
when a ban starts, or log changes to a running Notes document.</p>
<p>⸻</p>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>This Shortcut takes raw municipal data and turns it into something useful that I can check
at a glance. It removes friction, saves me time, and gives me peace of mind knowing I can
always find out the current fire ban status instantly.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/32c07658e4f34b15b8d3bde1997d8e0f" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Fire%20Ban%20Status%20Icon.jpg" alt="Fire Ban Status app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/32c07658e4f34b15b8d3bde1997d8e0f" target="_blank" rel="noopener">
    Fire Ban Status
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></description><content:encoded><![CDATA[<p>I built a Shortcut that makes it incredibly easy to check whether there’s currently a fire
ban in Dysart et al. Instead of digging through a municipal website or scrolling a feed, I
can now get a clean, glanceable update with one tap.</p>
<p>⸻</p>
<h3 id="how-i-built-it">How I Built It</h3>
<p>The Shortcut pulls from this endpoint:</p>
<p><a href="https://www.dysartetal.ca//modules/NewsModule/services/getalertbannerfeeds.ashx">https://www.dysartetal.ca//modules/NewsModule/services/getalertbannerfeeds.ashx</a></p>
<p>That feed contains JSON data with alert banners, including fire ban notices. Here’s what
happens step by step:</p>
<ol>
<li>
<p>Fetch the feed – Using “Get Contents of URL,” the Shortcut retrieves the raw JSON.</p>
</li>
<li>
<p>Parse into a dictionary – I convert the response into a Dictionary so each item can be checked.</p>
</li>
<li>
<p>Scan for fire ban notices – A “Match Text” action looks for the string Fire Ban. If
there are matches, I know there’s an active ban.</p>
</li>
<li>
<p>Extract title and description – I loop through the items, grab the title and
description fields, and convert the HTML-rich text into plain strings.</p>
</li>
<li>
<p>Build a styled HTML card – If a ban is active, the Shortcut injects the title and
description into a block of HTML with big, bold text so it’s easy to read.</p>
</li>
<li>
<p>Display the result – The HTML card is shown in a Safari-style web view. If no fire
ban is in effect, I get a simple alert that says: “No Fire Ban Status currently available.”</p>
</li>
</ol>
<p>⸻</p>
<h3 id="why-i-use-it">Why I Use It</h3>
<p>Municipal websites aren’t always designed for quick updates, especially on a phone. With
this Shortcut, I don’t have to waste time hunting for information—I get a direct answer in seconds.</p>
<p>It’s also a great example of how I like to use Shortcuts: not for giant, flashy automations,
but for small, thoughtful utilities that make my day smoother.</p>
<p>⸻</p>
<h3 id="customizing-the-shortcut">Customizing the Shortcut</h3>
<p>Since the Shortcut outputs HTML, it’s easy to tweak the look:</p>
<ul>
<li>Change font sizes to make the text more readable.</li>
<li>Add colors—red for “ban in effect,” green for “ban lifted.”</li>
<li>Include extra fields from the feed if needed.</li>
</ul>
<p>And because it’s all built with system actions, I can extend it further: send a push notification
when a ban starts, or log changes to a running Notes document.</p>
<p>⸻</p>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>This Shortcut takes raw municipal data and turns it into something useful that I can check
at a glance. It removes friction, saves me time, and gives me peace of mind knowing I can
always find out the current fire ban status instantly.</p>
<article class="app-card">
  <a class="app-card__icon" href="https://www.icloud.com/shortcuts/32c07658e4f34b15b8d3bde1997d8e0f" target="_blank" rel="noopener">
    <img src="/images/Shortcuts%20Icons/Fire%20Ban%20Status%20Icon.jpg" alt="Fire Ban Status app icon" width="52" height="52">
  </a>
  <a class="app-card__title" href="https://www.icloud.com/shortcuts/32c07658e4f34b15b8d3bde1997d8e0f" target="_blank" rel="noopener">
    Fire Ban Status
  </a>
</article>

<h3 id="apps--tools-i-used-to-create-this-shortcut">Apps &amp; Tools I Used to Create this Shortcut</h3>
<div class="app-row">
  
  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Inspect%20Browser%20Icon.jpg" alt="Inspect Browser app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/inspect-browser/id1203594958?uo=4" target="_blank" rel="noopener">
      Inspect Browser
    </a>
  </article>


  <article class="app-card">
    <a class="app-card__icon" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      <img src="/images/App%20Store%20App%20Icons/Jayson%20Icon.jpg" alt="Jayson app icon" width="52" height="52">
    </a>
    <a class="app-card__title" href="https://apps.apple.com/ca/app/jayson/id1447750768?uo=4" target="_blank" rel="noopener">
      Jayson
    </a>
  </article>


</div>

<div class="amj-cta" aria-label="Support and subscription links">
  <div class="amj-cta__item amj-cta__item--coffee">
    <a class="amj-cta__button amj-cta__button--coffee" href="https://www.buymeacoffee.com/AidanMJ25" target="_blank" rel="noopener">
      <span>Buy Me a Coffee</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/posts/index.xml" target="_blank" rel="noopener" aria-label="Subscribe via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Subscribe via RSS</span>
    </a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--newsletter" href="https://buttondown.com/AidanMJ25" target="_blank" rel="noopener">Newsletter via Email</a>
  </div>

  <div class="amj-cta__item">
    <a class="amj-cta__button amj-cta__button--rss" href="https://blog.aidanmaurinjones.com/newsletter/index.xml" target="_blank" rel="noopener" aria-label="Newsletter via RSS">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.18 17.82a1.82 1.82 0 1 1 0-3.64 1.82 1.82 0 0 1 0 3.64Zm-3-8.18v2.73a8.64 8.64 0 0 1 8.64 8.64h2.73A11.36 11.36 0 0 0 3.18 9.64Zm0-4.09v2.73A15.45 15.45 0 0 1 18.55 23h2.73C21.27 11.73 12.45 2.91 3.18 5.55Z"/></svg>
      <span>Newsletter via RSS</span>
    </a>
  </div>
</div>

]]></content:encoded></item></channel></rss>