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;
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
return stringBuilder.toString();
}
- @Nullable
+ @NonNull
@Override
protected String htmlText() {
- StringBuilder htmlBuilder = new StringBuilder();
- htmlBuilder.append("<html><body>\n");
- /* show all known episodes. */
- htmlBuilder.append("<table>\n<caption>All Known Episodes</caption>\n");
- htmlBuilder.append("<thead>\n");
- htmlBuilder.append("<tr>");
- htmlBuilder.append("<th>Season</th>");
- htmlBuilder.append("<th>Episode</th>");
- htmlBuilder.append("<th>Filename</th>");
- htmlBuilder.append("<th>Size</th>");
- htmlBuilder.append("<th>File(s)</th>");
- htmlBuilder.append("<th>Seeds</th>");
- htmlBuilder.append("<th>Leechers</th>");
- htmlBuilder.append("<th>Magnet</th>");
- htmlBuilder.append("<th>Download</th>");
- htmlBuilder.append("</tr>\n");
- htmlBuilder.append("</thead>\n");
- htmlBuilder.append("<tbody>\n");
- Episode lastEpisode = null;
- for (Map.Entry<Integer, List<Episode>> seasonEntry : episodes.stream().sorted(Comparator.<Episode>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("<tr style=\"color: #008000; font-weight: bold;\">");
- } else if (newTorrentFiles.contains(torrentFile)) {
- htmlBuilder.append("<tr style=\"color: #008000;\">");
- } else {
- htmlBuilder.append("<tr>");
- }
- if ((lastEpisode == null) || !lastEpisode.equals(episode)) {
- htmlBuilder.append("<td>").append(episode.season()).append("</td><td>").append(episode.episode()).append("</td>");
- } else {
- htmlBuilder.append("<td colspan=\"2\"></td>");
- }
- htmlBuilder.append("<td class='filename'>").append(StringEscapeUtils.escapeHtml4(torrentFile.name())).append("</td>");
- htmlBuilder.append("<td>").append(StringEscapeUtils.escapeHtml4(torrentFile.size())).append("</td>");
- htmlBuilder.append("<td>").append(torrentFile.fileCount()).append("</td>");
- htmlBuilder.append("<td>").append(torrentFile.seedCount()).append("</td>");
- htmlBuilder.append("<td>").append(torrentFile.leechCount()).append("</td>");
- htmlBuilder.append("<td><a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.magnetUri())).append("\">Link</a></td>");
- htmlBuilder.append("<td><a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.downloadUri())).append("\">Link</a></td>");
- htmlBuilder.append("</tr>\n");
- lastEpisode = episode;
- }
- }
- }
- htmlBuilder.append("</tbody>\n");
- htmlBuilder.append("</table>\n");
- htmlBuilder.append("</body></html>\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<Episode>();
+ for (Map.Entry<Integer, List<Episode>> seasonEntry : episodes.stream().sorted(Comparator.<Episode>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);
+ }));
+ }
+ }
+ }
+ }));
+ }));
+ }));
+ }));
}
//
return String.format("%s[episodes=%s]", getClass().getSimpleName(), episodes);
}
+ private static <T extends Tag> Function1<T, Unit> wrapper(Consumer<T> tagConsumer) {
+ return t -> {
+ tagConsumer.accept(t);
+ return null;
+ };
+ }
+
/**
* Stores attributes for an episode.
*