From 65b9f236b777ff70dabb066d9b1dfb4da2cacab8 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:06:58 +0800 Subject: [PATCH] fix: missing enclosure attribute length (#49) --- .../java/run/halo/feed/RssCacheManager.java | 5 ++- .../java/run/halo/feed/RssXmlBuilder.java | 44 ++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/run/halo/feed/RssCacheManager.java b/app/src/main/java/run/halo/feed/RssCacheManager.java index 7193fec..02d9a7b 100644 --- a/app/src/main/java/run/halo/feed/RssCacheManager.java +++ b/app/src/main/java/run/halo/feed/RssCacheManager.java @@ -49,7 +49,10 @@ private Mono generateRssXml(Mono loader) { .doOnNext(prop -> builder.withExtractRssTags(prop.getRssExtraTags())); return Mono.when(rssMono, generatorMono, extractTagsMono) - .then(Mono.fromSupplier(builder::toXmlString)); + // toXmlString is a blocking operation + .then(Mono.fromCallable(builder::toXmlString) + .subscribeOn(Schedulers.boundedElastic()) + ); } @EventListener(PluginConfigUpdatedEvent.class) diff --git a/app/src/main/java/run/halo/feed/RssXmlBuilder.java b/app/src/main/java/run/halo/feed/RssXmlBuilder.java index 5305b5e..0d9b732 100644 --- a/app/src/main/java/run/halo/feed/RssXmlBuilder.java +++ b/app/src/main/java/run/halo/feed/RssXmlBuilder.java @@ -15,13 +15,28 @@ import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.SAXReader; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; +import reactor.netty.http.client.HttpClient; import run.halo.feed.telemetry.TelemetryEndpoint; @Slf4j public class RssXmlBuilder { + static final String UA = + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Chrome/131.0.0.0 Safari/537.36"; + private final WebClient webClient = WebClient.builder() + .clientConnector(new ReactorClientHttpConnector(HttpClient.create() + .followRedirect(true)) + ) + .build(); + private RSS2 rss2; private String generator = "Halo v2.0"; private String extractRssTags; @@ -174,10 +189,17 @@ private void createItemElementToChannel(Element channel, RSS2.Item item) { } if (StringUtils.isNotBlank(item.getEnclosureUrl())) { - itemElement.addElement("enclosure") + var enclosureElement = itemElement.addElement("enclosure") .addAttribute("url", item.getEnclosureUrl()) - .addAttribute("length", item.getEnclosureLength()) .addAttribute("type", item.getEnclosureType()); + + var enclosureLength = item.getEnclosureLength(); + if (StringUtils.isBlank(enclosureLength)) { + // https://www.rssboard.org/rss-validator/docs/error/MissingAttribute.html + var fileBytes = getFileSizeBytes(item.getEnclosureUrl()); + enclosureLength = String.valueOf(fileBytes); + } + enclosureElement.addAttribute("length", enclosureLength); } nullSafeList(item.getCategories()) @@ -258,4 +280,22 @@ static String instantToString(Instant instant) { return instant.atOffset(ZoneOffset.UTC) .format(DateTimeFormatter.RFC_1123_DATE_TIME); } + + @NonNull + private Long getFileSizeBytes(String url) { + return webClient.get() + .uri(url) + .header(HttpHeaders.USER_AGENT, UA) + .retrieve() + .toBodilessEntity() + .map(HttpEntity::getHeaders) + .mapNotNull(headers -> headers.getFirst(HttpHeaders.CONTENT_LENGTH)) + .map(Long::parseLong) + .doOnError(e -> log.debug("Failed to get file size from url: {}", url, + Throwables.getRootCause(e)) + ) + .onErrorReturn(0L) + .blockOptional() + .orElseThrow(); + } }