From 17aa5bc18dc56a5392f32d9ed5f797966fa9131b Mon Sep 17 00:00:00 2001 From: 0xb00bface <0xboobface@gmail.com> Date: Sat, 9 Jan 2021 12:45:38 +0100 Subject: [PATCH] Change context menu behavior to make sense with bookmarked models - "Record Later" is hidden if it makes sense - Move models to Active tab, if the are in "Later" tab and then get started --- .../java/ctbrec/ui/ClipboardListener.java | 19 ++- .../ui/action/StartRecordingAction.java | 8 +- .../ui/controls/SearchPopoverTreeList.java | 25 ++-- .../ui/sites/camsoda/CamsodaShowsTab.java | 64 +++++----- .../java/ctbrec/ui/tabs/RecordLaterTab.java | 66 ++++------- .../ctbrec/ui/tabs/RecordedModelsTab.java | 101 +++++----------- .../main/java/ctbrec/ui/tabs/ThumbCell.java | 32 +++-- .../java/ctbrec/ui/tabs/ThumbOverviewTab.java | 111 ++++++------------ common/.classpath | 6 +- common/.settings/org.eclipse.jdt.core.prefs | 2 +- .../ctbrec/recorder/NextGenLocalRecorder.java | 111 +++++++----------- .../main/java/ctbrec/recorder/Recorder.java | 12 +- .../java/ctbrec/recorder/RemoteRecorder.java | 77 ++++++------ .../recorder/server/RecorderServlet.java | 43 ++++--- 14 files changed, 261 insertions(+), 416 deletions(-) diff --git a/client/src/main/java/ctbrec/ui/ClipboardListener.java b/client/src/main/java/ctbrec/ui/ClipboardListener.java index dc83cb96..d6ac591c 100644 --- a/client/src/main/java/ctbrec/ui/ClipboardListener.java +++ b/client/src/main/java/ctbrec/ui/ClipboardListener.java @@ -1,19 +1,18 @@ package ctbrec.ui; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.Objects; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ctbrec.Model; import ctbrec.recorder.Recorder; import ctbrec.sites.Site; import javafx.application.Platform; import javafx.scene.input.Clipboard; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Objects; public class ClipboardListener implements Runnable { @@ -54,7 +53,7 @@ public class ClipboardListener implements Runnable { Model m = site.createModelFromUrl(url); if (m != null) { try { - recorder.startRecording(m); + recorder.addModel(m); DesktopIntegration.notification("Add from clipboard", "Model added", "Model " + m.getDisplayName() + " added"); } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) { DesktopIntegration.notification("Add from clipboard", "Error", "Couldn't add URL from clipboard: " + e.getLocalizedMessage()); diff --git a/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java b/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java index 0f92466c..30b46858 100644 --- a/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java +++ b/client/src/main/java/ctbrec/ui/action/StartRecordingAction.java @@ -1,21 +1,21 @@ package ctbrec.ui.action; -import java.util.List; - import ctbrec.Model; import ctbrec.recorder.Recorder; import ctbrec.ui.controls.Dialogs; import javafx.application.Platform; import javafx.scene.Node; +import java.util.List; + public class StartRecordingAction extends ModelMassEditAction { public StartRecordingAction(Node source, List models, Recorder recorder) { super(source, models); action = (m) -> { try { - recorder.startRecording(m); - } catch(Exception e) { + recorder.addModel(m); + } catch (Exception e) { Platform.runLater(() -> Dialogs.showError(source.getScene(), "Couldn't start recording", "Starting recording of " + m.getName() + " failed", e)); } diff --git a/client/src/main/java/ctbrec/ui/controls/SearchPopoverTreeList.java b/client/src/main/java/ctbrec/ui/controls/SearchPopoverTreeList.java index e52c247c..aa8131b2 100644 --- a/client/src/main/java/ctbrec/ui/controls/SearchPopoverTreeList.java +++ b/client/src/main/java/ctbrec/ui/controls/SearchPopoverTreeList.java @@ -31,14 +31,6 @@ */ package ctbrec.ui.controls; -import java.net.URL; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ctbrec.Model; import ctbrec.recorder.Recorder; import ctbrec.ui.action.PlayAction; @@ -48,15 +40,18 @@ import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Cursor; import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.Skin; +import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.shape.Rectangle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URL; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; /** * Popover page that displays a list of samples and sample categories for a given SampleCategory. @@ -192,7 +187,7 @@ public class SearchPopoverTreeList extends PopoverTreeList implements Pop CompletableFuture.runAsync(new Task() { @Override protected Void call() throws Exception { - recorder.startRecording(model); + recorder.addModel(model); return null; } @@ -324,4 +319,4 @@ public class SearchPopoverTreeList extends PopoverTreeList implements Pop public void setRecorder(Recorder recorder) { this.recorder = recorder; } -} \ No newline at end of file +} diff --git a/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java b/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java index bf62446f..d4e0d342 100644 --- a/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java +++ b/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java @@ -1,5 +1,32 @@ package ctbrec.ui.sites.camsoda; +import ctbrec.Model; +import ctbrec.recorder.Recorder; +import ctbrec.sites.camsoda.Camsoda; +import ctbrec.ui.AutosizeAlert; +import ctbrec.ui.DesktopIntegration; +import ctbrec.ui.SiteUiFactory; +import ctbrec.ui.tabs.TabSelectionListener; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.concurrent.Task; +import javafx.geometry.Insets; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import okhttp3.Request; +import okhttp3.Response; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -15,41 +42,6 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; -import org.json.JSONArray; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ctbrec.Model; -import ctbrec.recorder.Recorder; -import ctbrec.sites.camsoda.Camsoda; -import ctbrec.ui.AutosizeAlert; -import ctbrec.ui.DesktopIntegration; -import ctbrec.ui.SiteUiFactory; -import ctbrec.ui.tabs.TabSelectionListener; -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.concurrent.Task; -import javafx.geometry.Insets; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.control.Alert; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.Tab; -import javafx.scene.control.TitledPane; -import javafx.scene.control.Tooltip; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.GridPane; -import javafx.scene.text.Font; -import javafx.scene.text.FontWeight; -import okhttp3.Request; -import okhttp3.Response; - public class CamsodaShowsTab extends Tab implements TabSelectionListener { private static final Logger LOG = LoggerFactory.getLogger(CamsodaShowsTab.class); @@ -222,7 +214,7 @@ public class CamsodaShowsTab extends Tab implements TabSelectionListener { setCursor(Cursor.WAIT); CompletableFuture.runAsync(() -> { try { - recorder.startRecording(model); + recorder.addModel(model); } catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) { showErrorDialog("Oh no!", "Couldn't add model to the recorder", "Recorder error: " + e.getMessage()); } finally { diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java b/client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java index 1824776d..4f939985 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java @@ -1,21 +1,5 @@ package ctbrec.ui.tabs; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ctbrec.Config; import ctbrec.Model; import ctbrec.StringUtil; @@ -25,13 +9,7 @@ import ctbrec.ui.AutosizeAlert; import ctbrec.ui.DesktopIntegration; import ctbrec.ui.JavaFxModel; import ctbrec.ui.PreviewPopupHandler; -import ctbrec.ui.action.CheckModelAccountAction; -import ctbrec.ui.action.EditNotesAction; -import ctbrec.ui.action.FollowAction; -import ctbrec.ui.action.IgnoreModelsAction; -import ctbrec.ui.action.PlayAction; -import ctbrec.ui.action.ResumeAction; -import ctbrec.ui.action.StopRecordingAction; +import ctbrec.ui.action.*; import ctbrec.ui.controls.CustomMouseBehaviorContextMenu; import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.SearchBox; @@ -48,35 +26,31 @@ import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.Alert; -import javafx.scene.control.Button; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.Tab; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; +import javafx.scene.control.*; 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.Tooltip; import javafx.scene.control.cell.PropertyValueFactory; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import javafx.scene.input.ContextMenuEvent; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; +import javafx.scene.input.*; import javafx.scene.layout.BorderPane; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.util.Callback; import javafx.util.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; public class RecordLaterTab extends Tab implements TabSelectionListener { private static final Logger LOG = LoggerFactory.getLogger(RecordLaterTab.class); @@ -298,7 +272,7 @@ public class RecordLaterTab extends Tab implements TabSelectionListener { if (newModel != null) { try { newModel.setMarkedForLaterRecording(true); - recorder.startRecording(newModel); + recorder.addModel(newModel); } catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) { Dialogs.showError(getTabPane().getScene(), "Couldn't add model", "The model " + newModel.getName() + " could not be added: ", e1); } @@ -324,7 +298,7 @@ public class RecordLaterTab extends Tab implements TabSelectionListener { try { Model m = site.createModel(modelName); m.setMarkedForLaterRecording(true); - recorder.startRecording(m); + recorder.addModel(m); } catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) { Dialogs.showError(getTabPane().getScene(), "Couldn't add model", "The model " + modelName + " could not be added:", e1); } diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java index d60a2411..99555d6f 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java @@ -1,58 +1,13 @@ package ctbrec.ui.tabs; -import static ctbrec.Recording.State.*; -import static ctbrec.ui.UnicodeEmoji.*; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ctbrec.Config; import ctbrec.Model; import ctbrec.Recording; import ctbrec.StringUtil; import ctbrec.recorder.Recorder; import ctbrec.sites.Site; -import ctbrec.ui.AutosizeAlert; -import ctbrec.ui.DesktopIntegration; -import ctbrec.ui.JavaFxModel; -import ctbrec.ui.PreviewPopupHandler; -import ctbrec.ui.StreamSourceSelectionDialog; -import ctbrec.ui.action.CheckModelAccountAction; -import ctbrec.ui.action.EditNotesAction; -import ctbrec.ui.action.FollowAction; -import ctbrec.ui.action.IgnoreModelsAction; -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.SetStopDateAction; -import ctbrec.ui.action.StartRecordingAction; -import ctbrec.ui.action.StopRecordingAction; -import ctbrec.ui.action.ToggleRecordingAction; +import ctbrec.ui.*; +import ctbrec.ui.action.*; import ctbrec.ui.controls.CustomMouseBehaviorContextMenu; import ctbrec.ui.controls.DateTimeCellFactory; import ctbrec.ui.controls.Dialogs; @@ -71,33 +26,13 @@ import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.Alert; -import javafx.scene.control.Button; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.Tab; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; +import javafx.scene.control.*; import javafx.scene.control.TableColumn.CellEditEvent; 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.Tooltip; import javafx.scene.control.cell.CheckBoxTableCell; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.TextFieldTableCell; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import javafx.scene.input.ContextMenuEvent; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; +import javafx.scene.input.*; import javafx.scene.layout.BorderPane; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; @@ -106,6 +41,30 @@ import javafx.util.Callback; import javafx.util.Duration; import javafx.util.StringConverter; import javafx.util.converter.NumberStringConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static ctbrec.Recording.State.RECORDING; +import static ctbrec.ui.UnicodeEmoji.CLOCK; +import static ctbrec.ui.UnicodeEmoji.HEAVY_CHECK_MARK; public class RecordedModelsTab extends Tab implements TabSelectionListener { private static final Logger LOG = LoggerFactory.getLogger(RecordedModelsTab.class); @@ -407,7 +366,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { Model newModel = site.createModelFromUrl(url); if (newModel != null) { try { - recorder.startRecording(newModel); + recorder.addModel(newModel); } catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) { Dialogs.showError(getTabPane().getScene(), "Couldn't add model", "The model " + newModel.getName() + " could not be added: ", e1); } @@ -432,7 +391,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { if (Objects.equals(siteName.toLowerCase(), site.getClass().getSimpleName().toLowerCase())) { try { Model m = site.createModel(modelName); - recorder.startRecording(m); + recorder.addModel(m); } catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) { Dialogs.showError(getTabPane().getScene(), "Couldn't add model", "The model " + modelName + " could not be added:", e1); } diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java b/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java index d0985810..8f93d4c6 100644 --- a/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java +++ b/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java @@ -1,25 +1,8 @@ package ctbrec.ui.tabs; -import static ctbrec.Model.State.*; -import static ctbrec.io.HttpConstants.*; - -import java.io.IOException; -import java.util.Locale; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; - import ctbrec.Config; import ctbrec.Model; import ctbrec.Model.State; @@ -64,6 +47,18 @@ import javafx.scene.text.TextAlignment; import javafx.util.Duration; import okhttp3.Request; import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.*; +import java.util.function.Function; + +import static ctbrec.Model.State.OFFLINE; +import static ctbrec.Model.State.ONLINE; +import static ctbrec.io.HttpConstants.*; public class ThumbCell extends StackPane { @@ -511,7 +506,7 @@ public class ThumbCell extends StackPane { CompletableFuture.runAsync(() -> { try { if (start) { - recorder.startRecording(model); + recorder.addModel(model); setRecording(!model.isMarkedForLaterRecording()); } else { recorder.stopRecording(model); @@ -689,6 +684,7 @@ public class ThumbCell extends StackPane { void addInPausedState() { model.setSuspended(true); + model.setMarkedForLaterRecording(false); startStopAction(true); } } diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java index fa433a4d..ae0a1b9b 100644 --- a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java @@ -1,31 +1,5 @@ package ctbrec.ui.tabs; -import static ctbrec.ui.controls.Dialogs.*; - -import java.io.IOException; -import java.net.SocketTimeoutException; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ctbrec.Config; import ctbrec.Model; import ctbrec.event.EventBusHolder; @@ -33,24 +7,12 @@ import ctbrec.recorder.Recorder; import ctbrec.sites.Site; import ctbrec.sites.mfc.MyFreeCamsClient; import ctbrec.sites.mfc.MyFreeCamsModel; -import ctbrec.ui.AutosizeAlert; -import ctbrec.ui.DesktopIntegration; -import ctbrec.ui.SiteUiFactory; -import ctbrec.ui.TipDialog; -import ctbrec.ui.TokenLabel; +import ctbrec.ui.*; import ctbrec.ui.action.IgnoreModelsAction; import ctbrec.ui.action.OpenRecordingsDir; import ctbrec.ui.action.SetStopDateAction; -import ctbrec.ui.controls.CustomMouseBehaviorContextMenu; -import ctbrec.ui.controls.FasterVerticalScrollPaneSkin; -import ctbrec.ui.controls.SearchBox; -import ctbrec.ui.controls.SearchPopover; -import ctbrec.ui.controls.SearchPopoverTreeList; -import javafx.animation.FadeTransition; -import javafx.animation.Interpolator; -import javafx.animation.ParallelTransition; -import javafx.animation.ScaleTransition; -import javafx.animation.TranslateTransition; +import ctbrec.ui.controls.*; +import javafx.animation.*; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -66,34 +28,24 @@ import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.Parent; -import javafx.scene.control.Alert; -import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; -import javafx.scene.control.TextField; -import javafx.scene.control.Tooltip; +import javafx.scene.control.*; import javafx.scene.image.ImageView; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import javafx.scene.input.ContextMenuEvent; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.FlowPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.StackPane; +import javafx.scene.input.*; +import javafx.scene.layout.*; import javafx.scene.transform.Transform; import javafx.util.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.text.DecimalFormat; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import static ctbrec.ui.controls.Dialogs.showError; public class ThumbOverviewTab extends Tab implements TabSelectionListener { private static final Logger LOG = LoggerFactory.getLogger(ThumbOverviewTab.class); @@ -473,6 +425,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { private ContextMenu createContextMenu(ThumbCell cell) { Model model = cell.getModel(); boolean modelIsTrackedByRecorder = recorder.isTracked(model); + MenuItem openInPlayer = new MenuItem("Open in Player"); openInPlayer.setOnAction(e -> startPlayer(getSelectedThumbCells(cell))); @@ -481,7 +434,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { MenuItem stop = new MenuItem("Stop Recording"); stop.setOnAction(e -> startStopAction(getSelectedThumbCells(cell), false)); - MenuItem startStop = recorder.isTracked(cell.getModel()) ? stop : start; + MenuItem startStop = recorder.isTracked(model) ? stop : start; MenuItem recordUntil = new MenuItem("Start Recording Until"); recordUntil.setOnAction(e -> startRecordingWithTimeLimit(getSelectedThumbCells(cell))); @@ -494,7 +447,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { pause.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), true)); MenuItem resume = new MenuItem("Resume Recording"); resume.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), false)); - MenuItem pauseResume = recorder.isSuspended(cell.getModel()) ? resume : pause; + MenuItem pauseResume = recorder.isSuspended(model) ? resume : pause; MenuItem follow = new MenuItem("Follow"); follow.setOnAction(e -> follow(getSelectedThumbCells(cell), true)); @@ -508,7 +461,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { refresh.setOnAction(e -> refresh()); MenuItem openRecDir = new MenuItem("Open recording directory"); - openRecDir.setOnAction(e -> new OpenRecordingsDir(cell, cell.getModel()).execute()); + openRecDir.setOnAction(e -> new OpenRecordingsDir(cell, model).execute()); MenuItem copyUrl = createCopyUrlMenuItem(cell); MenuItem sendTip = createTipMenuItem(cell); @@ -520,24 +473,27 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { contextMenu.setHideOnEscape(true); contextMenu.setAutoFix(true); contextMenu.getItems().addAll(openInPlayer, new SeparatorMenuItem(), startStop); - if(modelIsTrackedByRecorder) { - contextMenu.getItems().add(pauseResume); + if (modelIsTrackedByRecorder) { + contextMenu.getItems().addAll(pauseResume, recordLater); } else { - contextMenu.getItems().addAll(recordUntil, addPaused, recordLater); + contextMenu.getItems().addAll(recordUntil, addPaused); + if (!recorder.isMarkedForLaterRecording(model)) { + contextMenu.getItems().add(recordLater); + } } contextMenu.getItems().add(new SeparatorMenuItem()); - if(site.supportsFollow()) { + if (site.supportsFollow()) { MenuItem followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow; followOrUnFollow.setDisable(!site.credentialsAvailable()); contextMenu.getItems().add(followOrUnFollow); } - if(site.supportsTips()) { + if (site.supportsTips()) { contextMenu.getItems().add(sendTip); } contextMenu.getItems().addAll(copyUrl, ignore, refresh, openRecDir); - if(cell.getModel() instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) { + if (model instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) { MenuItem debug = new MenuItem("debug"); - debug.setOnAction(e -> MyFreeCamsClient.getInstance().getSessionState(cell.getModel())); + debug.setOnAction(e -> MyFreeCamsClient.getInstance().getSessionState(model)); contextMenu.getItems().add(debug); } @@ -552,6 +508,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { private void startRecordingWithTimeLimit(List list) { for (ThumbCell cell : list) { + cell.getModel().setMarkedForLaterRecording(false); cell.startStopAction(true); new SetStopDateAction(cell, cell.getModel(), recorder).execute(); } @@ -711,6 +668,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { private void startStopAction(List selection, boolean start) { for (ThumbCell thumbCell : selection) { + thumbCell.getModel().setSuspended(false); + thumbCell.getModel().setMarkedForLaterRecording(false); thumbCell.startStopAction(start); } } diff --git a/common/.classpath b/common/.classpath index 3c5e7d17..13fa9dd6 100644 --- a/common/.classpath +++ b/common/.classpath @@ -6,11 +6,7 @@ - - - - - + diff --git a/common/.settings/org.eclipse.jdt.core.prefs b/common/.settings/org.eclipse.jdt.core.prefs index 8b5c4dca..3a0745fd 100644 --- a/common/.settings/org.eclipse.jdt.core.prefs +++ b/common/.settings/org.eclipse.jdt.core.prefs @@ -11,6 +11,6 @@ org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 diff --git a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java index ac3d08a6..7af9a570 100644 --- a/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/NextGenLocalRecorder.java @@ -1,7 +1,17 @@ package ctbrec.recorder; -import static ctbrec.SubsequentAction.*; -import static ctbrec.event.Event.Type.*; +import com.google.common.eventbus.Subscribe; +import ctbrec.Config; +import ctbrec.Model; +import ctbrec.Recording; +import ctbrec.Recording.State; +import ctbrec.event.*; +import ctbrec.io.HttpClient; +import ctbrec.recorder.download.Download; +import ctbrec.recorder.postprocessing.PostProcessor; +import ctbrec.sites.Site; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; @@ -11,50 +21,14 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.*; +import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.Subscribe; - -import ctbrec.Config; -import ctbrec.Model; -import ctbrec.Recording; -import ctbrec.Recording.State; -import ctbrec.event.Event; -import ctbrec.event.EventBusHolder; -import ctbrec.event.ModelIsOnlineEvent; -import ctbrec.event.NoSpaceLeftEvent; -import ctbrec.event.RecordingStateChangedEvent; -import ctbrec.io.HttpClient; -import ctbrec.recorder.download.Download; -import ctbrec.recorder.postprocessing.PostProcessor; -import ctbrec.sites.Site; +import static ctbrec.SubsequentAction.PAUSE; +import static ctbrec.SubsequentAction.REMOVE; +import static ctbrec.event.Event.Type.MODEL_ONLINE; public class NextGenLocalRecorder implements Recorder { @@ -197,8 +171,13 @@ public class NextGenLocalRecorder implements Recorder { } @Override - public void startRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException { - if (!models.contains(model)) { + 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()); + startRecordingProcess(existing.get()); + } else { LOG.info("Model {} added", model); recorderLock.lock(); try { @@ -210,7 +189,6 @@ public class NextGenLocalRecorder implements Recorder { } finally { recorderLock.unlock(); } - startRecordingProcess(model); } } @@ -389,22 +367,6 @@ public class NextGenLocalRecorder implements Recorder { } } - @Override - public boolean isTracked(Model model) { - recorderLock.lock(); - try { - int index = models.indexOf(model); - if (index >= 0) { - Model modelFromList = models.get(index); - return !modelFromList.isMarkedForLaterRecording(); - } else { - return false; - } - } finally { - recorderLock.unlock(); - } - } - @Override public List getModels() { recorderLock.lock(); @@ -512,16 +474,31 @@ public class NextGenLocalRecorder implements Recorder { } } + @Override + public boolean isTracked(Model model) { + Optional m = findModel(model); + boolean markedForRecording = m.map(Model::isMarkedForLaterRecording).orElse(false); + return m.isPresent() && !markedForRecording; + } + @Override public boolean isSuspended(Model model) { + return findModel(model).map(Model::isSuspended).orElse(false); + } + + @Override + public boolean isMarkedForLaterRecording(Model model) { + return findModel(model).map(Model::isMarkedForLaterRecording).orElse(false); + } + + private Optional findModel(Model m) { recorderLock.lock(); try { - int index = models.indexOf(model); + int index = models.indexOf(m); if (index >= 0) { - Model m = models.get(index); - return m.isSuspended(); + return Optional.of(models.get(index)); } else { - return false; + return Optional.empty(); } } finally { recorderLock.unlock(); @@ -725,6 +702,6 @@ public class NextGenLocalRecorder implements Recorder { @Override public int getModelCount() { - return models.size(); + return (int) models.stream().filter(m -> !m.isMarkedForLaterRecording()).count(); } } diff --git a/common/src/main/java/ctbrec/recorder/Recorder.java b/common/src/main/java/ctbrec/recorder/Recorder.java index 58a730e9..4c88b47b 100644 --- a/common/src/main/java/ctbrec/recorder/Recorder.java +++ b/common/src/main/java/ctbrec/recorder/Recorder.java @@ -1,17 +1,17 @@ package ctbrec.recorder; +import ctbrec.Model; +import ctbrec.Recording; +import ctbrec.io.HttpClient; + import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.stream.Collectors; -import ctbrec.Model; -import ctbrec.Recording; -import ctbrec.io.HttpClient; - public interface Recorder { - public void startRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; + public void addModel(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; public void stopRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; public void stopRecordingAt(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException; @@ -59,6 +59,8 @@ public interface Recorder { public boolean isSuspended(Model model); + public boolean isMarkedForLaterRecording(Model model); + /** * Returns only the models from getModels(), which are online * @return diff --git a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java index 6cde231e..0ebcbdd6 100644 --- a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java +++ b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java @@ -1,5 +1,25 @@ package ctbrec.recorder; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import ctbrec.Config; +import ctbrec.Hmac; +import ctbrec.Model; +import ctbrec.Recording; +import ctbrec.event.EventBusHolder; +import ctbrec.event.NoSpaceLeftEvent; +import ctbrec.event.RecordingStateChangedEvent; +import ctbrec.io.*; +import ctbrec.sites.Site; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.Request.Builder; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -7,38 +27,7 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Duration; import java.time.Instant; -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; -import org.slf4j.LoggerFactory; - -import com.squareup.moshi.JsonAdapter; -import com.squareup.moshi.Moshi; - -import ctbrec.Config; -import ctbrec.Hmac; -import ctbrec.Model; -import ctbrec.Recording; -import ctbrec.event.EventBusHolder; -import ctbrec.event.NoSpaceLeftEvent; -import ctbrec.event.RecordingStateChangedEvent; -import ctbrec.io.BandwidthMeter; -import ctbrec.io.FileJsonAdapter; -import ctbrec.io.HttpClient; -import ctbrec.io.HttpException; -import ctbrec.io.InstantJsonAdapter; -import ctbrec.io.ModelJsonAdapter; -import ctbrec.sites.Site; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.Request.Builder; -import okhttp3.RequestBody; -import okhttp3.Response; +import java.util.*; public class RemoteRecorder implements Recorder { @@ -86,7 +75,7 @@ public class RemoteRecorder implements Recorder { } @Override - public void startRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException { + public void addModel(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException { sendRequest("start", model); } @@ -179,17 +168,27 @@ public class RemoteRecorder implements Recorder { @Override public boolean isTracked(Model model) { - return models != null && models.contains(model); + Optional m = findModel(model); + boolean markedForRecording = m.map(Model::isMarkedForLaterRecording).orElse(false); + return m.isPresent() && !markedForRecording; } @Override public boolean isSuspended(Model model) { - int index = models.indexOf(model); + return findModel(model).map(Model::isSuspended).orElse(false); + } + + @Override + public boolean isMarkedForLaterRecording(Model model) { + return findModel(model).map(Model::isMarkedForLaterRecording).orElse(false); + } + + private Optional findModel(Model m) { + int index = Optional.ofNullable(models).map(list -> list.indexOf(m)).orElse(-1); if (index >= 0) { - Model m = models.get(index); - return m.isSuspended(); + return Optional.of(models.get(index)); } else { - return false; + return Optional.empty(); } } @@ -594,6 +593,6 @@ public class RemoteRecorder implements Recorder { @Override public int getModelCount() { - return models.size(); + return (int) models.stream().filter(m -> !m.isMarkedForLaterRecording()).count(); } } diff --git a/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java b/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java index 7dcb1c00..44cb2b58 100644 --- a/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java +++ b/server/src/main/java/ctbrec/recorder/server/RecorderServlet.java @@ -1,27 +1,7 @@ package ctbrec.recorder.server; -import static javax.servlet.http.HttpServletResponse.*; - -import java.io.File; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.time.Instant; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; - import ctbrec.Config; import ctbrec.Model; import ctbrec.Recording; @@ -31,6 +11,23 @@ import ctbrec.io.InstantJsonAdapter; import ctbrec.io.ModelJsonAdapter; import ctbrec.recorder.Recorder; import ctbrec.sites.Site; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import static javax.servlet.http.HttpServletResponse.*; public class RecorderServlet extends AbstractCtbrecServlet { @@ -73,7 +70,7 @@ public class RecorderServlet extends AbstractCtbrecServlet { switch (request.action) { case "start": LOG.debug("Starting recording for model {} - {}", request.model.getName(), request.model.getUrl()); - recorder.startRecording(request.model); + recorder.addModel(request.model); String response = "{\"status\": \"success\", \"msg\": \"Recording started\"}"; resp.getWriter().write(response); break; @@ -262,7 +259,7 @@ public class RecorderServlet extends AbstractCtbrecServlet { for (Site site : sites) { Model model = site.createModelFromUrl(url); if (model != null) { - recorder.startRecording(model); + recorder.addModel(model); return; } } @@ -276,7 +273,7 @@ public class RecorderServlet extends AbstractCtbrecServlet { for (Site site : sites) { if (Objects.equals(siteName.toLowerCase(), site.getClass().getSimpleName().toLowerCase())) { Model m = site.createModel(modelName); - recorder.startRecording(m); + recorder.addModel(m); return; } }