diff --git a/application/config.json.template b/application/config.json.template index 5884522c60..7225704286 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -187,6 +187,7 @@ } ], "fallbackChannelPattern": "java-news-and-changes", + "videoLinkPattern": "http(s)?://www\\.youtube.com.*", "pollIntervalInMinutes": 10 }, "memberCountCategoryPattern": "Info", diff --git a/application/src/main/java/org/togetherjava/tjbot/config/RSSFeedsConfig.java b/application/src/main/java/org/togetherjava/tjbot/config/RSSFeedsConfig.java index 1c3371f71a..b18ec6fb1f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/RSSFeedsConfig.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/RSSFeedsConfig.java @@ -16,6 +16,7 @@ public record RSSFeedsConfig(@JsonProperty(value = "feeds", required = true) List feeds, @JsonProperty(value = "fallbackChannelPattern", required = true) String fallbackChannelPattern, + @JsonProperty(value = "videoLinkPattern", required = true) String videoLinkPattern, @JsonProperty(value = "pollIntervalInMinutes", required = true) int pollIntervalInMinutes) { /** @@ -23,6 +24,8 @@ public record RSSFeedsConfig(@JsonProperty(value = "feeds", required = true) Lis * * @param feeds The list of RSS feeds to subscribe to. * @param fallbackChannelPattern The pattern used to identify the fallback text channel to use. + * @param videoLinkPattern pattern determining if a link is a video. It is then posted in a way + * to support Discord video embeds. * @param pollIntervalInMinutes The interval (in minutes) for polling the RSS feeds for updates. * @throws NullPointerException if any of the parameters (feeds or fallbackChannelPattern) are * null @@ -30,5 +33,6 @@ public record RSSFeedsConfig(@JsonProperty(value = "feeds", required = true) Lis public RSSFeedsConfig { Objects.requireNonNull(feeds); Objects.requireNonNull(fallbackChannelPattern); + Objects.requireNonNull(videoLinkPattern); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java b/application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java index c86f305cda..56aea37b74 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java @@ -4,9 +4,9 @@ import com.apptasticsoftware.rssreader.RssReader; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.utils.cache.SnowflakeCacheView; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.apache.commons.text.StringEscapeUtils; import org.jetbrains.annotations.Nullable; import org.jooq.tools.StringUtils; @@ -79,6 +79,7 @@ public final class RSSHandlerRoutine implements Routine { private final RssReader rssReader; private final RSSFeedsConfig config; private final Predicate fallbackChannelPattern; + private final Predicate isVideoLink; private final Map> targetChannelPatterns; private final int interval; private final Database database; @@ -95,6 +96,7 @@ public RSSHandlerRoutine(Config config, Database database) { this.database = database; this.fallbackChannelPattern = Pattern.compile(this.config.fallbackChannelPattern()).asMatchPredicate(); + isVideoLink = Pattern.compile(this.config.videoLinkPattern()).asMatchPredicate(); this.targetChannelPatterns = new HashMap<>(); this.config.feeds().forEach(feed -> { if (feed.targetChannelPattern() != null) { @@ -155,7 +157,7 @@ private void sendRSS(JDA jda, RSSFeed feedConfig) { } rssItems.reversed() .stream() - .filter(shouldItemBePosted.get()) + .filter(shouldItemBePosted.orElseThrow()) .forEachOrdered(item -> postItem(textChannels, item, feedConfig)); } @@ -241,8 +243,8 @@ private Optional getLatestPostDateFromItems(List items, * @param feedConfig the RSS feed configuration */ private void postItem(List textChannels, Item rssItem, RSSFeed feedConfig) { - MessageEmbed embed = constructEmbedMessage(rssItem, feedConfig).build(); - textChannels.forEach(channel -> channel.sendMessageEmbeds(List.of(embed)).queue()); + MessageCreateData message = constructMessage(rssItem, feedConfig); + textChannels.forEach(channel -> channel.sendMessage(message).queue()); } /** @@ -346,13 +348,18 @@ private List getTextChannelsFromFeed(JDA jda, RSSFeed feed) { } /** - * Provides the {@link EmbedBuilder} from an RSS item used for sending RSS posts. + * Provides the message from an RSS item used for sending RSS posts. * * @param item the RSS item to construct the embed message from * @param feedConfig the configuration of the RSS feed - * @return the constructed {@link EmbedBuilder} containing information from the RSS item + * @return the constructed message containing information from the RSS item */ - private static EmbedBuilder constructEmbedMessage(Item item, RSSFeed feedConfig) { + private MessageCreateData constructMessage(Item item, RSSFeed feedConfig) { + if (item.getLink().filter(isVideoLink).isPresent()) { + // Automatic video previews are created on normal messages, not on embeds + return MessageCreateData.fromContent(item.getLink().orElseThrow()); + } + final EmbedBuilder embedBuilder = new EmbedBuilder(); String title = item.getTitle().orElse("No title"); String titleLink = item.getLink().orElse(""); @@ -381,7 +388,7 @@ private static EmbedBuilder constructEmbedMessage(Item item, RSSFeed feedConfig) embedBuilder.setDescription("No description"); } - return embedBuilder; + return MessageCreateData.fromEmbeds(embedBuilder.build()); } /**