diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-10-22 22:13:32 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-10-22 22:13:32 +0000 |
| commit | d4538340fdbe7016a7b3a2eb040c7b133df19efe (patch) | |
| tree | 2328d0d28772d730773904d435e04b80ae1b25ce /app/src/main/java/org/terst/feedreader/data/FeedParser.kt | |
| parent | 9bf135585885b043a05f3e74197314bdb4633c67 (diff) | |
Name a title-less feed item by its own opening words
RSS requires an item to carry a title or a description, not both, and
plenty of feeds take the second option. Mastodon's tag feeds are the
case that surfaced it: every one of the 20 items in
mastodon.social/tags/giftlink.rss has a description and no title at
all, so subscribing to one produced a list of blank rows with nothing
to read or tap.
A post says what it is, it just says it in the body, so the item is
now named by its own first sentence -- falling back to its opening
words when the sentence runs long, and to its link when there are no
words at all.
Two details that the live feed taught rather than the fixture:
Inline tags are removed without leaving a gap, and only block
boundaries become a space. Mastodon splits a hashtag as
`#<span>giftlink</span>` and a URL as `<span class="invisible">https://
</span><span>wapo.st/x</span>`, so turning every tag into a space tore
both apart -- first pass produced "# HumaneRights # USPolitics" and
"the loophole https:// wapo.".
A full stop only ends a sentence when whitespace or the end of the
text follows it, or the dot in "wapo.st/abc" ends it instead -- which
is how that same title got cut at "https://wapo.".
It also skips an opening fragment shorter than 20 characters: naming
an article "Wow." helps nobody.
Deliberately free of android.text.Html, unlike the parser's existing
entity decoding -- that pulls in the framework, which is why
FeedParser has no unit tests. This part does, 22 of them.
Verified on a device against the live feed: 20 items, 0 blank titles,
URLs and hashtags intact.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data/FeedParser.kt')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/FeedParser.kt | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/app/src/main/java/org/terst/feedreader/data/FeedParser.kt b/app/src/main/java/org/terst/feedreader/data/FeedParser.kt index 7a3ce93..ecb59dd 100644 --- a/app/src/main/java/org/terst/feedreader/data/FeedParser.kt +++ b/app/src/main/java/org/terst/feedreader/data/FeedParser.kt @@ -157,7 +157,11 @@ object FeedParser { // landing as the article's primary key. An empty-string id broke // Navigation Compose's route matching and crashed on tap. guid = itemGuid?.ifBlank { null } ?: itemLink.ifBlank { null }, - title = itemTitle, + // RSS requires a title OR a description, not both, and feeds that + // take the second option are common enough to matter: every item in + // a Mastodon tag feed is title-less, which showed as a list of blank + // rows. See ItemTitles. + title = ItemTitles.titleFor(itemTitle, content, itemLink), link = itemLink, author = itemAuthor, publishedAt = itemDate, @@ -245,7 +249,9 @@ object FeedParser { items += ParsedItem( // Same blank-vs-null fix as the RSS path above. guid = entryId?.ifBlank { null } ?: entryLink.ifBlank { null }, - title = entryTitle, + // Atom does require a title, but a feed that omits one should not + // render as a blank row either -- same treatment as RSS above. + title = ItemTitles.titleFor(entryTitle, content, entryLink), link = entryLink, author = entryAuthor, publishedAt = entryDate, |
