package net.pterodactylus.rhynodge.states;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nonnull;
+
+import net.pterodactylus.rhynodge.Reaction;
import net.pterodactylus.rhynodge.State;
+import net.pterodactylus.rhynodge.output.DefaultOutput;
+import net.pterodactylus.rhynodge.output.Output;
import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.collect.Lists;
+import static com.google.common.collect.Ordering.from;
+import static java.lang.String.format;
/**
* {@link State} that contains information about an arbitrary number of torrent
@JsonProperty
private List<TorrentFile> files = Lists.newArrayList();
+ private final Set<TorrentFile> newTorrentFiles = new HashSet<>();
+
/**
* Creates a new torrent state without torrent files.
*/
public TorrentState() {
- this(Collections.<TorrentFile> emptySet());
+ this(Collections.<TorrentFile>emptySet());
}
/**
files.addAll(torrentFiles);
}
+ public TorrentState(Collection<TorrentFile> torrentFiles, Collection<TorrentFile> newTorrentFiles) {
+ files.addAll(torrentFiles);
+ this.newTorrentFiles.addAll(newTorrentFiles);
+ }
+
//
// ACCESSORS
//
+ @Override
+ public boolean isEmpty() {
+ return files.isEmpty();
+ }
+
+ @Override
+ public boolean triggered() {
+ return !newTorrentFiles.isEmpty();
+ }
+
/**
* Returns all torrent files of this state.
*
return this;
}
+ @Nonnull
+ @Override
+ protected String summary(Reaction reaction) {
+ return format("Found %d new Torrent(s) for “%s!”", newTorrentFiles.size(), reaction.name());
+ }
+
+ @Nonnull
+ @Override
+ protected String plainText() {
+ StringBuilder plainText = new StringBuilder();
+ plainText.append("New Torrents:\n\n");
+ for (TorrentFile torrentFile : newTorrentFiles) {
+ plainText.append(torrentFile.name()).append('\n');
+ plainText.append('\t').append(torrentFile.size()).append(" in ").append(torrentFile.fileCount()).append(" file(s)\n");
+ plainText.append('\t').append(torrentFile.seedCount()).append(" seed(s), ").append(torrentFile.leechCount()).append(" leecher(s)\n");
+ if ((torrentFile.magnetUri() != null) && (torrentFile.magnetUri().length() > 0)) {
+ plainText.append('\t').append(torrentFile.magnetUri()).append('\n');
+ }
+ if ((torrentFile.downloadUri() != null) && (torrentFile.downloadUri().length() > 0)) {
+ plainText.append('\t').append(torrentFile.downloadUri()).append('\n');
+ }
+ plainText.append('\n');
+ }
+ return plainText.toString();
+ }
+
+ @Nullable
+ @Override
+ protected String htmlText() {
+ StringBuilder htmlBuilder = new StringBuilder();
+ htmlBuilder.append("<html><body>\n");
+ htmlBuilder.append("<table>\n<caption>All Known Torrents</caption>\n");
+ htmlBuilder.append("<thead>\n");
+ htmlBuilder.append("<tr>");
+ 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");
+ for (TorrentFile torrentFile : sortNewFirst().sortedCopy(files)) {
+ if (newTorrentFiles.contains(torrentFile)) {
+ htmlBuilder.append("<tr style=\"color: #008000; font-weight: bold;\">");
+ } else {
+ htmlBuilder.append("<tr>");
+ }
+ htmlBuilder.append("<td>").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");
+ }
+ htmlBuilder.append("</tbody>\n");
+ htmlBuilder.append("</table>\n");
+ htmlBuilder.append("</body></html>\n");
+ return htmlBuilder.toString();
+ }
+
+ /**
+ * Returns an ordering that sorts torrent files by whether they are new
+ * (according to {@link #files}) or not. New files will be sorted
+ * first.
+ *
+ * @return An ordering for “new files first”
+ */
+ private Ordering<TorrentFile> sortNewFirst() {
+ return from((TorrentFile leftTorrentFile, TorrentFile rightTorrentFile) -> {
+ if (newTorrentFiles.contains(leftTorrentFile) && !newTorrentFiles.contains(rightTorrentFile)) {
+ return -1;
+ }
+ if (!newTorrentFiles.contains(leftTorrentFile) && newTorrentFiles.contains(rightTorrentFile)) {
+ return 1;
+ }
+ return 0;
+ });
+ }
+
//
// ITERABLE METHODS
//
*/
@Override
public String toString() {
- return String.format("%s[files=%s]", getClass().getSimpleName(), files);
+ return format("%s[files=%s]", getClass().getSimpleName(), files);
}
/**
*/
private String generateId() {
if (magnetUri != null) {
- String id = extractId(magnetUri);
- if (id != null) {
- return id;
- }
- return magnetUri;
+ return extractId(magnetUri).orElse(magnetUri);
}
return (downloadUri != null) ? downloadUri : name;
}
* The magnet URI to extract the “xt” from
* @return The extracted ID, or {@code null} if no ID could be found
*/
- private static String extractId(String magnetUri) {
- List<NameValuePair> parameters = URLEncodedUtils.parse(magnetUri.substring("magnet:?".length()), Charset.forName("UTF-8"));
+ private static Optional<String> extractId(String magnetUri) {
+ if ((magnetUri == null) || (magnetUri.length() < 8)) {
+ return Optional.empty();
+ }
+ List<NameValuePair> parameters = URLEncodedUtils.parse(magnetUri.substring("magnet:?".length()), StandardCharsets.UTF_8);
for (NameValuePair parameter : parameters) {
if (parameter.getName().equals("xt")) {
- return parameter.getValue().toLowerCase();
+ return Optional.of(parameter.getValue().toLowerCase());
}
}
- return null;
+ return Optional.empty();
}
//
*/
@Override
public String toString() {
- return String.format("%s(%s,%s,%s)", name(), size(), magnetUri(), downloadUri());
+ return format("%s(%s,%s,%s)", name(), size(), magnetUri(), downloadUri());
}
}