<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Elfeed on Noetic Nought</title>
    <link>https://punchagan.muse-amuse.in/tags/elfeed/</link>
    <description>Recent content in Elfeed on Noetic Nought</description>
    <generator>Hugo</generator>
    <language>en-US</language>
    <copyright>© 2006-2026 CC-BY-SA-4.0</copyright>
    <lastBuildDate>Fri, 30 Jan 2026 16:58:00 +0530</lastBuildDate>
    <atom:link href="https://punchagan.muse-amuse.in/tags/elfeed/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Why my Elfeed index was 0 bytes</title>
      <link>https://punchagan.muse-amuse.in/blog/elfeed-index-0-bytes/</link>
      <pubDate>Fri, 30 Jan 2026 16:58:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/elfeed-index-0-bytes/</guid>
      <description>&lt;p&gt;My Linux machine crashed, while I was in the middle of a video call. I&#xA;restarted quickly, and continued the discussion. Later, when I was trying to&#xA;sync &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;Elfeed&lt;/a&gt; updates onto the &lt;a href=&#34;https://github.com/punchagan/elfeed-offline/&#34;&gt;Elfeed Offline&lt;/a&gt; app on my phone, I found it acting&#xA;weird. All the &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/offline-friendly-elfeed-web-ui/&#34;&gt;bazillion things&lt;/a&gt; needed to get it working were in place, but it&#xA;was still complaining about the Emacs Elfeed server not being accessible. I&#xA;tried opening Elfeed inside Emacs and failed! The index file in &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/elfeed-db-back-up-hooks/&#34;&gt;Elfeed&amp;rsquo;s DB was&#xA;empty&lt;/a&gt;! Gone! Poof!&lt;/p&gt;&#xA;&lt;p&gt;Frustrating, but I didn&amp;rsquo;t have time to look into what happened. I would&amp;rsquo;ve been&#xA;furious if I had been using Elfeed for longer and had a lot more metadata&#xA;saved. But, it was only a few weeks of lost metadata - posts I read, starred,&#xA;etc. I quickly setup a &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/elfeed-db-back-up-hooks/&#34;&gt;Git based backup&lt;/a&gt; to prevent future losses and moved on.&lt;/p&gt;&#xA;&lt;p&gt;Later, I found time to dig into what might have happened&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-breadcrumbs&#34;&gt;The breadcrumbs&lt;/h2&gt;&#xA;&lt;p&gt;Elfeed stores all the metadata for all the posts in an &lt;code&gt;index&lt;/code&gt; file with a&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Content-addressable_storage&#34;&gt;content addressed store&lt;/a&gt; of the contents of each of the posts. The index file is&#xA;simply a dump of the hash-table containing the metadata for the subscribed&#xA;feeds, their entries and metadata like tags, read/unread status, etc.&lt;/p&gt;&#xA;&lt;p&gt;The DB save happens in &lt;a href=&#34;https://github.com/skeeto/elfeed/blob/a39fb78e34ee25dc8baea83376f929d7c128344f/elfeed-db.el#L271&#34;&gt;&lt;code&gt;elfeed-db-save&lt;/code&gt;&lt;/a&gt;, which simply dumps the hash-table to&#xA;disk inside a call to the &lt;code&gt;with-temp-file&lt;/code&gt; macro.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elfeed-db-save&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; &amp;lt;snip&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;with-temp-file&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;expand-file-name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elfeed-db-directory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; ...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;princ&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;;;; Elfeed Database Index (version %s)\n\n&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       &lt;span class=&#34;nv&#34;&gt;elfeed-db-version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; ...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;prin1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elfeed-db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;with-temp-file&lt;/code&gt;, as its documentation says, lets you create a new buffer,&#xA;evaluate the &lt;code&gt;body&lt;/code&gt; there, and write the buffer to &lt;code&gt;file&lt;/code&gt;. For a moment, I&#xA;thought there was some temporary file involved, but nope! I guess the name&#xA;comes as an extension from &lt;code&gt;with-temp-buffer&lt;/code&gt; which does create a temporary&#xA;buffer where the &lt;code&gt;body&lt;/code&gt; of the macro gets evaluated. Stripped to its core, &lt;a href=&#34;https://github.com/emacs-mirror/emacs/blob/3b547e4f5dc99dc157b52a059cf234f7a5d15112/lisp/subr.el#L5300-L5318&#34;&gt;this&#xA;function&lt;/a&gt; is:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;temp-file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;temp-buffer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;generate-new-buffer&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; *temp file*&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;prog1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;temp-buffer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;,@&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;temp-buffer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;write-region&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;temp-file&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;write-region-and-o-trunc&#34;&gt;&lt;code&gt;write-region&lt;/code&gt; and &lt;code&gt;O_TRUNC&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;So, &lt;a href=&#34;https://github.com/emacs-mirror/emacs/blob/3b547e4f5dc99dc157b52a059cf234f7a5d15112/src/fileio.c#L5512&#34;&gt;&lt;code&gt;write-region&lt;/code&gt; is the workhorse&lt;/a&gt; which writes the contents of the temporary&#xA;buffer to disk. It&amp;rsquo;s a roughly 300 line long C function that essentially opens&#xA;the file with the flags &lt;code&gt;O_WRONLY | O_CREAT | O_TRUNC&lt;/code&gt; (in this case) and then&#xA;does something to write the contents to the file, etc. Honestly, I didn&amp;rsquo;t look&#xA;at anything else too carefully after I spotted the &lt;code&gt;O_TRUNC&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The man page of &lt;code&gt;open&lt;/code&gt; explains &lt;code&gt;O_TRUNC&lt;/code&gt; as follows:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;O_TRUNC :: If the file already exists and is a regular file and the access mode&#xA;allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to&#xA;length 0.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Voilà!&lt;/p&gt;&#xA;&lt;p&gt;The write is not atomic. The file first gets truncated to length 0, and then we&#xA;hope that the new contents get correctly written before something goes wrong.&lt;/p&gt;&#xA;&lt;p&gt;It now makes sense why the file got truncated to 0 bytes. The crash happened&#xA;after the &lt;code&gt;open&lt;/code&gt;, but before the write. Somehow the crash happened in this&#xA;short window, and poof!&lt;/p&gt;&#xA;&lt;h2 id=&#34;emacs-has-backup-files-doesn-t-it&#34;&gt;Emacs has backup files, doesn&amp;rsquo;t it?&lt;/h2&gt;&#xA;&lt;p&gt;Temporary files with &lt;code&gt;~&lt;/code&gt; in their file extensions have definitely annoyed me in&#xA;the past when Emacs created them where I didn&amp;rsquo;t want them. So, I do know that&#xA;Emacs has back-up mechanisms out of the box. But, it turns out that the backups&#xA;occur in code paths that are more interactive, like &lt;code&gt;save-buffer&lt;/code&gt;,&#xA;&lt;code&gt;write-file&lt;/code&gt;, etc. And not via the programmatic APIs like &lt;code&gt;write-region&lt;/code&gt; or the&#xA;higher level &lt;code&gt;with-temp-file&lt;/code&gt;. &lt;code&gt;save-buffer&lt;/code&gt; calls &lt;code&gt;backup-buffer&lt;/code&gt; before&#xA;writing, but &lt;code&gt;write-region&lt;/code&gt; is much more low-level and doesn&amp;rsquo;t deal with&#xA;backups.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-fix&#34;&gt;The fix&lt;/h2&gt;&#xA;&lt;p&gt;My &amp;ldquo;fix&amp;rdquo; for this is to backup the Elfeed data in a git repository to be able&#xA;to recover from any such corruptions of data, which I already wrote about &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/elfeed-db-back-up-hooks/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I know that any code that uses &lt;code&gt;with-temp-file&lt;/code&gt; (or &lt;code&gt;write-region&lt;/code&gt;) could be&#xA;affected by this, and the right fix for this may be to write to a temporary&#xA;file and rename it. Maybe next time I lose data I&amp;rsquo;ll actually fix it properly.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Elfeed DB backup hooks</title>
      <link>https://punchagan.muse-amuse.in/blog/elfeed-db-back-up-hooks/</link>
      <pubDate>Tue, 20 Jan 2026 23:13:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/elfeed-db-back-up-hooks/</guid>
      <description>&lt;p&gt;I had a bunch of things running on my laptop &amp;ndash; video call with screenshare, my&#xA;Windows VM, Firefox with a lot of tabs, etc. And my laptop crashed! I didn&amp;rsquo;t&#xA;have the time to dig into what, why and how.&lt;/p&gt;&#xA;&lt;p&gt;Later in the day, I discovered my Elfeed&amp;rsquo;s DB was gone &amp;ndash; blown away. :( I&amp;rsquo;m&#xA;guessing the crash happened in the middle of &lt;code&gt;elfeed-db-save&lt;/code&gt;, and the data was&#xA;lost.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve now added some back-up for the DB, since I intend to use Elfeed regularly.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defvar&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-timer&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Timer for debounced elfeed database saves.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-and-backup&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Save the elfeed database and commit to git.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;boundp&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;elfeed-db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elfeed-db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-db-save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;default-directory&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elfeed-db-directory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;file-exists-p&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;.git&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;call-process&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;*elfeed-db-backup*&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;add&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;-A&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;call-process&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;*elfeed-db-backup*&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;commit&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;-m&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;auto-backup&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;call-process&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;*elfeed-db-backup*&amp;#34;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;push&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;origin&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-soon&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Schedule a database save after 10 seconds of idle.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;interactive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-timer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cancel-timer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;setq&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-timer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;run-with-idle-timer&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-and-backup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;; Save and backup when tags change (elfeed-web usage)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-hook&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;elfeed-tag-hooks&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kp&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-soon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-hook&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;elfeed-untag-hooks&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kp&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-soon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;; Save and backup when new entries are added&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-hook&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;elfeed-db-update-hook&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/elfeed-db-save-soon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>An offline-friendly Elfeed web UI</title>
      <link>https://punchagan.muse-amuse.in/blog/offline-friendly-elfeed-web-ui/</link>
      <pubDate>Wed, 07 Jan 2026 02:31:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/offline-friendly-elfeed-web-ui/</guid>
      <description>&lt;p&gt;I want to read articles from my RSS subscriptions on my phone without signing&#xA;up to a hosted service or running a public server.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;Elfeed&lt;/a&gt;, the Emacs feed reader, already lets me manage my subscriptions and read&#xA;from within Emacs. It comes with an experimental web UI, but needs the server&#xA;(running on my laptop) to be accessible whenever I want to read. My phone&#xA;becomes useless the moment my laptop sleeps.&lt;/p&gt;&#xA;&lt;p&gt;So, I built an alternate web UI with a service worker that caches content on&#xA;the client side for a smooth offline reading experience. It&amp;rsquo;s written in &lt;a href=&#34;https://ocaml.org/&#34;&gt;OCaml&lt;/a&gt;&#xA;and compiled to JavaScript using &lt;a href=&#34;https://ocsigen.org/js_of_ocaml/latest/manual/overview&#34;&gt;&lt;code&gt;js_of_ocaml&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-bother-with-rss-feeds&#34;&gt;Why bother with RSS feeds?&lt;/h2&gt;&#xA;&lt;p&gt;It is annoyingly easy to fall into the trap of short form videos or other&#xA;algorithmically &amp;ldquo;curated&amp;rdquo; feeds and get sucked into scrolling mindlessly. I&#xA;fear this is going to get even worse with all the generative AI stuff.&lt;/p&gt;&#xA;&lt;p&gt;I want to be more deliberate about what I consume. RSS feels calmer and gives&#xA;me a greater sense of control. Or it may just be nostalgia from good old Google&#xA;Reader days.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-emacs-and-elfeed&#34;&gt;Why Emacs and Elfeed?&lt;/h2&gt;&#xA;&lt;p&gt;Since Google Reader was killed, I&amp;rsquo;ve bounced between many readers but none of&#xA;them has really stuck with me. I&amp;rsquo;ve had &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/elfeed-hook-to-fetch-full-content/&#34;&gt;different phases&lt;/a&gt; of using Elfeed, over&#xA;the years, though.&lt;/p&gt;&#xA;&lt;p&gt;I like the fact that everything is local with Elfeed &amp;ndash; no hosted services, no&#xA;public servers. And since it lives inside Emacs, everything from tagging to how&#xA;entries are displayed can be tweaked.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-elfeed-offline&#34;&gt;Why Elfeed offline?&lt;/h2&gt;&#xA;&lt;p&gt;Elfeed also ships a basic web UI that lets me read my feeds from a different&#xA;device, but only when my laptop is online and reachable. I&amp;rsquo;d like to be able to&#xA;read these posts even when I&amp;rsquo;m &amp;ldquo;on the road&amp;rdquo;, say, while waiting for a train or&#xA;while taking a cab ride.&lt;/p&gt;&#xA;&lt;p&gt;I knew it should be possible to do this with some client side caching. And, I&#xA;considered improving the web UI of Elfeed itself but it doesn&amp;rsquo;t seem to be&#xA;&lt;a href=&#34;https://github.com/skeeto/elfeed/pulls&#34;&gt;actively maintained&lt;/a&gt; in the last couple of years. Creating a separate project&#xA;would also give me more freedom to experiment.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-does-it-work&#34;&gt;How does it work?&lt;/h2&gt;&#xA;&lt;p&gt;Elfeed offline comes with a tiny &lt;a href=&#34;https://camlworks.github.io/dream/&#34;&gt;Dream&lt;/a&gt; based webserver that acts as a proxy in&#xA;front of the Emacs Elfeed webserver for the API requests. The Dream web server&#xA;also serves the static assets like the HTML, JavaScript, stylesheets and the&#xA;Service Worker for the web app. The diagram below shows how data flows between the different components.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-artist&#34; data-lang=&#34;artist&#34;&gt;+---------------+     +-----------------+&#xA;|  Emacs Elfeed |&amp;lt;---&amp;gt;|     Dream       |&#xA;|     Server    |     |   Web-server    |&#xA;+---------------+     +-----------------+&#xA;                               ^&#xA;                               |&#xA;                               v&#xA; +------------+        +----------------+       +---------+&#xA; |    Web     |        |    Service     |       | Browser |&#xA; |  Client    |&amp;lt;------&amp;gt;|     Worker     |&amp;lt;-----&amp;gt;|  Cache  |&#xA; +------------+        +----------------+       +---------+&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Service Worker intercepts all the &lt;code&gt;GET&lt;/code&gt; requests from the client and&#xA;responds using a &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Caching#cache_first_with_cache_refresh&#34;&gt;cache-first-with-cache-refresh&lt;/a&gt; strategy. This makes the&#xA;reading experience feel very responsive. The web client also implements a &amp;ldquo;good&#xA;enough&amp;rdquo; clone of the original search functionality of Elfeed to allow searching&#xA;and filtering content while offline.&lt;/p&gt;&#xA;&lt;p&gt;The web app also lets me mark entries as read or star them when I&amp;rsquo;m offline.&#xA;The Service Worker caches these operations and updates the server when the&#xA;server becomes reachable. There&amp;rsquo;s no smart conflict resolution here, and the&#xA;API requests just overwrite and update the state on the server.&lt;/p&gt;&#xA;&lt;p&gt;I have been using this for a couple of weeks now, and am quite happy with how&#xA;responsive the UI feels and the number of posts I managed to read so far.&lt;/p&gt;&#xA;&lt;p&gt;But, there are definitely some rough edges to smoothen out.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a pain to make sure that both the servers are running when I&amp;rsquo;m online&#xA;and want to sync new updates to my phone. I&amp;rsquo;m considering adding a tiny Emacs&#xA;helper to manage this.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I need to remember to open the app on my phone to trigger a cache update&#xA;before stepping away from my laptop. I want to explore using the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Background_Synchronization_API&#34;&gt;Background&#xA;Sync API&lt;/a&gt; (not available on Firefox) to possibly make this easier.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The UI could use some improvements to indicate pending syncs when offline and&#xA;also indicate the last sync with the server to help ensure everything is&#xA;synced before stepping away from my laptop.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Service workers need the server to be accessible via https. I have a wrapper&#xA;script around mkcert to make this easy, but some apps on my phone &lt;a href=&#34;https://www.reddit.com/r/UPI/comments/1p4le9x/what_happened_to_my_bhim_app/&#34;&gt;refuse to&#xA;work&lt;/a&gt; correctly when there are user installed certificates.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;why-ocaml&#34;&gt;Why OCaml?&lt;/h2&gt;&#xA;&lt;p&gt;At work, I write OCaml every day and enjoy it. This project seemed like a good&#xA;one to try out &lt;code&gt;js_of_ocaml&lt;/code&gt; since everything is local and I don&amp;rsquo;t need to&#xA;worry about bundle sizes, etc.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;js_of_ocaml&lt;/code&gt; makes it quite convenient to share code between the server and&#xA;the client side. And given there&amp;rsquo;s also a &amp;ldquo;third&amp;rdquo; Service Worker component in&#xA;the mix, I thought it would make life easier. For instance, the message types&#xA;and the serialization code for the messages between the client and the service&#xA;worker are shared.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m also using this project to experiment with Dune&amp;rsquo;s &amp;ldquo;soon to be released&amp;rdquo;™&#xA;&lt;a href=&#34;https://dune.readthedocs.io/en/stable/tutorials/dune-package-management/index.html&#34;&gt;package management&lt;/a&gt; that our team at Tarides is working on building.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-can-you-use-it&#34;&gt;How can you use it?&lt;/h2&gt;&#xA;&lt;p&gt;You can try out Elfeed offline&amp;rsquo;s UI &lt;a href=&#34;https://elfeed-offline.muse-amuse.in/&#34;&gt;here&lt;/a&gt; as a static site (with some posts from&#xA;Planet Emacslife and The OCaml Planet). You should be able to read posts,&#xA;search and filter for posts, mark them as read or star them. Any changes you&#xA;make should be preserved between reloads.&lt;/p&gt;&#xA;&lt;p&gt;If you are an Emacs user but don&amp;rsquo;t use Elfeed, you can checkout the &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;Elfeed&amp;rsquo;s&#xA;README&lt;/a&gt; for instructions to set it up. It also has links to a bunch of blog&#xA;posts and videos that show off the features of Elfeed.&lt;/p&gt;&#xA;&lt;p&gt;If you are already using Elfeed, you should be able to set it up quite easily&#xA;if you&amp;rsquo;re happy installing some OCaml tooling. The installations instructions&#xA;are available in the &lt;a href=&#34;https://github.com/punchagan/elfeed-offline/blob/main/README.org&#34;&gt;README&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;outro&#34;&gt;Outro&lt;/h2&gt;&#xA;&lt;p&gt;I have been enjoying using Elfeed offline for the past couple of weeks. And I&amp;rsquo;m&#xA;hoping I&amp;rsquo;ll end up spending much more time reading in it, than fixing and&#xA;building it. It currently definitely feels like something I built for myself,&#xA;but I&amp;rsquo;d love to hear from others who try it out.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Elfeed hook to fetch full content</title>
      <link>https://punchagan.muse-amuse.in/blog/elfeed-hook-to-fetch-full-content/</link>
      <pubDate>Sat, 19 Dec 2015 13:42:29 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/elfeed-hook-to-fetch-full-content/</guid>
      <description>&lt;p&gt;I have started to use &lt;a href=&#34;http://pinboard.in&#34;&gt;Pinboard&lt;/a&gt;&amp;rsquo;s &lt;code&gt;unread&lt;/code&gt; tag as my to-read list.  It has a&#xA;bookmark-let that works pretty well for adding stuff into my &amp;ldquo;to-read&amp;rdquo; list.  I&#xA;then catch up on this list using &lt;code&gt;elfeed&lt;/code&gt; and subscribing to the unread items&#39;&#xA;RSS feed.  The work-flow is pretty nice for adding stuff into the list, and&#xA;finding items on the list. But, when it comes to the actual reading part, the&#xA;entries in the feed don&amp;rsquo;t have the actual content I want to read, and I end up&#xA;opening the links in a browser.&lt;/p&gt;&#xA;&lt;p&gt;Inspired by a &lt;a href=&#34;https://github.com/sursh/blaggregator/pull/80#issuecomment-165849126&#34;&gt;comment from FiloSottile&lt;/a&gt;, I realized it should be pretty easy to&#xA;setup a hook that fetches the actual content to make my reading work-flow&#xA;smoother. I wrote a &lt;a href=&#34;https://github.com/punchagan/dotfiles/blob/3285e9408b91bbf5e1c78974d003be84926f9954/bin/get_article.py&#34;&gt;small script&lt;/a&gt;, using &lt;a href=&#34;https://github.com/buriy/python-readability&#34;&gt;python-readability&lt;/a&gt;, to fetch the page&#xA;content, given a URL. This script is then hooked onto &lt;code&gt;elfeed-new-entry-hook&lt;/code&gt;,&#xA;to fetch content of for new entries as they are fetched.  All the old entries&#xA;can be easily fixed with a single call to &lt;code&gt;elfeed-apply-hooks-now&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/get-url-content&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Fetches the content for a url.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;shell-command-to-string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;~/bin/get_article.py %s&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/get-entry-content&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Fetches content for pinboard entries that are not tweets.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;interactive&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elfeed-show-entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;list&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-entry-link&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;feed-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-deref&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-entry-feed-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;content&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-deref&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-entry-content&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;s-matches?&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;feeds.pinboard.in/&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;feed-id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;s-matches?&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;twitter.com/\\|pdf$\\|png$\\|jpg$&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;string-equal&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;setq&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;content&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/get-url-content&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;setf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-entry-content&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elfeed-ref&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-hook&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;elfeed-new-entry-hook&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/get-entry-content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
  </channel>
</rss>
