{
  "version": "https://jsonfeed.org/version/1",
  "title": "rss on jocmp",
  "icon": "https://avatars.micro.blog/avatars/2026/14/52207.jpg",
  "home_page_url": "https://jocmp.com/",
  "feed_url": "https://jocmp.com/feed.json",
  "items": [
      {
        "id": "http://jocmp.micro.blog/2025/08/22/the-guts-of-a-new/",
        "title": "The Guts of a New Machine",
        "content_html": "<p>ReadYou just released <a href=\"https://github.com/ReadYouApp/ReadYou/releases/tag/0.15.0\">v0.15.0</a> this past week. I&rsquo;ve been waiting to see their take on one very specific feature: large screen support. I tried it out. It&rsquo;s great! There&rsquo;s a subtle animation for article filters in the list column. There&rsquo;s also an expand/collapse option to view the article in full screen. This is a new paradigm that Google has been pushing in Keep and Gmail. In the face of these improvements, I&rsquo;ve been thinking to myself, why did I build Capy Reader when ReadYou has such an advanced UI?</p>\n<p>In retrospect, I set out to build Capy Reader for two reasons: exploration and compatibility. I wanted to explore how RSS readers worked under the hood, how they looked up feeds, and why they made the trade-offs they made. <a href=\"https://github.com/Ranchero-Software/NetNewsWire/tree/main/Technotes\">NetNewsWire&rsquo;s technotes</a> were a major help here since they delve into sync strategies and software architecture. Needless to say, there&rsquo;s no shortage of information.</p>\n<p>I built Capy Reader for compatibility <a href=\"https://feedbin.com/\">with Feedbin</a> too. There are plenty of readers available that work with Feedbin, sure, but none of them are exactly a pleasant experience. So when I built Capy, I built it for that. From there, I thought I could skirt around the need for Feedbin sign-in credentials in Google Play&rsquo;s review process by building out Local accounts. That wasn&rsquo;t the case. Before I knew it, I was supporting Local accounts, Feedbin, and Google Reader (both Miniflux and FreshRSS). This was a far cry from the original, simple vision of Capy as a Feedbin-only client.</p>\n<p>This brings me back to ReadYou&rsquo;s latest improvements. I&rsquo;m now considering forking ReadYou and using it as the basis of Capy Reader going forward. There are a few goals I have in mind that would make this unique:</p>\n<ul>\n<li>Feed discovery. Plugging in Capy Reader&rsquo;s existing feed finder to avoid having to search for exact feed URLs to add a feed.</li>\n<li>Feedbin and Miniflux support. These are components I can port from Capy&rsquo;s existing codebase.</li>\n<li>Inclusion in Google Play. In contrast, ReadYou is only available in F-Droid.</li>\n</ul>\n<p>There are two more considerations I want to highlight if I go this route. Capy Reader would be relicensed under <a href=\"https://www.gnu.org/licenses/gpl-3.0.en.html\">GPLv3</a>, and I&rsquo;d also want to build any revisions in a way that could be upstreamed to ReadYou.</p>\n<p>All of this is preliminary. These are untested ruminations, and talk is easy. If you have any reasons why you use ReadYou over Capy, or Capy over ReadYou, drop me a line <a href=\"https://mastodon.social/@_jocmp\">on Mastodon</a>!</p>\n",
        "date_published": "2025-08-22T16:18:34-05:00",
        "url": "https://jocmp.com/2025/08/22/the-guts-of-a-new/",
        "tags": ["capyreader","rss"]
      },
      {
        "id": "http://jocmp.micro.blog/2025/08/02/capy-log-open-in-browser/",
        "title": "Capy Log: Open In Browser, Article List Tweaks",
        "content_html": "<p>Summer in the midwest is careening towards autumn, and version <a href=\"https://github.com/jocmp/capyreader/releases/tag/2025.08.1153\">2025.08.1153</a> of Capy Reader is in review for the Play Store. I haven&rsquo;t been adding huge feature changes lately. Instead, I&rsquo;ve been trying to pick apart the app and understand some underlying jank that exists. More on that later. While there aren&rsquo;t huge changes in this release, I did get around to adding &ldquo;Open in browser&rdquo; as an option to view articles.</p>\n<h2 id=\"open-in-browser\">Open In Browser</h2>\n<p>&ldquo;Open in browser&rdquo; by default has been a long outstanding feature. It was <a href=\"https://github.com/jocmp/capyreader/discussions/715\">first requested in January</a> of this year. I feel bad sometimes when there&rsquo;s a huge delta between time requested and time implemented, but I spent a lot of time waffling on this feature.</p>\n<p>It&rsquo;s deceptively simple but the &ldquo;open in browser&rdquo; requires two key expectations</p>\n<ol>\n<li>The article opens in the browser</li>\n<li>The article is marked as read</li>\n</ol>\n<p>This second expectation prevents a direct call to an <code>ACTION_VIEW</code> intent since there is not a way to simultaneously launch two actions from a widget RemoteView. The trade-off then is to create a <a href=\"https://marcellogalhardo.dev/posts/2023/trampoline-activities/\">trampoline activity</a> which first opens the app with a transparent view, and then opens the browser. The trampoline activity can be avoided when the &ldquo;open in browser&rdquo; action is initiated within the app since the article state is already within context.</p>\n<p>Putting it all together, the new &ldquo;open in browser&rdquo; feature in Capy does what it says on the tin:</p>\n<p><video controls=\"controls\" playsinline=\"playsinline\" src=\"https://cdn.uploads.micro.blog/238475/2025/demo.mp4\" poster=\"https://jocmp.com/uploads/2025/poster.png\" preload=\"none\"></video></p>\n<h2 id=\"feed-selection-ui-improvements\">Feed Selection UI Improvements</h2>\n<p>One outstanding problem in Capy Reader has been feed list transitions. To spot the bug in previous versions:</p>\n<ol>\n<li>Scroll part way down a page, note the status and toolbar change color</li>\n<li>Open the feed list and select another feed</li>\n<li>Jank! The previous article list will scroll - or teleport - to the first index, and then the next feed will load in</li>\n</ol>\n<p>Here&rsquo;s an example of the problem at 4x speed. The top bar state jank is noticeable at the 10 second mark when it still appears as the changed color when the list has already switched to the next feed.</p>\n<p><video src=\"https://cdn.uploads.micro.blog/238475/2025/before.mp4\" poster=\"https://jocmp.com/uploads/2025/650a7c3a16.png\" controls=\"controls\" preload=\"metadata\"></video></p>\n<p>The solution I found was to <a href=\"https://github.com/jocmp/capyreader/pull/1354/commits/1431818cbc8717816273bc427770127ea76e8458\">rebuild the article pager</a> in the view layer. This in turn invalidates the list state which simultaneously invalidates the scrollbar state.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"><code class=\"language-kotlin\" data-lang=\"kotlin\"><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">import</span> androidx.paging.Pager\n</span></span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">import</span> androidx.paging.PagingConfig\n</span></span><span style=\"display:flex;\"><span>\n</span></span><span style=\"display:flex;\"><span><span style=\"color:#75715e\">// In View Model\n</span></span></span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">fun</span> <span style=\"color:#a6e22e\">buildPager</span>(): Pager {\n</span></span><span style=\"display:flex;\"><span>    <span style=\"color:#66d9ef\">return</span> Pager(\n</span></span><span style=\"display:flex;\"><span>        config = PagingConfig(\n</span></span><span style=\"display:flex;\"><span>            pageSize = <span style=\"color:#ae81ff\">50</span>,\n</span></span><span style=\"display:flex;\"><span>            prefetchDistance = <span style=\"color:#ae81ff\">10</span>,\n</span></span><span style=\"display:flex;\"><span>        ),\n</span></span><span style=\"display:flex;\"><span>        pagingSourceFactory = {\n</span></span><span style=\"display:flex;\"><span>            findArticles(<span style=\"color:#f92672\">..</span>.)\n</span></span><span style=\"display:flex;\"><span>        }\n</span></span><span style=\"display:flex;\"><span>    )\n</span></span><span style=\"display:flex;\"><span>}\n</span></span><span style=\"display:flex;\"><span>\n</span></span><span style=\"display:flex;\"><span><span style=\"color:#75715e\">// Pager is now in Compose view layer\n</span></span></span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">val</span> articles = remember(<span style=\"color:#f92672\">..</span>.) {\n</span></span><span style=\"display:flex;\"><span>   viewModel.buildPager(<span style=\"color:#f92672\">..</span>.)\n</span></span><span style=\"display:flex;\"><span>}\n</span></span></code></pre></div><p>The last wrinkle with this approach is pager updates in response to in-feed actions. One example of this is swipe-to-refresh on the &ldquo;Unread&rdquo; filter. When the refresh finishes, articles that have been read disappear. If the invalidation flag - in this case a timestamp - is passed to the <code>remember</code> function then the feed will flash causing the list to flicker and jump back to the first index. Instead the solution is to track a separate variable within the view model. When the timestamp changes, the view-level <code>articles</code> variable <a href=\"https://github.com/jocmp/capyreader/pull/1365/files#diff-a3dc4554d8145d70c4d38aeebda102f8988a6794752336fe21357326112e00d7\">is refreshed</a> which triggers a new call to the <code>pagingSourceFactory</code>.</p>\n<p>Here&rsquo;s a demo putting it all together:</p>\n<p><video src=\"https://cdn.uploads.micro.blog/238475/2025/after.mp4\" poster=\"https://jocmp.com/uploads/2025/726aff4e1c.png\" controls=\"controls\" preload=\"metadata\"></video></p>\n<p>Something so subtle that you might not have even noticed, but your brain did.</p>\n<h2 id=\"whats-next\">What&rsquo;s next</h2>\n<p>In the next few updates I hope to add more settings around &ldquo;open in browser&rdquo; based on <a href=\"https://github.com/jocmp/capyreader/discussions/1306\">early feedback</a>. Additionally, I have an outstanding UI tweak around the <a href=\"https://github.com/jocmp/capyreader/discussions/1211\">local blocklists</a> that I really want to wrap up and deliver.</p>\n",
        "date_published": "2025-08-02T14:49:32-05:00",
        "url": "https://jocmp.com/2025/08/02/capy-log-open-in-browser/",
        "tags": ["capyreader","rss","programming"]
      },
      {
        "id": "http://jocmp.micro.blog/2025/07/12/full-content-extractors-comparing-defuddle/",
        "title": "Full Content Extractors: Comparing Defuddle and Postlight Parser",
        "content_html": "<p>One of the hardest problems with RSS feeds is displaying full content. It&rsquo;s essentially an unsolvable problem given the complexity of webpages and the lack of adherence to a semantic layout for any given blog or news site. It would be nice if each page had a header tag, and an article tag, but it&rsquo;s not that simple. Full content parsers attempt to solve this, but each has their own set of trade-offs.</p>\n<h2 id=\"legacy-contenders\">Legacy Contenders</h2>\n<p>Tools like Mozilla&rsquo;s Readability.js used to solve this in the past, but given <a href=\"https://www.theregister.com/2025/06/17/opinion_column_firefox/\">their recent woes</a> it&rsquo;s hard to trust it as a tool. <a href=\"https://github.com/postlight/parser\">Postlight Parser</a> née <a href=\"https://archive.postlight.com/insights/mercury-goes-open-source\">Mercury Parser</a> was a better option. Instead of trying to solve all webpages with a set of common heuristics, each domain could be overridden with a custom parser. In effect, The Verge could have a Verge-specific parser while Ars Technica could have a slightly different parser.</p>\n<p>It would be simple to stop there, but Postlight Parser was a product of its time. Around 2015, there was a <a href=\"https://www.theverge.com/23711172/google-amp-accelerated-mobile-pages-search-publishers-lawsuit\">push by Google</a> to speed up the web by simplifying webpages with AMP. Postlight was one of many companies that stepped in with their own set of tools like the parser to improve development with AMP. But as time passed, AMP fell out of fashion, and Postlight was <a href=\"https://archive.postlight.com/insights/postlight-joins-launch-by-ntt-data\">acquired by NTT Data</a>.</p>\n<p>Postlight Parser essentially ended with the acquisition. It&rsquo;s still possible to find Postlight Parser in the wild, however. Feedbin, a web-based feed reader, uses Postlight Parser to <a href=\"https://feedbin.com/blog/2019/03/11/the-future-of-full-content/\">power its full content mode</a>. Core development has ground to a halt with the last release <a href=\"https://github.com/postlight/parser/releases/tag/v2.2.3\">in 2022</a>.</p>\n<h2 id=\"a-new-entrant\">A New Entrant</h2>\n<p>Readability.js and Postlight Parser may very well represent the past of full content extraction. However a new project called Defuddle might take their place. <a href=\"https://github.com/kepano/defuddle\">Defuddle</a> was released in early 2025 by the developer behind the note-taking app Obsidian. It takes the Readability.js route of a one-size-fits-all input function with different internal heuristics.</p>\n<p>The following is a brief and non-exhaustive comparison between v2.2.3 of Postlight Parser and v0.6.4 of Defuddle using a small node.js application (<a href=\"https://github.com/jocmp/parser-comparison\">source code on GitHub</a>). Defuddle seems to work best when the site&rsquo;s markup is already well formatted which is the case with The Verge. In the <a href=\"https://www.theverge.com/24324299/asus-rog-zephyrus-g16-2024-gaming-laptop-review-amd-strix-point\">following review article</a>, Defuddle picks up more images, headers, and content like the overall review score than Postlight Parser.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2025/parser-compare-verge.png\" width=\"600\" height=\"449\" alt=\"\">\n<p>Parsing fails if you throw <a href=\"https://sg.news.yahoo.com/mcdonald-pore-launches-chilli-crab-064000706.html\">an article from Yahoo News Singapore</a> at either Defuddle or Postlight Parser. Defuddle has a slight edge in that it at least extracts images and article content but still captures garbage text like &ldquo;ADVERTISEMENT.&rdquo;</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2025/parser-compare-yn-sg.png\" width=\"600\" height=\"449\" alt=\"\">\n<p>In short, better base markup still results in a better outcome. Defuddle is clearly the project to watch given Postlight Parser&rsquo;s lack of updates, and it&rsquo;s backed by a live project with Obsidian. Full content parsers come and go but the need to tame the chaos of the web is never ending.</p>\n",
        "date_published": "2025-07-12T18:03:00-05:00",
        "url": "https://jocmp.com/2025/07/12/full-content-extractors-comparing-defuddle/",
        "tags": ["rss","programming","mercury parser"]
      }
  ]
}
