From f7775b46710aef21d3ee943c91f65adfa4909a5e Mon Sep 17 00:00:00 2001 From: 0xb00bface <0xboobface@gmail.com> Date: Sat, 17 Oct 2020 16:43:23 +0200 Subject: [PATCH] Add button to pause recording entirely without pausing all models --- CHANGELOG.md | 10 +++++ .../ui/action/ToggleRecordingAction.java | 42 +++++++++++++++++++ .../ctbrec/ui/tabs/RecordedModelsTab.java | 13 +++++- .../ctbrec/recorder/NextGenLocalRecorder.java | 18 ++++++++ .../main/java/ctbrec/recorder/Recorder.java | 19 ++++++++- .../java/ctbrec/recorder/RemoteRecorder.java | 30 +++++++++++++ .../recorder/server/RecorderServlet.java | 10 +++++ 7 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 client/src/main/java/ctbrec/ui/action/ToggleRecordingAction.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d51fc2..158fa26d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +3.10.3 +======================== +* Fix: Recordings couldn't be found in client server setup, if the client was + running on Windows and the server on Linux +* Fix: Video length detection was done on the original file instead of the + post-processed one +* Added scrollbars to the settings tab to support smaller screens +* Added auto-redirect to the web-interface +* Added button to pause recording entirely without pausing all models + 3.10.2 ======================== * Fix: Flirt4Free browsing diff --git a/client/src/main/java/ctbrec/ui/action/ToggleRecordingAction.java b/client/src/main/java/ctbrec/ui/action/ToggleRecordingAction.java new file mode 100644 index 00000000..6e9fc155 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/action/ToggleRecordingAction.java @@ -0,0 +1,42 @@ +package ctbrec.ui.action; + +import ctbrec.recorder.Recorder; +import ctbrec.ui.controls.Dialogs; +import javafx.application.Platform; +import javafx.scene.Cursor; +import javafx.scene.control.ToggleButton; + +public class ToggleRecordingAction { + + private ToggleButton toggleButton; + private Recorder recorder; + private boolean pause; + + public ToggleRecordingAction(ToggleButton toggleButton, Recorder recorder) { + this.toggleButton = toggleButton; + this.recorder = recorder; + pause = toggleButton.isSelected(); + } + + public void execute() { + toggleButton.setCursor(Cursor.WAIT); + Thread t = new Thread(() -> { + try { + if (pause) { + recorder.pause(); + Platform.runLater(() -> toggleButton.setText("Resume Recorder")); + } else { + recorder.resume(); + Platform.runLater(() -> toggleButton.setText("Pause Recorder")); + } + } catch (Exception e) { + Dialogs.showError(toggleButton.getScene(), "Toggle Recorder", "An error ocurred while toggling the recorder", e); + Platform.runLater(() -> toggleButton.setSelected(!toggleButton.isSelected())); + } finally { + Platform.runLater(() -> toggleButton.setCursor(Cursor.DEFAULT)); + } + }); + t.setDaemon(true); + t.start(); + } +} diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java index 6c4d6613..005fb456 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java @@ -45,6 +45,7 @@ import ctbrec.ui.action.PauseAction; import ctbrec.ui.action.PlayAction; import ctbrec.ui.action.ResumeAction; import ctbrec.ui.action.StopRecordingAction; +import ctbrec.ui.action.ToggleRecordingAction; import ctbrec.ui.controls.DateTimeCellFactory; import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.SearchBox; @@ -79,6 +80,7 @@ import javafx.scene.control.TableColumn.SortType; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.TextField; +import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleGroup; import javafx.scene.control.Tooltip; import javafx.scene.control.cell.CheckBoxTableCell; @@ -122,6 +124,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { Button addModelButton = new Button("Record"); Button pauseAll = new Button("Pause All"); Button resumeAll = new Button("Resume All"); + ToggleButton toggleRecording = new ToggleButton("Pause Recording"); TextField filter; public RecordedModelsTab(String title, Recorder recorder, List sites) { @@ -274,12 +277,15 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { BorderPane.setMargin(addModelBox, new Insets(5)); addModelButton.setOnAction(this::addModel); addModelButton.setPadding(new Insets(5)); - addModelBox.getChildren().addAll(modelLabel, model, addModelButton, pauseAll, resumeAll); + addModelBox.getChildren().addAll(modelLabel, model, addModelButton, pauseAll, resumeAll, toggleRecording); HBox.setMargin(pauseAll, new Insets(0, 0, 0, 20)); pauseAll.setOnAction(this::pauseAll); resumeAll.setOnAction(this::resumeAll); pauseAll.setPadding(new Insets(5)); resumeAll.setPadding(new Insets(5)); + toggleRecording.setPadding(new Insets(5)); + toggleRecording.setOnAction(this::toggleRecording); + HBox.setMargin(toggleRecording, new Insets(0, 0, 0, 20)); HBox filterContainer = new HBox(); filterContainer.setSpacing(0); @@ -301,7 +307,6 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { filterContainer.getChildren().add(filter); addModelBox.getChildren().add(filterContainer); - BorderPane root = new BorderPane(); root.setPadding(new Insets(5)); root.setTop(addModelBox); @@ -437,6 +442,10 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } } + private void toggleRecording(ActionEvent evt) { + new ToggleRecordingAction(toggleRecording, recorder).execute(); + } + void initializeUpdateService() { updateService = createUpdateService(); updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(2))); diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java index dc5a1cc5..90a38395 100644 --- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java @@ -699,4 +699,22 @@ public class NextGenLocalRecorder implements Recorder { Map getRecordingProcesses() { return recordingProcesses; } + + @Override + public void pause() throws InvalidKeyException, NoSuchAlgorithmException, IOException { + LOG.info("Pausing recorder"); + try { + recording = false; + stopRecordingProcesses(); + } catch (Exception e) { + recording = true; + throw e; + } + } + + @Override + public void resume() throws InvalidKeyException, NoSuchAlgorithmException, IOException { + LOG.info("Resuming recorder"); + recording = true; + } } diff --git a/common/src/main/java/ctbrec/recorder/Recorder.java b/common/src/main/java/ctbrec/recorder/Recorder.java index 7b87a107..3c2ce825 100644 --- a/common/src/main/java/ctbrec/recorder/Recorder.java +++ b/common/src/main/java/ctbrec/recorder/Recorder.java @@ -113,7 +113,7 @@ public interface Recorder { public void rerunPostProcessing(Recording recording) throws IOException, InvalidKeyException, NoSuchAlgorithmException; /** - * Tells the recorder, that the recrodng priority for the given model has changed + * Tells the recorder, that the recording priority for the given model has changed * * @param model the model with changed priority. The new value can be retrieved with {@link Model#getPriority()} * @throws IOException @@ -123,4 +123,21 @@ public interface Recorder { public void priorityChanged(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; public void setNote(Recording rec, String note) throws IOException, InvalidKeyException, NoSuchAlgorithmException; + + /** + * Pauses the recording of models entirely. The state of which models should be recorded and which are paused + * is kept. + * @throws IOException + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void pause() throws InvalidKeyException, NoSuchAlgorithmException, IOException; + + /** + * Resumes recording + * @throws IOException + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void resume() throws InvalidKeyException, NoSuchAlgorithmException, IOException; } diff --git a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java index 4b473772..a8771de2 100644 --- a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java +++ b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Optional; import org.json.JSONObject; import org.slf4j.Logger; @@ -42,6 +43,7 @@ import okhttp3.Response; public class RemoteRecorder implements Recorder { private static final String SUCCESS = "success"; + private static final String COULDNT_SEND_REQUEST_SERVER_HTTP_STATUS = "Couldn't send request to server. Response {} - {}"; private static final Logger LOG = LoggerFactory.getLogger(RemoteRecorder.class); @@ -98,6 +100,24 @@ public class RemoteRecorder implements Recorder { sendRequest("stopAt", model); } + private Optional sendRequest(String action) throws IOException, InvalidKeyException, NoSuchAlgorithmException { + String msg = "{\"action\": \"" + action + "\"}"; + LOG.debug("Sending request to recording server: {}", msg); + RequestBody requestBody = RequestBody.create(JSON, msg); + Request.Builder builder = new Request.Builder().url(getRecordingEndpoint()).post(requestBody); + addHmacIfNeeded(msg, builder); + Request request = builder.build(); + try (Response response = client.execute(request)) { + String responseBody = response.body().string(); + if (response.isSuccessful()) { + return Optional.of(responseBody); + } else { + LOG.error(COULDNT_SEND_REQUEST_SERVER_HTTP_STATUS, response.code(), responseBody); + return Optional.empty(); + } + } + } + private void sendRequest(String action, Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException { String payload = modelRequestAdapter.toJson(new ModelRequest(action, model)); LOG.debug("Sending request to recording server: {}", payload); @@ -561,4 +581,14 @@ public class RemoteRecorder implements Recorder { public void setNote(Recording recording, String note) throws IOException, InvalidKeyException, NoSuchAlgorithmException { sendRequest("setNote", recording); } + + @Override + public void pause() throws InvalidKeyException, NoSuchAlgorithmException, IOException { + sendRequest("pauseRecorder"); + } + + @Override + public void resume() throws InvalidKeyException, NoSuchAlgorithmException, IOException { + sendRequest("resumeRecorder"); + } } diff --git a/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java b/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java index a7919586..7dcb1c00 100644 --- a/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java +++ b/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java @@ -223,6 +223,16 @@ public class RecorderServlet extends AbstractCtbrecServlet { response = "{\"status\": \"success\"}"; resp.getWriter().write(response); break; + case "pauseRecorder": + recorder.pause(); + response = "{\"status\": \"success\"}"; + resp.getWriter().write(response); + break; + case "resumeRecorder": + recorder.resume(); + response = "{\"status\": \"success\"}"; + resp.getWriter().write(response); + break; default: resp.setStatus(SC_BAD_REQUEST); response = "{\"status\": \"error\", \"msg\": \"Unknown action ["+request.action+"]\"}";