File: sample_rss.py

package info (click to toggle)
gnome-feeds 2.2.0-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,524 kB
  • sloc: python: 5,369; sh: 93; xml: 28; makefile: 2
file content (107 lines) | stat: -rw-r--r-- 28,679 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
SAMPLE_RSS = '''
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet href="/feed_style.xsl" type="text/xsl"?>
<rss version="2.0"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:media="https://www.rssboard.org/media-rss">
    <channel>
        <title>GabMus&#39;s Dev Log</title>
        <link>https://gabmus.org/</link>
        <description>Recent content on GabMus&#39;s Dev Log</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <copyright>Gabriele Musco - [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).</copyright>
        <lastBuildDate>Mon, 14 Feb 2022 11:31:20 +0100</lastBuildDate>
        <atom:link href="https://gabmus.org/index.xml" rel="self" type="application/rss+xml" />
        <icon>https://gabmus.org/logo.svg</icon>
        <item>
            <title>Swatch: a color palette manager</title>
            <link>https://gabmus.org/posts/swatch_a_color_palette_manager/</link>
            <pubDate>Mon, 14 Feb 2022 11:31:20 +0100</pubDate>
            <guid>https://gabmus.org/posts/swatch_a_color_palette_manager/</guid>
            <description>
                <![CDATA[<p>Between one thing and the other, I found myself in need for a palette manager: something to let me categorize different palettes and easily pick and name colors depending on their use.</p><p>I had a look at some already available options, but nothing seemed to fit the bill, so (as it&rsquo;s often the case) I decided to make my own.</p><hr><p>I want to make a quick tangent on how easy it has become for me to quickly <del>hack together</del> build a GTK app.</p><p>A big part of the reason is reusing existing code and tooling from my other projects, as well as learning the proper way to do things.</p><p>Another big reason is the great ecosystem that&rsquo;s been growing around GNOME technologies recently, particularly after the release of GTK4.</p><p>First of all, libadwaita is a huge help for building any kind of application. It ships a bunch of widgets and other useful tidbits such as pre-built style classes, implementing the rules defined in the GNOME HIG. This allows for quick building, clean code and great looks out of the box.</p><p>But libadwaita has already been praised enough by me and other developers, so that&rsquo;s not really anything new.</p><p>The other incredibly useful tool that I&rsquo;m using for my apps is <a href="https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/">Blueprint</a> by <a href="https://www.jwestman.net/">James Westman</a>. Without going into too much detail, it&rsquo;s a markup language for building GTK4 UIs in a clean and simple way. You then use the blueprint compiler to compile it to regular XML without ever having to look at it yourself.</p><hr><p>Going back to Swatch, it&rsquo;s really as simple as it gets: you can create as many palettes as you want, and you can add colors to each palette. You can give custom names to everything, and you can quickly copy the color in hexadecimal (or <code>rgb()</code>) format. I also decided to give Swatch two view modes: list and grid, similar to what you&rsquo;d see in a file manager.</p><p><img src="/images/post_pics/Swatch_a_color_palette_manager/scrot1.png" alt=""></p><p>And with that said, this little tool does exactly what I need. Hopefully you can find it useful as well.</p><p><a href="https://gitlab.gnome.org/gabmus/swatch">The code is available on GNOME GitLab</a> as usual, and you can try it for yourself using the latest flatpak CI build.</p><p>As for a proper release, I&rsquo;m planning to tag one and submit it to Flathub as soon as the GNOME 42 runtime comes out, so stay tuned for that!</p>
]]>
            </description>
            <media:thumbnail url="https://gabmus.org/images/post_pics/Swatch_a_color_palette_manager/scrot0.png" />
        </item>
        <item>
            <title>Block ads in WebKitGtk</title>
            <link>https://gabmus.org/posts/block_ads_in_webkitgtk/</link>
            <pubDate>Sat, 27 Nov 2021 19:08:53 +0100</pubDate>
            <guid>https://gabmus.org/posts/block_ads_in_webkitgtk/</guid>
            <description>
                <![CDATA[<p>One of the most requested features (and for a good reason) in Feeds has always been ad blocking.</p><p>I never came around to implement it, mostly because I couldn&rsquo;t find a guide or any similar resource, except for <a href="https://gitlab.gnome.org/GNOME/Epiphany">GNOME Web&rsquo;s source code</a>, and that&rsquo;s not exactly easy to navigate. At least, it isn&rsquo;t for me.</p><p>Today I decided to come back to it, and I found that it&rsquo;s actually a rather easy task! That&rsquo;s why I wanted to document this process, in hope that someone might find it useful one day.</p><p>First off, you&rsquo;ll need one or more <strong>blocklists</strong>, in JSON format. I used <a href="https://easylist.to/">EasyList</a>, in particular <a href="https://easylist-downloads.adblockplus.org/easylist_min_content_blocker.json">here&rsquo;s the link to the JSON block list</a>. Blocklists should be updated frequently, so it&rsquo;s advisable to have some sort of mechanism to download and update them at runtime automatically.</p><p>Let&rsquo;s now jump to the code, which will be Python in this case, but hopefully can be easily adapted to other languages.</p><p>I&rsquo;ll use some closures for convenience.</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python3" data-lang="python3"><span style="display:flex;"><span><span style="color:#6272a4"># have a function that downloads text</span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">def</span><span style="color:#50fa7b">download_text</span>(url: <span style="color:#8be9fd;font-style:italic">str</span>) <span style="color:#ff79c6">-&gt;</span><span style="color:#8be9fd;font-style:italic">str</span>:
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># ...</span></span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#6272a4"># create the filter store somewhere in your code, ideally you should</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"># only have one in your application</span></span></span><span style="display:flex;"><span>my_filter_store <span style="color:#ff79c6">=</span> WebKit2<span style="color:#ff79c6">.</span>UserContentFilterStore<span style="color:#ff79c6">.</span>new(<span style="color:#f1fa8c">&#39;some/cache/path&#39;</span>)
</span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#6272a4"># a name that will be used to save/retrieve blocklists from the store</span></span></span><span style="display:flex;"><span>BLOCKLIST_ID <span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#39;blocklist&#39;</span></span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">def</span><span style="color:#50fa7b">apply_adblock</span>(
</span></span><span style="display:flex;"><span>        webview: WebKit2<span style="color:#ff79c6">.</span>WebView,
</span></span><span style="display:flex;"><span>        filter_store: WebKit2<span style="color:#ff79c6">.</span>UserContentFilterStore,
</span></span><span style="display:flex;"><span>        blocklist_url: <span style="color:#8be9fd;font-style:italic">str</span></span></span><span style="display:flex;"><span>) <span style="color:#ff79c6">-&gt;</span><span style="color:#ff79c6">None</span>:
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 0: Retrieve the WebKit2.UserContentManager from the WebView</span></span></span><span style="display:flex;"><span>    content_manager <span style="color:#ff79c6">=</span> webview<span style="color:#ff79c6">.</span>get_user_content_manager()
</span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">def</span><span style="color:#50fa7b">save_blocklist_cb</span>(caller, res, <span style="color:#ff79c6">*</span>args):
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 6: Once saving is done we can retrieve the newly created</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    WebKit2.UserContentFilter with save_finish and finally add th</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    filter to the WebKit2.UserContentManager</span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">try</span>:
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">filter</span><span style="color:#ff79c6">=</span> filter_store<span style="color:#ff79c6">.</span>save_finish(res)
</span></span><span style="display:flex;"><span>            content_manager<span style="color:#ff79c6">.</span>add_filter(<span style="color:#8be9fd;font-style:italic">filter</span>)
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">except</span> GLib<span style="color:#ff79c6">.</span>Error:
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">print</span>(<span style="color:#f1fa8c">&#39;Error saving blocklist&#39;</span>)
</span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">def</span><span style="color:#50fa7b">download_blocklist_cb</span>(blocklist: <span style="color:#8be9fd;font-style:italic">str</span>):
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 5: Now that we have the blocklist (as a string containing a json),</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    we&#39;ll need to convert it to GLib.Bytes, then save it in the store.</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    Yes, we need to save it even if we want to refresh it every time,</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    this is just the way this works.</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    This is also async and when it&#39;s done it will call continue on to</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    save_blocklist_cb</span></span></span><span style="display:flex;"><span>        filter_store<span style="color:#ff79c6">.</span>save(
</span></span><span style="display:flex;"><span>            BLOCKLIST_ID, GLib<span style="color:#ff79c6">.</span>Bytes<span style="color:#ff79c6">.</span>new(blocklist<span style="color:#ff79c6">.</span>encode()), <span style="color:#ff79c6">None</span>,
</span></span><span style="display:flex;"><span>            save_blocklist_cb
</span></span><span style="display:flex;"><span>        )
</span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">def</span><span style="color:#50fa7b">download_blocklist</span>():
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 4: Download the blocklist and continue on to download_blocklist_cb</span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">try</span>:
</span></span><span style="display:flex;"><span>            res <span style="color:#ff79c6">=</span> download_text(blocklist_url)
</span></span><span style="display:flex;"><span>            GLib<span style="color:#ff79c6">.</span>idle_add(download_blocklist_cb, res)
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">except</span>:
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">print</span>(<span style="color:#f1fa8c">&#39;Error downloading the blocklist&#39;</span>)
</span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">def</span><span style="color:#50fa7b">filter_load_cb</span>(caller, res, <span style="color:#ff79c6">*</span>args):
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 2: load_finish will either succeed, and return a</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    WebKit2.UserContentFilter object or raise a GLib.Error in case</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    it cannot find the blocklist in the store (ie: on the first run)</span></span></span><span style="display:flex;"><span><span style="color:#ff79c6">try</span>:
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">filter</span><span style="color:#ff79c6">=</span> filter_store<span style="color:#ff79c6">.</span>load_finish(res)
</span></span><span style="display:flex;"><span>            content_manager<span style="color:#ff79c6">.</span>add_filter(<span style="color:#8be9fd;font-style:italic">filter</span>)
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">except</span> GLib<span style="color:#ff79c6">.</span>Error:
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 3: If loading the blocklist from the store fails, download the</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    blocklist (async to avoid blocking of course) and save it</span></span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">print</span>(<span style="color:#f1fa8c">&#39;blocklist store not found, downloading...&#39;</span>)
</span></span><span style="display:flex;"><span>            Thread(target<span style="color:#ff79c6">=</span>download_blocklist, daemon<span style="color:#ff79c6">=</span><span style="color:#ff79c6">True</span>)<span style="color:#ff79c6">.</span>start()
</span></span><span style="display:flex;"><span></span></span><span style="display:flex;"><span><span style="color:#6272a4"># 1: try to load the blocklist from the store, this is async and will call</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">#    filter_load_cb when it&#39;s done</span></span></span><span style="display:flex;"><span>    filter_store<span style="color:#ff79c6">.</span>load(BLOCKLIST_ID, <span style="color:#ff79c6">None</span>, filter_load_cb, <span style="color:#ff79c6">None</span>)
</span></span></code></pre></div><p>I decided to comment the example code above instead of writing disconnected descriptions here, hopefully it makes sense.</p><p>This said, if you want to look at the actual code that I&rsquo;m using in Feeds, <a href="https://gitlab.gnome.org/World/gfeeds/-/blob/0a3d3da66d7d4ede155db24fb0f83f03b47f5489/gfeeds/webview.py#L78">you can find it here</a> (this is a snapshot to today&rsquo;s current latest commit, in the future you may want to look at newer code). It contains some logic to automatically refresh or even remove the blocklist.</p><p>Let me know what you think in the comments, and feel free to point out any errors, or if something is unclear.</p>
]]>
            </description>
            <media:thumbnail url="https://gabmus.org/images/post_pics/Block_ads_in_WebKitGtk/block_ads_webkit.avif" />
        </item>
        <item>
            <title>Gtk4, LibAdwaita and the new Feeds</title>
            <link>https://gabmus.org/posts/gtk4_libadwaita_and_the_new_feeds/</link>
            <pubDate>Sun, 21 Nov 2021 11:52:10 +0100</pubDate>
            <guid>https://gabmus.org/posts/gtk4_libadwaita_and_the_new_feeds/</guid>
            <description>
                <![CDATA[<p>So, something big is coming for my news reader app <a href="https://gfeeds.gabmus.org">Feeds</a>.</p><p>Most of this year, as far as personal projects go, I spent at close contact with Gtk4, <a href="https://gitlab.gnome.org/gnome/libadwaita">libadwaita</a> and the awesome people over at the various matrix chat rooms.</p><p>I&rsquo;ve spent this time porting <a href="https://whatip.gabmus.org">What IP</a>, <a href="https://hydrapaper.gabmus.org">HydraPaper</a> and <a href="https://giara.gabmus.org">Giara</a> to Gtk4+libadwaita.</p><p><img src="/images/post_pics/Gtk4_LibAdwaita_and_the_new_Feeds/whatip_hydrapaper_giara.avif" alt="What IP, HydraPaper and Giara at their latest iteration, side by side"></p><p>I&rsquo;m really happy of the results, and I&rsquo;m even happier with how this new stack is shaping up.</p><p>The porting process for the most part has been relatively painless across the board, with only minor changes (albeit, many of them) needed for the actual porting. Along with the updated stack, I&rsquo;ve been able to introduce new features and improvements, for the most part thanks to the new widgets available in libadwaita making my life a lot easier.</p><p>What IP being the simpler of the bunch didn&rsquo;t really change much from its original iteration, except for some code cleanups. But hey, the theme is different and it looks amazing!</p><p>HydraPaper also stayed pretty much the same, with the exception of a new wallpaper folder selector (that you can see in the image above) in the form of a brand new widget, the mighty Flap! It&rsquo;s a sidebar that can open above other widgets, mostly a glorified overlay, but with extra bells and whistles. On a regular monitor you can open it with the usual button on the headerbar, the same that opened a Popover before, but on a touchscreen you can swipe to open it! Plus, compared to the previous Popover implementation, the new Flap is part of the main window, meaning it can scale to fill the entire vertical space of the window, making this selector/filter much easier to interact with thanks to the increased size.</p><p>Giara being one of the more complex apps, received a lot more work and attention. First off, the post views have been re-implemented using ListView, a brand new (still somewhat janky) widget in Gtk4 that allows for better optimized lists, where rows get recycled instead of adding up, with performance quickly grinding to a halt. This change required a lot of work, since my usual terrible implementation of ListBox is 100% incompatible with the way ListView works. But with a lot of help and elbow grease, I managed to land it, making the whole experience of mindlessly scrolling through reddit a little less frustrating (hopefully). Also, thanks to another awesome widget, AdwCarousel, I was able to add support for image galleries. And they support touch gestures, too! Along with these changes, I also added an internal fullscreen image viewer, very much inspired by the one in telegram-desktop.</p><hr><p>But let&rsquo;s jump to the actual reason why I&rsquo;m writing this post, <em>The new Feeds</em>.</p><p><img src="/images/post_pics/Gtk4_LibAdwaita_and_the_new_Feeds/feeds.avif" alt="What the new Feeds will look like"></p><p>You see, I wanted to start porting Feeds to Gtk4 sooner than it ended up happening. Unfortunately, I wasn&rsquo;t able to up until recently. The reason being WebKit. WebKit support for Gtk4 has been broken for a while, and just recently (not all that recently, tho) it got to a point where it was usable enough for me to start the port. At the time of writing this, you still need to enable Gtk4 support in WebKit by using custom build flags, making development possible by building WebKit myself (which, by the way, takes <em>a lot</em> of time), but at the same time making distribution unfeasible. Flatpak being the main way I distribute my apps, it could work in theory, but having a 1GB+ bundle for a simple news reader isn&rsquo;t really a great user experience, so for now I&rsquo;m holding off this release, waiting for it to become available in the GNOME runtime.</p><p>But let&rsquo;s move on to what&rsquo;s actually new in Feeds.</p><p>First of all, from a user facing perspective, The whole look of the app is quite different. Apart from the new Adwaita theme in libadwaita, the article list uses the new <code>navigation-sidebar</code> style class, with cool rounded corners for the rows and no separators between them, but still providing enough visual separation. Label sizes in the rows have also been tweaked slightly.</p><p>Oh, and of course, I added article pictures! The code is based on the custom picture widget I made for Giara, and let me tell you: they make any article that more interesting!</p><p>As for visual changes, another big one is the new filter view, again based on the Flap widget.</p><p><img src="/images/post_pics/Gtk4_LibAdwaita_and_the_new_Feeds/feeds_filters.avif" alt=""></p><p>It&rsquo;s a similar story to HydraPaper, the old Popover implementation was hard to use and unintuitive. A sidebar is a much more common pattern, plus the added vertical size makes it easier to find the feed you wanna look at.</p><p>As for the articles list, you may think ListView would be perfect here as well, and that&rsquo;s what I thought as well. Unfortunately due to some technical issues with how ListView row selection and activation work at this current time, while it does work, it&rsquo;s not really all that convenient. I added the ListView to Feeds, and you can enable it in the preferences, in the advanced section, but I kept the ListBox around as a default, and I also changed its API so that it&rsquo;s the same as the ListView implementation. You can switch between one or the other and try them out for yourself, hopefully at some point I can get rid of the ListBox and have the ListView be the default.</p><p>With all the nice changes and cool things this port brought with it, I decided to tackle one of the most annoying issues I&rsquo;ve had with Feeds: the actual feed parsing.</p><p>Up until recently I&rsquo;ve been using the very popular <a href="https://github.com/kurtmckee/feedparser/">feedparser</a> python library, but I&rsquo;ve always been dissatisfied with both its performance and its weird quirks. I came to the conclusion that it&rsquo;s not the kind of library I was looking for.</p><p>I tried searching for alternatives, and I broadened my search to any language, but unfortunately I couldn&rsquo;t find something I really liked.</p><p>So I decided to write my own! And for the best performance I wrote it in&hellip; C++! Maybe some of you were expecting Rust? Maybe one day, but I don&rsquo;t really know Rust right now 😕</p><p>This new library is called <a href="https://gitlab.com/gabmus/syndication-domination">Sydndication Domination</a> or syndom for short (it&rsquo;s a bit cheesy, I know). Syndom is tailor made for Feeds, but of course it can be used for any application.</p><p>It&rsquo;s based around an awesome XML parser for C++ called <a href="https://pugixml.org/">pugixml</a>, if you ever need to parse XML I suggest you take a look at it. Syndom is able to parse an RSS or Atom file and extract all the useful information a news reader would need, and most importantly, <em>it</em> does the heavy lifting of trying all the different places a certain information can be found in. It can also parse Opml files for importing feeds, as well as Html files for extracting other useful information from, say a blog post, like the featured image, the feed URL, the title or the description.</p><p>The whole thing comes together inside Feeds with python bindings, created using another library called <a href="https://github.com/pybind/pybind11/">pybind11</a>.</p><p>Honestly this has probably been the biggest change to ever come to Feeds. The performance difference is enormous, it&rsquo;s like night and day, and I couldn&rsquo;t be happier about it.</p><p>So that&rsquo;s all I wanted you to know, hopefully I can release Feeds sooner rather than later as I really, <em>really</em> want people to use this new version rather than the crusty old one.</p><p>If you want to try it for yourself <a href="https://cloud.disroot.org/s/2Dj94NxWn6HRAZC">you can download a recent snapshot I made manually from this link</a>. Please do let me know what you think in the comments or <a href="https://matrix.to/#/#org.gabmus:matrix.org">in the matrix room</a> if you prefer. And feel free to report any bugs you encounter along the way!</p>
]]>
            </description>
            <media:thumbnail url="https://gabmus.org/images/post_pics/Gtk4_LibAdwaita_and_the_new_Feeds/feeds.avif" />
        </item>
        <item>
            <title>Switching to Cactus Comments</title>
            <link>https://gabmus.org/posts/switching_to_cactus_comments/</link>
            <pubDate>Wed, 16 Jun 2021 10:24:30 +0200</pubDate>
            <guid>https://gabmus.org/posts/switching_to_cactus_comments/</guid>
            <description>
                <![CDATA[<p>I&rsquo;ve been using Commento for a while for comments (without much adoption to be honest), and while I really love the project, and the simplicity of its approach, there&rsquo;s always been one unavoidable thing I never really liked too much: if you want to comment, you have to register to my commento instance.</p><p>That&rsquo;s less than ideal, considering that if I did have lots of people who wanted to comment, that&rsquo;d have been quite a strain on my humble home server, where my commento instance is hosted.</p><p>Today I found <a href="https://karmanyaah.malhotra.cc/tech/2021/06/website-things/">this post</a> on Mastodon (feel free to <a href="https://linuxrocks.online/@gabmus">follow me there</a> by the way) by Karmanyaah Malhotra about how he reworked his website recently. I always enjoy reading about other people&rsquo;s websites, so I quickly read through it, just to find out about this comment system called <a href="https://cactus.chat">Cactus Comments</a>.</p><p>Cactus Comments uses <a href="https://matrix.org/">Matrix</a> to create a federated comment section on your website. If you have a Matrix account on any instance, you can comment on Cactus! Heck you can even use a full-fledged Matrix client to do so! That&rsquo;s just great.</p><p>It&rsquo;s free to use and self hostable as well, so there&rsquo;s really not much of an excuse not to try it out. Plus if you already have a Matrix account you&rsquo;re already halfway there.</p><p>I integrated it in my <a href="https://gitlab.com/gabmus/hugo-ficurinia">Ficurinia Hugo theme</a> without much effort, so there&rsquo;s another bonus point.</p><p>And that&rsquo;s it, I&rsquo;m really happy about this new comment system, it&rsquo;s one less service running on my home server and due to its decentralized and federated nature it will hopefully encourage more people to leave interesting comments and get a conversation going!</p>
]]>
            </description>
            <media:thumbnail url="https://gabmus.org/images/post_pics/Switching_to_Cactus_Comments/cactus.avif" />
        </item>
        <item>
            <title>Raspberry Pi Pico pinout in your terminal</title>
            <link>https://gabmus.org/posts/raspberry_pi_pico_pinout_in_your_terminal/</link>
            <pubDate>Tue, 09 Mar 2021 13:14:27 +0100</pubDate>
            <guid>https://gabmus.org/posts/raspberry_pi_pico_pinout_in_your_terminal/</guid>
            <description>
                <![CDATA[<p>I&rsquo;m playing around with the new <a href="https://www.raspberrypi.org/products/raspberry-pi-pico">Raspberry Pi Pico</a>, and I quickly realized that I&rsquo;d really love to have a quick pinout reference in my terminal.</p><p>I thought of making a man page, but I would have lost the color (I don&rsquo;t know how to use arbitrary colors in groff), so I just created a simple text file with ascii escape sequences for colors and called it a day. It works, and it&rsquo;s pretty!</p><p>I&rsquo;m uploading it here for your convenience (and mine as well), you should be able to grab it from your *NIX box by just typing:</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>curl https://gabmus.org/pico_pinout
</span></span></code></pre></div><p>If you want to save it in a file, just add <code>&gt; some_file_name</code> to the above.</p>
]]>
            </description>
            <media:thumbnail url="https://gabmus.org/images/post_pics/Raspberry_Pi_Pico_pinout_in_your_terminal/screenshot.avif" />
        </item>
    </channel>
</rss>
'''