2 * Rhynodge - NewTorrentTrigger.java - Copyright © 2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.rhynodge.triggers;
20 import static com.google.common.base.Preconditions.checkState;
22 import java.util.List;
25 import net.pterodactylus.rhynodge.Reaction;
26 import net.pterodactylus.rhynodge.State;
27 import net.pterodactylus.rhynodge.Trigger;
28 import net.pterodactylus.rhynodge.output.DefaultOutput;
29 import net.pterodactylus.rhynodge.output.Output;
30 import net.pterodactylus.rhynodge.states.TorrentState;
31 import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
33 import org.apache.commons.lang3.StringEscapeUtils;
35 import com.google.common.collect.Lists;
36 import com.google.common.collect.Ordering;
37 import com.google.common.collect.Sets;
40 * {@link Trigger} implementation that is triggered by {@link TorrentFile}s that
41 * appear in the current {@link TorrentState} but not in the previous one.
43 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
45 public class NewTorrentTrigger implements Trigger {
47 /** All known torrents. */
48 private final Set<TorrentFile> allTorrentFiles = Sets.newHashSet();
50 /** The newly detected torrent files. */
51 private final List<TorrentFile> newTorrentFiles = Lists.newArrayList();
61 public State mergeStates(State previousState, State currentState) {
62 checkState(currentState instanceof TorrentState, "currentState is not a TorrentState but a %s", currentState.getClass().getName());
63 checkState(previousState instanceof TorrentState, "previousState is not a TorrentState but a %s", currentState.getClass().getName());
64 TorrentState currentTorrentState = (TorrentState) currentState;
65 TorrentState previousTorrentState = (TorrentState) previousState;
67 allTorrentFiles.clear();
68 newTorrentFiles.clear();
69 allTorrentFiles.addAll(previousTorrentState.torrentFiles());
70 for (TorrentFile torrentFile : currentTorrentState) {
71 if (allTorrentFiles.add(torrentFile)) {
72 newTorrentFiles.add(torrentFile);
76 return new TorrentState(allTorrentFiles);
83 public boolean triggers() {
84 return !newTorrentFiles.isEmpty();
91 public Output output(Reaction reaction) {
92 DefaultOutput output = new DefaultOutput(String.format("Found %d new Torrent(s) for “%s!”", newTorrentFiles.size(), reaction.name()));
93 output.addText("text/plain", getPlainTextList(reaction));
94 output.addText("text/html", getHtmlTextList(reaction));
103 * Generates a plain text list of torrent files.
106 * The reaction that was triggered
107 * @return The generated plain text
109 private String getPlainTextList(Reaction reaction) {
110 StringBuilder plainText = new StringBuilder();
111 plainText.append("New Torrents:\n\n");
112 for (TorrentFile torrentFile : newTorrentFiles) {
113 plainText.append(torrentFile.name()).append('\n');
114 plainText.append('\t').append(torrentFile.size()).append(" in ").append(torrentFile.fileCount()).append(" file(s)\n");
115 plainText.append('\t').append(torrentFile.seedCount()).append(" seed(s), ").append(torrentFile.leechCount()).append(" leecher(s)\n");
116 if ((torrentFile.magnetUri() != null) && (torrentFile.magnetUri().length() > 0)) {
117 plainText.append('\t').append(torrentFile.magnetUri()).append('\n');
119 if ((torrentFile.downloadUri() != null) && (torrentFile.downloadUri().length() > 0)) {
120 plainText.append('\t').append(torrentFile.downloadUri()).append('\n');
122 plainText.append('\n');
124 return plainText.toString();
128 * Generates an HTML list of the given torrent files.
131 * The reaction that was triggered
132 * @return The generated HTML
134 private String getHtmlTextList(Reaction reaction) {
135 StringBuilder htmlBuilder = new StringBuilder();
136 htmlBuilder.append("<html><body>\n");
137 htmlBuilder.append("<table>\n<caption>All Known Torrents</caption>\n");
138 htmlBuilder.append("<thead>\n");
139 htmlBuilder.append("<tr>");
140 htmlBuilder.append("<th>Filename</th>");
141 htmlBuilder.append("<th>Size</th>");
142 htmlBuilder.append("<th>File(s)</th>");
143 htmlBuilder.append("<th>Seeds</th>");
144 htmlBuilder.append("<th>Leechers</th>");
145 htmlBuilder.append("<th>Magnet</th>");
146 htmlBuilder.append("<th>Download</th>");
147 htmlBuilder.append("</tr>\n");
148 htmlBuilder.append("</thead>\n");
149 htmlBuilder.append("<tbody>\n");
150 for (TorrentFile torrentFile : sortNewFirst().sortedCopy(allTorrentFiles)) {
151 if (newTorrentFiles.contains(torrentFile)) {
152 htmlBuilder.append("<tr style=\"color: #008000; font-weight: bold;\">");
154 htmlBuilder.append("<tr>");
156 htmlBuilder.append("<td>").append(StringEscapeUtils.escapeHtml4(torrentFile.name())).append("</td>");
157 htmlBuilder.append("<td>").append(StringEscapeUtils.escapeHtml4(torrentFile.size())).append("</td>");
158 htmlBuilder.append("<td>").append(torrentFile.fileCount()).append("</td>");
159 htmlBuilder.append("<td>").append(torrentFile.seedCount()).append("</td>");
160 htmlBuilder.append("<td>").append(torrentFile.leechCount()).append("</td>");
161 htmlBuilder.append("<td><a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.magnetUri())).append("\">Link</a></td>");
162 htmlBuilder.append("<td><a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.downloadUri())).append("\">Link</a></td>");
163 htmlBuilder.append("</tr>\n");
165 htmlBuilder.append("</tbody>\n");
166 htmlBuilder.append("</table>\n");
167 htmlBuilder.append("</body></html>\n");
168 return htmlBuilder.toString();
172 * Returns an ordering that sorts torrent files by whether they are new
173 * (according to {@link #newTorrentFiles}) or not. New files will be sorted
176 * @return An ordering for “new files first”
178 private Ordering<TorrentFile> sortNewFirst() {
179 return new Ordering<TorrentFile>() {
182 public int compare(TorrentFile leftTorrentFile, TorrentFile rightTorrentFile) {
183 if (newTorrentFiles.contains(leftTorrentFile) && !newTorrentFiles.contains(rightTorrentFile)) {
186 if (!newTorrentFiles.contains(leftTorrentFile) && newTorrentFiles.contains(rightTorrentFile)) {