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
This commit is contained in:
0xb00bface 2021-01-09 12:45:38 +01:00
parent 2ecc447902
commit 17aa5bc18d
14 changed files with 261 additions and 416 deletions

View File

@ -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());

View File

@ -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<? extends Model> 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));
}

View File

@ -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<Model> implements Pop
CompletableFuture.runAsync(new Task<Void>() {
@Override
protected Void call() throws Exception {
recorder.startRecording(model);
recorder.addModel(model);
return null;
}
@ -324,4 +319,4 @@ public class SearchPopoverTreeList extends PopoverTreeList<Model> implements Pop
public void setRecorder(Recorder recorder) {
this.recorder = recorder;
}
}
}

View File

@ -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 {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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<ThumbCell> 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<ThumbCell> selection, boolean start) {
for (ThumbCell thumbCell : selection) {
thumbCell.getModel().setSuspended(false);
thumbCell.getModel().setMarkedForLaterRecording(false);
thumbCell.startStopAction(start);
}
}

View File

@ -6,11 +6,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>

View File

@ -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

View File

@ -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<Model> 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<Model> getModels() {
recorderLock.lock();
@ -512,16 +474,31 @@ public class NextGenLocalRecorder implements Recorder {
}
}
@Override
public boolean isTracked(Model model) {
Optional<Model> 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<Model> 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();
}
}

View File

@ -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

View File

@ -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<Model> 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<Model> 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();
}
}

View File

@ -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;
}
}