<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cli on tigger.dev</title><link>/tags/cli/</link><description>Recent content in Cli on tigger.dev</description><generator>Hugo</generator><language>en-gb-oed</language><copyright>© Tadhg O'Brien</copyright><lastBuildDate>Tue, 03 Feb 2026 14:28:52 +0000</lastBuildDate><atom:link href="/tags/cli/index.xml" rel="self" type="application/rss+xml"/><item><title>DIY Audiobooks with make-audiobook</title><link>/make-audiobook/</link><pubDate>Tue, 03 Feb 2026 14:28:52 +0000</pubDate><guid>/make-audiobook/</guid><description>&lt;p&gt;&#10;For six months in 2022, I stared at a hospital ceiling. Paralysed from the neck down, audiobooks weren&amp;#39;t a luxury—they were my lifeline to the outside world.&lt;/p&gt;&#10;&lt;p&gt;&#10;That experience taught me something important: access to audio content shouldn&amp;#39;t depend on whether a publisher has bothered to record it, whether you can afford the audiobook price, or whether you&amp;#39;re willing to hand your reading habits to a cloud service.&lt;/p&gt;&#10;&lt;div id="outline-container-headline-1" class="outline-2"&gt;&#10;&lt;h2 id="headline-1"&gt;&#10;The Problem&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;&#10;&lt;p&gt;&#10;Most ebook-to-audio tools I found fell into three camps: cloud-based services that upload your books to someone else&amp;#39;s servers, complex setups requiring GPU clusters and Python dependency hell, or clunky commercial software with subscription fees.&lt;/p&gt;</description></item><item><title>A file renaming tool for humans</title><link>/smart-rename/</link><pubDate>Sun, 01 Feb 2026 00:00:00 +0000</pubDate><guid>/smart-rename/</guid><description>&lt;p&gt;&#10;I deal with a lot of PDFs. Medical invoices, insurance correspondence, bank statements, tax documents—they all arrive with names like &lt;code class="verbatim"&gt;e134-a1cf-4b4b-af65-ccf83c5270cb.pdf&lt;/code&gt; or &lt;code class="verbatim"&gt;Document(3).pdf&lt;/code&gt; or, my personal favourite, &lt;code class="verbatim"&gt;scan.pdf&lt;/code&gt;. Every. Single. Time.&lt;/p&gt;&#10;&lt;p&gt;&#10;So I started renaming files to something like &lt;code class="verbatim"&gt;2025-09-30-125.00-rahona-clinic.pdf&lt;/code&gt;. Now I know what it is without opening the thing - an invoice, with the date and amount right there in the name. I&amp;#39;m halfway to the spreadsheet already. And thanks to ISO date format, they sort nicely too.&lt;/p&gt;</description></item><item><title>Image manipulation from the command line</title><link>/magick-get-image-res/</link><pubDate>Fri, 04 Jul 2025 18:17:43 +0100</pubDate><guid>/magick-get-image-res/</guid><description>&lt;div id="outline-container-headline-1" class="outline-2"&gt;&#10;&lt;h2 id="headline-1"&gt;&#10;Get an image&amp;#39;s resolution&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick identify going-fishing.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;going-fishing.jpg JPEG 5422x3648 5422x3648+0+0 8-bit sRGB 12.2217MiB 0.000u 0:00.003&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-2" class="outline-2"&gt;&#10;&lt;h2 id="headline-2"&gt;&#10;Convert an image to a different format&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-2" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg going-fishing.png&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-3" class="outline-2"&gt;&#10;&lt;h2 id="headline-3"&gt;&#10;Resize an image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -resize 800x600 going-fishing-resized.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-4" class="outline-3"&gt;&#10;&lt;h3 id="headline-4"&gt;&#10;Only specify width or height&#10;&lt;/h3&gt;&#10;&lt;div id="outline-text-headline-4" class="outline-text-3"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -resize 800x going-fishing-resized-width.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -resize x600 going-fishing-resized-height.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-5" class="outline-3"&gt;&#10;&lt;h3 id="headline-5"&gt;&#10;By percentage&#10;&lt;/h3&gt;&#10;&lt;div id="outline-text-headline-5" class="outline-text-3"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -resize 50% going-fishing-resized-percent.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-6" class="outline-2"&gt;&#10;&lt;h2 id="headline-6"&gt;&#10;Crop an image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-6" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -crop 800x600+100+100 going-fishing-cropped.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-7" class="outline-2"&gt;&#10;&lt;h2 id="headline-7"&gt;&#10;Rotate an image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-7" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -rotate &lt;span style="color:#ae81ff"&gt;90&lt;/span&gt; going-fishing-rotated.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-8" class="outline-2"&gt;&#10;&lt;h2 id="headline-8"&gt;&#10;Add a border to an image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-8" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -bordercolor black -border 10x10 going-fishing-bordered.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-9" class="outline-2"&gt;&#10;&lt;h2 id="headline-9"&gt;&#10;Add text to an image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-9" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -gravity South -pointsize &lt;span style="color:#ae81ff"&gt;36&lt;/span&gt; -fill white -annotate +0+10 &lt;span style="color:#e6db74"&gt;&amp;#34;Going Fishing&amp;#34;&lt;/span&gt; going-fishing-text.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-10" class="outline-2"&gt;&#10;&lt;h2 id="headline-10"&gt;&#10;Convert an image to grayscale&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-10" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -colorspace Gray going-fishing-grayscale.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-11" class="outline-2"&gt;&#10;&lt;h2 id="headline-11"&gt;&#10;Create a thumbnail&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-11" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg -thumbnail 150x150 going-fishing-thumbnail.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-12" class="outline-2"&gt;&#10;&lt;h2 id="headline-12"&gt;&#10;Combine multiple images into a single image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-12" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert image1.jpg image2.jpg image3.jpg +append combined-horizontal.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert image1.jpg image2.jpg image3.jpg -append combined-vertical.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;div id="outline-container-headline-13" class="outline-2"&gt;&#10;&lt;h2 id="headline-13"&gt;&#10;Watermark an image&#10;&lt;/h2&gt;&#10;&lt;div id="outline-text-headline-13" class="outline-text-2"&gt;&#10;&lt;div class="src src-bash"&gt;&#10;&lt;div class="highlight"&gt;&lt;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;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ magick convert going-fishing.jpg watermark.png -gravity southeast -geometry +10+10 -composite going-fishing-watermarked.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;</description></item><item><title>Filtering and searching in hledger</title><link>/hledger-filter-queries/</link><pubDate>Wed, 19 Mar 2025 03:45:29 +0000</pubDate><guid>/hledger-filter-queries/</guid><description>&lt;p&gt;&#10;I am an advocate of plaintext accounting, and hledger is my go-to tool for this. A &lt;a href="https://hledger.org/"&gt;good summary of WTF and why on their landing page&lt;/a&gt;. All of the various bank accounts and cards I use have some sort of CSV or XML export function. Feeding these in to hledger gives me a powerful direct view on my finances that I can analyze in aggregate for budgeting and planning, but also zoom in to a specific transaction or range of transactions.&lt;/p&gt;</description></item></channel></rss>