diff --git a/client/src/main/java/ctbrec/ui/action/AbstractAction.java b/client/src/main/java/ctbrec/ui/action/AbstractAction.java
new file mode 100644
index 00000000..08d37fd7
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/action/AbstractAction.java
@@ -0,0 +1,56 @@
+package ctbrec.ui.action;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import ctbrec.ui.tasks.TaskExecutionException;
+import javafx.application.Platform;
+
+public abstract class AbstractAction
{
+
+ private R result;
+
+ public CompletableFuture> execute(P param) {
+ try {
+ result = doExecute(param);
+ Platform.runLater(() -> onSuccess(Optional.ofNullable(result)));
+ return CompletableFuture.completedFuture(Optional.of(result));
+ } catch (Exception e) {
+ Platform.runLater(() -> onError(e));
+ return CompletableFuture.failedFuture(e);
+ } finally {
+ Platform.runLater(() -> done(Optional.ofNullable(result)));
+ }
+ }
+
+ protected abstract R doExecute(P param) throws InvalidKeyException, NoSuchAlgorithmException, IOException;
+
+ public CompletableFuture> executeAsync(P param) {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ result = doExecute(param);
+ Platform.runLater(() -> onSuccess(Optional.ofNullable(result)));
+ return Optional.of(result);
+ } catch (Exception e) {
+ Platform.runLater(() -> onError(e));
+ throw new TaskExecutionException(e);
+ } finally {
+ Platform.runLater(() -> done(Optional.ofNullable(result)));
+ }
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ public > T beforeOnGuiThread(Runnable r) {
+ return (T) this;
+ }
+
+ protected void onSuccess(Optional result) {}
+
+ protected void onError(Exception e) {}
+
+ protected void done(Optional result) {}
+}
diff --git a/client/src/main/java/ctbrec/ui/action/AbstractModelAction.java b/client/src/main/java/ctbrec/ui/action/AbstractModelAction.java
new file mode 100644
index 00000000..3632d20a
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/action/AbstractModelAction.java
@@ -0,0 +1,80 @@
+package ctbrec.ui.action;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+import ctbrec.GlobalThreadPool;
+import ctbrec.Model;
+import ctbrec.recorder.Recorder;
+import ctbrec.ui.controls.Dialogs;
+import ctbrec.ui.tasks.AbstractModelTask;
+import javafx.application.Platform;
+import javafx.scene.Cursor;
+import javafx.scene.Node;
+
+public abstract class AbstractModelAction {
+
+ protected Node source;
+ protected List extends Model> models;
+ protected Recorder recorder;
+ private AbstractModelTask task;
+
+ protected AbstractModelAction(Node source, List extends Model> models, Recorder recorder, AbstractModelTask task) {
+ this.source = source;
+ this.models = models;
+ this.recorder = recorder;
+ this.task = task;
+ }
+
+ protected CompletableFuture> execute(String errorHeader, String errorMsg) {
+ source.setCursor(Cursor.WAIT);
+ return CompletableFuture.supplyAsync(() -> {
+ final List result = new ArrayList<>(models.size());
+ final List> futures = new ArrayList<>(models.size());
+ for (Model model : models) {
+ futures.add(task
+ .executeSync(model)
+ .whenComplete((mdl, ex) ->
+ result.add(new Result(model, ex))));
+ }
+ Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
+ List failed = result.stream().filter(Result::failed).collect(Collectors.toList());
+ if (!failed.isEmpty()) {
+ Throwable t = failed.get(0).getThrowable();
+ String failedModelList = failed.stream().map(Result::getModel).map(Model::getDisplayName).collect(Collectors.joining(", "));
+ String msg = MessageFormat.format(errorMsg, failedModelList);
+ Dialogs.showError(source.getScene(), errorHeader, msg, t);
+ }
+ return result;
+ }, GlobalThreadPool.get());
+ }
+
+ public static class Result {
+ private Model model;
+ private Throwable throwable;
+
+ public Result(Model model, Throwable t) {
+ this.model = model;
+ this.throwable = t;
+ }
+
+ public boolean successful() {
+ return throwable == null;
+ }
+
+ public boolean failed() {
+ return throwable != null;
+ }
+
+ public Model getModel() {
+ return model;
+ }
+
+ public Throwable getThrowable() {
+ return throwable;
+ }
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/action/FollowAction.java b/client/src/main/java/ctbrec/ui/action/FollowAction.java
index 2cb53c84..f60cd099 100644
--- a/client/src/main/java/ctbrec/ui/action/FollowAction.java
+++ b/client/src/main/java/ctbrec/ui/action/FollowAction.java
@@ -1,30 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
-import ctbrec.ui.controls.Dialogs;
-import javafx.application.Platform;
+import ctbrec.recorder.Recorder;
+import ctbrec.ui.tasks.FollowTask;
import javafx.scene.Node;
-public class FollowAction extends ModelMassEditAction {
+public class FollowAction extends AbstractModelAction {
- private static final Logger LOG = LoggerFactory.getLogger(FollowAction.class);
+ public FollowAction(Node source, List extends Model> models, Recorder recorder) {
+ super(source, models, recorder, new FollowTask(recorder));
+ }
- public FollowAction(Node source, List extends Model> models) {
- super(source, models);
- action = m -> {
- try {
- m.getSite().login();
- m.follow();
- } catch(Exception e) {
- LOG.error("Couldn't follow model {}", m, e);
- Platform.runLater(() ->
- Dialogs.showError(source.getScene(), "Couldn't follow model", "Following " + m.getName() + " failed: " + e.getMessage(), e));
- }
- };
+ public CompletableFuture> execute() {
+ return super.execute("Couldn't follow model", "Following of {0} failed:");
}
}
diff --git a/client/src/main/java/ctbrec/ui/action/IgnoreModelsAction.java b/client/src/main/java/ctbrec/ui/action/IgnoreModelsAction.java
index fe2d125d..e4e95531 100644
--- a/client/src/main/java/ctbrec/ui/action/IgnoreModelsAction.java
+++ b/client/src/main/java/ctbrec/ui/action/IgnoreModelsAction.java
@@ -7,6 +7,7 @@ import ctbrec.Config;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.ui.JavaFxModel;
+import ctbrec.ui.action.AbstractModelAction.Result;
import ctbrec.ui.controls.Dialogs;
import javafx.scene.Node;
@@ -44,7 +45,8 @@ public class IgnoreModelsAction {
if (withRemoveDialog) {
boolean removeAsWell = Dialogs.showConfirmDialog("Ignore Model", null, "Remove as well?", source.getScene());
if (removeAsWell) {
- new StopRecordingAction(source, selectedModels, recorder).execute(callback);
+ new StopRecordingAction(source, selectedModels, recorder).execute()
+ .whenComplete((r, ex) -> r.stream().map(Result::getModel).forEach(callback::accept));
}
} else {
for (Model model : selectedModels) {
diff --git a/client/src/main/java/ctbrec/ui/action/MarkForLaterRecordingAction.java b/client/src/main/java/ctbrec/ui/action/MarkForLaterRecordingAction.java
index 2aa0b3b0..915cb952 100644
--- a/client/src/main/java/ctbrec/ui/action/MarkForLaterRecordingAction.java
+++ b/client/src/main/java/ctbrec/ui/action/MarkForLaterRecordingAction.java
@@ -15,9 +15,9 @@ public class MarkForLaterRecordingAction extends ModelMassEditAction {
action = m -> {
try {
recorder.markForLaterRecording(m, recordLater);
- } catch(Exception e) {
- Platform.runLater(() ->
- Dialogs.showError(source.getScene(), "Couldn't resume recording of model", "Resuming recording of " + m.getName() + " failed", e));
+ } catch (Exception e) {
+ Platform.runLater(() -> Dialogs.showError(source.getScene(), "Couldn't model mark model for later recording",
+ "Marking for later recording of " + m.getName() + " failed", e));
}
};
}
diff --git a/client/src/main/java/ctbrec/ui/action/ModelMassEditAction.java b/client/src/main/java/ctbrec/ui/action/ModelMassEditAction.java
index 65f42c20..b342f18b 100644
--- a/client/src/main/java/ctbrec/ui/action/ModelMassEditAction.java
+++ b/client/src/main/java/ctbrec/ui/action/ModelMassEditAction.java
@@ -43,33 +43,35 @@ public class ModelMassEditAction {
execute(m -> {});
}
+ public void executeSync(Consumer callback) {
+ Platform.runLater(() -> source.setCursor(Cursor.WAIT));
+ Consumer cb = Objects.requireNonNull(callback, "Callback is null, call execute() instead");
+ List> futures = new LinkedList<>();
+ for (Model model : getModels()) {
+ futures.add(GlobalThreadPool.submit(() -> {
+ action.accept(model);
+ cb.accept(model);
+ }));
+ }
+ Exception ex = null;
+ for (Future> future : futures) {
+ try {
+ future.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } catch (ExecutionException e) {
+ ex = e;
+ }
+ }
+ if (ex != null) {
+ LOG.error("Error while executing model mass edit", ex);
+ Dialogs.showError(source.getScene(), "Error", "Error while execution action", ex);
+ }
+ Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
+ }
+
public void execute(Consumer callback) {
- GlobalThreadPool.submit(() -> {
- Platform.runLater(() -> source.setCursor(Cursor.WAIT));
- Consumer cb = Objects.requireNonNull(callback, "Callback is null, call execute() instead");
- List> futures = new LinkedList<>();
- for (Model model : getModels()) {
- futures.add(GlobalThreadPool.submit(() -> {
- action.accept(model);
- cb.accept(model);
- }));
- }
- Exception ex = null;
- for (Future> future : futures) {
- try {
- future.get();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- ex = e;
- }
- }
- if (ex != null) {
- LOG.error("Error while executing model mass edit", ex);
- Dialogs.showError(source.getScene(), "Error", "Error while execution action", ex);
- }
- Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
- });
+ GlobalThreadPool.submit(() -> executeSync(callback));
}
@SuppressWarnings("unchecked")
diff --git a/client/src/main/java/ctbrec/ui/action/PauseAction.java b/client/src/main/java/ctbrec/ui/action/PauseAction.java
index b938160e..9b0425df 100644
--- a/client/src/main/java/ctbrec/ui/action/PauseAction.java
+++ b/client/src/main/java/ctbrec/ui/action/PauseAction.java
@@ -1,24 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
-import ctbrec.ui.controls.Dialogs;
-import javafx.application.Platform;
+import ctbrec.ui.tasks.PauseRecordingTask;
import javafx.scene.Node;
-public class PauseAction extends ModelMassEditAction {
+public class PauseAction extends AbstractModelAction {
- public PauseAction(Node source, List extends Model> models, Recorder recorder) {
- super(source, models);
- action = m -> {
- try {
- recorder.suspendRecording(m);
- } catch(Exception e) {
- Platform.runLater(() ->
- Dialogs.showError(source.getScene(), "Couldn't suspend recording of model", "Suspending recording of " + m.getName() + " failed", e));
- }
- };
+ public PauseAction(Node source, List models, Recorder recorder) {
+ super(source, models, recorder, new PauseRecordingTask(recorder));
+ }
+
+ public CompletableFuture> execute() {
+ return super.execute("Couldn't pause recording", "Pausing recording of {0} failed:");
}
}
diff --git a/client/src/main/java/ctbrec/ui/action/ResumeAction.java b/client/src/main/java/ctbrec/ui/action/ResumeAction.java
index 2bbff45f..cab269e9 100644
--- a/client/src/main/java/ctbrec/ui/action/ResumeAction.java
+++ b/client/src/main/java/ctbrec/ui/action/ResumeAction.java
@@ -1,24 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
-import ctbrec.ui.controls.Dialogs;
-import javafx.application.Platform;
+import ctbrec.ui.tasks.ResumeRecordingTask;
import javafx.scene.Node;
-public class ResumeAction extends ModelMassEditAction {
+public class ResumeAction extends AbstractModelAction {
- public ResumeAction(Node source, List extends Model> models, Recorder recorder) {
- super(source, models);
- action = m -> {
- try {
- recorder.resumeRecording(m);
- } catch(Exception e) {
- Platform.runLater(() ->
- Dialogs.showError(source.getScene(), "Couldn't resume recording of model", "Resuming recording of " + m.getName() + " failed", e));
- }
- };
+ public ResumeAction(Node source, List models, Recorder recorder) {
+ super(source, models, recorder, new ResumeRecordingTask(recorder));
+ }
+
+ public CompletableFuture> execute() {
+ return super.execute("Couldn't resume recording", "Resuming recording of {0} failed:");
}
}
diff --git a/client/src/main/java/ctbrec/ui/action/SetStopDateAction.java b/client/src/main/java/ctbrec/ui/action/SetStopDateAction.java
index b4983763..ee9cbf36 100644
--- a/client/src/main/java/ctbrec/ui/action/SetStopDateAction.java
+++ b/client/src/main/java/ctbrec/ui/action/SetStopDateAction.java
@@ -8,7 +8,6 @@ import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
-import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
@@ -20,6 +19,8 @@ import ctbrec.SubsequentAction;
import ctbrec.recorder.Recorder;
import ctbrec.ui.controls.DateTimePicker;
import ctbrec.ui.controls.Dialogs;
+import ctbrec.ui.tasks.StartRecordingTask;
+import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Node;
@@ -83,7 +84,7 @@ public class SetStopDateAction {
}
return true;
}, GlobalThreadPool.get()).whenComplete((r, e) -> {
- source.setCursor(Cursor.DEFAULT);
+ Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
if (e != null) {
LOG.error("Error", e);
}
@@ -97,13 +98,17 @@ public class SetStopDateAction {
model.setRecordUntil(stopAt);
model.setRecordUntilSubsequentAction(action);
try {
- if (!recorder.isTracked(model)) {
- new StartRecordingAction(source, List.of(model), recorder).execute(m -> {
+ if (!recorder.isTracked(model) || model.isMarkedForLaterRecording()) {
+ new StartRecordingTask(recorder).executeSync(model)
+ .thenAccept(m -> {
try {
recorder.stopRecordingAt(m);
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e1) {
showError(e1);
}
+ }).exceptionally(ex -> {
+ showError(ex);
+ return null;
});
} else {
recorder.stopRecordingAt(model);
@@ -113,8 +118,8 @@ public class SetStopDateAction {
}
}
- private void showError(Exception e) {
- Dialogs.showError(source.getScene(), "Error", "Couln't set stop date", e);
+ private void showError(Throwable t) {
+ Platform.runLater(() -> Dialogs.showError(source.getScene(), "Error", "Couln't set stop date", t));
}
diff --git a/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java b/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java
index 693eb3c3..697bd439 100644
--- a/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java
+++ b/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java
@@ -1,24 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
-import ctbrec.ui.controls.Dialogs;
-import javafx.application.Platform;
+import ctbrec.ui.tasks.StartRecordingTask;
import javafx.scene.Node;
-public class StartRecordingAction extends ModelMassEditAction {
+public class StartRecordingAction extends AbstractModelAction {
- public StartRecordingAction(Node source, List extends Model> models, Recorder recorder) {
- super(source, models);
- action = m -> {
- try {
- recorder.addModel(m);
- } catch (Exception e) {
- Platform.runLater(() ->
- Dialogs.showError(source.getScene(), "Couldn't start recording", "Starting recording of " + m.getName() + " failed", e));
- }
- };
+ public StartRecordingAction(Node source, List models, Recorder recorder) {
+ super(source, models, recorder, new StartRecordingTask(recorder));
+ }
+
+ public CompletableFuture> execute() {
+ return super.execute("Couldn't start recording", "Starting recording of {0} failed:");
}
}
diff --git a/client/src/main/java/ctbrec/ui/action/StopRecordingAction.java b/client/src/main/java/ctbrec/ui/action/StopRecordingAction.java
index ca185e8d..be18e0ef 100644
--- a/client/src/main/java/ctbrec/ui/action/StopRecordingAction.java
+++ b/client/src/main/java/ctbrec/ui/action/StopRecordingAction.java
@@ -1,24 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
-import ctbrec.ui.controls.Dialogs;
-import javafx.application.Platform;
+import ctbrec.ui.tasks.StopRecordingTask;
import javafx.scene.Node;
-public class StopRecordingAction extends ModelMassEditAction {
+public class StopRecordingAction extends AbstractModelAction {
public StopRecordingAction(Node source, List extends Model> models, Recorder recorder) {
- super(source, models);
- action = m -> {
- try {
- recorder.stopRecording(m);
- } catch(Exception e) {
- Platform.runLater(() ->
- Dialogs.showError(source.getScene(), "Couldn't stop recording", "Stopping recording of " + m.getName() + " failed", e));
- }
- };
+ super(source, models, recorder, new StopRecordingTask(recorder));
+ }
+
+ public CompletableFuture> execute() {
+ return super.execute("Couldn't stop recording", "Stopping recording of {0} failed:");
}
}
diff --git a/client/src/main/java/ctbrec/ui/action/UnfollowAction.java b/client/src/main/java/ctbrec/ui/action/UnfollowAction.java
new file mode 100644
index 00000000..2a7e81d8
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/action/UnfollowAction.java
@@ -0,0 +1,20 @@
+package ctbrec.ui.action;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import ctbrec.Model;
+import ctbrec.recorder.Recorder;
+import ctbrec.ui.tasks.UnfollowTask;
+import javafx.scene.Node;
+
+public class UnfollowAction extends AbstractModelAction {
+
+ public UnfollowAction(Node source, List extends Model> models, Recorder recorder) {
+ super(source, models, recorder, new UnfollowTask(recorder));
+ }
+
+ public CompletableFuture> execute() {
+ return super.execute("Couldn't unfollow model", "Unfollowing of {0} failed:");
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/menu/FollowUnfollowHandler.java b/client/src/main/java/ctbrec/ui/menu/FollowUnfollowHandler.java
new file mode 100644
index 00000000..3adfb9a4
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/menu/FollowUnfollowHandler.java
@@ -0,0 +1,49 @@
+package ctbrec.ui.menu;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ctbrec.Model;
+import ctbrec.recorder.Recorder;
+import ctbrec.ui.action.AbstractModelAction.Result;
+import ctbrec.ui.action.FollowAction;
+import ctbrec.ui.action.TriConsumer;
+import ctbrec.ui.action.UnfollowAction;
+import javafx.scene.Node;
+
+public class FollowUnfollowHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(FollowUnfollowHandler.class);
+
+ private Node source;
+ private Recorder recorder;
+ private TriConsumer callback;
+
+ public FollowUnfollowHandler(Node source, Recorder recorder, TriConsumer callback) {
+ this.source = source;
+ this.recorder = recorder;
+ this.callback = callback;
+ }
+
+ protected void follow(List selectedModels) {
+ new FollowAction(source, selectedModels, recorder).execute().thenAccept(r -> {
+ r.stream().filter(rs -> rs.getThrowable() == null).map(Result::getModel).forEach(m -> callback.accept(m, true, true));
+ r.stream().filter(rs -> rs.getThrowable() != null).map(Result::getModel).forEach(m -> callback.accept(m, true, false));
+ }).exceptionally(ex -> {
+ LOG.error("Couldn't follow model", ex);
+ return null;
+ });
+ }
+
+ protected void unfollow(List selectedModels) {
+ new UnfollowAction(source, selectedModels, recorder).execute().thenAccept(r -> {
+ r.stream().filter(rs -> rs.getThrowable() == null).map(Result::getModel).forEach(m -> callback.accept(m, false, true));
+ r.stream().filter(rs -> rs.getThrowable() != null).map(Result::getModel).forEach(m -> callback.accept(m, false, false));
+ }).exceptionally(ex -> {
+ LOG.error("Couldn't unfollow model", ex);
+ return null;
+ });
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/menu/ModelMenuContributor.java b/client/src/main/java/ctbrec/ui/menu/ModelMenuContributor.java
index ab0a74d5..328df984 100644
--- a/client/src/main/java/ctbrec/ui/menu/ModelMenuContributor.java
+++ b/client/src/main/java/ctbrec/ui/menu/ModelMenuContributor.java
@@ -5,7 +5,6 @@ import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
@@ -13,23 +12,20 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
-import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.ModelGroup;
import ctbrec.recorder.Recorder;
import ctbrec.ui.AutosizeAlert;
import ctbrec.ui.DesktopIntegration;
-import ctbrec.ui.SiteUiFactory;
import ctbrec.ui.StreamSourceSelectionDialog;
+import ctbrec.ui.action.AbstractModelAction.Result;
import ctbrec.ui.action.AddToGroupAction;
import ctbrec.ui.action.EditNotesAction;
import ctbrec.ui.action.IgnoreModelsAction;
import ctbrec.ui.action.MarkForLaterRecordingAction;
import ctbrec.ui.action.OpenRecordingsDir;
-import ctbrec.ui.action.PauseAction;
import ctbrec.ui.action.PlayAction;
import ctbrec.ui.action.RemoveTimeLimitAction;
-import ctbrec.ui.action.ResumeAction;
import ctbrec.ui.action.SetPortraitAction;
import ctbrec.ui.action.SetStopDateAction;
import ctbrec.ui.action.StartRecordingAction;
@@ -38,8 +34,6 @@ import ctbrec.ui.action.TipAction;
import ctbrec.ui.action.TriConsumer;
import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.tabs.FollowedTab;
-import javafx.application.Platform;
-import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.ContextMenu;
@@ -214,9 +208,9 @@ public class ModelMenuContributor {
var site = selectedModels.get(0).getSite();
if (site.supportsFollow()) {
var follow = new MenuItem("Follow");
- follow.setOnAction(e -> follow(selectedModels, true));
+ follow.setOnAction(e -> new FollowUnfollowHandler(source, recorder, followCallback).follow(selectedModels));
var unfollow = new MenuItem("Unfollow");
- unfollow.setOnAction(e -> follow(selectedModels, false));
+ unfollow.setOnAction(e -> new FollowUnfollowHandler(source, recorder, followCallback).unfollow(selectedModels));
var followOrUnFollow = isFollowedTab() ? unfollow : follow;
followOrUnFollow.setDisable(!site.credentialsAvailable());
@@ -233,52 +227,6 @@ public class ModelMenuContributor {
return false;
}
- protected void follow(List selectedModels, boolean follow) {
- for (Model model : selectedModels) {
- follow(model, follow);
- }
- }
-
- CompletableFuture follow(Model model, boolean follow) {
- source.setCursor(Cursor.WAIT);
- return CompletableFuture.supplyAsync(() -> {
- var success = true;
- try {
- if (follow) {
- SiteUiFactory.getUi(model.getSite()).login();
- boolean followed = model.follow();
- if (followed) {
- success = true;
- } else {
- Dialogs.showError(source.getScene(), "Couldn't follow model", "", null);
- success = false;
- }
- } else {
- SiteUiFactory.getUi(model.getSite()).login();
- boolean unfollowed = model.unfollow();
- if (unfollowed) {
- success = true;
- } else {
- Dialogs.showError(source.getScene(), "Couldn't unfollow model", "", null);
- success = false;
- }
- }
- return success;
- } catch (Exception e1) {
- LOG.error("Couldn't follow/unfollow model {}", model.getName(), e1);
- String msg = "I/O error while following/unfollowing model " + model.getName() + ": ";
- Dialogs.showError(source.getScene(), "Couldn't follow/unfollow model", msg, e1);
- return false;
- } finally {
- final boolean result = success;
- Platform.runLater(() -> {
- source.setCursor(Cursor.DEFAULT);
- followCallback.accept(model, follow, result);
- });
- }
- }, GlobalThreadPool.get());
- }
-
private void addSwitchStreamSource(ContextMenu menu, List selectedModels) {
var model = selectedModels.get(0);
if (!recorder.isTracked(model)) {
@@ -352,9 +300,9 @@ public class ModelMenuContributor {
var first = selectedModels.get(0);
if (recorder.isTracked(first)) {
var pause = new MenuItem("Pause Recording");
- pause.setOnAction(e -> new PauseAction(source, selectedModels, recorder).execute(m -> executeCallback()));
+ pause.setOnAction(e -> new PauseResumeHandler(source, recorder, callback).pause(selectedModels));
var resume = new MenuItem("Resume Recording");
- resume.setOnAction(e -> new ResumeAction(source, selectedModels, recorder).execute(m -> executeCallback()));
+ resume.setOnAction(e -> new PauseResumeHandler(source, recorder, callback).resume(selectedModels));
var pauseResume = recorder.isSuspended(first) ? resume : pause;
menu.getItems().add(pauseResume);
}
@@ -399,10 +347,6 @@ public class ModelMenuContributor {
var start = new MenuItem(text);
menu.getItems().add(start);
start.setOnAction(e -> {
- selectedModels.forEach(m -> {
- m.setMarkedForLaterRecording(false);
- m.setSuspended(false);
- });
selectedModels.forEach(m -> new SetStopDateAction(source, m, recorder).execute() //
.thenAccept(b -> executeCallback()));
});
@@ -473,11 +417,23 @@ public class ModelMenuContributor {
}
private void startRecording(List models) {
- new StartRecordingAction(source, models, recorder).execute(startStopCallback);
+ new StartRecordingAction(source, models, recorder).execute()
+ .whenComplete((r, ex) -> {
+ if (ex != null) {
+ LOG.error("Error while starting recordings", ex);
+ }
+ r.stream().map(Result::getModel).forEach(startStopCallback);
+ });
}
private void stopRecording(List models) {
- new StopRecordingAction(source, models, recorder).execute(startStopCallback);
+ new StopRecordingAction(source, models, recorder).execute()
+ .whenComplete((r, ex) -> {
+ if (ex != null) {
+ LOG.error("Error while stopping recordings", ex);
+ }
+ r.stream().map(Result::getModel).forEach(startStopCallback);
+ });
}
private void executeCallback() {
diff --git a/client/src/main/java/ctbrec/ui/menu/PauseResumeHandler.java b/client/src/main/java/ctbrec/ui/menu/PauseResumeHandler.java
new file mode 100644
index 00000000..d6aae631
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/menu/PauseResumeHandler.java
@@ -0,0 +1,51 @@
+package ctbrec.ui.menu;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ctbrec.Model;
+import ctbrec.recorder.Recorder;
+import ctbrec.ui.action.PauseAction;
+import ctbrec.ui.action.ResumeAction;
+import javafx.scene.Node;
+
+public class PauseResumeHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PauseResumeHandler.class);
+
+ private Node source;
+ private Recorder recorder;
+ private Runnable callback;
+
+ public PauseResumeHandler(Node source, Recorder recorder, Runnable callback) {
+ this.source = source;
+ this.recorder = recorder;
+ this.callback = callback;
+ }
+
+ protected void pause(List selectedModels) {
+ new PauseAction(source, selectedModels, recorder).execute()
+ .exceptionally(ex -> {
+ LOG.error("Error while pausing recordings", ex);
+ return null;
+ }).whenComplete((r, ex) -> executeCallback());
+ }
+
+ protected void resume(List selectedModels) {
+ new ResumeAction(source, selectedModels, recorder).execute()
+ .exceptionally(ex -> {
+ LOG.error("Error while resuming recordings", ex);
+ return null;
+ }).whenComplete((r, ex) -> executeCallback());
+ }
+
+ private void executeCallback() {
+ try {
+ callback.run();
+ } catch (Exception e) {
+ LOG.error("Error while executing menu callback", e);
+ }
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java
index 6d69d316..c0ee2160 100644
--- a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java
+++ b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java
@@ -476,10 +476,15 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
})
.withFollowCallback( (mdl, fllw, success) -> {
if (Boolean.TRUE.equals(fllw) && Boolean.TRUE.equals(success)) {
- getThumbCell(mdl).ifPresent(this::showAddToFollowedAnimation);
+ Platform.runLater(() -> getThumbCell(mdl).ifPresent(this::showAddToFollowedAnimation));
}
if (Boolean.FALSE.equals(fllw)) {
- selectedThumbCells.clear();
+ Platform.runLater(() -> {
+ if (this instanceof FollowedTab) {
+ getThumbCell(mdl).ifPresent(thumbCell -> grid.getChildren().remove(thumbCell));
+ }
+ selectedThumbCells.clear();
+ });
}
})
.withIgnoreCallback(m -> getThumbCell(m).ifPresent(thumbCell -> {
diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java
index 7e20a59c..f66e8d1d 100644
--- a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java
+++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java
@@ -18,6 +18,7 @@ import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import ctbrec.ui.JavaFxModel;
+import ctbrec.ui.action.AbstractModelAction.Result;
import ctbrec.ui.action.CheckModelAccountAction;
import ctbrec.ui.action.StopRecordingAction;
import ctbrec.ui.controls.Dialogs;
@@ -61,8 +62,8 @@ public class RecordLaterTab extends AbstractRecordedModelsTab implements TabSele
root.setCenter(scrollPane);
setContent(root);
- checkModelAccountExistance.setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder)
- .execute(Model::isMarkedForLaterRecording));
+ checkModelAccountExistance
+ .setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder).execute(Model::isMarkedForLaterRecording));
restoreState();
}
@@ -166,10 +167,12 @@ public class RecordLaterTab extends AbstractRecordedModelsTab implements TabSele
}
if (confirmed) {
List models = selectedModels.stream().map(JavaFxModel::getDelegate).collect(Collectors.toList());
- new StopRecordingAction(getTabPane(), models, recorder).execute(m -> Platform.runLater(() -> {
- table.getSelectionModel().clearSelection(table.getItems().indexOf(m));
- table.getItems().remove(m);
- }));
+ new StopRecordingAction(getTabPane(), models, recorder).execute().whenComplete((r, ex) -> {
+ r.stream().map(Result::getModel).forEach(m -> Platform.runLater(() -> {
+ table.getSelectionModel().clearSelection(table.getItems().indexOf(m));
+ table.getItems().remove(m);
+ }));
+ });
portraitCache.invalidateAll(models);
}
}
diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java
index 4e5a3e15..dbb3517c 100644
--- a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java
+++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java
@@ -26,6 +26,7 @@ import ctbrec.Recording;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import ctbrec.ui.JavaFxModel;
+import ctbrec.ui.action.AbstractModelAction.Result;
import ctbrec.ui.action.CheckModelAccountAction;
import ctbrec.ui.action.PauseAction;
import ctbrec.ui.action.ResumeAction;
@@ -358,10 +359,12 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
}
if (confirmed) {
List models = selectedModels.stream().map(JavaFxModel::getDelegate).collect(Collectors.toList());
- new StopRecordingAction(getTabPane(), models, recorder).execute(m -> Platform.runLater(() -> {
- table.getSelectionModel().clearSelection(table.getItems().indexOf(m));
- table.getItems().remove(m);
- }));
+ new StopRecordingAction(getTabPane(), models, recorder).execute().whenComplete((r, ex) -> {
+ r.stream().map(Result::getModel).forEach(m -> Platform.runLater(() -> {
+ table.getSelectionModel().clearSelection(table.getItems().indexOf(m));
+ table.getItems().remove(m);
+ }));
+ });
portraitCache.invalidateAll(models);
}
}
diff --git a/client/src/main/java/ctbrec/ui/tasks/AbstractModelTask.java b/client/src/main/java/ctbrec/ui/tasks/AbstractModelTask.java
new file mode 100644
index 00000000..6b05fc8a
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/AbstractModelTask.java
@@ -0,0 +1,38 @@
+package ctbrec.ui.tasks;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import ctbrec.GlobalThreadPool;
+import ctbrec.Model;
+import ctbrec.recorder.Recorder;
+
+public abstract class AbstractModelTask {
+ protected Recorder recorder;
+ private Consumer concreteTask;
+
+ protected AbstractModelTask(Recorder recorder, Consumer concreteTask) {
+ this.recorder = recorder;
+ this.concreteTask = concreteTask;
+ }
+
+ public CompletableFuture executeSync(Model model) {
+ try {
+ concreteTask.accept(model);
+ return CompletableFuture.completedFuture(model);
+ } catch (Exception e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ }
+
+ public CompletableFuture execute(Model model) {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ concreteTask.accept(model);
+ return model;
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ }, GlobalThreadPool.get());
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/FollowTask.java b/client/src/main/java/ctbrec/ui/tasks/FollowTask.java
new file mode 100644
index 00000000..18f1f4ff
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/FollowTask.java
@@ -0,0 +1,22 @@
+package ctbrec.ui.tasks;
+
+import ctbrec.recorder.Recorder;
+
+public class FollowTask extends AbstractModelTask {
+
+ public FollowTask(Recorder recorder) {
+ super(recorder, model -> {
+ try {
+ if (model.getSite().login()) {
+ if (!model.follow()) {
+ throw new TaskExecutionException(new RuntimeException("Following " + model.getSite().getName() + " failed"));
+ }
+ } else {
+ throw new TaskExecutionException(new RuntimeException("Login to " + model.getSite().getName() + " failed"));
+ }
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/PauseRecordingTask.java b/client/src/main/java/ctbrec/ui/tasks/PauseRecordingTask.java
new file mode 100644
index 00000000..9af14a61
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/PauseRecordingTask.java
@@ -0,0 +1,17 @@
+package ctbrec.ui.tasks;
+
+import ctbrec.recorder.Recorder;
+
+public class PauseRecordingTask extends AbstractModelTask {
+
+ public PauseRecordingTask(Recorder recorder) {
+ super(recorder, model -> {
+ try {
+ model.setSuspended(true);
+ recorder.suspendRecording(model);
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/ResumeRecordingTask.java b/client/src/main/java/ctbrec/ui/tasks/ResumeRecordingTask.java
new file mode 100644
index 00000000..7e90ef6b
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/ResumeRecordingTask.java
@@ -0,0 +1,17 @@
+package ctbrec.ui.tasks;
+
+import ctbrec.recorder.Recorder;
+
+public class ResumeRecordingTask extends AbstractModelTask {
+
+ public ResumeRecordingTask(Recorder recorder) {
+ super(recorder, model -> {
+ try {
+ model.setSuspended(false);
+ recorder.resumeRecording(model);
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/StartRecordingTask.java b/client/src/main/java/ctbrec/ui/tasks/StartRecordingTask.java
new file mode 100644
index 00000000..e374e827
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/StartRecordingTask.java
@@ -0,0 +1,17 @@
+package ctbrec.ui.tasks;
+
+import ctbrec.recorder.Recorder;
+
+public class StartRecordingTask extends AbstractModelTask {
+
+ public StartRecordingTask(Recorder recorder) {
+ super(recorder, model -> {
+ try {
+ model.setMarkedForLaterRecording(false);
+ recorder.addModel(model);
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/StopRecordingTask.java b/client/src/main/java/ctbrec/ui/tasks/StopRecordingTask.java
new file mode 100644
index 00000000..8d2be77d
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/StopRecordingTask.java
@@ -0,0 +1,16 @@
+package ctbrec.ui.tasks;
+
+import ctbrec.recorder.Recorder;
+
+public class StopRecordingTask extends AbstractModelTask {
+
+ public StopRecordingTask(Recorder recorder) {
+ super(recorder, model -> {
+ try {
+ recorder.stopRecording(model);
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/TaskExecutionException.java b/client/src/main/java/ctbrec/ui/tasks/TaskExecutionException.java
new file mode 100644
index 00000000..a8ca51c0
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/TaskExecutionException.java
@@ -0,0 +1,9 @@
+package ctbrec.ui.tasks;
+
+public class TaskExecutionException extends RuntimeException {
+
+ public TaskExecutionException(Exception e) {
+ super(e);
+ }
+
+}
diff --git a/client/src/main/java/ctbrec/ui/tasks/UnfollowTask.java b/client/src/main/java/ctbrec/ui/tasks/UnfollowTask.java
new file mode 100644
index 00000000..75fb3794
--- /dev/null
+++ b/client/src/main/java/ctbrec/ui/tasks/UnfollowTask.java
@@ -0,0 +1,22 @@
+package ctbrec.ui.tasks;
+
+import ctbrec.recorder.Recorder;
+
+public class UnfollowTask extends AbstractModelTask {
+
+ public UnfollowTask(Recorder recorder) {
+ super(recorder, model -> {
+ try {
+ if (model.getSite().login()) {
+ if (!model.unfollow()) {
+ throw new TaskExecutionException(new RuntimeException("Unfollowing " + model.getSite().getName() + " failed"));
+ }
+ } else {
+ throw new TaskExecutionException(new RuntimeException("Login to " + model.getSite().getName() + " failed"));
+ }
+ } catch (Exception e) {
+ throw new TaskExecutionException(e);
+ }
+ });
+ }
+}
diff --git a/client/src/test/java/ctbrec/ui/tasks/StartRecordingTaskTest.java b/client/src/test/java/ctbrec/ui/tasks/StartRecordingTaskTest.java
new file mode 100644
index 00000000..cd881ce9
--- /dev/null
+++ b/client/src/test/java/ctbrec/ui/tasks/StartRecordingTaskTest.java
@@ -0,0 +1,85 @@
+package ctbrec.ui.tasks;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import ctbrec.Model;
+import ctbrec.recorder.Recorder;
+
+class StartRecordingTaskTest {
+
+ private Recorder recorder;
+ private Model model;
+
+ @BeforeEach
+ void setup() {
+ recorder = mock(Recorder.class);
+ model = mock(Model.class);
+ }
+
+ @Test
+ void testExecuteSyncHappyPath() {
+ CompletableFuture future = new StartRecordingTask(recorder).executeSync(model);
+ try {
+ assertEquals(future.get(), model);
+ } catch (InterruptedException | ExecutionException e) {
+ fail("happy path should not throw an " + e.getClass().getSimpleName());
+ }
+ }
+
+ @Test
+ void testExecuteSyncWithException() throws InvalidKeyException, NoSuchAlgorithmException, IOException {
+ String exMsg = "recorder not available";
+ doThrow(new IOException(exMsg)).when(recorder).addModel(model);
+ CompletableFuture future = new StartRecordingTask(recorder).executeSync(model);
+ ExecutionException ex = assertThrows(ExecutionException.class, future::get);
+ assertTrue(getRootCause(ex) instanceof IOException);
+ assertEquals(exMsg, getRootCause(ex).getMessage());
+ }
+
+ @Test
+ void testExecuteHappyPath() {
+ CompletableFuture future = new StartRecordingTask(recorder).execute(model);
+ try {
+ assertEquals(future.get(), model);
+ } catch (InterruptedException | ExecutionException e) {
+ fail("happy path should not throw an " + e.getClass().getSimpleName());
+ }
+ }
+
+ @Test
+ void testExecuteWithException() throws InvalidKeyException, NoSuchAlgorithmException, IOException {
+ String exMsg = "recorder not available";
+ doThrow(new IOException(exMsg)).when(recorder).addModel(model);
+ CompletableFuture future = new StartRecordingTask(recorder).execute(model);
+ ExecutionException ex = assertThrows(ExecutionException.class, future::get);
+ assertTrue(ex.getCause() instanceof TaskExecutionException);
+ assertTrue(getRootCause(ex) instanceof IOException);
+ assertEquals(exMsg, getRootCause(ex).getMessage());
+ }
+
+ @Test
+ void markedForLaterShouldGetStarted() throws InvalidKeyException, NoSuchAlgorithmException, IOException {
+ when(model.isMarkedForLaterRecording()).thenReturn(true);
+ new StartRecordingTask(recorder).executeSync(model);
+ verify(model).setMarkedForLaterRecording(false);
+ verify(recorder).addModel(model);
+ }
+
+ private Throwable getRootCause(Throwable t) {
+ if (t.getCause() != null) {
+ return getRootCause(t.getCause());
+ } else {
+ return t;
+ }
+ }
+}
diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java
index 63dae26a..8b260767 100644
--- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java
+++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java
@@ -70,7 +70,7 @@ public class NextGenLocalRecorder implements Recorder {
private volatile boolean recording = true;
private ReentrantLock recorderLock = new ReentrantLock();
private ReentrantLock modelGroupLock = new ReentrantLock();
- private RecorderHttpClient client = new RecorderHttpClient();
+ private RecorderHttpClient client;
private Map recordingProcesses = Collections.synchronizedMap(new HashMap<>());
private RecordingManager recordingManager;
private RecordingPreconditions preconditions;
@@ -90,6 +90,7 @@ public class NextGenLocalRecorder implements Recorder {
public NextGenLocalRecorder(Config config, List sites) throws IOException {
this.config = config;
+ client = new RecorderHttpClient(config);
downloadPool = Executors.newScheduledThreadPool(5, createThreadFactory("Download", MAX_PRIORITY));
threadPoolScaler = new ThreadPoolScaler((ThreadPoolExecutor) downloadPool, 5);
recordingManager = new RecordingManager(config, sites);
@@ -265,15 +266,7 @@ public class NextGenLocalRecorder implements Recorder {
@Override
public void addModel(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
Optional existing = findModel(model);
- if (existing.isPresent()) {
- existing.get().setSuspended(model.isSuspended());
- existing.get().setMarkedForLaterRecording(model.isMarkedForLaterRecording());
- if (model.isMarkedForLaterRecording() && getRecordingProcesses().containsKey(model)) {
- stopRecording(model);
- } else {
- startRecordingProcess(existing.get());
- }
- } else {
+ if (!existing.isPresent()) {
LOG.info("Model {} added", model);
recorderLock.lock();
try {
@@ -574,7 +567,7 @@ public class NextGenLocalRecorder implements Recorder {
Optional existingModel = findModel(model);
if (existingModel.isPresent()) {
Model m = existingModel.get();
- LOG.debug("Mark. Model found: {}", m);
+ LOG.debug("Mark for later: {}. Model found: {}", mark, m);
m.setMarkedForLaterRecording(mark);
if (mark && getCurrentlyRecording().contains(m)) {
LOG.debug("Stopping recording of {}", m);
@@ -585,8 +578,8 @@ public class NextGenLocalRecorder implements Recorder {
stopRecording(model);
}
} else {
- LOG.debug("Model {} not found to mark for later recording", model);
if (mark) {
+ LOG.debug("Model {} not found to mark for later recording", model);
model.setMarkedForLaterRecording(true);
addModel(model);
}