diff --git a/code/services-application/search-service/java/nu/marginalia/search/SearchService.java b/code/services-application/search-service/java/nu/marginalia/search/SearchService.java index 31abe74d..f5639a74 100644 --- a/code/services-application/search-service/java/nu/marginalia/search/SearchService.java +++ b/code/services-application/search-service/java/nu/marginalia/search/SearchService.java @@ -1,6 +1,7 @@ package nu.marginalia.search; import com.google.inject.Inject; +import io.jooby.Jooby; import io.prometheus.client.Counter; import io.prometheus.client.Histogram; import nu.marginalia.WebsiteUrl; @@ -18,6 +19,7 @@ public class SearchService extends JoobyService { private final WebsiteUrl websiteUrl; private final StaticResources staticResources; + private final SearchSiteSubscriptionService siteSubscriptionService; private static final Logger logger = LoggerFactory.getLogger(SearchService.class); private static final Histogram wmsa_search_service_request_time = Histogram.build() @@ -38,6 +40,7 @@ public class SearchService extends JoobyService { StaticResources staticResources, SearchFrontPageService frontPageService, SearchAddToCrawlQueueService addToCrawlQueueService, + SearchSiteSubscriptionService siteSubscriptionService, SearchSiteInfoService siteInfoService, SearchCrosstalkService crosstalkService, SearchBrowseService searchBrowseService, @@ -57,6 +60,14 @@ public class SearchService extends JoobyService { this.websiteUrl = websiteUrl; this.staticResources = staticResources; + this.siteSubscriptionService = siteSubscriptionService; + } + + @Override + public void startJooby(Jooby jooby) { + super.startJooby(jooby); + + jooby.get("/export-opml", siteSubscriptionService::exportOpml); } // // SearchServiceMetrics.get("/search", searchQueryService::pathSearch); diff --git a/code/services-application/search-service/java/nu/marginalia/search/svc/SearchSiteSubscriptionService.java b/code/services-application/search-service/java/nu/marginalia/search/svc/SearchSiteSubscriptionService.java index 6bd9f8ad..42cead7f 100644 --- a/code/services-application/search-service/java/nu/marginalia/search/svc/SearchSiteSubscriptionService.java +++ b/code/services-application/search-service/java/nu/marginalia/search/svc/SearchSiteSubscriptionService.java @@ -4,6 +4,8 @@ import com.google.inject.Inject; import io.jooby.Context; import io.jooby.Cookie; import io.jooby.Value; +import nu.marginalia.api.feeds.FeedsClient; +import nu.marginalia.api.feeds.RpcFeed; import nu.marginalia.db.DbDomainQueries; import nu.marginalia.model.EdgeDomain; import org.slf4j.Logger; @@ -12,19 +14,25 @@ import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Set; +import java.util.concurrent.ExecutionException; public class SearchSiteSubscriptionService { private final DbDomainQueries dbDomainQueries; + private final FeedsClient feedsClient; private static final Logger logger = LoggerFactory.getLogger(SearchSiteSubscriptionService.class); @Inject - public SearchSiteSubscriptionService(DbDomainQueries dbDomainQueries) { + public SearchSiteSubscriptionService(DbDomainQueries dbDomainQueries, FeedsClient feedsClient) { this.dbDomainQueries = dbDomainQueries; + this.feedsClient = feedsClient; } public HashSet getSubscriptions(Context context) { @@ -90,4 +98,32 @@ public class SearchSiteSubscriptionService { putSubscriptions(context, subscriptions); } + + public Object exportOpml(Context ctx) throws ExecutionException, InterruptedException { + ctx.setResponseType("text/xml.opml"); + ctx.setResponseHeader("Content-Disposition", "attachment; filename=feeds.opml"); + + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("Marginalia Subscriptions\n"); + sb.append("").append(LocalDateTime.now().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.RFC_1123_DATE_TIME)).append("\n"); + sb.append("\n"); + + sb.append("\n"); + for (int domainId : getSubscriptions(ctx)) { + RpcFeed feed = feedsClient.getFeed(domainId).get(); + sb.append("\n"); + } + sb.append("\n"); + sb.append(""); + + return sb.toString(); + } } diff --git a/code/services-application/search-service/resources/jte/serp/start.jte b/code/services-application/search-service/resources/jte/serp/start.jte index bfaf8e4d..aa4c131f 100644 --- a/code/services-application/search-service/resources/jte/serp/start.jte +++ b/code/services-application/search-service/resources/jte/serp/start.jte @@ -81,7 +81,14 @@ @else
-
Subscriptions
+
+ Subscriptions +
+ + + Export as OPML + +
@for (NewsItemCluster cluster : model.news()) !{NewsItem item = cluster.first();}