From: David ‘Bombe’ Roden Date: Tue, 7 Oct 2025 09:34:47 +0000 (+0200) Subject: ♻️ Use kotlinx.html to generate HTML X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=6ee056df804b4b20896d6d27257bf9e7a802122d;p=rhynodge.git ♻️ Use kotlinx.html to generate HTML --- diff --git a/src/main/java/net/pterodactylus/rhynodge/states/EpisodeState.java b/src/main/java/net/pterodactylus/rhynodge/states/EpisodeState.java index 4520c8c..52d6f1a 100644 --- a/src/main/java/net/pterodactylus/rhynodge/states/EpisodeState.java +++ b/src/main/java/net/pterodactylus/rhynodge/states/EpisodeState.java @@ -28,7 +28,11 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; +import kotlinx.html.Tag; import net.pterodactylus.rhynodge.Reaction; import net.pterodactylus.rhynodge.State; import net.pterodactylus.rhynodge.filters.EpisodeFilter; @@ -36,12 +40,21 @@ import net.pterodactylus.rhynodge.states.EpisodeState.Episode; import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile; import com.fasterxml.jackson.annotation.JsonProperty; -import org.apache.commons.lang3.StringEscapeUtils; import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; +import static kotlinx.html.Gen_consumer_tagsKt.html; +import static kotlinx.html.Gen_tag_groupsKt.table; +import static kotlinx.html.Gen_tag_unionsKt.a; +import static kotlinx.html.Gen_tags_hKt.body; +import static kotlinx.html.Gen_tags_tKt.caption; +import static kotlinx.html.Gen_tags_tKt.tbody; +import static kotlinx.html.Gen_tags_tKt.td; +import static kotlinx.html.Gen_tags_tKt.th; +import static kotlinx.html.Gen_tags_tKt.thead; +import static kotlinx.html.Gen_tags_tKt.tr; +import static kotlinx.html.stream.StreamKt.createHTML; /** * {@link State} implementation that stores episodes of TV shows, parsed via @@ -169,59 +182,58 @@ public class EpisodeState extends AbstractState implements Iterable { return stringBuilder.toString(); } - @Nullable + @NonNull @Override protected String htmlText() { - StringBuilder htmlBuilder = new StringBuilder(); - htmlBuilder.append("\n"); - /* show all known episodes. */ - htmlBuilder.append("\n\n"); - htmlBuilder.append("\n"); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append("\n"); - htmlBuilder.append("\n"); - htmlBuilder.append("\n"); - Episode lastEpisode = null; - for (Map.Entry> seasonEntry : episodes.stream().sorted(Comparator.naturalOrder().reversed()).collect(groupingBy(Episode::season, LinkedHashMap::new, toList())).entrySet()) { - for (Episode episode : seasonEntry.getValue()) { - for (TorrentFile torrentFile : episode) { - if (newEpisodes.contains(episode)) { - htmlBuilder.append(""); - } else if (newTorrentFiles.contains(torrentFile)) { - htmlBuilder.append(""); - } else { - htmlBuilder.append(""); - } - if ((lastEpisode == null) || !lastEpisode.equals(episode)) { - htmlBuilder.append(""); - } else { - htmlBuilder.append(""); - } - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append(""); - htmlBuilder.append("\n"); - lastEpisode = episode; - } - } - } - htmlBuilder.append("\n"); - htmlBuilder.append("
All Known Episodes
SeasonEpisodeFilenameSizeFile(s)SeedsLeechersMagnetDownload
").append(episode.season()).append("").append(episode.episode()).append("").append(StringEscapeUtils.escapeHtml4(torrentFile.name())).append("").append(StringEscapeUtils.escapeHtml4(torrentFile.size())).append("").append(torrentFile.fileCount()).append("").append(torrentFile.seedCount()).append("").append(torrentFile.leechCount()).append("LinkLink
\n"); - htmlBuilder.append("\n"); - return htmlBuilder.toString(); + var tagConsumer = createHTML(false, false); + return html(tagConsumer, null, wrapper(html -> { + body(html, null, wrapper(body -> { + table(body, null, wrapper(table -> { + caption(table, null, wrapper(caption -> caption.text("All Known Episodes"))); + thead(table, null, wrapper(tableHead -> tr(tableHead, null, wrapper(row -> { + th(row, null, null, wrapper(th -> th.text("Season"))); + th(row, null, null, wrapper(th -> th.text("Episode"))); + th(row, null, null, wrapper(th -> th.text("Filename"))); + th(row, null, null, wrapper(th -> th.text("Size"))); + th(row, null, null, wrapper(th -> th.text("File(s)"))); + th(row, null, null, wrapper(th -> th.text("Seeds"))); + th(row, null, null, wrapper(th -> th.text("Leechers"))); + th(row, null, null, wrapper(th -> th.text("Magnet"))); + th(row, null, null, wrapper(th -> th.text("Download"))); + })))); + tbody(table, null, wrapper(tableBody -> { + var lastEpisode = new AtomicReference(); + for (Map.Entry> seasonEntry : episodes.stream().sorted(Comparator.naturalOrder().reversed()).collect(groupingBy(Episode::season, LinkedHashMap::new, toList())).entrySet()) { + for (Episode episode : seasonEntry.getValue()) { + for (TorrentFile torrentFile : episode) { + tr(tableBody, null, wrapper(row -> { + if (newEpisodes.contains(episode)) { + row.getAttributes().put("style", "color: #008000; font-weight: bold;"); + } else if (newTorrentFiles.contains(torrentFile)) { + row.getAttributes().put("style", "color: #008000;"); + } + if ((lastEpisode.get() == null) || !lastEpisode.get().equals(episode)) { + td(row, null, wrapper(cell -> cell.text(episode.season()))); + td(row, null, wrapper(cell -> cell.text(episode.episode()))); + } else { + td(row, null, wrapper(cell -> cell.getAttributes().put("colspan", "2"))); + } + td(row, "filename", wrapper(cell -> cell.text(torrentFile.name()))); + td(row, null, wrapper(cell -> cell.text(torrentFile.size()))); + td(row, null, wrapper(cell -> cell.text(torrentFile.fileCount()))); + td(row, null, wrapper(cell -> cell.text(torrentFile.seedCount()))); + td(row, null, wrapper(cell -> cell.text(torrentFile.leechCount()))); + td(row, null, wrapper(cell -> a(cell, torrentFile.magnetUri(), null, null, wrapper(link -> link.text("Link"))))); + td(row, null, wrapper(cell -> a(cell, torrentFile.downloadUri(), null, null, wrapper(link -> link.text("Link"))))); + lastEpisode.set(episode); + })); + } + } + } + })); + })); + })); + })); } // @@ -244,6 +256,13 @@ public class EpisodeState extends AbstractState implements Iterable { return String.format("%s[episodes=%s]", getClass().getSimpleName(), episodes); } + private static Function1 wrapper(Consumer tagConsumer) { + return t -> { + tagConsumer.accept(t); + return null; + }; + } + /** * Stores attributes for an episode. *