<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Knowledge Base</title><link>https://bgstack15.ddns.net/blog/</link><description>Preserving for the future: Shell scripts, AoC, and more</description><atom:link href="https://bgstack15.ddns.net/blog/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:bgstack15@gmail.com"&gt;bgstack15&lt;/a&gt; 
&lt;a rel="license" href="https://www.gnu.org/licenses/gpl-3.0.html"&gt;
&lt;img alt="GNU General Public License v3.0"
style="border-width:0; margin-bottom:12px;"
src="https://bgstack15.ddns.net/.images/gplv3-127x51.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Tue, 08 Sep 2026 21:13:21 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>LWSP upgrade for Luanti 5.17.0</title><link>https://bgstack15.ddns.net/blog/posts/2026/09/07/lwsp-upgrade-for-luanti-5-17-0/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;Luanti's recent release of version &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/luanti-org/luanti/releases/tag/5.17.0"&gt;5.17.0&lt;/a&gt; added a feature that validates ContentDB package author using a simple &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/luanti-org/luanti/commit/77e12fe21b94d5743109f95b8a47ac5fbde68294"&gt;regex&lt;/a&gt;, but &lt;a href="https://bgstack15.ddns.net/blog/posts/2025/09/20/novel-project-luanti-web-services-proxy/"&gt;Luanti WebServices Proxy&lt;/a&gt; overloads the author field with the backend server connection information, so I had to update LWSP to fix this.&lt;/p&gt;
&lt;p&gt;The validations fit entirely in this block, in file &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/luanti-org/luanti/blob/master/builtin/mainmenu/content/contentdb.lua"&gt;builtin/mainmenu/content/contentdb.lua&lt;/a&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;#packages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;release&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;"^[%w _%-.]+$"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;"^[a-z0-9_]+$"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"ContentDB: Dropping invalid package: "&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nc"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So it's lua, thankfully, which is way easier for me to read than C++. An easy fix would be to adjust the client lua file to add a colon and tilde in the package author regex.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;package.author:match("^[%w _%-.~:]+$") and
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But seeing as how nobody else will adjust their client configs to allow that, so I &lt;a href="https://bgstack15.ddns.net/blog/cgit/luanti/lwsp/commit/?id=d79a5bb9235f8c05bfaaf453ecf89af5d64be588"&gt;adjusted lwsp&lt;/a&gt; to split author and host+proto with &lt;code&gt;_AT_&lt;/code&gt; rather than &lt;code&gt;~&lt;/code&gt;, and also replace a colon with &lt;code&gt;_colon_&lt;/code&gt;. It's longer and a little less pretty, but it matches the vanilla client expectations. Not everyone who might use lwsp will use a stackrpms build of Luanti.&lt;/p&gt;</description><category>luanti</category><category>regex</category><category>webapps</category><guid>https://bgstack15.ddns.net/blog/posts/2026/09/07/lwsp-upgrade-for-luanti-5-17-0/</guid><pubDate>Mon, 07 Sep 2026 12:40:00 GMT</pubDate></item><item><title>Librewolf 154 problem and downgrade problems</title><link>https://bgstack15.ddns.net/blog/posts/2026/09/03/librewolf-154-problem-and-downgrade-problems/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I don't have a good story today. I was a few months behind on my Librewolf &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/build.opensuse.org/package/show/home:bgstack15:aftermozilla/librewolf"&gt;releases&lt;/a&gt;, so I wanted to work on that. So last week I got 154.0.1 packaged.&lt;/p&gt;
&lt;p&gt;And today I finally installed it, and then I learned the settings panel is completely empty! It's broken. But the app compiles and operates. I needed to tweak some settings, and I couldn't find them in &lt;code&gt;about:config&lt;/code&gt;, so I wanted to use the &lt;code&gt;about:preferences&lt;/code&gt;. It's only broken in my build, which I'm sure has something to do with my debianized-firefox+librewolf-patches process.&lt;/p&gt;
&lt;p&gt;So in the meantime, I downgraded back to 150.0.1 and restored my browser profile from backup (that I take monthly). But my browser had deleted the &lt;a href="https://bgstack15.ddns.net/blog/posts/2026/05/14/passkeys-from-vaultwarden-or-keepassxc/"&gt;extensions for passkeys&lt;/a&gt;, and I need passkeys unfortunately. So I had to go find those again. Apparently, the files had been deleted from the profile directory. It was shockingly hard to get ahold of the .xpi files directly; the Firefox extensions website really wants to have the browser use the file rather than letting you download it: "The appification of stuff" instead of letting a power user download the file and use it.&lt;/p&gt;
&lt;p&gt;When I was able to have it try to use the file (begrudgingly directly from the website), the browser said it was corrupted and would not work. So it didn't even save the file anywhere.&lt;/p&gt;
&lt;p&gt;I started panicking, because I absolutely need a passkey for certain sites. They would not let me log in with a password.&lt;/p&gt;
&lt;p&gt;Remember, this was the previous version of the browser that had worked 1.5 hours ago before updating.&lt;/p&gt;
&lt;p&gt;I reset my browser profile to fresh and tried the extensions again; I can just import my history and bookmarks if I have to. Unfortunately, it still thought the files were corrupted. So I started investigating those. I eventually found a way to "install addons temporarily" which showed me one error message.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Internal error: Invalid string format contentSecurityPolicySandbox&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, that string didn't exist anywhere in these xpi files, and also I hadn't changed any settings about that. Even a fresh 150.0.1 profile malfunctioned too.&lt;/p&gt;
&lt;p&gt;I started poking at the &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/gitlab.com/bgstack15/librewolf-debian/-/tree/b154.0.1?ref_type=heads"&gt;patches&lt;/a&gt; (&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/codeberg.org/librewolf/source/src/branch/main/patches"&gt;more&lt;/a&gt;) to see if anything was related to that string, and I couldn't find anything.&lt;/p&gt;
&lt;p&gt;For some reason, when I blanked the profile a second time, then I could install the extensions again. And then when I restored my backup of the browser profile, all of a sudden it was back, with the extensions working.&lt;/p&gt;
&lt;p&gt;So for now, everything is working for me again, but on an old version of the browser.&lt;/p&gt;
&lt;p&gt;And I still have to fix the debianized librewolf build process so that the settings page works. I don't know what level of effort that will take. I don't want to give up on debianizing librewolf. I'm sure the Debian people have good reasons to debianize Firefox, and I want that, plus the librewolf bits.&lt;/p&gt;</description><category>narrative</category><category>rant</category><category>troubleshooting</category><guid>https://bgstack15.ddns.net/blog/posts/2026/09/03/librewolf-154-problem-and-downgrade-problems/</guid><pubDate>Thu, 03 Sep 2026 12:40:00 GMT</pubDate></item><item><title>Run thumbnailer for arbitrary paths</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/30/run-thumbnailer-for-arbitrary-paths/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;For some reason, it's complex to tell a &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/specifications.freedesktop.org/thumbnail/latest-single/"&gt;thumbnailer program&lt;/a&gt; to index arbitrary paths, such as a single directory or even single file. I don't relish using dbus, but begrudgingly use it to accomplish some goals. I'm pragmatic, to a degree.&lt;/p&gt;
&lt;p&gt;Apparently tools like &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/docs.xfce.org/xfce/tumbler/start"&gt;tumbler&lt;/a&gt; need dbus to receive messages about what paths to index.&lt;/p&gt;
&lt;p&gt;So I vibecoded some syntax for dbus commands and some filetypes for a &lt;code&gt;find&lt;/code&gt; operation, and wrote some functions that I find useful.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/files/2026/listings/thumbnail_functions.sh.html"&gt;files/2026/listings/thumbnail_functions.sh&lt;/a&gt;  &lt;a href="https://bgstack15.ddns.net/blog/files/2026/listings/thumbnail_functions.sh"&gt;(Source)&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;
&lt;span class="normal"&gt;62&lt;/span&gt;
&lt;span class="normal"&gt;63&lt;/span&gt;
&lt;span class="normal"&gt;64&lt;/span&gt;
&lt;span class="normal"&gt;65&lt;/span&gt;
&lt;span class="normal"&gt;66&lt;/span&gt;
&lt;span class="normal"&gt;67&lt;/span&gt;
&lt;span class="normal"&gt;68&lt;/span&gt;
&lt;span class="normal"&gt;69&lt;/span&gt;
&lt;span class="normal"&gt;70&lt;/span&gt;
&lt;span class="normal"&gt;71&lt;/span&gt;
&lt;span class="normal"&gt;72&lt;/span&gt;
&lt;span class="normal"&gt;73&lt;/span&gt;
&lt;span class="normal"&gt;74&lt;/span&gt;
&lt;span class="normal"&gt;75&lt;/span&gt;
&lt;span class="normal"&gt;76&lt;/span&gt;
&lt;span class="normal"&gt;77&lt;/span&gt;
&lt;span class="normal"&gt;78&lt;/span&gt;
&lt;span class="normal"&gt;79&lt;/span&gt;
&lt;span class="normal"&gt;80&lt;/span&gt;
&lt;span class="normal"&gt;81&lt;/span&gt;
&lt;span class="normal"&gt;82&lt;/span&gt;
&lt;span class="normal"&gt;83&lt;/span&gt;
&lt;span class="normal"&gt;84&lt;/span&gt;
&lt;span class="normal"&gt;85&lt;/span&gt;
&lt;span class="normal"&gt;86&lt;/span&gt;
&lt;span class="normal"&gt;87&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# File: thumbnail_functions.sh&lt;/span&gt;
&lt;span class="c1"&gt;# Location: https://bgstack15.ddns.net/blog/posts/2026/08/30/run-thumbnailer-for-arbitrary-paths/&lt;/span&gt;
&lt;span class="c1"&gt;# Author: bgstack15&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2026-08-17-2 19:29&lt;/span&gt;
&lt;span class="c1"&gt;# Title: Functions for Thumbnail Operations&lt;/span&gt;
&lt;span class="c1"&gt;# Purpose: Store all thumbnail operations in one location&lt;/span&gt;
&lt;span class="c1"&gt;# History:&lt;/span&gt;
&lt;span class="c1"&gt;# Usage:&lt;/span&gt;
&lt;span class="c1"&gt;#    source this file, and call the functions you want&lt;/span&gt;
&lt;span class="c1"&gt;#    . thumbnail_functions.sh&lt;/span&gt;
&lt;span class="c1"&gt;#    thumbnail_dir ~/Downloads&lt;/span&gt;
&lt;span class="c1"&gt;# Reference:&lt;/span&gt;
&lt;span class="c1"&gt;#    man busctl&lt;/span&gt;
&lt;span class="c1"&gt;# Improve:&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    A thumbnailer implementation, perhaps tumbler&lt;/span&gt;
&lt;span class="c1"&gt;# Documentation:&lt;/span&gt;
&lt;span class="c1"&gt;#    Running these commands in other windows:&lt;/span&gt;
&lt;span class="c1"&gt;#       busctl --user monitor org.freedesktop.thumbnails.Thumbnailer1&lt;/span&gt;
&lt;span class="c1"&gt;#       G_MESSAGES_PREFIXED= G_MESSAGES_DEBUG=all /usr/lib/x86_64-linux-gnu/tumbler-1/tumblerd&lt;/span&gt;
&lt;span class="c1"&gt;#    Bare command:&lt;/span&gt;
&lt;span class="c1"&gt;#       busctl --user call org.freedesktop.thumbnails.Thumbnailer1 /org/freedesktop/thumbnails/Thumbnailer1 org.freedesktop.thumbnails.Thumbnailer1 Queue asasssu 2 file:///home/bgstack15/Downloads/godzilla.jpg file:///home/bgstack15/Downloads/mary-had-a-little-lamb.jpg 2 "image/jpeg" "image/jpeg" "xx-large" "" 0&lt;/span&gt;
&lt;span class="c1"&gt;#       gdbus call --session --dest org.freedesktop.thumbnails.Thumbnailer1 --object-path /org/freedesktop/thumbnails/Thumbnailer1 --method org.freedesktop.thumbnails.Thumbnailer1.Queue "['file:///home/bgstack15/Downloads/godzilla.jpg']" "['image/jpeg']" "normal" "[]" "0"&lt;/span&gt;
&lt;span class="c1"&gt;#       WARNING: dbus-send does not correctly handle commas in the filenames. I was unable to discover how to escape the comma.&lt;/span&gt;
&lt;span class="c1"&gt;#       dbus-send --dest=org.freedesktop.thumbnails.Thumbnailer1 /org/freedesktop/thumbnails/Thumbnailer1 org.freedesktop.thumbnails.Thumbnailer1.Queue array:string:"file:///path/to/your/file.jpg" array:string:"image/jpeg" string:"normal" string:"leave-on-disk" uint32:0&lt;/span&gt;

thumbnail_dir&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;THUMBNAIL_SIZE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;normal&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;_recursive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RECURSIVE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;_max_depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAX_DEPTH&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_recursive&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; "&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -qiE -e &lt;span class="s1"&gt;' -r | --recursive '&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;/dev/null &lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="c1"&gt;# safety max depth.&lt;/span&gt;
            &lt;span class="nv"&gt;_max_depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;
        &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="nv"&gt;_infiles&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;
        find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -mindepth &lt;span class="m"&gt;1&lt;/span&gt; -maxdepth &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_max_depth&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -type f &lt;span class="se"&gt;\(&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
            -iname &lt;span class="s1"&gt;'*.png'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.jpg'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.jpeg'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.webp'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.gif'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
            -o -iname &lt;span class="s1"&gt;'*.bmp'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.tif'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.tiff'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.svg'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.avif'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
            -o -iname &lt;span class="s1"&gt;'*.heic'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.ico'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.jp2'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.jxl'&lt;/span&gt; -o -iname &lt;span class="s1"&gt;'*.apng'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
            &lt;span class="se"&gt;\)&lt;/span&gt; -print0 &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;'s/ /%20/g;'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -0 -I&lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s '&lt;/span&gt; &lt;span class="s2"&gt;"{}"&lt;/span&gt;
    &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="nv"&gt;_uris&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; _word &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_infiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'"file://%s" '&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;done&lt;/span&gt;
    &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="nv"&gt;_mimetypes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; _word &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_infiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="nv"&gt;_n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;'s/%20/ /g;'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            file -b --mime-type &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -I&lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s '&lt;/span&gt; &lt;span class="s2"&gt;"{}"&lt;/span&gt;
        &lt;span class="k"&gt;done&lt;/span&gt;
    &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="nv"&gt;_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_infiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; wc -w &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;eval&lt;/span&gt; busctl --user call org.freedesktop.thumbnails.Thumbnailer1 /org/freedesktop/thumbnails/Thumbnailer1 &lt;span class="se"&gt;\&lt;/span&gt;
        org.freedesktop.thumbnails.Thumbnailer1 Queue &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"asasssu"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_len&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_uris&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_len&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_mimetypes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"\"\""&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

thumbnail_file&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;THUMBNAIL_SIZE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;normal&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;_mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; file -b --mime-type &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;/dev/null &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;'s/ /%20/g;'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    busctl --user call org.freedesktop.thumbnails.Thumbnailer1 /org/freedesktop/thumbnails/Thumbnailer1 &lt;span class="se"&gt;\&lt;/span&gt;
        org.freedesktop.thumbnails.Thumbnailer1 Queue &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"asasssu"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"1"&lt;/span&gt; &lt;span class="s2"&gt;"file://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"1"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_mimetype&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So now I can run the following, to force the thumbnailer to interpret a directory.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;thumbnail_functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;thumbnail_dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="n"&gt;Downloads&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><category>cli</category><category>dbus</category><category>images</category><category>script</category><category>thumbnail</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/30/run-thumbnailer-for-arbitrary-paths/</guid><pubDate>Sun, 30 Aug 2026 13:07:00 GMT</pubDate></item><item><title>mcl_villager_cheats now includes a "reload trades" button</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/26/mcl-villager-cheats-now-includes-a-reload-trades-button/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I was inspired by some recent conversations about an upcoming &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/content.luanti.org/packages/StrandedPasta/vrestocker/"&gt;new Luanti mod&lt;/a&gt; about randomizing the trades a villager offers, and I wrote my own implementation! It involved copying the entirety of the villager code from &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/codeberg.org/mineclonia/mineclonia"&gt;Mineclonia&lt;/a&gt; (&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/content.luanti.org/packages/ryvnf/mineclonia/"&gt;ContentDB&lt;/a&gt;) and adding a &lt;a href="https://bgstack15.ddns.net/blog/cgit/luanti/mcl_villager_cheats/tree/diff-villager.patch"&gt;small patch&lt;/a&gt;. Well, and the logic for changing the trades too.&lt;/p&gt;
&lt;p&gt;The concept of rotating trades of a villager can be done in-game, for a villager who has never traded, by removing his job block and replacing it. This button short-circuits that. And my implementation leaves it possible even after the villager has participated in a trade. So yes, it's cheating, but that's in the name of the mod. I don't even have a configuration setting for disabling it if the villager xp &amp;gt; 0 (that is, he has traded at all). I could add it, if anybody is interested.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/files/2026/listings/diff-villager.patch.html"&gt;files/2026/listings/diff-villager.patch&lt;/a&gt;  &lt;a href="https://bgstack15.ddns.net/blog/files/2026/listings/diff-villager.patch"&gt;(Source)&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;Date: 2026-08-11&lt;/span&gt;
&lt;span class="w"&gt;Message: The difference between Mineclonia villager.lua and mcl_villager_cheats villager.lua&lt;/span&gt;
&lt;span class="w"&gt;Last-Version: 0.123.0&lt;/span&gt;
&lt;span class="w"&gt;Author: bgstack15&lt;/span&gt;
&lt;span class="w"&gt;Command: diff -aur ~/.minetest/games/mineclonia/mods/ENTITIES/mobs_mc/villager.lua ~/.minetest/mods/mcl_villager_cheats/villager.lua&lt;/span&gt;
&lt;span class="gd"&gt;--- .minetest/games/mineclonia/mods/ENTITIES/mobs_mc/villager.lua	2026-07-26 14:20:37.152618130 -0400&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+++ .minetest/mods/mcl_villager_cheats/villager.lua	                2026-08-11 11:52:24.416485282 -0400&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gu"&gt;@@ -711,6 +711,12 @@&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt; list[current_player;main;3.97,7.98;9,1;]&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;]]&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+-- stackrpms,6&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+fs_footer_template = fs_footer_template ..&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	"image_button[4.0,0.2;1.0,1.0;mcl_villager_cheats_reload.png;reload;]" ..&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	"tooltip[reload;Randomize available trades" ..&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	core.colorize("#47f424","\n(" .. core.get_current_modname() .. ")") ..&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	";#000000;#ffffff]"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-- arg 1 = %s = wanted&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-- arg 2 = %s = wanted tooltip&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gu"&gt;@@ -903,6 +909,15 @@&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;core.register_on_player_receive_fields (function (player, formname, fields)&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;	if formname == "mobs_mc:trading_formspec" then&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+		--stackrpms,9&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+		if fields.reload then&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+			local trader = trading_players[player]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+			if trader and is_valid (trader) then&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+				mcl_villager_cheats.reload_trades(trader)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+				local entity = trader:get_luaentity ()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+				entity:reload_trades()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+			end&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+		end&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;		if fields.quit then&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;			return_fields (player)&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;			local trader = trading_players[player]&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gu"&gt;@@ -942,6 +957,11 @@&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;		type = "detached",&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;		name = inv_name,&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;	})&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	-- stackrpms,5 Need to remove the previous inventory, so this new inventory&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	if inv then&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+		core.remove_detached_inventory(inv_name)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+		inv = nil&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+	end&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;	if not inv then&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;		inv = core.create_detached_inventory (inv_name, inv_class,&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;							  playername)&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gu"&gt;@@ -6783,4 +6803,5 @@&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-- Villager spawning.&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;------------------------------------------------------------------------&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="gd"&gt;-mcl_mobs.register_egg ("mobs_mc:villager", S("Villager"), "#563d33", "#bc8b72", 0)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+-- stackrpms,2 Do not run this again&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="gi"&gt;+--mcl_mobs.register_egg ("mobs_mc:villager", S("Villager"), "#563d33", "#bc8b72", 0)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/2026/scrot-mcl_villager_cheats-reload-button.png"&gt;&lt;img alt="" src="https://bgstack15.ddns.net/blog/2026/scrot-mcl_villager_cheats-reload-button.png"&gt;&lt;/a&gt;&lt;/p&gt;</description><category>game</category><category>luanti</category><category>mineclonia</category><category>mod</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/26/mcl-villager-cheats-now-includes-a-reload-trades-button/</guid><pubDate>Wed, 26 Aug 2026 13:05:00 GMT</pubDate></item><item><title>Mineclonia in Devuan Ceres needs SDL2</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/22/mineclonia-in-devuan-ceres-needs-sdl2/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;In Devuan Ceres (unstable), I had a problem with &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/build.opensuse.org/package/show/home:bgstack15/mineclonia"&gt;Mineclonia&lt;/a&gt; (my build of &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/luanti.org"&gt;Luanti&lt;/a&gt;). Shift+left click would not move items in the inventory screens. A shift+left click normally moves the entire stack (to whichever destination). Shift+middle click still works. So somehow it's just shift+left click.&lt;/p&gt;
&lt;p&gt;I &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/luanti-org/luanti/issues/17421"&gt;was not the first&lt;/a&gt; to discover this bug.&lt;/p&gt;
&lt;p&gt;Come to find out, in Devuan unstable, &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/packages.debian.org/sid/libsdl2-2.0-0"&gt;libsdl2-2.0-0&lt;/a&gt; version 2.32.70+ds-1 is a sdl2-compat layer for sdl3. That is, it uses SDL3 but with the bindings for sdl2 so an application can use it like it uses sdl2.&lt;/p&gt;
&lt;p&gt;Apparently I wanted to install &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/packages.debian.org/sid/libsdl2-classic"&gt;libsdl2-classic&lt;/a&gt; which is real SDL2. And then I need to add this to my invocation of my game:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;SDL_DYNAMIC_API='/usr/$LIB/sdl2-classic/libSDL2-2.0.so.0' mineclonia
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I can live with that. I'm sure libsdl2-classic will go away eventually, but then also eventually hopefully they'll fix their &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/luanti-org/luanti/issues/17421#issuecomment-5267353234"&gt;bug in SDL3&lt;/a&gt;.&lt;/p&gt;</description><category>debugging</category><category>game</category><category>luanti</category><category>mineclonia</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/22/mineclonia-in-devuan-ceres-needs-sdl2/</guid><pubDate>Sat, 22 Aug 2026 13:25:00 GMT</pubDate></item><item><title>git submodule instructions</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/18/git-submodule-instructions/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;For some reason I can't ever get this right, and have to search it over and over. Shamelessly ripped from &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/stackoverflow.com/questions/1030169/pull-latest-changes-for-all-git-submodules/1032653#1032653"&gt;Pull latest changes for all git submodules - Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you failed to &lt;code&gt;git clone --recurse-submodules &amp;lt;repo&amp;gt;&lt;/code&gt;, then you can initialize with this command inside the repo directory.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;git submodule update --init --recursive
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update with this.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;git submodule update --recursive
&lt;/pre&gt;&lt;/div&gt;</description><category>cli</category><category>git</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/18/git-submodule-instructions/</guid><pubDate>Tue, 18 Aug 2026 13:12:00 GMT</pubDate></item><item><title>Reduce file size of images in Linux</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/14/reduce-file-size-of-images-in-linux/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;This is a quick and dirty method that is going to lose quality of an image, and all metadata. Do this if you're just in a hurry to share something without full info. It will replace the input file, so do this only on a copy!&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;jpegoptim --max=85 --strip-all input.jpg
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;Straight from &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/www.digitalocean.com/community/tutorials/reduce-file-size-of-images-linux"&gt;Reduce File Size of Images in Linux - CLI and GUI methods | DigitalOcean&lt;/a&gt;&lt;/p&gt;</description><category>cli</category><category>convert</category><category>images</category><category>linux</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/14/reduce-file-size-of-images-in-linux/</guid><pubDate>Fri, 14 Aug 2026 12:38:00 GMT</pubDate></item><item><title>AoE2DE CaptureAge on Linux for 2026</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I ended up having to use a fuller script from &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/gist.github.com/TeknoHamster/d8b2f90a1cd618074aa1e35c81e7bc4b"&gt;TeknoHamster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also had to do some crazy tricks with protontricks or winetricks to run &lt;code&gt;protontrikcs 813780 d3dcompiler_47&lt;/code&gt;. I think what ended up working was adjusting the script to run a winetricks command in the WINEPREFIX.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/files/2026/listings/captureage.sh.html"&gt;files/2026/listings/captureage.sh&lt;/a&gt;  &lt;a href="https://bgstack15.ddns.net/blog/files/2026/listings/captureage.sh"&gt;(Source)&lt;/a&gt;&lt;/p&gt;&lt;div class="code"&gt;&lt;table class="codetable"&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-1"&gt;&lt;code data-line-number=" 1"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-2"&gt;&lt;code data-line-number=" 2"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Taken directly from https://gist.githubusercontent.com/TeknoHamster/d8b2f90a1cd618074aa1e35c81e7bc4b/raw/972832a3e37ef32d255804d19aae99550ec9fb26/captureage from https://gist.github.com/TeknoHamster/d8b2f90a1cd618074aa1e35c81e7bc4b&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-3"&gt;&lt;code data-line-number=" 3"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-4"&gt;&lt;code data-line-number=" 4"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nv"&gt;APPID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;813780&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-5"&gt;&lt;code data-line-number=" 5"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nv"&gt;STEAM_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STEAM_PATH&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.local/share/Steam&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-6"&gt;&lt;code data-line-number=" 6"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nv"&gt;PROTON_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROTON_NAME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;Proton&lt;/span&gt;&lt;span class="p"&gt; - Experimental&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-7"&gt;&lt;code data-line-number=" 7"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-8"&gt;&lt;code data-line-number=" 8"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PROTON_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-9"&gt;&lt;code data-line-number=" 9"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;STEAMAPPS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAM_PATH&lt;/span&gt;&lt;span class="s2"&gt;/steamapps"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-10"&gt;&lt;code data-line-number="10"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;STEAM_COMPAT_DATA_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAMAPPS&lt;/span&gt;&lt;span class="s2"&gt;/compatdata/&lt;/span&gt;&lt;span class="nv"&gt;$APPID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-11"&gt;&lt;code data-line-number="11"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;STEAM_COMPAT_CLIENT_INSTALL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAM_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-12"&gt;&lt;code data-line-number="12"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAM_COMPAT_DATA_PATH&lt;/span&gt;&lt;span class="s2"&gt;/pfx"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-13"&gt;&lt;code data-line-number="13"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GAME_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAMAPPS&lt;/span&gt;&lt;span class="s2"&gt;/common/AoE2DE"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-14"&gt;&lt;code data-line-number="14"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GAME_DIR_WIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'S:\common\AoE2DE'&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-15"&gt;&lt;code data-line-number="15"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CAPTUREAGE_STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WINEPREFIX&lt;/span&gt;&lt;span class="s2"&gt;/drive_c/users/steamuser/AppData/Roaming/CaptureAge/persistedState_prod.json"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-16"&gt;&lt;code data-line-number="16"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CAPTUREAGE_EXE_WIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'C:\users\steamuser\AppData\Local\Programs\CaptureAge\CaptureAge.exe'&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-17"&gt;&lt;code data-line-number="17"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CAPTUREAGE_DIR_WIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'C:\users\steamuser\AppData\Local\Programs\CaptureAge'&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-18"&gt;&lt;code data-line-number="18"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;STEAM_COMPAT_INSTALL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GAME_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-19"&gt;&lt;code data-line-number="19"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;STEAM_COMPAT_LIBRARY_PATHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAMAPPS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-20"&gt;&lt;code data-line-number="20"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PROTON_SET_GAME_DRIVE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-21"&gt;&lt;code data-line-number="21"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Adjust the path to the proton executable used by Age of Empires II&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-22"&gt;&lt;code data-line-number="22"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PROTON_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROTON_EXEC&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$STEAMAPPS&lt;/span&gt;&lt;span class="p"&gt;/common/&lt;/span&gt;&lt;span class="nv"&gt;$PROTON_NAME&lt;/span&gt;&lt;span class="p"&gt;/proton&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-23"&gt;&lt;code data-line-number="23"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;# export WINEDEBUG=warn+all # This is for debug logs&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-24"&gt;&lt;code data-line-number="24"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;# export OBS_VKCAPTURE=1 # Enable this for OBS Videogame capture&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-25"&gt;&lt;code data-line-number="25"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-26"&gt;&lt;code data-line-number="26"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;prepare_prefix&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-27"&gt;&lt;code data-line-number="27"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="nb"&gt;local&lt;/span&gt; game_dir_win
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-28"&gt;&lt;code data-line-number="28"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="nb"&gt;local&lt;/span&gt; game_dir_escaped
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-29"&gt;&lt;code data-line-number="29"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-30"&gt;&lt;code data-line-number="30"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="nv"&gt;game_dir_win&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GAME_DIR_WIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-31"&gt;&lt;code data-line-number="31"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="nv"&gt;game_dir_escaped&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;game_dir_win&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\\\\&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-32"&gt;&lt;code data-line-number="32"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-33"&gt;&lt;code data-line-number="33"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  mkdir -p &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WINEPREFIX&lt;/span&gt;&lt;span class="s2"&gt;/dosdevices"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-34"&gt;&lt;code data-line-number="34"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  ln -sfn &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAMAPPS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WINEPREFIX&lt;/span&gt;&lt;span class="s2"&gt;/dosdevices/s:"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-35"&gt;&lt;code data-line-number="35"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-36"&gt;&lt;code data-line-number="36"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WINEPREFIX&lt;/span&gt;&lt;span class="s2"&gt;/user.reg"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-37"&gt;&lt;code data-line-number="37"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    &lt;span class="nv"&gt;GAME_DIR_ESCAPED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$game_dir_escaped&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; perl -0pi -e &lt;span class="s1"&gt;'BEGIN{$r=$ENV{GAME_DIR_ESCAPED}} s#"Install Location"="[^"]*"#"Install Location"="$r"#g'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WINEPREFIX&lt;/span&gt;&lt;span class="s2"&gt;/user.reg"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-38"&gt;&lt;code data-line-number="38"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-39"&gt;&lt;code data-line-number="39"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-40"&gt;&lt;code data-line-number="40"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CAPTUREAGE_STATE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-41"&gt;&lt;code data-line-number="41"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    &lt;span class="nv"&gt;tmp_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-42"&gt;&lt;code data-line-number="42"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    jq --arg dir &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$game_dir_win&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'.lastUsedGameDirectory = $dir'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CAPTUREAGE_STATE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$tmp_state&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mv &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$tmp_state&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CAPTUREAGE_STATE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-43"&gt;&lt;code data-line-number="43"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-44"&gt;&lt;code data-line-number="44"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-45"&gt;&lt;code data-line-number="45"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-46"&gt;&lt;code data-line-number="46"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;reg_add&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-47"&gt;&lt;code data-line-number="47"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROTON_EXEC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; run reg add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-48"&gt;&lt;code data-line-number="48"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-49"&gt;&lt;code data-line-number="49"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;#This creates Windows registries to make the Spectate with CA button work&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-50"&gt;&lt;code data-line-number="50"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;register_captureage&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-51"&gt;&lt;code data-line-number="51"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="nb"&gt;local&lt;/span&gt; protocol_command
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-52"&gt;&lt;code data-line-number="52"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-53"&gt;&lt;code data-line-number="53"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="nv"&gt;protocol_command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"\"&lt;/span&gt;&lt;span class="nv"&gt;$CAPTUREAGE_EXE_WIN&lt;/span&gt;&lt;span class="s2"&gt;\" \"%1\""&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-54"&gt;&lt;code data-line-number="54"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-55"&gt;&lt;code data-line-number="55"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; root &lt;span class="k"&gt;in&lt;/span&gt; HKCU&lt;span class="se"&gt;\\&lt;/span&gt;Software&lt;span class="se"&gt;\\&lt;/span&gt;Classes HKLM&lt;span class="se"&gt;\\&lt;/span&gt;Software&lt;span class="se"&gt;\\&lt;/span&gt;Classes&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-56"&gt;&lt;code data-line-number="56"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    reg_add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="s2"&gt;\\captureage"&lt;/span&gt; /ve /d &lt;span class="s2"&gt;"URL:captureage"&lt;/span&gt; /f
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-57"&gt;&lt;code data-line-number="57"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    reg_add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="s2"&gt;\\captureage"&lt;/span&gt; /v &lt;span class="s2"&gt;"URL Protocol"&lt;/span&gt; /d &lt;span class="s2"&gt;""&lt;/span&gt; /f
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-58"&gt;&lt;code data-line-number="58"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    reg_add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="s2"&gt;\\captureage\\shell\\open\\command"&lt;/span&gt; /ve /d &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$protocol_command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /f
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-59"&gt;&lt;code data-line-number="59"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-60"&gt;&lt;code data-line-number="60"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-61"&gt;&lt;code data-line-number="61"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; root &lt;span class="k"&gt;in&lt;/span&gt; HKCU HKLM&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-62"&gt;&lt;code data-line-number="62"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    reg_add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="s2"&gt;\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CaptureAge.exe"&lt;/span&gt; /ve /d &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CAPTUREAGE_EXE_WIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /f
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-63"&gt;&lt;code data-line-number="63"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;    reg_add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="s2"&gt;\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CaptureAge.exe"&lt;/span&gt; /v &lt;span class="s2"&gt;"Path"&lt;/span&gt; /d &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CAPTUREAGE_DIR_WIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /f
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-64"&gt;&lt;code data-line-number="64"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;  &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-65"&gt;&lt;code data-line-number="65"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-66"&gt;&lt;code data-line-number="66"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-67"&gt;&lt;code data-line-number="67"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;#install capture age (only needed once). Adjust the location to point to the installer you downloaded.&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-68"&gt;&lt;code data-line-number="68"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;#"$PROTON_EXEC" run "$PWD/CaptureAgeSetup.exe"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-69"&gt;&lt;code data-line-number="69"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-70"&gt;&lt;code data-line-number="70"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;# run capture age&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-71"&gt;&lt;code data-line-number="71"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Older version of CA:DE were installed in AppData/Local/Programs/CaptureAge . If it doesn't launch for you, check this path&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-72"&gt;&lt;code data-line-number="72"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;prepare_prefix
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-73"&gt;&lt;code data-line-number="73"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;register_captureage
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="linenos linenodiv"&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/#-74"&gt;&lt;code data-line-number="74"&gt;&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROTON_EXEC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; run &lt;span class="s2"&gt;"C:/users/steamuser/AppData/Local/Programs/CaptureAge/CaptureAge.exe"&lt;/span&gt;
&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</description><category>aoe2de</category><category>captureage</category><category>game</category><category>linux</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/10/aoe2de-captureage-on-linux-for-2026/</guid><pubDate>Mon, 10 Aug 2026 13:10:00 GMT</pubDate></item><item><title>onfoss.org from browser history</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/06/onfoss.org-from-browser-history/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I was on a travel laptop and I was looking through my browser history. I found this really awesome site I didn't recall visiting: &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/onfoss.org/"&gt;onfoss.org&lt;/a&gt;. This is some group of people who get together to virtual LAN party!&lt;/p&gt;
&lt;p&gt;This is really fascinating, that I didn't remember this at all! This place links to so many free and libre software titles. I've only heard of some of them. &lt;/p&gt;
&lt;p&gt;I already play some of them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/supertuxkart.net/"&gt;SuperTuxKart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/git.minetest.land/VoxeLibre/VoxeLibre"&gt;VoxeLibre&lt;/a&gt;, a game in the &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/www.luanti.org/en/"&gt;Luanti&lt;/a&gt; engine&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/play0ad.com/"&gt;0 A.D.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I've heard of a few that I haven't played.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/Anuken/Mindustry"&gt;Mindustry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/www.bzflag.org/"&gt;BZFlag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/wz2100.net/"&gt;Warzone 2100&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.openra.net/"&gt;OpenRA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And loads I haven't heard of before!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/yvt/openspades"&gt;OpenSpades&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/OpenHV/OpenHV"&gt;OpenHV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/quetoo.org/"&gt;QueToo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/hurrycurry.metamuffin.org/"&gt;Hurry Curry!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/czlowiekimadlo.itch.io/tanks-of-freedom-ii"&gt;Tanks of Freedom II&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/lavenderdotpet/LibreQuake"&gt;LibreQuake&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/spaceships.me/"&gt;Spaceships&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/HasangerGames/suroi"&gt;Suroi&lt;/a&gt;, a FLOSS clone of &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/surviv.io"&gt;surviv.io&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/unvanquished.net/"&gt;Unvaunquished&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/www.teeworlds.com/"&gt;Teeworlds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/nzp-team/nzportable"&gt;Nazi Zombies: Portable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/aetup.itch.io/pixelpusher"&gt;Pixelpusher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/opensoldat/opensoldat"&gt;OpenSoldat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/TeamHypersomnia/Hypersomnia"&gt;Hypersominia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/xonotic.org/"&gt;Xonotic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/assault.cubers.net/"&gt;AssaultCube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/http:/www.openarena.ws/smfnews.php"&gt;OpenArena&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There's so many here that I hadn't heard of before! Most of them are first-person shooters, and I play only a couple of those. But they're all FLOSS, which is very important!&lt;/p&gt;</description><category>browser</category><category>floss</category><category>games</category><category>history</category><category>narrative</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/06/onfoss.org-from-browser-history/</guid><pubDate>Thu, 06 Aug 2026 12:41:00 GMT</pubDate></item><item><title>Idea: use protonup for Lego Universe</title><link>https://bgstack15.ddns.net/blog/posts/2026/08/02/idea-use-protonup-for-lego-universe/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I have not formalized this process, but I tested it at least once: you can use &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/pypi.org/project/protonup/"&gt;protonup&lt;/a&gt; to get a Wine (Proton) environment for running &lt;a href="https://bgstack15.ddns.net/blog/categories/lego-universe/"&gt;Lego Universe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I use &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/devuan.org"&gt;Devuan&lt;/a&gt; GNU+Linux, release Ceres (unstable) which is based on Debian Sid (unstable), and the current package for &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/packages.debian.org/sid/wine"&gt;wine&lt;/a&gt; is version 10.0~repack-12, but 10.0~repack-6 is the last wine package that runs Lego Universe client. I suspect it is an oversight, related to the combining of 32-bit and 64-bit/wow64 stuff I don't understand, and people in Debian unstable don't seem to test or care about.&lt;/p&gt;
&lt;p&gt;If you want to fetch 10.0~repack-6, set this in file &lt;code&gt;/etc/apt/sources.list.d/snapshot.list&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c"&gt;# 2025-11-02-1 16:05 Fix DLU Lego Universe client&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;deb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;[check-valid-until=no]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;http://snapshot.debian.org/archive/debian/20251001T203719Z/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;unstable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;main&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So for over half a year now I've had to pin an old version of wine, albeit the same upstream version string but a different repack in my Linux distro. I dislike having to pin to old versions of things (that are too big for me to compile myself).&lt;/p&gt;
&lt;p&gt;If I ever need to upgrade wine to current (and they haven't fixed the 32-bit/64-bit whatever), I could use protonup to easily fetch GE-Proton.&lt;/p&gt;
&lt;p&gt;To install protonup, I had to use a virtual environment.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;python3 -m venv ~/venv1
. ~/venv1/bin/activate
pip install protonup
protonup --releases | tail # find highest version
protonup -t GE-Proton11-1
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It will prompt to confirm the installation, and also print the deployed directory.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Installed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bgstack15&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steam&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;compatibilitytools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;GE&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Proton11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Use that for &lt;code&gt;PROTONPREFIX&lt;/code&gt; or &lt;code&gt;WINEPREFIX&lt;/code&gt; when running an application.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/2026/lego-universe-wine.png"&gt;&lt;img alt="" src="https://bgstack15.ddns.net/blog/2026/lego-universe-wine.png"&gt;&lt;/a&gt;&lt;/p&gt;</description><category>lego-universe</category><category>proton</category><guid>https://bgstack15.ddns.net/blog/posts/2026/08/02/idea-use-protonup-for-lego-universe/</guid><pubDate>Sun, 02 Aug 2026 12:42:00 GMT</pubDate></item></channel></rss>