<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on manueljimenezs</title><link>https://manueljimenezs.github.io/posts/</link><description>manueljimenezs (Posts)</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 20 Jul 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://manueljimenezs.github.io/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Building my first Flatpak</title><link>https://manueljimenezs.github.io/2025/07/building-my-first-flatpak/</link><pubDate>Sun, 20 Jul 2025 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2025/07/building-my-first-flatpak/</guid><description>&lt;p>
&lt;figure>
&lt;img src="https://manueljimenezs.github.io/img/2025-07-21-building-my-first-flatpak/sdrpp_steamdeck.jpg" alt="A SteamDeck running the SDR software SDR&amp;#43;&amp;#43; via Flatpak">
&lt;figcaption>A SteamDeck running the SDR software SDR&amp;#43;&amp;#43; via Flatpak&lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>First things first, I&amp;rsquo;ve had a SteamDeck for some time now. Even though you can use it for its primary purpose, playing games 😆, there&amp;rsquo;s so much you can do with it.&lt;/p>
&lt;p>At my family&amp;rsquo;s home there is a radio antenna on the roof, that can be used with the typical ham radio handhelds and transceivers. In my case, I have it setup with a Raspberry Pi, a &lt;a href="https://swling.com/blog/2023/08/the-new-rtl-sdr-dongle-version-4/">RTL-SDR v4 dongle&lt;/a> connected to it and to the antenna. That way I can listen to HF, UHF and VHF bands from anywhere I want.&lt;/p>
&lt;p>That concludes the server part. There are a few clients that can be used to connect to the Pi via RTL-TCP, some of them are GQRX, SDRSharp, CubicSDR, and SDR++. The former is what I have been using lately.&lt;/p>
&lt;p>I was looking for a more portable way to access the SDR, so the SteamDeck was a perfect fit for this. There&amp;rsquo;s is only one problem, everything in SteamOS is usually installed via Flatpak because by default SteamOS sits behind an immutable file system, so having SDR++ via Flatpak would be great, but looking on the official repos there is no Flatpak package.&lt;/p>
&lt;h1 id="the-beginning" >The beginning
&lt;span>
&lt;a href="#the-beginning">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>This is a short definition about what a Flatpak is&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Flatpak is a technology for distributing and running sandboxed desktop applications on Linux. It allows developers to package their applications with all necessary dependencies, making it easier to distribute software across different Linux distributions.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>There are some basic things that are necessary for building a Flatpak:&lt;/p>
&lt;ul>
&lt;li>The YAML manifest: where modules, metadata and build steps are defined&lt;/li>
&lt;li>The icon and desktop file&lt;/li>
&lt;/ul>
&lt;p>This is an example of the manifest file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">id&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">org.sdrpp.App&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">runtime&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">org.kde.Platform&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">runtime-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;5.15-23.08&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">sdk&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">org.kde.Sdk&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">sdrpp&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">finish-args&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- --&lt;span class="l">share=network&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- --&lt;span class="l">socket=pulseaudio&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- --&lt;span class="l">filesystem=home&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- --&lt;span class="l">device=usb&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- --&lt;span class="l">socket=x11&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- --&lt;span class="l">device=dri&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">modules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">rtl-sdr&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">buildsystem&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">cmake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">config-opts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- -&lt;span class="l">DINSTALL_UDEV_RULES=OFF&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- -&lt;span class="l">DDETACH_KERNEL_DRIVER=ON&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">sources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">url&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://github.com/rtlsdrblog/rtl-sdr-blog.git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">v1.3.6&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;strong>runtime&lt;/strong> defines a set of libraries where the program is going to run on. In this case, SDR++ is a QT app so the KDE Runtime would guarantee the least hassle to make this run.&lt;/p>
&lt;p>Each &lt;strong>module&lt;/strong> defines a dependency, needed to build the software from source, you can also set where does it fetch the sources from with the &lt;code>sources:&lt;/code> tag, doesn&amp;rsquo;t matter if sources are local or not. After reading the SDR++ repo for quite a while i managed to gather all the module dependencies and their options. I only built this with the RTL-SDR driver and &amp;lsquo;didnt bother with compatibility for other drivers as that would have made the build process even more complex.&lt;/p>
&lt;p>In &lt;strong>finish-args&lt;/strong> you define the permissions the final app will need.&lt;/p>
&lt;h1 id="handicaps" >Handicaps
&lt;span>
&lt;a href="#handicaps">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>I had a few problems trying to run the app due to an error linking &lt;strong>stdc++fs&lt;/strong> whilte trying to build the source. After battling a little bit with ChatGPT it led me to the right path: modify the upstream code so it doesn&amp;rsquo;t try to link &lt;code>stdc++fs&lt;/code>. &lt;em>(modern GCC versions (≥9) integrate std::filesystem directly into libstdc++, so explicitly linking -lstdc++fs results in an error because it doesn&amp;rsquo;t exist!)&lt;/em>&lt;/p>
&lt;h1 id="trial-and-error" >Trial and error
&lt;span>
&lt;a href="#trial-and-error">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>I was building and trying to run the app with these commands:&lt;/p>
&lt;pre tabindex="0">&lt;code>flatpak-builder --force-clean build-dir org.sdrpp.App.yaml --install build-dir --user
flatpak run org.sdrpp.App.yaml
&lt;/code>&lt;/pre>&lt;p>You can also open a shell inside the Flatpak environment like this for debugging:&lt;/p>
&lt;pre tabindex="0">&lt;code>flatpak run --command=sh --devel org.sdrpp.App
&lt;/code>&lt;/pre>&lt;p>Now that was running it is time to add the icons and the .desktop file shortcut to make it pretty. You can check the repo &lt;a href="https://github.com/manueljimenezs/sdrpp-flatpak">here&lt;/a>&lt;/p></description></item><item><title>Scraping one of the main Spanish TV broadcasters with cookies, Python and yt-dlp</title><link>https://manueljimenezs.github.io/2023/02/scraping-one-of-the-main-spanish-tv-broadcasters-with-cookies-python-and-yt-dlp/</link><pubDate>Sun, 19 Feb 2023 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2023/02/scraping-one-of-the-main-spanish-tv-broadcasters-with-cookies-python-and-yt-dlp/</guid><description>&lt;p>As a little project I wondered: Would it be possible to scrape the contents of a Spanish channel website so I could get their content offline and without any loss? That way you would be able to watch it everywhere, with no ads and no resolution limits. (This broadcaster is also known for their bad practices in ad breaks, on-screen elements and an unbrowsable website if not using adblock).&lt;/p>
&lt;p>I was thinking about publishing the code in the first place, but I think it will be more safe and productive to write about the process of doing it so you could extend it to any websites you like:&lt;/p>
&lt;blockquote>
&lt;p>If you give a man a fish, you feed him for a day. If you teach a man to fish, you feed him for a lifetime.&lt;/p>
&lt;/blockquote>
&lt;div class="notice warning">
&lt;span class="icon alert">
&lt;object data="/icons/alert.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>This is generic information, the URLs provided in this article are not real. This is only for educational purposes about working with python, requests and cookies.&lt;/p>
&lt;/div>
&lt;h1 id="analyzing-the-problem" >Analyzing the problem
&lt;span>
&lt;a href="#analyzing-the-problem">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>To be able to see any content on that channel platform, you will need to create a user account. That means, we will need to create an account to be able to make and send our requests to their internal API&lt;/p>
&lt;p>For this I used any modern browser and I toggled the &lt;strong>Developer tools&lt;/strong> in the &lt;strong>Networking&lt;/strong> tab. That way you will be able to see the login sequence.&lt;/p>
&lt;p>In this case, the login is a POST request to an API endpoint sending your username and password as an input. Then it generates a session token inside a cookie and allows you to interact with the internal API.&lt;/p>
&lt;p>You could replicate that in python like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Session&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># create a new session object to store session data for future requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">credentials&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;username:&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;myuser&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;password:&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;mypassword&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://api.web.com/login&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">credentials&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="notice info">
&lt;span class="icon info">
&lt;object data="/icons/info.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>You can use the &lt;code>python-dotenv&lt;/code> package to store credentials inside an external file&lt;/p>
&lt;/div>
&lt;h1 id="choose-an-example-content" >Choose an example content
&lt;span>
&lt;a href="#choose-an-example-content">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>The best way to scrape something is to use actual data, but be careful: some websites have request limits and may block you with a &lt;code>HTTP 429 Too Many Requests&lt;/code> error. One way of avoiding this is dumping your jsons and content locally and scraping over that local copy.&lt;/p>
&lt;p>After logging in, we will send a GET request with the URL of the content we want to scrape (e.g: &lt;code>http://web.com/episode/example&lt;/code>) Use a browser in developer mode first to see what you need to look for. For me, the useful data was stored inside two &lt;code>&amp;lt;script&amp;gt;&lt;/code> tags.&lt;/p>
&lt;p>For this, you may find the &lt;code>re&lt;/code> and &lt;code>BeautifulSoup4&lt;/code> packages useful for filtering the info you need. In this case, a simple call to re was all I needed:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">html&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://web.com/episode/example&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">matches&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">findall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;script&amp;gt;(.*?)&amp;lt;/script&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">html&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Inside those tags theres another url that will lead you to the specific content API endpoint, the response is a JSON where you could scrape the metadata and the streaming url&lt;/p>
&lt;div class="notice info">
&lt;span class="icon info">
&lt;object data="/icons/info.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>You can use the &lt;code>json get('')&lt;/code> functions or the &lt;code>jmespath&lt;/code> package to fetch the data you want from a json into variables&lt;/p>
&lt;/div>
&lt;h1 id="interfacing-your-code-with-yt-dlp" >Interfacing your code with yt-dlp
&lt;span>
&lt;a href="#interfacing-your-code-with-yt-dlp">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>yt-dlp is a fork of youtube-dl, a python utility to download video from lots of sources you can install it with:&lt;/p>
&lt;pre tabindex="0">&lt;code>pip3 install yt-dlp
&lt;/code>&lt;/pre>&lt;p>Suppose we already extracted a filename string and the m3u8 playlist with the content we want to download. We can pass them to yt-dlp like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">yt_dlp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># * the options we will pass to yt-dlp *&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># in this case only the outtmpl property to specify the&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># output filename we extracted in a previous request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ydl_opts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;outtmpl&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">title&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="s1">&amp;#39;.mp4&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;mpegurl&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="n">yt_dlp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">YoutubeDL&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ydl_opts&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">ydl&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ydl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">download&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That will have your file downloaded, yt-dlp will take care of downloading the separate audio and video streams and merging them into a file.&lt;/p>
&lt;p>I hope you find this information useful and try to get your hands dirty with something that comes to your mind. Scraping can be very powerful for automation, IoT, Telegram notifications&amp;hellip;&lt;/p></description></item><item><title>Patching the kernel as a custom package in Archlinux</title><link>https://manueljimenezs.github.io/2022/11/patching-the-kernel-as-a-custom-package-in-archlinux/</link><pubDate>Sun, 06 Nov 2022 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2022/11/patching-the-kernel-as-a-custom-package-in-archlinux/</guid><description>&lt;p>&lt;a href="https://manueljimenezs.github.io/2021/09/how-i-ended-up-compiling-my-own-linux-kernel/">Following the adventure of patching the linux kernel&lt;/a>, I tried to automate it a bit. Part of the process is well documented as always in the &lt;a href="https://wiki.archlinux.org/title/Kernel/Arch_Build_System">wiki&lt;/a>&lt;/p>
&lt;p>The idea is to fetch the official Archlinux sources for the linux kernel so we can modify them and add our patches.&lt;/p>
&lt;div class="notice info">
&lt;span class="icon info">
&lt;object data="/icons/info.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>Could I buy a graphics card with a normal HDMI port for a hundred bucks and skip all of this mess? Yes, but where is the fun in that?&lt;/p>
&lt;/div>
&lt;p>Start by creating a new src folder in your homedir.&lt;/p>
&lt;p>We will need the &lt;code>asp&lt;/code> package that will take care of fetching the sources for us by issuing these commands:&lt;/p>
&lt;pre tabindex="0">&lt;code>asp update
asp export linux
&lt;/code>&lt;/pre>&lt;p>I will also add my custom kernel patches in a &lt;code>patches/*.diff&lt;/code> dir, you can see
&lt;a href="https://manueljimenezs.github.io/2021/09/how-i-ended-up-compiling-my-own-linux-kernel/">why I need to patch the kernel here&lt;/a>&lt;/p>
&lt;p>There is also another issue here: the config for the kernel issued by asp is different than the upstream package, meaning that we will need to modify it, otherwise my system, which is a BTRFS filesystem, will not boot:&lt;/p>
&lt;pre tabindex="0">&lt;code>cd linux
mv config config.old
sed -r &amp;#34;s/^(|#)CONFIG_BTRFS_FS=.*/CONFIG_BTRFS_FS=y/g&amp;#34; config.old &amp;gt; config
&lt;/code>&lt;/pre>&lt;p>I also built a PKGBUILD patch with e.g &lt;code>diff -Naru PKGBUILD PKGBUILD.old &amp;gt; custom_PKGBUILD.patch&lt;/code> to apply it on each kernel release, this gets rid of building the docs and their dependencies, also does a shallow clone and introduces my &lt;code>0001-amdgpu-clock.patch&lt;/code> patchfile. That way the build will take less time:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-patch" data-lang="patch">&lt;span class="line">&lt;span class="cl">&lt;span class="gd">--- PKGBUILD 2022-10-29 12:28:27.038231602 +0200
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+++ PKGBUILD 2022-10-29 12:28:27.038231602 +0200
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span>&lt;span class="gu">@@ -1,6 +1,6 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span> # Maintainer: Jan Alexander Steffens (heftig) &amp;lt;heftig@archlinux.org&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">-pkgbase=linux
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+pkgbase=linux-amdclock
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span> pkgver=6.0.5.arch1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> pkgrel=1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> pkgdesc=&amp;#39;Linux&amp;#39;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">@@ -10,14 +10,13 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span> license=(GPL2)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> makedepends=(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> bc libelf pahole cpio perl tar xz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">- xmlto python-sphinx python-sphinx_rtd_theme graphviz imagemagick texlive-latexextra
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span> git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> )
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> options=(&amp;#39;!strip&amp;#39;)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> _srcname=archlinux-linux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> source=(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">- &amp;#34;$_srcname::git+https://github.com/archlinux/linux?signed#tag=$_srctag&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span> config # the main kernel config file
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ 0001-amdgpu-clock.patch
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span> )
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> validpgpkeys=(
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &amp;#39;ABAF11C65A2970B130ABE3C479BE3E4300411886&amp;#39; # Linus Torvalds
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">@@ -26,13 +25,14 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span> &amp;#39;C7E7849466FE2358343588377258734B41C31549&amp;#39; # David Runge &amp;lt;dvzrv@archlinux.org&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> )
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sha256sums=(&amp;#39;SKIP&amp;#39;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">- &amp;#39;05168cbbeb6378eec6c84fe3300cede4fa5cf6130c39fb8af95040529bd390a6&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+ &amp;#39;SKIP&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> export KBUILD_BUILD_HOST=archlinux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> export KBUILD_BUILD_USER=$pkgbase
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> export KBUILD_BUILD_TIMESTAMP=&amp;#34;$(date -Ru${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> prepare() {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">+ git clone --depth=1 --branch=$_srctag &amp;#34;https://github.com/archlinux/linux&amp;#34; $_srcname
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span> cd $_srcname
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> echo &amp;#34;Setting version...&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">@@ -60,7 +60,7 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> build() {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> cd $_srcname
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">- make htmldocs all
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+ make all
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> _package() {
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That patch is then applied like this: &lt;code>patch -p0 &amp;lt; ../custom_PKGBUILD.patch&lt;/code>&lt;/p>
&lt;p>Now the only thing left is to build and install it:&lt;/p>
&lt;pre tabindex="0">&lt;code>makepkg -s
sudo pacman -U linux-amdclock-*.zst
&lt;/code>&lt;/pre>&lt;p>You can bundle all of it in a shell script to save time in further upgrades:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>rm -rf linux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">asp update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">asp &lt;span class="nb">export&lt;/span> linux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cp patches/* linux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> linux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mv config config.old
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># enable support for / as BTRFS filesystem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sed -r &lt;span class="s2">&amp;#34;s/^(|#)CONFIG_BTRFS_FS=.*/CONFIG_BTRFS_FS=y/g&amp;#34;&lt;/span> config.old &amp;gt; config
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">patch -p0 &amp;lt; ../custom_PKGBUILD.patch
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Enriching your articles with Hugo</title><link>https://manueljimenezs.github.io/2022/04/enriching-your-articles-with-hugo/</link><pubDate>Sat, 09 Apr 2022 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2022/04/enriching-your-articles-with-hugo/</guid><description>&lt;p>Hugo has some tricks to enrich the contents of the posts and is highly customizable. With some imagination, one can implement features that are in no way inferior to some popular CMS out there.&lt;/p>
&lt;hr>
&lt;h1>Table Of Contents&lt;/h1>
&lt;div class="toc">
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>
&lt;ul>
&lt;li>&lt;a href="#table-of-contents">Table of contents&lt;/a>&lt;/li>
&lt;li>&lt;a href="#add-captions-to-images">Add captions to images&lt;/a>&lt;/li>
&lt;li>&lt;a href="#invert-some-diagrams-and-images-on-dark-mode">Invert (some) diagrams and images on dark mode&lt;/a>&lt;/li>
&lt;li>&lt;a href="#update-alert-boxes">Update: alert boxes&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/div>
&lt;hr>
&lt;h2 id="table-of-contents" >Table of contents
&lt;span>
&lt;a href="#table-of-contents">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>When writing a long post, a table of contents can be quite useful to quickly access parts of the article. Hugo comes with a &lt;code>TableOfContents&lt;/code> module by default. We&amp;rsquo;re going to use something called &lt;a href="https://gohugo.io/content-management/shortcodes/">shortcodes&lt;/a>. Shortcodes allow you to write small snippets of code that are triggered with a macro. This way we can optionally add a table of contents.&lt;/p>
&lt;p>We&amp;rsquo;re gonna create a file &lt;code>layouts/shortcodes/toc.html&lt;/code> with the following content:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hr&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Table Of Contents&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;toc&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ .Page.TableOfContents }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hr&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next time we add &lt;code>{{ toc }}&lt;/code> inside a Markdown file, it will insert a new table of contents in that place.&lt;/p>
&lt;h2 id="add-captions-to-images" >Add captions to images
&lt;span>
&lt;a href="#add-captions-to-images">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>Another useful feature is having descriptions of the images inserted. In this case we are going to take advantage of the &lt;code>title&lt;/code> property of the &lt;code>img&lt;/code> tag.&lt;/p>
&lt;p>We are also going to take advantage of the Markdown syntax for inserting images: While the usual way to inserting images is like this &lt;code>![Alt text](location)&lt;/code>, you can also add a title that will not be displayed like this &lt;code>![Alt text](location &amp;quot;my description&amp;quot;)&lt;/code>.&lt;/p>
&lt;p>Create this file: &lt;code>layouts/_default/_markup/render-image.html&lt;/code>&lt;/p>
&lt;pre tabindex="0">&lt;code>{{ if .Title }}
&amp;lt;figure&amp;gt;
&amp;lt;img src=&amp;#34;{{ .Destination | safeURL }}&amp;#34; alt=&amp;#34;{{ .Text }}&amp;#34;&amp;gt;
&amp;lt;figcaption&amp;gt;{{ .Title }}&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;
{{ else }}
&amp;lt;img src=&amp;#34;{{ .Destination | safeURL }}&amp;#34; alt=&amp;#34;{{ .Text }}&amp;#34;&amp;gt;
{{ end }}
&lt;/code>&lt;/pre>&lt;p>Now you can add images with captions whenever you want, jump to the next section to see an example of an image with such feature.&lt;/p>
&lt;h2 id="invert-some-diagrams-and-images-on-dark-mode" >Invert (some) diagrams and images on dark mode
&lt;span>
&lt;a href="#invert-some-diagrams-and-images-on-dark-mode">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>This is a greeeat feature 👌, especially for the actual users of dark mode, so they don&amp;rsquo;t get blinded with white squares!. Again we are going to use shortcodes. This shortcode is pretty simple, when used, the content inside will be surrounded by an &lt;code>.invert&lt;/code> class, just add this snippet of code to &lt;code>layouts/shortcodes/invert.html&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;invert&amp;#34;&lt;/span> &lt;span class="p">&amp;gt;&lt;/span>{{ .Inner | markdownify }}&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You will also need to do something with that class. In my case I went to my theme&amp;rsquo;s css, located in &lt;code>themes/mytheme/assets/css/main.css&lt;/code>. Inside the dark mode condition, we will insert this code, which will invert the images located inside that class:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="p">@&lt;/span>&lt;span class="k">media&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nt">prefers-color-scheme&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nt">dark&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nc">invert&lt;/span> &lt;span class="nt">img&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">-webkit-&lt;/span>&lt;span class="k">filter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">invert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">85&lt;/span>&lt;span class="kt">%&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c">/* safari 6.0 - 9.0 */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">filter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">invert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">85&lt;/span>&lt;span class="kt">%&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, in any Markdown document you could insert the following tag, and automatically that image will be inverted, useful for diagrams, not that much for photos. That&amp;rsquo;s why we don&amp;rsquo;t want to always apply the inversion:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-md" data-lang="md">&lt;span class="line">&lt;span class="cl">{{&lt;span class="p">&amp;lt;&lt;/span> &lt;span class="nt">invert&lt;/span> &lt;span class="p">&amp;gt;&lt;/span>}}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">![&lt;span class="nt">Alt Txt&lt;/span>](&lt;span class="na">/img/test.svg&lt;/span>)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{&lt;span class="p">&amp;lt;&lt;/span> &lt;span class="p">/&lt;/span>&lt;span class="nt">invert&lt;/span> &lt;span class="p">&amp;gt;&lt;/span>}}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here&amp;rsquo;s an example: (try toggling your system to dark/light mode!)&lt;/p>
&lt;div class="invert" >&lt;figure>
&lt;img src="https://manueljimenezs.github.io/img/systemd.dependency.service.svg" alt="Alt Txt">
&lt;figcaption>This diagram will adapt to the theme of the page&lt;/figcaption>
&lt;/figure>&lt;/div>
&lt;h2 id="update-alert-boxes" >Update: alert boxes
&lt;span>
&lt;a href="#update-alert-boxes">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>Alert boxes are the definitive tool to catch the attention of the reader. Particularly when &lt;em>everything has gone out of hand&lt;/em> and we may break things 😂.&lt;/p>
&lt;p>Add this snippet of code to &lt;code>layouts/shortcodes/notice.html&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;notice {{ .Get 0 }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ if (or (eq (.Get 0) &amp;#34;alert&amp;#34; ) (eq (.Get 0) &amp;#34;warning&amp;#34;)) }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">span&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;icon alert&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">object&lt;/span> &lt;span class="na">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;/icons/alert.svg&amp;#34;&lt;/span> &lt;span class="na">width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;24&amp;#34;&lt;/span> &lt;span class="na">height&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;24&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">object&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">span&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ else if (eq (.Get 0) &amp;#34;info&amp;#34;)}}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">span&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;icon info&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">object&lt;/span> &lt;span class="na">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;/icons/info.svg&amp;#34;&lt;/span> &lt;span class="na">width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;24&amp;#34;&lt;/span> &lt;span class="na">height&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;24&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">object&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">span&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ else }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">span&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;icon info&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">object&lt;/span> &lt;span class="na">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;/icons/info.svg&amp;#34;&lt;/span> &lt;span class="na">width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;24&amp;#34;&lt;/span> &lt;span class="na">height&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;24&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">object&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">span&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>{{ .Inner | markdownify }}&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>With css you can customize it a little bit:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">notice&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">position&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">relative&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">border-radius&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="kt">px&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">margin-bottom&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="kt">px&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">notice&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nc">alert&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="nc">notice&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nc">warning&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">background-color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">var&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="n">warning&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">bg&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="kc">color&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">border&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">solid&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="kt">px&lt;/span> &lt;span class="nb">rgb&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">164&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">27&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">27&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">notice&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nc">info&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">background-color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nf">var&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">bg&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="kc">color&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">border&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">solid&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="kt">px&lt;/span> &lt;span class="nb">rgb&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">21&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">81&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">170&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">notice&lt;/span> &lt;span class="nt">p&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">padding&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="mf">0.8&lt;/span>&lt;span class="kt">em&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="kt">em&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">icon&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nc">alert&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="nc">icon&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nc">info&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">position&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">absolute&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">top&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">0.6&lt;/span>&lt;span class="kt">rem&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">left&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">0.5&lt;/span>&lt;span class="kt">rem&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can use it in a post like this:&lt;/p>
&lt;pre tabindex="0">&lt;code>{{&amp;lt;notice warning&amp;gt;}}
This is a warning
{{&amp;lt;/notice&amp;gt;}}
&lt;/code>&lt;/pre>&lt;p>Aaand, this is the final result 🎉:&lt;/p>
&lt;div class="notice warning">
&lt;span class="icon alert">
&lt;object data="/icons/alert.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>This is a warning&lt;/p>
&lt;/div>
&lt;div class="notice info">
&lt;span class="icon info">
&lt;object data="/icons/info.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>This is an info block. (You &lt;em>can&lt;/em> &lt;strong>use&lt;/strong> &lt;code>markdown&lt;/code> &lt;u>code&lt;/u>)&lt;/p>
&lt;/div>
&lt;div class="notice note">
&lt;span class="icon note">
&lt;object data="/icons/note.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>This is a note block. (You &lt;em>can&lt;/em> &lt;strong>use&lt;/strong> &lt;code>markdown&lt;/code> &lt;u>code&lt;/u>)&lt;/p>
&lt;/div>
&lt;p>Sources&lt;/p>
&lt;p>&lt;a href="https://ruddra.com/hugo-add-toc-anywhere/">ruddra&lt;/a> | &lt;a href="https://sebastiandedeyne.com/captioned-images-with-markdown-render-hooks-in-hugo/">sebastiandedeyne&lt;/a>&lt;/p></description></item><item><title>This blog now runs under Hugo</title><link>https://manueljimenezs.github.io/2022/04/this-blog-now-runs-under-hugo/</link><pubDate>Sun, 03 Apr 2022 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2022/04/this-blog-now-runs-under-hugo/</guid><description>&lt;p>So I wanted to give another chance to Hugo, I was using Jekyll for a while but I didn&amp;rsquo;t quite like the hassle of managing ruby dependencies and versions.&lt;/p>
&lt;p>At the same time, I also took the opportunity to entirely redo the layout of the page, using the &lt;a href="https://themes.gohugo.io/themes/hugo-theme-anubis/">Anubis&lt;/a> theme as a base. I liked that the old design was quite minimal and i wanted to preserve that. I also tried to avoid using JavaScript so if you block it, it will look exactly the same, on any device 😁.&lt;/p>
&lt;p>Also migrating the posts from one platform to another worked flawlessly with almost no modification to the source files 👍.&lt;/p>
&lt;p>Now I use two repositories for managing this page, one repo for serving the static build, and other repo for making the edits.&lt;/p>
&lt;p>Using a &lt;a href="https://github.com/peaceiris/actions-hugo">workflow&lt;/a> is very convenient with this setup becase you can write posts from everywhere without having a local enviroment to deploy.&lt;/p>
&lt;h1 id="setting-up-the-environment" >Setting up the environment
&lt;span>
&lt;a href="#setting-up-the-environment">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>If you want to make a similar setup, here&amp;rsquo;s the steps to reproduce it:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Create the &lt;code>user.github.io&lt;/code> repo, here is where you will deploy the final statified webpage.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Create another repo &lt;code>myblog-hugo&lt;/code>, here is where you will edit the page.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Create a new personal access token &lt;strong>and copy the code generated!&lt;/strong>:
&lt;a href="https://github.com/settings/tokens/new">https://github.com/settings/tokens/new&lt;/a>
&lt;div class="notice info">
&lt;span class="icon info">
&lt;object data="/icons/info.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>Note that maybe you have to check the &lt;code>repo&lt;/code> checkbox while generating the token, so push access from one repo to another is allowed.&lt;/p>
&lt;/div>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Go to both repositories &amp;gt; section Secrets and add a new Secret pasting the code generated. Name it as you like (e.g &lt;code>hugosecret&lt;/code>).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>In your &lt;code>myblog-hugo&lt;/code> repo, create the following file at &lt;code>.github/workflows/main.yml&lt;/code> with this content, changing the &lt;code>&amp;lt;user&amp;gt;&lt;/code> variable to your liking.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">hugo build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">master&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build-deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Setup Hugo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">peaceiris/actions-hugo@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hugo-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;0.96.0&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">hugo --minify&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">peaceiris/actions-gh-pages@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PERSONAL_TOKEN&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.HUGOSECRET }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">EXTERNAL_REPOSITORY&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">&amp;lt;user&amp;gt;/&amp;lt;user&amp;gt;.github.io&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PUBLISH_BRANCH&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">master&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PUBLISH_DIR&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./public/&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>How I ended up compiling my own Linux kernel</title><link>https://manueljimenezs.github.io/2021/09/how-i-ended-up-compiling-my-own-linux-kernel/</link><pubDate>Mon, 20 Sep 2021 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2021/09/how-i-ended-up-compiling-my-own-linux-kernel/</guid><description>&lt;p>I didn&amp;rsquo;t expect this day would arrive. It&amp;rsquo;s all fun and games until you buy a cheap graphic card with only a DVI port in it. It works great for FullHD resolutions. The problem is when you have resolutions and framerates bigger than that.&lt;/p>
&lt;p>In the Linux kernel, the maximum pixel clock (the speed at which pixels are transmitted over a port) is limited to 165 MHz leading to messing with the images when displaying bigger resolutions than fullHD.&lt;/p>
&lt;p>There are two solutions to this problem:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Using lower resolutions/framerates, this means not taking advantage of e.g ultrawide monitors. (Spoiler: nobody wants this 😛)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Tweaking your kernel, increasing the clock ratio and happily use your shiny screen as it was intended.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="getting-your-hands-dirty" >Getting your hands dirty
&lt;span>
&lt;a href="#getting-your-hands-dirty">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>After a long journey searching on the interwebs, I found that increasing the pixel clock to 250 MHz is enough for WFHD resolutions. There is even a &lt;a href="https://www.monitortests.com/pixelclock.php">calculator&lt;/a> for that.&lt;/p>
&lt;div class="notice warning">
&lt;span class="icon alert">
&lt;object data="/icons/alert.svg" width="20" height="20">&lt;/object>
&lt;/span>
&lt;p>Note that you may be running your graphics card out of spec, and you can &lt;strong>irreversibly damage&lt;/strong> your hardware so be very cautious with this.&lt;/p>
&lt;/div>
&lt;p>Here is the line in the Linux kernel that we&amp;rsquo;re going to change. This change is provide as a patch file, which concisely represents how and where a change in a file is made. Something like &lt;code>diff --git oldfile.txt newfile.txt&lt;/code> will suffice.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-diff" data-lang="diff">&lt;span class="line">&lt;span class="cl">&lt;span class="gd">--- a/drivers/gpu/drm/amd/display/include/signal_types.h 2020-12-17 20:11:00.261706513 +0100
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+++ b/drivers/gpu/drm/amd/display/include/signal_types.h 2020-12-17 20:09:14.391997315 +0100
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gi">&lt;/span>&lt;span class="gu">@@ -29,7 +29,7 @@
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span> /* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> #define TMDS_MIN_PIXEL_CLOCK 25000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> /* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">-#define TMDS_MAX_PIXEL_CLOCK 165000
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gd">&lt;/span>&lt;span class="gi">+#define TMDS_MAX_PIXEL_CLOCK 250000
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I also created a script that downloads the linux source code, automatically applies all the patches and compiles it with a basic config. &lt;a href="https://github.com/manueljimenezs/linux-build-script">Here&lt;/a> is the full set of files.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="nv">KERNELVER&lt;/span>&lt;span class="o">=&lt;/span>linux-5.14.2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">get_and_prepare&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> wget https://cdn.kernel.org/pub/linux/kernel/v5.x/&lt;span class="nv">$KERNELVER&lt;/span>.tar.xz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> tar -xf &lt;span class="nv">$KERNELVER&lt;/span>.tar.xz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> cp -r config &lt;span class="nv">$KERNELVER&lt;/span>/.config
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">patch_kernel&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> i in &lt;span class="k">$(&lt;/span>ls patches&lt;span class="k">)&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> patch -Np1 -d &lt;span class="nv">$KERNELVER&lt;/span> &amp;lt; patches/0001-amdgpu-clock.patch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">build&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">export&lt;/span> &lt;span class="nv">KBUILD_BUILD_HOST&lt;/span>&lt;span class="o">=&lt;/span>archlinux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">export&lt;/span> &lt;span class="nv">KBUILD_BUILD_USER&lt;/span>&lt;span class="o">=&lt;/span>linux-amdclock
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">cd&lt;/span> &lt;span class="nv">$KERNELVER&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> make -j10
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> make modules -j10
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo cp -v arch/x86/boot/bzImage /boot/vmlinuz-linux-amdclock
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo make modules_install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> ! &lt;span class="nb">command&lt;/span> -v wget &lt;span class="p">&amp;amp;&lt;/span>&amp;gt; /dev/null&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Please install wget&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">exit&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">case&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$1&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> in
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -b&lt;span class="p">|&lt;/span>--build-only&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">exit&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">;;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -p&lt;span class="p">|&lt;/span>--patch-only&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> patch_kernel
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">exit&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">;;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">esac&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">get_and_prepare
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">patch_kernel
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">build
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>On each update you would have to increase the kernel version and recompile the new kernel to copy it to your bootdir.&lt;/p>
&lt;p>Also, you would have to blacklist the &lt;code>linux&lt;/code> package on your distribution&amp;rsquo;s package manager so it doesn&amp;rsquo;t automatically update and you don&amp;rsquo;t lose the changes made.&lt;/p>
&lt;p>In the case of Archlinux, as aaalwayss ;)) the wiki clearly explains it: &lt;a href="https://wiki.archlinux.org/title/Pacman#Skip_package_from_being_upgraded">link&lt;/a>&lt;/p></description></item><item><title>Full-disk encryption on Archlinux with LVM+LUKS+BTRFS</title><link>https://manueljimenezs.github.io/2020/05/full-disk-encryption-on-archlinux-with-lvm-luks-btrfs/</link><pubDate>Thu, 28 May 2020 19:19:54 +0100</pubDate><guid>https://manueljimenezs.github.io/2020/05/full-disk-encryption-on-archlinux-with-lvm-luks-btrfs/</guid><description>&lt;hr>
&lt;h1>Table Of Contents&lt;/h1>
&lt;div class="toc">
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>
&lt;ul>
&lt;li>&lt;a href="#planning-the-disk-layout">Planning the disk layout&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-the-disk-layout-and-volumes">Setting up the disk layout and volumes&lt;/a>&lt;/li>
&lt;li>&lt;a href="#continue-with-the-usual-arch-install">Continue with the usual Arch install&lt;/a>&lt;/li>
&lt;li>&lt;a href="#finishing-the-installation">Finishing the installation&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/div>
&lt;hr>
&lt;p>This article will guide you through a basic Archlinux installation with full-disk encryption and the usage of the BTRFS filesystem for managing subvolumes and snapshots.&lt;/p>
&lt;p>The steps shown here are all available in the Arch Wiki, but I wanted to make an installation example from scratch until OS startup.&lt;/p>
&lt;p>This installation will presume you are booting from an &lt;strong>EFI System&lt;/strong> and that you will be using a SWAP partition. Again, this is a concrete real-world example but feel free to make it match to your likings.&lt;/p>
&lt;h2 id="planning-the-disk-layout" >Planning the disk layout
&lt;span>
&lt;a href="#planning-the-disk-layout">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;!-- more -->
&lt;p>In this case we&amp;rsquo;re going to make two main partitions in a GPT partition table:&lt;/p>
&lt;ul>
&lt;li>&lt;code>/dev/sda1&lt;/code>, the ESP (UEFI Boot Partition) that will hold our kernel and the bootloader. Formatted as FAT32 with a size of 512MB with &lt;code>mkfs.fat -F 32 /dev/sda1&lt;/code>&lt;/li>
&lt;li>&lt;code>/dev/sda2&lt;/code>, is a partition that will contain an encrypted container which at the same time will contain an LVM physical volume which at the same time will contain logical volumes for both the &lt;strong>root&lt;/strong> and &lt;strong>swap&lt;/strong> filesystems. Yeah, this seems a little bit crazy but it is a very flexible configuration :)&lt;/li>
&lt;/ul>
&lt;div class="invert" >&lt;img src="https://manueljimenezs.github.io/img/2020-05-28-disk-encryption/diagram.svg" alt="">&lt;/div>
&lt;h2 id="setting-up-the-disk-layout-and-volumes" >Setting up the disk layout and volumes
&lt;span>
&lt;a href="#setting-up-the-disk-layout-and-volumes">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>Supposing you&amp;rsquo;ve already created the two partitions mentioned about and formatted &lt;code>/dev/sda1&lt;/code> as FAT32, the next step is to create the encrpyted container:&lt;/p>
&lt;pre tabindex="0">&lt;code># cryptsetup luksFormat /dev/sda2
# cryptsetup open /dev/sda2 cryptlvm
&lt;/code>&lt;/pre>&lt;p>Consecutively, a physical volume called &lt;code>cryptlvm&lt;/code> is going to be created. We will also add that physical volume to a volume group called &lt;code>secure&lt;/code>&lt;/p>
&lt;pre tabindex="0">&lt;code># pvcreate /dev/mapper/cryptlvm
# vgcreate secure /dev/mapper/cryptlvm
&lt;/code>&lt;/pre>&lt;p>Then we&amp;rsquo;re going to focus on creating the &lt;strong>swap&lt;/strong> and &lt;strong>root&lt;/strong> filesystems:&lt;/p>
&lt;p>The &lt;strong>swap&lt;/strong> partition will be 4GB and the rest will be used for the BTRFS system partition&lt;/p>
&lt;pre tabindex="0">&lt;code>lvcreate -L 4G secure -n swap
lvcreate -l 100%FREE secure -n root
&lt;/code>&lt;/pre>&lt;p>Initialize the &lt;strong>swap&lt;/strong> partition:&lt;/p>
&lt;pre tabindex="0">&lt;code>mkswap /dev/mapper/secure-swap
swapon /dev/mapper/secure-swap
&lt;/code>&lt;/pre>&lt;p>Create the &lt;strong>BTRFS&lt;/strong> filesystem and their subsequent subvolumes: &amp;lsquo;@&amp;rsquo; for root, &amp;lsquo;@home&amp;rsquo; for the home folder and &amp;lsquo;@snapshots&amp;rsquo; for making filesystem backups. This makes it to discriminate directories when making backups.&lt;/p>
&lt;pre tabindex="0">&lt;code>mkfs.btrfs /dev/mapper/secure-system
mount /dev/mapper/secure-system /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
umount /mnt
&lt;/code>&lt;/pre>&lt;p>Now we&amp;rsquo;re going to mount all the volumes and we&amp;rsquo;re going to enable zstd compression.&lt;/p>
&lt;pre tabindex="0">&lt;code>mount -o subvol=@,compression=zstd /dev/mapper/secure-system /mnt
mkdir -p /mnt/{home,boot}
mount -o subvol=@home,compression=zstd /dev/mapper/secure-system /mnt/home
mount /dev/sda1 /mnt/boot
&lt;/code>&lt;/pre>&lt;h2 id="continue-with-the-usual-arch-install" >Continue with the usual Arch install
&lt;span>
&lt;a href="#continue-with-the-usual-arch-install">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>&lt;strong>Follow the normal install of the base system and basic config. in the &lt;a href="https://wiki.archlinux.org/index.php/installation_guide">Installation guide&lt;/a>&lt;/strong>&lt;/p>
&lt;h2 id="finishing-the-installation" >Finishing the installation
&lt;span>
&lt;a href="#finishing-the-installation">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>When arriving at the mkinitcpio part some extra steps will be required:&lt;/p>
&lt;p>Install &lt;code>intel-ucode&lt;/code> (or the AMD counterpart) and install systemd-boot on the ESP:&lt;/p>
&lt;pre tabindex="0">&lt;code>bootctl –path=/boot install
&lt;/code>&lt;/pre>&lt;p>Head over to the ESP (/boot) and create &lt;code>arch.conf&lt;/code> inside the &lt;code>entries&lt;/code> directory with the following content:&lt;/p>
&lt;pre tabindex="0">&lt;code>title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img # ONLY FOR INTEL CPUs!!
initrd /initramfs-linux.img
options luks.uuid=&amp;lt;LUKS_UUID&amp;gt; root=/dev/mapper/secure-system rootflags=subvol=@ rd.luks.options=discard
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Replace &lt;code>&amp;lt;LUKS_UUID&amp;gt;&lt;/code> with the UUID shown in &lt;code>blkid&lt;/code> in the filesystem flagged as LUKS.&lt;/strong>&lt;/p>
&lt;p>Add &lt;code>default arch&lt;/code> inside the &lt;code>loader.conf&lt;/code> file.&lt;/p>
&lt;p>Edit the HOOKS line in &lt;code>/etc/mkinitcpio.conf&lt;/code> with the following modules:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf">HOOKS=(base systemd autodetect modconf keyboard sd-vconsole block sd-encrypt sd-lvm2 filesystems fsck)
&lt;/code>&lt;/pre>&lt;p>Lastly run &lt;code>mkinitcpio -p linux&lt;/code> and &lt;code>reboot&lt;/code>. If you&amp;rsquo;re lucky enough you will enter to your newly installed operating system.&lt;/p></description></item><item><title>Running vanilla GNOME on Ubuntu</title><link>https://manueljimenezs.github.io/2020/03/running-vanilla-gnome-on-ubuntu/</link><pubDate>Mon, 16 Mar 2020 20:19:54 +0100</pubDate><guid>https://manueljimenezs.github.io/2020/03/running-vanilla-gnome-on-ubuntu/</guid><description>&lt;ul>
&lt;li>
&lt;p>Install &lt;code>gnome-session&lt;/code> and some components:&lt;/p>
&lt;p>&lt;code>sudo apt install gnome-session gnome-tweaks chrome-gnome-shell&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Restore the default login screen style:&lt;/p>
&lt;p>&lt;code>sudo update-alternatives --config gdm3.css&lt;/code>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Select &lt;code>/usr/share/gnome-shell/theme/gnome-shell.css&lt;/code>&lt;/p>
&lt;p>&lt;strong>Log out&lt;/strong> from your PC and switch the session to GNOME by clicking the gear icon&lt;/p>
&lt;p>Go to extensions.gnome.org and install the User Themes extension&lt;/p>
&lt;p>Go to Tweaks and set themes, icons, etc in Adwaita&lt;/p>
&lt;p>
&lt;img src="https://manueljimenezs.github.io/img/2020-03-16-vanilla-gnome/tweaks-style.png" alt="">
&lt;/p>
&lt;h1 id="removing-snapd" >Removing snapd
&lt;span>
&lt;a href="#removing-snapd">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>Snaps are a self-contained package technology that allows software to be installed without worrying about incompatible libraries. The downside is that apps are bigger in size and the startup may be slower.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">sudo rm -rf /var/cache/snapd/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt autoremove --purge snapd gnome-software-plugin-snap
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -rf ~/snap
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You may have to run &lt;code>apt install gnome-calculator gnome-system-monitor&lt;/code> to get back some default applications that were initially shipped as snaps.&lt;/p></description></item><item><title>rEFInd: An elegant bootloader</title><link>https://manueljimenezs.github.io/2019/10/refind-an-elegant-bootloader/</link><pubDate>Tue, 29 Oct 2019 20:39:54 +0100</pubDate><guid>https://manueljimenezs.github.io/2019/10/refind-an-elegant-bootloader/</guid><description>&lt;hr>
&lt;h1>Table Of Contents&lt;/h1>
&lt;div class="toc">
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#introduction">Introduction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#efi-requirements">EFI Requirements&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#the-esp">The ESP&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#refind">rEFInd&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#manual-install">Manual install&lt;/a>&lt;/li>
&lt;li>&lt;a href="#adding-linux">Adding Linux&lt;/a>&lt;/li>
&lt;li>&lt;a href="#extra-ubuntu-copying-kernels-to-esp">Extra: Ubuntu: Copying kernels to ESP&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/div>
&lt;hr>
&lt;p>
&lt;img src="https://manueljimenezs.github.io/img/refind_scr.png" alt="Refind Bootloader">
&lt;/p>
&lt;h1 id="introduction" >Introduction
&lt;span>
&lt;a href="#introduction">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>From the year 2013, Microsoft switched its operating system&amp;rsquo;s booting mode to a technology called EFI, already being used in Macs for a long time.&lt;/p>
&lt;p>In UEFI (The PC implementation) multiple applications can coexist, this means you can combine multiple bootloaders such as Windows Boot, GRUB, systemd-boot without taking over each other.&lt;/p>
&lt;h1 id="efi-requirements" >EFI Requirements
&lt;span>
&lt;a href="#efi-requirements">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;ul>
&lt;li>Your motherboard has to be supported (&amp;gt;2013)&lt;/li>
&lt;li>Your disk has to be formatted in GPT instead of MBR&lt;/li>
&lt;li>You need an ESP (EFI system partition) that stores all the &lt;em>bootable&lt;/em> executables&lt;/li>
&lt;/ul>
&lt;h2 id="the-esp" >The ESP
&lt;span>
&lt;a href="#the-esp">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>The ESP (EFI system partition) is a small FAT32 partition (~512MB) that stores all the bootloaders:&lt;/p>
&lt;pre tabindex="0">&lt;code>.
├── Boot
│   ├── BOOT.CSV
│   ├── bootx64.efi
│   └── ref.bak
├── Microsoft
│   ├── Boot
│   └── Recovery
├── refind
│   ├── BOOT.CSV
│   ├── drivers_x64
│   ├── icons
│   ├── keys
│   ├── refind.conf
│   ├── refind.conf.bak
│   ├── refind_x64.efi
│   └── themes
├── tools
└── ubuntu
├── fw
└── fwupx64.efi
&lt;/code>&lt;/pre>&lt;p>The default bootloader is stored in the firmware level in something we call &lt;em>EFI Variables&lt;/em> that we&amp;rsquo;ll configure in just a moment. In some motherboards the default bootloader can be chosen in the motherboard config screen.&lt;/p>
&lt;p>The &lt;code>Boot&lt;/code> directory is a fallback option just in case those variables are not set, you could copy any &lt;code>.efi&lt;/code> file in other folder to &lt;code>bootx64.efi&lt;/code> to make it your fallback option.&lt;/p>
&lt;h1 id="refind" >rEFInd
&lt;span>
&lt;a href="#refind">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h1>&lt;p>rEFInd is a graphic bootloader that is smart enough to find the bootable entries without much configuration, it is also able to remember the last booted option to be selected on the next boot. It is also able to boot USB sticks and be bootable from any install media.&lt;/p>
&lt;h2 id="manual-install" >Manual install
&lt;span>
&lt;a href="#manual-install">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>Supposing you have an ESP partition in a GPT disk (If you are using Windows 10, you probably are) you just have to copy &lt;a href="https://sourceforge.net/projects/refind/files/0.11.4/refind-bin-0.11.4.zip/download">the refind folder&lt;/a> into the /EFI folder of the ESP (There are also OS-specific installers that do this)&lt;/p>
&lt;p>Once copied you have to tell your motherboard to boot from it by default.&lt;/p>
&lt;p>In Linux there is an utility that list the boot order called &lt;code>efibootmgr&lt;/code>&lt;/p>
&lt;pre tabindex="0">&lt;code>BootCurrent: 0002
Timeout: 1 seconds
BootOrder: 0002,0000,0006,0001,0003,0004
Boot0000* Windows Boot Manager
Boot0001* UEFI:CD/DVD Drive
Boot0002* rEFInd Boot Manager
Boot0003* UEFI:Removable Device
Boot0004* UEFI:Network Device
Boot0006* proxmox
&lt;/code>&lt;/pre>&lt;p>To add rEFInd:&lt;/p>
&lt;p>&lt;code>efibootmgr -c -l \\EFI\\refind\\refind_x64.efi -L rEFInd&lt;/code>&lt;/p>
&lt;p>To change the boot order:&lt;/p>
&lt;p>&lt;code>efibootmgr -o 0,1,2&lt;/code>&lt;/p>
&lt;p>To remove an entry:&lt;/p>
&lt;p>&lt;code>efibootmgr -Bb 0000&lt;/code>&lt;/p>
&lt;p>Refind has a &lt;code>refind.conf&lt;/code> and lots of themes to customize it.&lt;/p>
&lt;h2 id="adding-linux" >Adding Linux
&lt;span>
&lt;a href="#adding-linux">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>Windows is automatically detected by refind and some Linux distros too, but if you want to be sure add a &lt;code>refind_linux.conf&lt;/code> file into your Linux Partition in the &lt;code>/boot/&lt;/code> directory:&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;#34;Boot using default options&amp;#34; &amp;#34;root=PARTUUID=a9fbd673-2ba9-4dcd-be6b-97423dd74c89 rw initrd=/boot/amd-ucode.img initrd=/boot/initramfs-%v.img&amp;#34;
&lt;/code>&lt;/pre>&lt;p>the root points to the ID of the partition in which the distro is installed, it can be retrieved with &lt;code>blkid&lt;/code>.&lt;/p>
&lt;h2 id="extra-ubuntu-copying-kernels-to-esp" >Extra: Ubuntu: Copying kernels to ESP
&lt;span>
&lt;a href="#extra-ubuntu-copying-kernels-to-esp">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;pre tabindex="0">&lt;code>manu@x240:~$ cat /etc/kernel/postinst.d/zz-kernel-esp
#!/bin/bash
#
# This is a simple custom kernel hook to populate the systemd-boot entries
# whenever kernels are added or removed during an update.
#
vmlinuz=$(find /boot -maxdepth 1 -name &amp;#34;vmlinuz-*-generic&amp;#34;)
version=$(echo $vmlinuz | grep -o -P &amp;#34;\d+\.\d+\.\d+\-\d+&amp;#34; | sort -V | head -n -1)
latest=$(echo $vmlinuz | grep -o -P &amp;#34;\d+\.\d+\.\d+\-\d+&amp;#34; | sort -V | tail -n 1)
echo &amp;#34;&amp;gt;&amp;gt; COPYING ${latest}-generic. LATEST VERSION.&amp;#34;
for file in initrd.img vmlinuz; do
cp &amp;#34;/boot/${file}-${latest}-generic&amp;#34; &amp;#34;/boot/efi/EFI/ubuntu/${file}-generic&amp;#34;
done
&lt;/code>&lt;/pre></description></item><item><title>Building a router with a Raspberry Pi and OpenWRT</title><link>https://manueljimenezs.github.io/2019/07/building-a-router-with-a-raspberry-pi-and-openwrt/</link><pubDate>Sat, 06 Jul 2019 00:00:00 +0000</pubDate><guid>https://manueljimenezs.github.io/2019/07/building-a-router-with-a-raspberry-pi-and-openwrt/</guid><description>&lt;p>
&lt;img src="https://manueljimenezs.github.io/img/rpi-openwrt/pi-wrt.jpeg" alt="">
&lt;/p>
&lt;p>OpenWRT is a well known distribution among routers. It provides a wide variety of possibilities with the inclusion of a package manager &lt;code>opkg&lt;/code>. Here I&amp;rsquo;m going to be installing OpenWRT on a Raspberry Pi 3 B+ and creating a wireless access point with its own subnet that doesn&amp;rsquo;t have access to the rest of the network. This could be useful for isolating IoT devices or creating a &amp;lsquo;&amp;lsquo;guest&amp;rsquo;&amp;rsquo; network.&lt;/p>
&lt;p>The &lt;a href="https://openwrt.org/toh/raspberry_pi_foundation/raspberry_pi">OpenWRT Wiki&lt;/a> gives a bit of light on the installation of OpenWRT on the Pi. First of all I&amp;rsquo;m going to use the &lt;strong>snapshot&lt;/strong> build instead of the release located at &lt;a href="https://downloads.openwrt.org/snapshots/targets/brcm2708/bcm2710/">https://downloads.openwrt.org/snapshots/targets/brcm2708/bcm2710/&lt;/a>. If you use the release build the onboard wi-fi will not be detected.&lt;/p>
&lt;p>There are a few considerations before flashing the image that should be worth taking a look:&lt;/p>
&lt;ul>
&lt;li>The default IP for thr RPi will be &lt;code>192.168.1.1&lt;/code>, this will collide with your main router address so you have to temporarily change your router IP to something like &lt;code>192.168.1.3&lt;/code> and after having access to the raspberry pi changing it back.&lt;/li>
&lt;li>If using a Pi 3B+, your country has to be set with &lt;code>raspi-config&lt;/code> in a Raspbian environment for the onboard wireless to work.&lt;/li>
&lt;/ul>
&lt;p>Ok so we will be plugging the pi into an ethernet device like any other normal computer to give it access to the internet.&lt;/p>
&lt;p>Unzip and flash the &lt;code>rpi-3-ext4-factory.img.gz&lt;/code> image located in the previous link and turn on the pi.&lt;/p>
&lt;p>Run &lt;code>ssh root@192.168.1.1&lt;/code> and you will be presented with a shell prompt.&lt;/p>
&lt;h2 id="configure-the-internet-access" >Configure the internet access
&lt;span>
&lt;a href="#configure-the-internet-access">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>Do an &lt;code>ip addr&lt;/code> and look for the ethernet interface, in this case it will be &lt;code>eth0&lt;/code>.&lt;/p>
&lt;p>In OpenWRT the interfaces are configured in &lt;code>/etc/config/network&lt;/code> add or modify the lan entry in that file:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-config" data-lang="config">config interface &amp;#39;lan&amp;#39;
option type &amp;#39;bridge&amp;#39;
option proto &amp;#39;static&amp;#39;
option ipaddr &amp;#39;192.168.1.2&amp;#39;
option gateway &amp;#39;192.168.1.1&amp;#39;
option netmask &amp;#39;255.255.255.0&amp;#39;
option ip6assign &amp;#39;60&amp;#39;
option ifname &amp;#39;eth0&amp;#39;
&lt;/code>&lt;/pre>&lt;p>For updating the packages we will also need to configure the DNS servers so edit the &lt;code>/etc/config/dhcp&lt;/code> and add &lt;code>list server 1.1.1.1&lt;/code> or something similar to the &lt;code>config dnsmasq&lt;/code> entry.&lt;/p>
&lt;p>With that set you could do an &lt;code>/etc/init.d/network restart&lt;/code> to apply the changes.&lt;/p>
&lt;h3 id="installing-the-software-and-the-web-interface" >Installing the software and the web interface
&lt;span>
&lt;a href="#installing-the-software-and-the-web-interface">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h3>&lt;p>Run &lt;code>opkg update&lt;/code> and then run &lt;code>opkg install luci&lt;/code>. If you want to install packages from the interface also install &lt;code>luci-app-opkg&lt;/code>&lt;/p>
&lt;p>&lt;code>reboot&lt;/code> the device and access your Pi from a browser:&lt;/p>
&lt;p>
&lt;img src="https://manueljimenezs.github.io/img/rpi-openwrt/luci-first-boot.png" alt="">
&lt;/p>
&lt;h2 id="configuring-the-zones-and-creating-an-isolated-ap-for-guests" >Configuring the zones and creating an isolated AP for guests
&lt;span>
&lt;a href="#configuring-the-zones-and-creating-an-isolated-ap-for-guests">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>In the Web GUI, I configured a new interface called wifi and I linked it into the existing lan connection. Then you can specify different rules for restricting the access in that new network. My main router works in the &lt;code>192.168.1.0/24&lt;/code> range so the access point will have its own isolated network in the &lt;code>192.168.2.0/24&lt;/code> range. Here&amp;rsquo;s an &lt;code>/etc/config/network&lt;/code> example:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-config" data-lang="config">...
config interface &amp;#39;lan&amp;#39;
option type &amp;#39;bridge&amp;#39;
option proto &amp;#39;static&amp;#39;
option ipaddr &amp;#39;192.168.1.2&amp;#39;
option gateway &amp;#39;192.168.1.1&amp;#39;
option netmask &amp;#39;255.255.255.0&amp;#39;
option ip6assign &amp;#39;60&amp;#39;
option ifname &amp;#39;eth0&amp;#39;
config interface &amp;#39;wifi&amp;#39;
option proto &amp;#39;static&amp;#39;
option ipaddr &amp;#39;192.168.2.1&amp;#39;
option netmask &amp;#39;255.255.255.0&amp;#39;
&lt;/code>&lt;/pre>&lt;p>The zones are configured in &lt;code>/etc/config/firewall&lt;/code>&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-config" data-lang="config">...
config zone
option name &amp;#39;wifi&amp;#39;
option input &amp;#39;ACCEPT&amp;#39;
option output &amp;#39;ACCEPT&amp;#39;
option forward &amp;#39;ACCEPT&amp;#39;
option masq &amp;#39;1&amp;#39;
option network &amp;#39;lan wifi&amp;#39;
config forwarding
option dest &amp;#39;wan&amp;#39;
optioconfig interface &amp;#39;lan&amp;#39;
option type &amp;#39;bridge&amp;#39;
option proto &amp;#39;static&amp;#39;
option ipaddr &amp;#39;192.168.1.2&amp;#39;
option gateway &amp;#39;192.168.1.1&amp;#39;
option netmask &amp;#39;255.255.255.0&amp;#39;
option ip6assign &amp;#39;60&amp;#39;
option ifname &amp;#39;eth0&amp;#39;
config interface &amp;#39;wifi&amp;#39;
option proto &amp;#39;static&amp;#39;
option ipaddr &amp;#39;192.168.2.1&amp;#39;
option netmask &amp;#39;255.255.255.0&amp;#39;
n src &amp;#39;wifi&amp;#39;
config forwarding
option dest &amp;#39;wifi&amp;#39;
option src &amp;#39;wan&amp;#39;
config rule
option enabled &amp;#39;1&amp;#39;
option src &amp;#39;wifi&amp;#39;
option name &amp;#39;isolatewifi&amp;#39;
option proto &amp;#39;all&amp;#39;
option src_ip &amp;#39;192.168.2.0/24&amp;#39;
option dest_ip &amp;#39;192.168.1.0/24&amp;#39;
option target &amp;#39;DROP&amp;#39;
option dest &amp;#39;*&amp;#39;
&lt;/code>&lt;/pre>&lt;p>All of this can also be done in the web interface, but I put here the config files for clarity&amp;rsquo;s sake.&lt;/p></description></item><item><title>FFmpeg, the video Swiss Army Knife</title><link>https://manueljimenezs.github.io/2019/01/ffmpeg-the-video-swiss-army-knife/</link><pubDate>Thu, 24 Jan 2019 10:55:30 +0100</pubDate><guid>https://manueljimenezs.github.io/2019/01/ffmpeg-the-video-swiss-army-knife/</guid><description>&lt;p>You may have found yourself in a situation where you have to modify a video or extract its audio. Firing up a complete editor for such simple tasks could be a waste of energy and time.&lt;/p>
&lt;hr>
&lt;h1>Table Of Contents&lt;/h1>
&lt;div class="toc">
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>
&lt;ul>
&lt;li>&lt;a href="#change-the-aspect-ratio-of-a-video-without-re-encoding">Change the aspect ratio of a video without re-encoding&lt;/a>&lt;/li>
&lt;li>&lt;a href="#extracting-audio-from-a-file">Extracting audio from a file&lt;/a>&lt;/li>
&lt;li>&lt;a href="#cutting-a-video-file-without-reencoding">Cutting a video file without reencoding&lt;/a>&lt;/li>
&lt;li>&lt;a href="#converting-a-video-to-other-format">Converting a video to other format&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/div>
&lt;hr>
&lt;p>Here are some basic tips for FFmpeg that can sometimes make your workflow more efficient:&lt;/p>
&lt;h2 id="change-the-aspect-ratio-of-a-video-without-re-encoding" >Change the aspect ratio of a video without re-encoding
&lt;span>
&lt;a href="#change-the-aspect-ratio-of-a-video-without-re-encoding">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;p>This can be useful when the only thing we want to do is changing the proportions of a video without losing quality.&lt;/p>
&lt;p>For example for converting a 4:3 video to an stretched 16:9:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ffmpeg -i in.mp4 -aspect 16:9 -c copy out.mp4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>
&lt;img src="https://manueljimenezs.github.io/img/ffmpeg_aspect.png" alt="4:3 to 16:9">
&lt;/p>
&lt;p>The &lt;code>-c copy&lt;/code> option allows setting up the codec to a copy mode where ffmpeg doesn&amp;rsquo;t reencode the video and the results are done immediately.&lt;/p>
&lt;h2 id="extracting-audio-from-a-file" >Extracting audio from a file
&lt;span>
&lt;a href="#extracting-audio-from-a-file">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ffmpeg -i in.mp4 out.mp3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Note:&lt;/strong> the extensions shown here are completely arbitrary, ffmpeg supports a wide variety of codecs and formats which can be seen with the commands &lt;code>ffmpeg -codecs&lt;/code> and &lt;code>ffmpeg -formats&lt;/code>&lt;/p>
&lt;h2 id="cutting-a-video-file-without-reencoding" >Cutting a video file without reencoding
&lt;span>
&lt;a href="#cutting-a-video-file-without-reencoding">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ffmpeg -i in.mp4 -ss 00:00:25.0 -codec copy -t &lt;span class="m">30&lt;/span> out.mp4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>In this case the cut starts on second 25 and the video lasts 30 seconds&lt;/em>&lt;/p>
&lt;h2 id="converting-a-video-to-other-format" >Converting a video to other format
&lt;span>
&lt;a href="#converting-a-video-to-other-format">
&lt;svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg">&lt;path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/>&lt;/svg>
&lt;/a>
&lt;/span>
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ffmpeg -i in.ogv -c:v libx264 out.mp4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>-c:v libx264&lt;/code> sets the video codec&lt;/li>
&lt;li>&lt;code>-c:a vorbis&lt;/code> sets the audio codec&lt;/li>
&lt;li>&lt;code>-r 25&lt;/code> sets the framerate to 25fps&lt;/li>
&lt;li>&lt;code>-s &amp;lt;1280x720|hd720&amp;gt;&lt;/code> sets the video resolution to 720p&lt;/li>
&lt;li>&lt;code>-b:v 1M&lt;/code> sets the &lt;em>video&lt;/em> bitrate to 1MB/s&lt;/li>
&lt;/ul></description></item><item><title>Vertically split double PDF pages</title><link>https://manueljimenezs.github.io/2019/01/vertically-split-double-pdf-pages/</link><pubDate>Wed, 16 Jan 2019 20:39:54 +0100</pubDate><guid>https://manueljimenezs.github.io/2019/01/vertically-split-double-pdf-pages/</guid><description>&lt;p>Some people like to distribute their slides in a printing format, making reading and skipping pages really difficult.&lt;/p>
&lt;p>&lt;code>mupdf&lt;/code>, among other options, has a CLI utility to overcome this and have as a result one slide per page.&lt;/p>
&lt;pre tabindex="0">&lt;code>mutool poster -y 2 in.pdf out.pdf
&lt;/code>&lt;/pre></description></item></channel></rss>