a8e321c22efd1bd6dad16ab3a05ab30db223f0e8
[rhynodge.git] / src / main / java / net / pterodactylus / rhynodge / triggers / NewEpisodeTrigger.java
1 /*
2  * Rhynodge - NewEpisodeTrigger.java - Copyright © 2013 David Roden
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 package net.pterodactylus.rhynodge.triggers;
19
20 import static com.google.common.base.Preconditions.checkState;
21
22 import java.util.Collection;
23
24 import net.pterodactylus.rhynodge.Reaction;
25 import net.pterodactylus.rhynodge.State;
26 import net.pterodactylus.rhynodge.Trigger;
27 import net.pterodactylus.rhynodge.output.DefaultOutput;
28 import net.pterodactylus.rhynodge.output.Output;
29 import net.pterodactylus.rhynodge.states.EpisodeState;
30 import net.pterodactylus.rhynodge.states.EpisodeState.Episode;
31 import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
32
33 import org.apache.commons.lang3.StringEscapeUtils;
34
35 import com.google.common.base.Predicate;
36 import com.google.common.collect.Collections2;
37
38 /**
39  * {@link Trigger} implementation that compares two {@link EpisodeState}s for
40  * new and changed {@link Episode}s.
41  *
42  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
43  */
44 public class NewEpisodeTrigger implements Trigger {
45
46         /** All new episodes. */
47         private Collection<Episode> newEpisodes;
48
49         /** All changed episodes. */
50         private Collection<Episode> changedEpisodes;
51
52         //
53         // TRIGGER METHODS
54         //
55
56         /**
57          * {@inheritDoc}
58          */
59         @Override
60         public boolean triggers(State currentState, State previousState) {
61                 checkState(currentState instanceof EpisodeState, "currentState is not a EpisodeState but a %s", currentState.getClass().getName());
62                 checkState(previousState instanceof EpisodeState, "previousState is not a EpisodeState but a %s", currentState.getClass().getName());
63                 final EpisodeState currentEpisodeState = (EpisodeState) currentState;
64                 final EpisodeState previousEpisodeState = (EpisodeState) previousState;
65
66                 newEpisodes = Collections2.filter(currentEpisodeState.episodes(), new Predicate<Episode>() {
67
68                         @Override
69                         public boolean apply(Episode episode) {
70                                 return !previousEpisodeState.episodes().contains(episode);
71                         }
72                 });
73
74                 changedEpisodes = Collections2.filter(currentEpisodeState.episodes(), new Predicate<Episode>() {
75
76                         @Override
77                         public boolean apply(Episode episode) {
78                                 if (!previousEpisodeState.episodes().contains(episode)) {
79                                         return false;
80                                 }
81
82                                 /* find previous episode. */
83                                 final Episode previousEpisode = findPreviousEpisode(episode);
84
85                                 /* compare the list of torrent files. */
86                                 Collection<TorrentFile> newTorrentFiles = Collections2.filter(episode.torrentFiles(), new Predicate<TorrentFile>() {
87
88                                         @Override
89                                         public boolean apply(TorrentFile torrentFile) {
90                                                 return !previousEpisode.torrentFiles().contains(torrentFile);
91                                         }
92                                 });
93
94                                 return !newTorrentFiles.isEmpty();
95                         }
96
97                         private Episode findPreviousEpisode(Episode episode) {
98                                 for (Episode previousStateEpisode : previousEpisodeState) {
99                                         if (previousStateEpisode.equals(episode)) {
100                                                 return previousStateEpisode;
101                                         }
102                                 }
103                                 return null;
104                         }
105
106                 });
107
108                 return !newEpisodes.isEmpty() || !changedEpisodes.isEmpty();
109         }
110
111         /**
112          * {@inheritDoc}
113          */
114         @Override
115         public Output output(Reaction reaction) {
116                 String summary;
117                 if (!newEpisodes.isEmpty()) {
118                         if (!changedEpisodes.isEmpty()) {
119                                 summary = String.format("%d new and %d changed Torrent(s) for “%s!”", newEpisodes.size(), changedEpisodes.size(), reaction.name());
120                         } else {
121                                 summary = String.format("%d new Torrent(s) for “%s!”", newEpisodes.size(), reaction.name());
122                         }
123                 } else {
124                         summary = String.format("%d changed Torrent(s) for “%s!”", changedEpisodes.size(), reaction.name());
125                 }
126                 DefaultOutput output = new DefaultOutput(summary);
127                 output.addText("text/plain", generatePlainText(reaction, newEpisodes, changedEpisodes));
128                 output.addText("text/html", generateHtmlText(reaction, newEpisodes, changedEpisodes));
129                 return output;
130         }
131
132         //
133         // STATIC METHODS
134         //
135
136         /**
137          * Generates the plain text trigger output.
138          *
139          * @param reaction
140          *            The reaction that was triggered
141          * @param newEpisodes
142          *            The new episodes
143          * @param changedEpisodes
144          *            The changed episodes
145          * @return The plain text output
146          */
147         private static String generatePlainText(Reaction reaction, Collection<Episode> newEpisodes, Collection<Episode> changedEpisodes) {
148                 StringBuilder stringBuilder = new StringBuilder();
149                 if (!newEpisodes.isEmpty()) {
150                         stringBuilder.append(reaction.name()).append(" - New Episodes\n\n");
151                         for (Episode episode : newEpisodes) {
152                                 stringBuilder.append("- ").append(episode.identifier()).append("\n");
153                                 for (TorrentFile torrentFile : episode) {
154                                         stringBuilder.append("  - ").append(torrentFile.name()).append(", ").append(torrentFile.size()).append("\n");
155                                         if ((torrentFile.magnetUri() != null) && (torrentFile.magnetUri().length() > 0)) {
156                                                 stringBuilder.append("    Magnet: ").append(torrentFile.magnetUri()).append("\n");
157                                         }
158                                         if ((torrentFile.downloadUri() != null) && (torrentFile.downloadUri().length() > 0)) {
159                                                 stringBuilder.append("    Download: ").append(torrentFile.downloadUri()).append("\n");
160                                         }
161                                 }
162                         }
163                 }
164                 if (!changedEpisodes.isEmpty()) {
165                         stringBuilder.append(reaction.name()).append(" - Changed Episodes\n\n");
166                         for (Episode episode : changedEpisodes) {
167                                 stringBuilder.append("- ").append(episode.identifier()).append("\n");
168                                 for (TorrentFile torrentFile : episode) {
169                                         stringBuilder.append("  - ").append(torrentFile.name()).append(", ").append(torrentFile.size()).append("\n");
170                                         if ((torrentFile.magnetUri() != null) && (torrentFile.magnetUri().length() > 0)) {
171                                                 stringBuilder.append("    Magnet: ").append(torrentFile.magnetUri()).append("\n");
172                                         }
173                                         if ((torrentFile.downloadUri() != null) && (torrentFile.downloadUri().length() > 0)) {
174                                                 stringBuilder.append("    Download: ").append(torrentFile.downloadUri()).append("\n");
175                                         }
176                                 }
177                         }
178                 }
179                 return stringBuilder.toString();
180         }
181
182         /**
183          * Generates the HTML trigger output.
184          *
185          * @param reaction
186          *            The reaction that was triggered
187          * @param newEpisodes
188          *            The new episodes
189          * @param changedEpisodes
190          *            The changed episodes
191          * @return The HTML output
192          */
193         private static String generateHtmlText(Reaction reaction, Collection<Episode> newEpisodes, Collection<Episode> changedEpisodes) {
194                 StringBuilder htmlBuilder = new StringBuilder();
195                 htmlBuilder.append("<html><body>\n");
196                 htmlBuilder.append("<h1>").append(StringEscapeUtils.escapeHtml4(reaction.name())).append("</h1>\n");
197                 if (!newEpisodes.isEmpty()) {
198                         htmlBuilder.append("<h2>New Episodes</h2>\n");
199                         htmlBuilder.append("<ul>\n");
200                         for (Episode episode : newEpisodes) {
201                                 htmlBuilder.append("<li>Season ").append(episode.season()).append(", Episode ").append(episode.episode()).append("</li>\n");
202                                 htmlBuilder.append("<ul>\n");
203                                 for (TorrentFile torrentFile : episode) {
204                                         htmlBuilder.append("<li>").append(StringEscapeUtils.escapeHtml4(torrentFile.name())).append("</li>\n");
205                                         htmlBuilder.append("<div>");
206                                         htmlBuilder.append("<strong>").append(StringEscapeUtils.escapeHtml4(torrentFile.size())).append("</strong>, ");
207                                         htmlBuilder.append("<strong>").append(torrentFile.fileCount()).append("</strong> file(s), ");
208                                         htmlBuilder.append("<strong>").append(torrentFile.seedCount()).append("</strong> seed(s), ");
209                                         htmlBuilder.append("<strong>").append(torrentFile.leechCount()).append("</strong> leecher(s)</div>\n");
210                                         htmlBuilder.append("<div>");
211                                         if ((torrentFile.magnetUri() != null) && (torrentFile.magnetUri().length() > 0)) {
212                                                 htmlBuilder.append("<a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.magnetUri())).append("\">Magnet</a> ");
213                                         }
214                                         if ((torrentFile.downloadUri() != null) && (torrentFile.downloadUri().length() > 0)) {
215                                                 htmlBuilder.append("<a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.downloadUri())).append("\">Download</a>");
216                                         }
217                                         htmlBuilder.append("</div>\n");
218                                 }
219                                 htmlBuilder.append("</ul>\n");
220                         }
221                         htmlBuilder.append("</ul>\n");
222                 }
223                 if (!changedEpisodes.isEmpty()) {
224                         htmlBuilder.append("<h2>Changed Episodes</h2>\n");
225                         htmlBuilder.append("<ul>\n");
226                         for (Episode episode : changedEpisodes) {
227                                 htmlBuilder.append("<li>Season ").append(episode.season()).append(", Episode ").append(episode.episode()).append("</li>\n");
228                                 htmlBuilder.append("<ul>\n");
229                                 for (TorrentFile torrentFile : episode) {
230                                         htmlBuilder.append("<li>").append(StringEscapeUtils.escapeHtml4(torrentFile.name())).append("</li>\n");
231                                         htmlBuilder.append("<div>");
232                                         htmlBuilder.append("<strong>").append(StringEscapeUtils.escapeHtml4(torrentFile.size())).append("</strong>, ");
233                                         htmlBuilder.append("<strong>").append(torrentFile.fileCount()).append("</strong> file(s), ");
234                                         htmlBuilder.append("<strong>").append(torrentFile.seedCount()).append("</strong> seed(s), ");
235                                         htmlBuilder.append("<strong>").append(torrentFile.leechCount()).append("</strong> leecher(s)</div>\n");
236                                         htmlBuilder.append("<div>");
237                                         if ((torrentFile.magnetUri() != null) && (torrentFile.magnetUri().length() > 0)) {
238                                                 htmlBuilder.append("<a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.magnetUri())).append("\">Magnet</a> ");
239                                         }
240                                         if ((torrentFile.downloadUri() != null) && (torrentFile.downloadUri().length() > 0)) {
241                                                 htmlBuilder.append("<a href=\"").append(StringEscapeUtils.escapeHtml4(torrentFile.downloadUri())).append("\">Download</a>");
242                                         }
243                                         htmlBuilder.append("</div>\n");
244                                 }
245                                 htmlBuilder.append("</ul>\n");
246                         }
247                         htmlBuilder.append("</ul>\n");
248                 }
249                 htmlBuilder.append("</body></html>\n");
250                 return htmlBuilder.toString();
251         }
252
253 }