## Internal Concepts
-The core of Rhynodge comprises ``Reaction``s which in turn consist of ``Query``s, ``Filter``s, ``Trigger``s, and ``Action``s.
+The core of Rhynodge comprises ``Reaction``s which in turn consist of ``Query``s, ``Filter``s, ``Merger``s, and ``Action``s.
### Query
The result of a ``Filter`` is a ``State``, again.
-### Trigger
+### Merger
-A trigger decides if, given the current state and the previous state, a noteworthy change has occured. It could calculate the difference between two file lists, or of two Facebook post lists.
+A merger merges two states into a new state; the new state is responsible for detecting whether a noteworthy change has occured.
-The result of a ``Trigger`` is an ``Output``.
+The result of a ``Merger`` isâââonce againâââa ``State``.
### Watcher
-A watcher combines a query, a list of filters, and a trigger into a single unit which can be configured a lot easier than the separate components. For example, you could have a âTwitterâ that finds new status updates for a username and that only needs to be configured with that username; the rest of the configuration is contained in the watcher.
+A watcher combines a query, a list of filters, and a merger into a single unit which can be configured a lot easier than the separate components. For example, you could have a âTwitterâ that finds new status updates for a username and that only needs to be configured with that username; the rest of the configuration is contained in the watcher.
-A ``Watcher`` does not do any processing but instead offers a ``Query``, a list of ``Filter``s, and a ``Trigger``.
+A ``Watcher`` does not do any processing but instead offers a ``Query``, a list of ``Filter``s, and a ``Merger``.
### Action
-If a trigger found a change, the action is then executed. Again, an action can be almost anything: it can send an email, it can execute programs, print documents, initiate phone calls, take a picture from a webcamââ anything you can program can be used an an action.
+If a noteworthy change has been detected, the action is then executed. Again, an action can be almost anything: it can send an email, it can execute programs, print documents, initiate phone calls, take a picture from a webcamâââanything you can program can be used an an action.
import net.pterodactylus.rhynodge.output.Output;
/**
- * An action is performed when a {@link Trigger} determines that two given
- * {@link State}s of a {@link Query} signify a change.
+ * An action is performed when a {@link State} has {@link State#triggered()}
+ * a noteworthy change.
*
* @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
*/
import org.jetbrains.annotations.NotNull;
/**
- * Defines a filter that runs between {@link Query}s and {@link Trigger}s and
+ * Defines a filter that runs between {@link Query}s and {@link Merger}s and
* can be used to convert a {@link State} into another {@link State}. This can
* be used to extract further information from a state.
* <p>
import com.google.common.collect.Lists;
/**
- * A {@code Reaction} binds together {@link Query}s, {@link Trigger}s, and
+ * A {@code Reaction} binds together {@link Query}s, {@link Merger}s, and
* {@link Action}s, and it stores the intermediary {@link State}s.
*
* @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
/** The filters to run. */
private final List<Filter> filters = Lists.newArrayList();
- /** The trigger to detect changes. */
- private final Trigger trigger;
+ /** The merger merges old and new states. */
+ private final Merger merger;
/** The action to perform. */
private final Action action;
* The name of the reaction
* @param query
* The query to run
- * @param trigger
- * The trigger to detect changes
+ * @param merger
+ * The merger to merge states
* @param action
* The action to perform
*/
- public Reaction(String name, Query query, Trigger trigger, Action action) {
- this(name, query, Collections.<Filter> emptyList(), trigger, action);
+ public Reaction(String name, Query query, Merger merger, Action action) {
+ this(name, query, Collections.<Filter> emptyList(), merger, action);
}
/**
* The query to run
* @param filters
* The filters to run
- * @param trigger
- * The trigger to detect changes
+ * @param merger
+ * The merger to merge states
* @param action
* The action to perform
*/
- public Reaction(String name, Query query, List<Filter> filters, Trigger trigger, Action action) {
+ public Reaction(String name, Query query, List<Filter> filters, Merger merger, Action action) {
this.name = name;
this.query = query;
this.filters.addAll(filters);
- this.trigger = trigger;
+ this.merger = merger;
this.action = action;
}
}
/**
- * Returns the trigger to detect changes.
+ * Returns the merger to merge states.
*
- * @return The trigger to detect changes
+ * @return The merger to merge states
*/
- public Trigger trigger() {
- return trigger;
+ public Merger merger() {
+ return merger;
}
/**
*/
boolean success();
+ /**
+ * Returns whether this state triggers a change notification. This can
+ * only return {@code true} if this state is the result of a
+ * {@link Merger} merging two states.
+ *
+ * @return {@code true} if this state triggers a change notification,
+ * {@code false} otherwise
+ */
+ default boolean triggered() {
+ return false;
+ }
+
boolean isEmpty();
/**
+++ /dev/null
-/*
- * Rhynodge - Trigger.java - Copyright Š 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.rhynodge;
-
-import net.pterodactylus.rhynodge.states.FileState;
-
-/**
- * A trigger determines whether two different states actually warrant a change
- * trigger. For example, two {@link FileState}s might contain different file
- * sizes but a trigger might only care about whether the file appeared or
- * disappeared since the last check.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
- */
-public interface Trigger {
-
- /**
- * Merges the current state into the previous state, returning the merged
- * state.
- *
- * @param previousState
- * The previous state of the system
- * @param currentState
- * The current state of a system
- * @return The new state, containing a meaningful merge between the previous
- * and the current state
- */
- State mergeStates(State previousState, State currentState);
-
- /**
- * Checks whether the states given to {@link #mergeStates(State, State)}
- * warrant a change trigger.
- *
- * @return {@code true} if the states given to
- * {@link #mergeStates(State, State)} warrant a change trigger,
- * {@code false} otherwise
- */
- boolean triggers();
-
-}
/**
* A {@code Watcher} combines a {@link Query}, a number of {@link Filter}s, and
- * a {@link Trigger}, as these parts are closely related after all.
+ * a {@link Merger}, as these parts are closely related after all.
*
* @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
*/
public List<Filter> filters();
/**
- * Returns the trigger of the watcher.
+ * Returns the merger of the watcher.
*
- * @return The trigger of the watcher
+ * @return The merger of the watcher
*/
- public Trigger trigger();
+ public Merger merger();
}
import net.pterodactylus.rhynodge.Query;
import net.pterodactylus.rhynodge.Reaction;
import net.pterodactylus.rhynodge.State;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.actions.EmailAction;
+import net.pterodactylus.rhynodge.Merger;
import net.pterodactylus.rhynodge.output.DefaultOutput;
import net.pterodactylus.rhynodge.output.Output;
import net.pterodactylus.rhynodge.states.FailedState;
/**
* Runs a {@link Reaction}, starting with its {@link Query}, running the {@link
- * State} through its {@link Filter}s, and finally checking the {@link Trigger}
+ * State} through its {@link Filter}s, and finally checking the {@link Merger}
* for whether an {@link Action} needs to be executed.
*
* @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
reactionState.saveState(state);
return;
}
- Trigger trigger = reaction.trigger();
- State newState = trigger.mergeStates(lastSuccessfulState.get(), state);
+ Merger merger = reaction.merger();
+ State newState = merger.mergeStates(lastSuccessfulState.get(), state);
reactionState.saveState(newState);
- if (trigger.triggers()) {
+ if (newState.triggered()) {
logger.info(format("Trigger was hit for %s, executing action...", reaction.name()));
reaction.action().execute(newState.output(reaction));
}
@JsonProperty
private List<Part> filters = new ArrayList<Part>();
- /** The trigger of the chain. */
+ /** The merger of the chain. */
@JsonProperty
- private Part trigger;
+ private Part merger;
- /** A combination of query, filters, and a trigger. */
+ /** A combination of query, filters, and a merger. */
@JsonProperty
private Part watcher;
}
/**
- * Returns the trigger of this chain.
+ * Returns the merger of this chain.
*
- * @return The trigger of this chain
+ * @return The merger of this chain
*/
- public Part trigger() {
- return trigger;
+ public Part merger() {
+ return merger;
}
/**
for (Part filter : filters) {
hashCode ^= filter.hashCode();
}
- hashCode ^= trigger.hashCode();
+ hashCode ^= merger.hashCode();
}
hashCode ^= action.hashCode();
hashCode ^= updateInterval;
return false;
}
}
- if (!trigger.equals(chain.trigger)) {
+ if (!merger.equals(chain.merger)) {
return false;
}
}
logger.debug(String.format(" Parameter: %s=%s", parameter.name(), parameter.value()));
}
}
- logger.debug(String.format(" Trigger: %s", chain.trigger().name()));
- for (Parameter parameter : chain.trigger().parameters()) {
+ logger.debug(String.format(" Trigger: %s", chain.merger().name()));
+ for (Parameter parameter : chain.merger().parameters()) {
logger.debug(String.format(" Parameter: %s=%s", parameter.name(), parameter.value()));
}
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
import net.pterodactylus.rhynodge.Reaction;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.loader.Chain.Parameter;
import net.pterodactylus.rhynodge.loader.Chain.Part;
+import net.pterodactylus.rhynodge.Merger;
/**
* Creates {@link Reaction}s from {@link Chain}s.
Watcher watcher = createObject(chain.watcher().name(), "net.pterodactylus.rhynodge.watchers", extractParameters(chain.watcher().parameters()));
/* create reaction. */
- reaction = new Reaction(chain.name(), watcher.query(), watcher.filters(), watcher.trigger(), action);
+ reaction = new Reaction(chain.name(), watcher.query(), watcher.filters(), watcher.merger(), action);
} else {
filters.add(ReactionLoader.<Filter> createObject(filterPart.name(), "net.pterodactylus.rhynodge.filters", extractParameters(filterPart.parameters())));
}
- /* create trigger. */
- Trigger trigger = createObject(chain.trigger().name(), "net.pterodactylus.rhynodge.triggers", extractParameters(chain.trigger().parameters()));
+ /* create merger. */
+ Merger merger = createObject(chain.merger().name(), "net.pterodactylus.rhynodge.mergers", extractParameters(chain.merger().parameters()));
/* create reaction. */
- reaction = new Reaction(chain.name(), query, filters, trigger, action);
+ reaction = new Reaction(chain.name(), query, filters, merger, action);
}
reaction.setUpdateInterval(TimeUnit.SECONDS.toMillis(chain.updateInterval()));
--- /dev/null
+/*
+ * rhynodge - ComicMerger.java - Copyright Š 2013â2021 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.rhynodge.mergers;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+
+import net.pterodactylus.rhynodge.Merger;
+import net.pterodactylus.rhynodge.State;
+import net.pterodactylus.rhynodge.states.ComicState;
+import net.pterodactylus.rhynodge.states.ComicState.Comic;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * {@link Merger} implementation that merger two {@link ComicState}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
+ */
+public class ComicMerger implements Merger {
+
+ @Nonnull
+ @Override
+ public State mergeStates(@Nonnull State previousState, @Nonnull State currentState) {
+ checkArgument(previousState instanceof ComicState, "previous state must be a comic state");
+ checkArgument(currentState instanceof ComicState, "current state must be a comic state");
+
+ ComicState previousComicState = (ComicState) previousState;
+ ComicState currentComicState = (ComicState) currentState;
+
+ List<Comic> allComics = new ArrayList<>(previousComicState.comics());
+ Set<Comic> newComics = new HashSet<>();
+
+ for (Comic comic : currentComicState) {
+ if (!allComics.contains(comic)) {
+ allComics.add(comic);
+ newComics.add(comic);
+ }
+ }
+
+ return new ComicState(allComics, newComics);
+ }
+
+}
--- /dev/null
+/*
+ * Rhynodge - EpisodeMerger.java - Copyright Š 2013â2021 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.rhynodge.mergers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import net.pterodactylus.rhynodge.Merger;
+import net.pterodactylus.rhynodge.State;
+import net.pterodactylus.rhynodge.states.EpisodeState;
+import net.pterodactylus.rhynodge.states.EpisodeState.Episode;
+import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
+
+/**
+ * {@link Merger} implementation that merges two {@link EpisodeState}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
+ */
+public class EpisodeMerger implements Merger {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nonnull
+ @Override
+ public State mergeStates(@Nonnull State previousState, @Nonnull State currentState) {
+ checkState(currentState instanceof EpisodeState, "currentState is not a EpisodeState but a %s", currentState.getClass().getName());
+ checkState(previousState instanceof EpisodeState, "previousState is not a EpisodeState but a %s", currentState.getClass().getName());
+
+ Collection<Episode> newEpisodes = new HashSet<>();
+ Collection<Episode> changedEpisodes = new HashSet<>();
+ Collection<TorrentFile> newTorrentFiles = new HashSet<>();
+ Map<Episode, Episode> allEpisodes = ((EpisodeState) previousState).episodes().stream().collect(toMap(identity(), identity()));
+ for (Episode episode : ((EpisodeState) currentState).episodes()) {
+ if (!allEpisodes.containsKey(episode)) {
+ allEpisodes.put(episode, episode);
+ newEpisodes.add(episode);
+ }
+ Episode existingEpisode = allEpisodes.get(episode);
+ for (TorrentFile torrentFile : new ArrayList<>(episode.torrentFiles())) {
+ int oldSize = existingEpisode.torrentFiles().size();
+ existingEpisode.addTorrentFile(torrentFile);
+ int newSize = existingEpisode.torrentFiles().size();
+ if (oldSize != newSize) {
+ newTorrentFiles.add(torrentFile);
+ }
+ if (!newEpisodes.contains(existingEpisode) && (oldSize != newSize)) {
+ changedEpisodes.add(existingEpisode);
+ }
+ }
+ }
+ return new EpisodeState(allEpisodes.values(), newEpisodes, changedEpisodes, newTorrentFiles);
+ }
+
+}
--- /dev/null
+/*
+ * Rhynodge - TorrentMerger.java - Copyright Š 2013â2021 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.rhynodge.mergers;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.Nonnull;
+
+import net.pterodactylus.rhynodge.Merger;
+import net.pterodactylus.rhynodge.State;
+import net.pterodactylus.rhynodge.states.TorrentState;
+import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * {@link Merger} implementation that merges two {@link TorrentState}s, taking
+ * careful note of which {@link TorrentFile}s appear in the current
+ * {@link TorrentState} but not in the previous one.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
+ */
+public class TorrentMerger implements Merger {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nonnull
+ @Override
+ public State mergeStates(@Nonnull State previousState, @Nonnull State currentState) {
+ checkState(currentState instanceof TorrentState, "currentState is not a TorrentState but a %s", currentState.getClass().getName());
+ checkState(previousState instanceof TorrentState, "previousState is not a TorrentState but a %s", currentState.getClass().getName());
+
+ Set<TorrentFile> allTorrentFiles = new HashSet<>(((TorrentState) previousState).torrentFiles());
+ Set<TorrentFile> newTorrentFiles = new HashSet<>();
+ for (TorrentFile torrentFile : (TorrentState) currentState) {
+ if (allTorrentFiles.add(torrentFile)) {
+ newTorrentFiles.add(torrentFile);
+ }
+ }
+
+ return new TorrentState(allTorrentFiles, newTorrentFiles);
+ }
+
+}
package net.pterodactylus.rhynodge.output;
-import net.pterodactylus.rhynodge.Trigger;
+import net.pterodactylus.rhynodge.State;
/**
- * Defines the output of a {@link Trigger}. As different output has to be
+ * Defines the output of a {@link State}. As different output has to be
* generated for different media, the {@link #text(String)} method takes as
* an argument the MIME type of the desired output.
*
*
* @param mimeType
* The MIME type of the text (âtext/plainâ and âtext/htmlâ should
- * be supported by all {@link Trigger}s)
+ * be supported by all {@link State}s)
* @return The text for the given MIME type, or {@code null} if there is no
* text defined for the given MIME type
*/
* <p>
* A {@link net.pterodactylus.rhynodge.Reaction} consists of three different
* elements: a {@link net.pterodactylus.rhynodge.Query}, a
- * {@link net.pterodactylus.rhynodge.Trigger}, and an
+ * {@link net.pterodactylus.rhynodge.Merger}, and an
* {@link net.pterodactylus.rhynodge.Action}.
* <p>
* A {@code Query} retrieves the current state of a system; this can simply be
* <p>
* After a {@code Query} retrieved the current
* {@link net.pterodactylus.rhynodge.State} of a system, this state and the
- * previously retrieved state are handed in to a {@code Trigger}. The trigger
- * then decides whether the state of the system can be considered a change.
+ * previously retrieved state are handed in to a {@code Merger}. The merger
+ * takes care of merging the two states in a way that the new state can
+ * {@link net.pterodactylus.rhynodge.State#triggered() decide} whether a
+ * noteworthy change has occured.
* <p>
* If a system has been found to trigger, an {@code Action} is executed. It
* performs arbitrary actions and can use both the current state and the
return comics.isEmpty();
}
+ @Override
+ public boolean triggered() {
+ return !newComics.isEmpty();
+ }
+
public List<Comic> comics() {
return comics;
}
return episodes.isEmpty();
}
+ @Override
+ public boolean triggered() {
+ return !newEpisodes.isEmpty() || !changedEpisodes.isEmpty() || !newTorrentFiles.isEmpty();
+ }
+
/**
* Returns all episodes contained in this state.
*
return files.isEmpty();
}
+ @Override
+ public boolean triggered() {
+ return !newTorrentFiles.isEmpty();
+ }
+
/**
* Returns all torrent files of this state.
*
+++ /dev/null
-/*
- * Rhynodge - AlwaysTrigger.java - Copyright Š 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.rhynodge.triggers;
-
-import net.pterodactylus.rhynodge.State;
-import net.pterodactylus.rhynodge.Trigger;
-
-/**
- * {@link Trigger} implementation that always triggers.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
- */
-public class AlwaysTrigger implements Trigger {
-
- private State currentState;
-
- /**
- * {@inheritDoc}
- * <p>
- * This implementation returns the current state.
- */
- @Override
- public State mergeStates(State previousState, State currentState) {
- this.currentState = currentState;
- return currentState;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * This implementation always returns {@code true}.
- */
- @Override
- public boolean triggers() {
- return true;
- }
-
-}
+++ /dev/null
-/*
- * rhynodge - NewComicTrigger.java - Copyright Š 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.rhynodge.triggers;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import net.pterodactylus.rhynodge.State;
-import net.pterodactylus.rhynodge.Trigger;
-import net.pterodactylus.rhynodge.states.ComicState;
-import net.pterodactylus.rhynodge.states.ComicState.Comic;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-/**
- * {@link Trigger} implementation that detects the presence of new {@link
- * Comic}s in a {@link ComicState}.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
- */
-public class NewComicTrigger implements Trigger {
-
- private boolean triggered = false;
-
- @Override
- public State mergeStates(State previousState, State currentState) {
- checkArgument(previousState instanceof ComicState, "previous state must be a comic state");
- checkArgument(currentState instanceof ComicState, "current state must be a comic state");
-
- ComicState previousComicState = (ComicState) previousState;
- ComicState currentComicState = (ComicState) currentState;
-
- List<Comic> allComics = new ArrayList<>(previousComicState.comics());
- Set<Comic> newComics = new HashSet<>();
-
- for (Comic comic : currentComicState) {
- if (!allComics.contains(comic)) {
- allComics.add(comic);
- newComics.add(comic);
- triggered = true;
- }
- }
-
- return new ComicState(allComics, newComics);
- }
-
- @Override
- public boolean triggers() {
- return triggered;
- }
-
-}
+++ /dev/null
-/*
- * Rhynodge - NewEpisodeTrigger.java - Copyright Š 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.rhynodge.triggers;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-
-import net.pterodactylus.rhynodge.State;
-import net.pterodactylus.rhynodge.Trigger;
-import net.pterodactylus.rhynodge.states.EpisodeState;
-import net.pterodactylus.rhynodge.states.EpisodeState.Episode;
-import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
-
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.function.Function.identity;
-import static java.util.stream.Collectors.toMap;
-
-/**
- * {@link Trigger} implementation that compares two {@link EpisodeState}s for
- * new and changed {@link Episode}s.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
- */
-public class NewEpisodeTrigger implements Trigger {
-
- private boolean triggered = false;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public State mergeStates(State previousState, State currentState) {
- checkState(currentState instanceof EpisodeState, "currentState is not a EpisodeState but a %s", currentState.getClass().getName());
- checkState(previousState instanceof EpisodeState, "previousState is not a EpisodeState but a %s", currentState.getClass().getName());
-
- Collection<Episode> newEpisodes = new HashSet<>();
- Collection<Episode> changedEpisodes = new HashSet<>();
- Collection<TorrentFile> newTorrentFiles = new HashSet<>();
- Map<Episode, Episode> allEpisodes = ((EpisodeState) previousState).episodes().stream().collect(toMap(identity(), identity()));
- for (Episode episode : ((EpisodeState) currentState).episodes()) {
- if (!allEpisodes.containsKey(episode)) {
- allEpisodes.put(episode, episode);
- newEpisodes.add(episode);
- triggered = true;
- }
- Episode existingEpisode = allEpisodes.get(episode);
- for (TorrentFile torrentFile : new ArrayList<>(episode.torrentFiles())) {
- int oldSize = existingEpisode.torrentFiles().size();
- existingEpisode.addTorrentFile(torrentFile);
- int newSize = existingEpisode.torrentFiles().size();
- if (oldSize != newSize) {
- newTorrentFiles.add(torrentFile);
- }
- if (!newEpisodes.contains(existingEpisode) && (oldSize != newSize)) {
- changedEpisodes.add(existingEpisode);
- }
- }
- }
- return new EpisodeState(allEpisodes.values(), newEpisodes, changedEpisodes, newTorrentFiles);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean triggers() {
- return triggered;
- }
-
-}
+++ /dev/null
-/*
- * Rhynodge - NewTorrentTrigger.java - Copyright Š 2013 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.rhynodge.triggers;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import net.pterodactylus.rhynodge.State;
-import net.pterodactylus.rhynodge.Trigger;
-import net.pterodactylus.rhynodge.states.TorrentState;
-import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
-
-import static com.google.common.base.Preconditions.checkState;
-
-/**
- * {@link Trigger} implementation that is triggered by {@link TorrentFile}s that
- * appear in the current {@link TorrentState} but not in the previous one.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David âBombeâ Roden</a>
- */
-public class NewTorrentTrigger implements Trigger {
-
- private boolean triggered = false;
-
- //
- // TRIGGER METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public State mergeStates(State previousState, State currentState) {
- checkState(currentState instanceof TorrentState, "currentState is not a TorrentState but a %s", currentState.getClass().getName());
- checkState(previousState instanceof TorrentState, "previousState is not a TorrentState but a %s", currentState.getClass().getName());
-
- Set<TorrentFile> allTorrentFiles = new HashSet<>(((TorrentState) previousState).torrentFiles());
- Set<TorrentFile> newTorrentFiles = new HashSet<>();
- for (TorrentFile torrentFile : (TorrentState) currentState) {
- if (allTorrentFiles.add(torrentFile)) {
- newTorrentFiles.add(torrentFile);
- triggered = true;
- }
- }
-
- return new TorrentState(allTorrentFiles, newTorrentFiles);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean triggers() {
- return triggered;
- }
-
-}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.AbstruseGooseComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Abstruse Goose comics.
public class AbstruseGooseWatcher extends DefaultWatcher {
public AbstruseGooseWatcher() {
- super(new HttpQuery("http://abstrusegoose.com/"), Arrays.asList(new HtmlFilter(), new AbstruseGooseComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://abstrusegoose.com/"), Arrays.asList(new HtmlFilter(), new AbstruseGooseComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.Collar6ComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Collar 6 comics.
/** Creates a new watcher for Cyanide and Happiness comics. */
public Collar6Watcher() {
- super(new HttpQuery("http://collar6.com/"), Arrays.asList(new HtmlFilter(), new Collar6ComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://collar6.com/"), Arrays.asList(new HtmlFilter(), new Collar6ComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.CtrlAltDelComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Ctrl Alt Del comics.
/** Creates a new watcher for Cyanide and Happiness comics. */
public CtrlAltDelWatcher() {
- super(new HttpQuery("http://www.cad-comic.com/cad/"), Arrays.asList(new HtmlFilter(), new CtrlAltDelComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.cad-comic.com/cad/"), Arrays.asList(new HtmlFilter(), new CtrlAltDelComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.CyanideAndHappinessComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Cyanide and Happiness
/** Creates a new watcher for Cyanide and Happiness comics. */
public CyanideAndHappinessWatcher() {
- super(new HttpQuery("http://www.explosm.net/comics/new/"), Arrays.asList(new HtmlFilter(), new CyanideAndHappinessComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.explosm.net/comics/new/"), Arrays.asList(new HtmlFilter(), new CyanideAndHappinessComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.Watcher;
+import net.pterodactylus.rhynodge.Merger;
/**
* Abstract base implementation of a {@link Watcher}.
/** The filters of the watcher. */
private final List<Filter> filters = new ArrayList<Filter>();
- /** The trigger of the watcher. */
- private final Trigger trigger;
+ /** The merger of the watcher. */
+ private final Merger merger;
/**
* Creates a new default watcher.
* The query of the watcher
* @param filters
* The filters of the watcher
- * @param trigger
- * The trigger of the watcher
+ * @param merger
+ * The merger of the watcher
*/
- protected DefaultWatcher(Query query, List<Filter> filters, Trigger trigger) {
+ protected DefaultWatcher(Query query, List<Filter> filters, Merger merger) {
this.query = query;
this.filters.addAll(filters);
- this.trigger = trigger;
+ this.merger = merger;
}
//
return filters;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public Trigger trigger() {
- return trigger;
+ public Merger merger() {
+ return merger;
}
}
import net.pterodactylus.rhynodge.filters.HtmlFilter
import net.pterodactylus.rhynodge.filters.comics.DrugsAndWiresComicFilter
+import net.pterodactylus.rhynodge.mergers.ComicMerger
import net.pterodactylus.rhynodge.queries.HttpQuery
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger
-class DrugsAndWiresWatcher: DefaultWatcher(query, filters, trigger)
+class DrugsAndWiresWatcher: DefaultWatcher(query, filters, merger)
private val query = HttpQuery("https://www.drugsandwires.fail/")
private val filters = listOf(HtmlFilter(), DrugsAndWiresComicFilter())
-private val trigger = NewComicTrigger()
+private val merger = ComicMerger()
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.GeneralProtectionFaultComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new General Protection Fault
/** Creates a new watcher for Cyanide and Happiness comics. */
public GeneralProtectionFaultWatcher() {
- super(new HttpQuery("http://www.gpf-comics.com/"), Arrays.asList(new HtmlFilter(), new GeneralProtectionFaultComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.gpf-comics.com/"), Arrays.asList(new HtmlFilter(), new GeneralProtectionFaultComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.GirlGeniusComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Genius Girl comics.
/** Creates a new watcher for Cyanide and Happiness comics. */
public GirlGeniusWatcher() {
- super(new HttpQuery("http://www.girlgeniusonline.com/comic.php"), Arrays.asList(new HtmlFilter(), new GirlGeniusComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.girlgeniusonline.com/comic.php"), Arrays.asList(new HtmlFilter(), new GirlGeniusComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.HeldentageFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new âHeldentageâ comics.
public class HeldentageWatcher extends DefaultWatcher {
public HeldentageWatcher() {
- super(new HttpQuery("http://www.der-flix.de/"), asList(new HtmlFilter(), new HeldentageFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.der-flix.de/"), asList(new HtmlFilter(), new HeldentageFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.KevinAndKellComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Kevin and Kell comics.
/** Creates a new watcher for Cyanide and Happiness comics. */
public KevinAndKellWatcher() {
- super(new HttpQuery("http://www.kevinandkell.com/"), Arrays.asList(new HtmlFilter(), new KevinAndKellComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.kevinandkell.com/"), Arrays.asList(new HtmlFilter(), new KevinAndKellComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.EpisodeFilter;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.KickAssTorrentsFilter;
+import net.pterodactylus.rhynodge.mergers.EpisodeMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewEpisodeTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public KickAssTorrentsEpisodeWatcher(String searchTerms) {
- super(createHttpQuery(searchTerms), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms), createFilters(), new EpisodeMerger());
}
//
return ImmutableList.of(new HtmlFilter(), new KickAssTorrentsFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter(), new EpisodeFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewEpisodeTrigger();
- }
-
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.KickAssTorrentsFilter;
+import net.pterodactylus.rhynodge.mergers.TorrentMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewTorrentTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public KickAssTorrentsWatcher(String searchTerms) {
- super(createHttpQuery(searchTerms), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms), createFilters(), new TorrentMerger());
}
//
return ImmutableList.of(new HtmlFilter(), new KickAssTorrentsFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewTorrentTrigger();
- }
-
}
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.HttpQueryFilter;
import net.pterodactylus.rhynodge.filters.comics.LeastICouldDoComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
/** Creates a new âLeast I Could Doâ watcher. */
public LeastICouldDoWatcher() {
- super(new HttpQuery("http://www.leasticoulddo.com/"), createFilters(), new NewComicTrigger());
+ super(new HttpQuery("http://www.leasticoulddo.com/"), createFilters(), new ComicMerger());
}
//
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.EpisodeFilter;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.PirateBayFilter;
+import net.pterodactylus.rhynodge.mergers.EpisodeMerger;
import net.pterodactylus.rhynodge.queries.FallbackQuery;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewEpisodeTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public PirateBayEpisodeWatcher(String searchTerms, String proxy) {
- super(createHttpQuery(searchTerms, extractProxyHost(proxy), extractProxyPort(proxy)), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms, extractProxyHost(proxy), extractProxyPort(proxy)), createFilters(), new EpisodeMerger());
}
private static String extractProxyHost(String proxy) {
return ImmutableList.of(new HtmlFilter(), new PirateBayFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter(), new EpisodeFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewEpisodeTrigger();
- }
-
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.PirateBayFilter;
+import net.pterodactylus.rhynodge.mergers.TorrentMerger;
import net.pterodactylus.rhynodge.queries.FallbackQuery;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewTorrentTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public PirateBayWatcher(String searchTerms, String proxy) {
- super(createHttpQuery(searchTerms, extractProxyHost(proxy), extractProxyPort(proxy)), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms, extractProxyHost(proxy), extractProxyPort(proxy)), createFilters(), new TorrentMerger());
}
private static String extractProxyHost(String proxy) {
return ImmutableList.of(new HtmlFilter(), new PirateBayFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewTorrentTrigger();
- }
-
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.PoorlyDrawnLinesComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Poorly Drawn Lines
/** Creates a new watcher for Cyanide and Happiness comics. */
public PoorlyDrawnLinesWatcher() {
- super(new HttpQuery("http://poorlydrawnlines.com/"), Arrays.asList(new HtmlFilter(), new PoorlyDrawnLinesComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://poorlydrawnlines.com/"), Arrays.asList(new HtmlFilter(), new PoorlyDrawnLinesComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.SaturdayMorningBreakfastCerealComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link Watcher} implementation that watches for new Saturday Morning
/** Creates a new watcher for Cyanide and Happiness comics. */
public SaturdayMorningBreakfastCerealWatcher() {
- super(new HttpQuery("http://www.smbc-comics.com/"), Arrays.asList(new HtmlFilter(), new SaturdayMorningBreakfastCerealComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.smbc-comics.com/"), Arrays.asList(new HtmlFilter(), new SaturdayMorningBreakfastCerealComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Watcher;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.webpages.savoy.SavoyTicketsFilter;
+import net.pterodactylus.rhynodge.mergers.LastStateMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.AlwaysTrigger;
/**
* {@link Watcher} implementation that shows tickets sold in the Savoy theatre.
new HtmlFilter(),
new SavoyTicketsFilter()
),
- new AlwaysTrigger()
+ new LastStateMerger()
);
}
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.HttpQueryFilter;
import net.pterodactylus.rhynodge.filters.comics.ScandinaviaAndTheWorldComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
public class ScandinaviaAndTheWorldWatcher extends DefaultWatcher {
public ScandinaviaAndTheWorldWatcher() {
- super(new HttpQuery("http://satwcomic.com/"), createFilters(), new NewComicTrigger());
+ super(new HttpQuery("http://satwcomic.com/"), createFilters(), new ComicMerger());
}
private static List<Filter> createFilters() {
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.SinfestComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link net.pterodactylus.rhynodge.Watcher} implementation that watches
public class SinfestWatcher extends DefaultWatcher {
public SinfestWatcher() {
- super(new HttpQuery("http://www.sinfest.net/"), Arrays.asList(new HtmlFilter(), new SinfestComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://www.sinfest.net/"), Arrays.asList(new HtmlFilter(), new SinfestComicFilter()), new ComicMerger());
}
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.filters.EpisodeFilter;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.TorrentHoundFilter;
+import net.pterodactylus.rhynodge.mergers.EpisodeMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewEpisodeTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public TorrentHoundEpisodeWatcher(String searchTerms) {
- super(createHttpQuery(searchTerms), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms), createFilters(), new EpisodeMerger());
}
//
return ImmutableList.of(new HtmlFilter(), new TorrentHoundFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter(), new EpisodeFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewEpisodeTrigger();
- }
-
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.TorrentHoundFilter;
+import net.pterodactylus.rhynodge.mergers.TorrentMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewTorrentTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public TorrentHoundWatcher(String searchTerms) {
- super(createHttpQuery(searchTerms), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms), createFilters(), new TorrentMerger());
}
//
return ImmutableList.of(new HtmlFilter(), new TorrentHoundFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewTorrentTrigger();
- }
-
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
import net.pterodactylus.rhynodge.filters.EpisodeFilter;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.TorrentzEuFilter;
+import net.pterodactylus.rhynodge.mergers.EpisodeMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewEpisodeTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public TorrentzEuEpisodeWatcher(String searchTerms) {
- super(createHttpQuery(searchTerms), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms), createFilters(), new EpisodeMerger());
}
//
return ImmutableList.of(new HtmlFilter(), new TorrentzEuFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter(), new EpisodeFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewEpisodeTrigger();
- }
-
}
import net.pterodactylus.rhynodge.Filter;
import net.pterodactylus.rhynodge.Query;
-import net.pterodactylus.rhynodge.Trigger;
-import net.pterodactylus.rhynodge.filters.EpisodeFilter;
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.SizeBlacklistFilter;
import net.pterodactylus.rhynodge.filters.torrents.TorrentzEuFilter;
+import net.pterodactylus.rhynodge.mergers.TorrentMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewEpisodeTrigger;
import com.google.common.collect.ImmutableList;
* The terms to search for
*/
public TorrentzEuWatcher(String searchTerms) {
- super(createHttpQuery(searchTerms), createFilters(), createTrigger());
+ super(createHttpQuery(searchTerms), createFilters(), new TorrentMerger());
}
//
return ImmutableList.of(new HtmlFilter(), new TorrentzEuFilter(), createDefaultBlacklistFilter(), new SizeBlacklistFilter());
}
- /**
- * Creates the trigger of the watcher.
- *
- * @return The trigger of the watcher
- */
- private static Trigger createTrigger() {
- return new NewEpisodeTrigger();
- }
-
}
import net.pterodactylus.rhynodge.filters.HtmlFilter;
import net.pterodactylus.rhynodge.filters.comics.XkcdComicFilter;
+import net.pterodactylus.rhynodge.mergers.ComicMerger;
import net.pterodactylus.rhynodge.queries.HttpQuery;
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger;
/**
* {@link net.pterodactylus.rhynodge.Watcher} implementation that watches XKCD
/** Creates a new XKCD watcher. */
public XkcdWatcher() {
- super(new HttpQuery("http://xkcd.com/"), Arrays.asList(new HtmlFilter(), new XkcdComicFilter()), new NewComicTrigger());
+ super(new HttpQuery("http://xkcd.com/"), Arrays.asList(new HtmlFilter(), new XkcdComicFilter()), new ComicMerger());
}
}
--- /dev/null
+package net.pterodactylus.rhynodge
+
+interface Merger {
+
+ fun mergeStates(previousState: State, currentState: State): State
+
+}
--- /dev/null
+package net.pterodactylus.rhynodge.mergers
+
+import net.pterodactylus.rhynodge.Merger
+import net.pterodactylus.rhynodge.State
+
+/**
+ * [Merger] implementation that always returns the current state.
+ */
+class LastStateMerger : Merger {
+
+ override fun mergeStates(previousState: State, currentState: State) = currentState
+
+}
import net.pterodactylus.rhynodge.filters.HtmlFilter
import net.pterodactylus.rhynodge.filters.comics.BusinessCatComicFilter
+import net.pterodactylus.rhynodge.mergers.ComicMerger
import net.pterodactylus.rhynodge.queries.HttpQuery
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger
-class BusinessCatWatcher : DefaultWatcher(query, filters, trigger)
+class BusinessCatWatcher : DefaultWatcher(query, filters, merger)
private val query = HttpQuery("https://www.businesscatcomic.com/")
private val filters = listOf(HtmlFilter(), BusinessCatComicFilter())
-private val trigger = NewComicTrigger()
+private val merger = ComicMerger()
import net.pterodactylus.rhynodge.filters.HtmlFilter
import net.pterodactylus.rhynodge.filters.comics.QuestionableContentComicFilter
+import net.pterodactylus.rhynodge.mergers.ComicMerger
import net.pterodactylus.rhynodge.queries.HttpQuery
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger
-class QuestionableContentWatcher : DefaultWatcher(query, filters, trigger)
+class QuestionableContentWatcher : DefaultWatcher(query, filters, merger)
private val query = HttpQuery("https://www.questionablecontent.net/")
private val filters = listOf(HtmlFilter(), QuestionableContentComicFilter())
-private val trigger = NewComicTrigger()
+private val merger = ComicMerger()
import net.pterodactylus.rhynodge.filters.HtmlFilter
import net.pterodactylus.rhynodge.filters.comics.SoggyCardboardComicFilter
+import net.pterodactylus.rhynodge.mergers.ComicMerger
import net.pterodactylus.rhynodge.queries.HttpQuery
-import net.pterodactylus.rhynodge.triggers.NewComicTrigger
-class SoggyCardboardWatcher : DefaultWatcher(query, filters, trigger)
+class SoggyCardboardWatcher : DefaultWatcher(query, filters, merger)
private val query = HttpQuery("http://www.soggycardboard.com/")
private val filters = listOf(HtmlFilter(), SoggyCardboardComicFilter())
-private val trigger = NewComicTrigger()
+private val merger = ComicMerger()
import net.pterodactylus.rhynodge.filters.*
import net.pterodactylus.rhynodge.filters.comics.*
+import net.pterodactylus.rhynodge.mergers.ComicMerger
import net.pterodactylus.rhynodge.queries.*
-import net.pterodactylus.rhynodge.triggers.*
-class TheMonsterUnderTheBedWatcher : DefaultWatcher(query, filters, trigger)
+class TheMonsterUnderTheBedWatcher : DefaultWatcher(query, filters, merger)
private val query = HttpQuery("http://themonsterunderthebed.net/")
private val filters = listOf(HtmlFilter(), TheMonsterUnderTheBedFilter())
-private val trigger = NewComicTrigger()
+private val merger = ComicMerger()
}
],
- "trigger":
+ "merger":
{
- "class": "NewEpisodeTrigger"
+ "class": "EpisodeMerger"
},
"action":
}
],
- "trigger":
+ "merger":
{
- "class": "NewTorrentTrigger"
+ "class": "TorrentMerger"
},
"action":
private final Query query = mock(Query.class);
private final Filter filter = mock(Filter.class);
- private final Trigger trigger = mock(Trigger.class);
+ private final Merger merger = mock(Merger.class);
private final Action action = mock(Action.class);
- private final Reaction reactionWithoutFilters = new Reaction("without", query, trigger, action);
- private final Reaction reactionWithFilters = new Reaction("with", query, asList(filter), trigger, action);
+ private final Reaction reactionWithoutFilters = new Reaction("without", query, merger, action);
+ private final Reaction reactionWithFilters = new Reaction("with", query, asList(filter), merger, action);
@Test
public void reactionStoresNameCorrectly() {
}
@Test
- public void reactionStoresTriggerCorrectly() {
- assertThat(reactionWithoutFilters.trigger(), is(trigger));
- assertThat(reactionWithFilters.trigger(), is(trigger));
+ public void reactionStoresMergerCorrectly() {
+ assertThat(reactionWithoutFilters.merger(), is(merger));
+ assertThat(reactionWithFilters.merger(), is(merger));
}
@Test
--- /dev/null
+package net.pterodactylus.rhynodge.mergers
+
+import net.pterodactylus.rhynodge.states.ComicState
+import net.pterodactylus.rhynodge.states.ComicState.Comic
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.contains
+import org.junit.Test
+
+class ComicMergerTest {
+
+ private val comicMerger = ComicMerger()
+
+ @Test
+ fun `comic merger does not reorder comics`() {
+ val oldComicState = ComicState(generateListOfComics())
+ val newComicState = ComicState(generateListOfComics().plusElement(Comic("new 1")))
+ val mergedComicState = comicMerger.mergeStates(oldComicState, newComicState) as ComicState
+ assertThat(mergedComicState.comics(), contains(*generateListOfComics().plusElement(Comic("new 1")).toTypedArray()))
+ }
+
+}
+
+private fun generateListOfComics(): List<Comic> = (1..40).map { Comic("comic $it") }
--- /dev/null
+package net.pterodactylus.rhynodge.mergers
+
+import net.pterodactylus.rhynodge.State
+import net.pterodactylus.rhynodge.states.StateManagerTest.TestState
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.sameInstance
+import org.junit.Test
+
+class LastStateMergerTest {
+
+ @Test
+ fun `merging states returns the current state`() {
+ assertThat(merger.mergeStates(previousState, successfulState), sameInstance(successfulState))
+ }
+
+ private val merger = LastStateMerger()
+ private val previousState = TestState()
+ private val successfulState: State = TestState()
+
+}
+++ /dev/null
-package net.pterodactylus.rhynodge.triggers
-
-import net.pterodactylus.rhynodge.State
-import net.pterodactylus.rhynodge.states.FailedState
-import net.pterodactylus.rhynodge.states.StateManagerTest.TestState
-import org.hamcrest.MatcherAssert.assertThat
-import org.hamcrest.Matchers.equalTo
-import org.hamcrest.Matchers.sameInstance
-import org.junit.Test
-
-class AlwaysTriggerTest {
-
- @Test
- fun `merging states returns the current state`() {
- assertThat(trigger.mergeStates(previousState, successfulState), sameInstance(successfulState))
- }
-
- @Test
- fun `successful state triggers`() {
- trigger.mergeStates(previousState, successfulState)
- assertThat(trigger.triggers(), equalTo(true))
- }
-
- @Test
- fun `failed state also triggers`() {
- trigger.mergeStates(previousState, failedState)
- assertThat(trigger.triggers(), equalTo(true))
- }
-
- private val trigger = AlwaysTrigger()
- private val previousState = TestState()
- private val successfulState: State = TestState()
- private val failedState: State = FailedState()
-
-}
+++ /dev/null
-package net.pterodactylus.rhynodge.triggers
-
-import net.pterodactylus.rhynodge.states.ComicState
-import net.pterodactylus.rhynodge.states.ComicState.Comic
-import org.hamcrest.MatcherAssert.assertThat
-import org.hamcrest.Matchers.contains
-import org.hamcrest.Matchers.equalTo
-import org.junit.Test
-
-class NewComicTriggerTest {
-
- private val newComicTrigger = NewComicTrigger()
-
- @Test
- fun `comic trigger recognizes there are no new comic`() {
- val oldComicState = ComicState(generateListOfComics())
- val newComicState = ComicState(generateListOfComics())
- newComicTrigger.mergeStates(oldComicState, newComicState)
- assertThat(newComicTrigger.triggers(), equalTo(false))
- }
-
- @Test
- fun `comic trigger recognizes new comics`() {
- val oldComicState = ComicState(generateListOfComics())
- val newComicState = ComicState(generateListOfComics().plusElement(Comic("new 1")))
- newComicTrigger.mergeStates(oldComicState, newComicState)
- assertThat(newComicTrigger.triggers(), equalTo(true))
- }
-
- @Test
- fun `comic trigger does not reorder comics`() {
- val oldComicState = ComicState(generateListOfComics())
- val newComicState = ComicState(generateListOfComics().plusElement(Comic("new 1")))
- val mergedComicState = newComicTrigger.mergeStates(oldComicState, newComicState) as ComicState
- assertThat(mergedComicState.comics(), contains(*generateListOfComics().plusElement(Comic("new 1")).toTypedArray()))
- }
-
-}
-
-private fun generateListOfComics(): List<Comic> = (1..40).map { Comic("comic $it") }