FeedEntryFullTextExtractor.java

package net.sasasin.sreader.service;

import com.rometools.rome.feed.synd.SyndContent;
import com.rometools.rome.feed.synd.SyndEntry;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import org.jsoup.Jsoup;
import org.springframework.stereotype.Service;

@Service
public class FeedEntryFullTextExtractor {

  public Optional<String> extract(SyndEntry entry) {
    List<String> candidates = new ArrayList<>();
    for (SyndContent content : entry.getContents()) {
      normalize(content).ifPresent(candidates::add);
    }
    normalize(entry.getDescription()).ifPresent(candidates::add);

    return candidates.stream()
        .map(String::trim)
        .filter(text -> !text.isBlank())
        .max(Comparator.comparingInt(String::length));
  }

  private Optional<String> normalize(SyndContent content) {
    if (content == null || content.getValue() == null || content.getValue().isBlank()) {
      return Optional.empty();
    }
    String value = content.getValue();
    if (isHtmlLike(content.getType(), value)) {
      return Optional.of(Jsoup.parseBodyFragment(value).body().text());
    }
    return Optional.of(value.strip());
  }

  private boolean isHtmlLike(String type, String value) {
    if (type != null) {
      String lower = type.toLowerCase(Locale.ROOT);
      if (lower.contains("html") || lower.contains("xhtml")) {
        return true;
      }
    }
    return value.matches("(?is).*<\\s*(p|div|br|article|section|span|a|img|ul|ol|li|h[1-6])\\b.*");
  }
}