Merge remote-tracking branch 'github/dev' into dev

This commit is contained in:
0xb00bface 2023-12-30 11:43:36 +01:00
commit 93cafcbd2d
25 changed files with 364 additions and 20 deletions

View File

@ -8,7 +8,8 @@ public enum Icon {
CLOCK_16(Icon.class.getResource("/16/clock.png").toExternalForm()),
GROUP_16(Icon.class.getResource("/16/users.png").toExternalForm()),
MEDIA_PLAYBACK_PAUSE_16(Icon.class.getResource("/16/media-playback-pause.png").toExternalForm()),
MEDIA_RECORD_16(Icon.class.getResource("/16/media-record.png").toExternalForm());
MEDIA_RECORD_16(Icon.class.getResource("/16/media-record.png").toExternalForm()),
MEDIA_FORCE_RECORD_16(Icon.class.getResource("/16/media-force-record.png").toExternalForm());
private String url;

View File

@ -27,6 +27,7 @@ public class JavaFxModel implements Model {
private final transient BooleanProperty onlineProperty = new SimpleBooleanProperty();
private final transient BooleanProperty recordingProperty = new SimpleBooleanProperty();
private final transient BooleanProperty pausedProperty = new SimpleBooleanProperty();
private final transient BooleanProperty forcePriorityProperty = new SimpleBooleanProperty();
private final transient SimpleIntegerProperty priorityProperty = new SimpleIntegerProperty();
private final transient SimpleObjectProperty<Instant> lastSeenProperty = new SimpleObjectProperty<>();
private final transient SimpleObjectProperty<Instant> lastRecordedProperty = new SimpleObjectProperty<>();
@ -119,6 +120,10 @@ public class JavaFxModel implements Model {
public BooleanProperty getPausedProperty() {
return pausedProperty;
}
public BooleanProperty getForcePriorityProperty() {
return forcePriorityProperty;
}
public SimpleIntegerProperty getPriorityProperty() {
return priorityProperty;
@ -258,6 +263,18 @@ public class JavaFxModel implements Model {
return delegate.getPriority();
}
@Override
public boolean isForcePriority() {
return delegate.isForcePriority();
}
@Override
public void setForcePriority(boolean forcePriority) {
delegate.setForcePriority(forcePriority);
forcePriorityProperty.set(forcePriority);
}
public SimpleObjectProperty<Instant> lastSeenProperty() {
return lastSeenProperty;
}

View File

@ -0,0 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.ui.tasks.ForcePriorityTask;
import javafx.scene.Node;
public class ForcePriorityAction extends AbstractModelAction {
public ForcePriorityAction(Node source, List<Model> models, Recorder recorder) {
super(source, models, recorder, new ForcePriorityTask(recorder));
}
public CompletableFuture<List<Result>> execute() {
return super.execute("Couldn't force ignoring priority", "Force priority of {0} failed:");
}
}

View File

@ -0,0 +1,20 @@
package ctbrec.ui.action;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.ui.tasks.ResumePriorityTask;
import javafx.scene.Node;
public class ResumePriorityAction extends AbstractModelAction {
public ResumePriorityAction(Node source, List<Model> models, Recorder recorder) {
super(source, models, recorder, new ResumePriorityTask(recorder));
}
public CompletableFuture<List<Result>> execute() {
return super.execute("Couldn't resume respecting priority", "Resuming priority of {0} failed:");
}
}

View File

@ -0,0 +1,51 @@
package ctbrec.ui.menu;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.ui.action.ForcePriorityAction;
import ctbrec.ui.action.ResumePriorityAction;
import javafx.scene.Node;
public class ForcePriorityHandler {
private static final Logger LOG = LoggerFactory.getLogger(ForcePriorityHandler.class);
private Node source;
private Recorder recorder;
private Runnable callback;
public ForcePriorityHandler(Node source, Recorder recorder, Runnable callback) {
this.source = source;
this.recorder = recorder;
this.callback = callback;
}
protected void forcePriority(List<Model> selectedModels) {
new ForcePriorityAction(source, selectedModels, recorder).execute()
.exceptionally(ex -> {
LOG.error("Error while forcing ignore priority", ex);
return null;
}).whenComplete((r, ex) -> executeCallback());
}
protected void resumePriority(List<Model> selectedModels) {
new ResumePriorityAction(source, selectedModels, recorder).execute()
.exceptionally(ex -> {
LOG.error("Error while resuming respecting priority", ex);
return null;
}).whenComplete((r, ex) -> executeCallback());
}
private void executeCallback() {
try {
callback.run();
} catch (Exception e) {
LOG.error("Error while executing menu callback", e);
}
}
}

View File

@ -101,6 +101,7 @@ public class ModelMenuContributor {
addStartPaused(menu, selectedModels);
addRecordLater(menu, selectedModels);
addPauseResume(menu, selectedModels);
addForceRecord(menu, selectedModels);
addGroupMenu(menu, selectedModels);
menu.getItems().add(new SeparatorMenuItem());
@ -272,6 +273,24 @@ public class ModelMenuContributor {
}
}
private void addForceRecord(ContextMenu menu, List<Model> selectedModels) {
var forcePriority = new MenuItem("Enable Force Recording");
forcePriority.setOnAction(e -> {
for (Model model : selectedModels) {
model.setMarkedForLaterRecording(false);
model.setSuspended(false);
}
if (!recorder.isTracked(selectedModels.get(0))) {
startStopAction(selectedModels, true);
}
new ForcePriorityHandler(source, recorder, callback).forcePriority(selectedModels);
});
var resumePriority = new MenuItem("Disable Force Recording");
resumePriority.setOnAction(e -> new ForcePriorityHandler(source, recorder, callback).resumePriority(selectedModels));
var forceResumePriority = recorder.isForcePriority(selectedModels.get(0)) ? resumePriority : forcePriority;
menu.getItems().add(forceResumePriority);
}
private void addRecordLater(ContextMenu menu, List<Model> selectedModels) {
var first = selectedModels.get(0);
var recordLater = new MenuItem("Record Later");

View File

@ -44,10 +44,6 @@ public class IgnoreList extends GridPane {
setVgap(10);
setPadding(new Insets(20, 10, 10, 10));
var headline = new Label("Ignore List");
headline.getStyleClass().add("settings-group-label");
add(headline, 0, 0);
ignoreListView = new ListView<>();
ignoreListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
ignoreListView.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
@ -55,7 +51,7 @@ public class IgnoreList extends GridPane {
removeSelectedModels();
}
});
add(ignoreListView, 0, 1);
add(ignoreListView, 0, 0);
GridPane.setHgrow(ignoreListView, Priority.ALWAYS);
var remove = new Button("Remove");

View File

@ -129,6 +129,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
private final VariablePlayGroundDialogFactory variablePlayGroundDialogFactory = new VariablePlayGroundDialogFactory();
private SimpleBooleanProperty checkForUpdates;
private PostProcessingStepPanel postProcessingStepPanel;
private SimpleStringProperty filterBlacklist;
private SimpleStringProperty filterWhitelist;
public SettingsTab(List<Site> sites, Recorder recorder) {
this.sites = sites;
@ -207,6 +209,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
dateTimeFormat = new SimpleStringProperty(null, "dateTimeFormat", settings.dateTimeFormat);
tabsSortable = new SimpleBooleanProperty(null, "tabsSortable", settings.tabsSortable);
checkForUpdates = new SimpleBooleanProperty(null, "checkForUpdates", settings.checkForUpdates);
filterBlacklist = new SimpleStringProperty(null, "filterBlacklist", settings.filterBlacklist);
filterWhitelist = new SimpleStringProperty(null, "filterWhitelist", settings.filterWhitelist);
}
private void createGui() {
@ -297,8 +301,13 @@ public class SettingsTab extends Tab implements TabSelectionListener {
Setting.of("Steps", postProcessingStepPanel),
Setting.of("", createHelpButton("Post-Processing Help", "http://localhost:5689/docs/PostProcessing.md")),
Setting.of("", createVariablePlayGroundButton()))),
Category.of("Events & Actions", new ActionSettingsPanel(recorder)), Category.of("Ignore List", ignoreList),
Category.of("Sites", siteCategories.toArray(new Category[0])),
Category.of("Events & Actions", new ActionSettingsPanel(recorder)),
Category.of("Filtering",
Group.of("Ignore List",
Setting.of("", ignoreList)),
Group.of("Text Filters",
Setting.of("Blacklist", filterBlacklist, "Default list of blacklist filters for site views, space seperated"),
Setting.of("Whitelist", filterWhitelist, "Default list of whitelist filters for site views, space seperated"))), Category.of("Sites", siteCategories.toArray(new Category[0])),
Category.of("Proxy",
Group.of("Proxy",
Setting.of("Type", proxyType).needsRestart(),

View File

@ -73,6 +73,7 @@ public class ThumbCell extends StackPane {
private static final Duration ANIMATION_DURATION = new Duration(250);
private static final Image imgRecordIndicator = new Image(MEDIA_RECORD_16.url());
private static final Image imgForceRecordIndicator = new Image(MEDIA_FORCE_RECORD_16.url());
private static final Image imgPauseIndicator = new Image(MEDIA_PLAYBACK_PAUSE_16.url());
private static final Image imgBookmarkIndicator = new Image(BOOKMARK_16.url());
private static final Image imgGroupIndicator = new Image(Icon.GROUP_16.url());
@ -122,6 +123,7 @@ public class ThumbCell extends StackPane {
this.imgAspectRatio = aspectRatio;
recording = recorder.isTracked(model);
model.setSuspended(recorder.isSuspended(model));
model.setForcePriority(recorder.isForcePriority(model));
this.setStyle("-fx-background-color: -fx-base");
streamPreview = new StreamPreview();
@ -497,7 +499,11 @@ public class ThumbCell extends StackPane {
recordingIndicatorTooltip.setText("Resume Recording");
} else {
modelRecordingState = ModelRecordingState.RECORDING;
recordingIndicator.setImage(imgRecordIndicator);
if (model.isForcePriority()) {
recordingIndicator.setImage(imgForceRecordIndicator);
} else {
recordingIndicator.setImage(imgRecordIndicator);
}
recordingIndicatorTooltip.setText("Pause Recording");
}
} else {

View File

@ -317,13 +317,29 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
if (updatesSuspended) {
return;
}
List<Model> models = filterIgnoredModels(updateService.getValue());
List<Model> models = filterModels(updateService.getValue());
updateGrid(models);
}
private List<Model> filterIgnoredModels(List<Model> models) {
private List<Model> filterModels(List<Model> models) {
List<String> ignored = Config.getInstance().getSettings().ignoredModels;
return models.stream().filter(m -> !ignored.contains(m.getUrl())).collect(Collectors.toList());
String filterBlacklist = Config.getInstance().getSettings().filterBlacklist;
String filterWhitelist = Config.getInstance().getSettings().filterWhitelist;
if (filterBlacklist.isBlank() && filterWhitelist.isBlank()) {
return models.stream()
.filter(m -> !ignored.contains(m.getUrl()))
.collect(Collectors.toList());
} else if (filterBlacklist.isBlank()) {
return models.stream()
.filter(m -> !ignored.contains(m.getUrl()))
.filter(m -> matches(m, filterWhitelist, true))
.collect(Collectors.toList());
}
return models.stream()
.filter(m -> !ignored.contains(m.getUrl()))
.filter(m -> !matches(m, filterBlacklist, true))
.filter(m -> matches(m, filterWhitelist, true))
.collect(Collectors.toList());
}
protected void updateGrid(List<? extends Model> models) {
@ -633,7 +649,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
var node = iterator.next();
if (node instanceof ThumbCell cell) {
var m = cell.getModel();
if (!matches(m, filter)) {
if (!matches(m, filter, false)) {
iterator.remove();
filteredThumbCells.add(cell);
cell.setSelected(false);
@ -645,7 +661,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
for (Iterator<ThumbCell> iterator = filteredThumbCells.iterator(); iterator.hasNext(); ) {
var thumbCell = iterator.next();
var m = thumbCell.getModel();
if (matches(m, filter)) {
if (matches(m, filter, false)) {
iterator.remove();
insert(thumbCell);
}
@ -687,12 +703,14 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
}
}
private boolean matches(Model m, String filter) {
private boolean matches(Model m, String filter, Boolean anyMatch) {
try {
String[] tokens = filter.split(" ");
var tokensMissing = false;
for (String token : tokens) {
if (!modelPropertiesMatchToken(token, m)) {
if (anyMatch && modelPropertiesMatchToken(token, m)) {
return true;
} else if (!modelPropertiesMatchToken(token, m)) {
tokensMissing = true;
}
}

View File

@ -36,6 +36,9 @@ public class ModelNameTableCell extends IconTableCell<ModelName> {
tooltip = group.getModelUrls().size() + " models:\n";
tooltip += group.getModelUrls().stream().collect(Collectors.joining("\n"));
});
if (m.isForcePriority()) {
this.setStyle(getStyle() + "-fx-text-fill: darkred;" + "-fx-font-weight: bold;");
}
}
super.updateItem(modelName, empty);
}

View File

@ -257,10 +257,12 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
if (index == -1) {
observableModels.add(updatedModel);
updatedModel.getPausedProperty().addListener(createPauseListener(updatedModel));
updatedModel.getForcePriorityProperty().addListener(createForcePriorityListener(updatedModel));
} else {
// make sure to update the JavaFX online property, so that the table cell is updated
JavaFxModel oldModel = observableModels.get(index);
oldModel.setSuspended(updatedModel.isSuspended());
oldModel.setForcePriority(updatedModel.isForcePriority());
oldModel.getOnlineProperty().set(updatedModel.getOnlineProperty().get());
oldModel.getRecordingProperty().set(updatedModel.getRecordingProperty().get());
oldModel.lastRecordedProperty().set(updatedModel.lastRecordedProperty().get());
@ -285,6 +287,20 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
};
}
private ChangeListener<Boolean> createForcePriorityListener(JavaFxModel updatedModel) {
return (obs, oldV, newV) -> {
if (Boolean.TRUE.equals(newV)) {
if (!recorder.isForcePriority(updatedModel)) {
forcePriority(Collections.singletonList(updatedModel));
}
} else {
if (recorder.isForcePriority(updatedModel)) {
resumePriority(Collections.singletonList(updatedModel));
}
}
};
}
private ScheduledService<List<JavaFxModel>> createUpdateService() {
ScheduledService<List<JavaFxModel>> modelUpdateService = new ScheduledService<>() {
@Override
@ -370,6 +386,16 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
new ResumeAction(getTabPane(), models, recorder).execute();
}
private void forcePriority(List<JavaFxModel> selectedModels) {
List<Model> models = selectedModels.stream().map(JavaFxModel::getDelegate).toList();
new ForcePriorityAction(getTabPane(), models, recorder).execute();
}
private void resumePriority(List<JavaFxModel> selectedModels) {
List<Model> models = selectedModels.stream().map(JavaFxModel::getDelegate).toList();
new ResumePriorityAction(getTabPane(), models, recorder).execute();
}
private class PriorityCellFactory implements Callback<TableColumn<JavaFxModel, Number>, TableCell<JavaFxModel, Number>> {
@Override
public TableCell<JavaFxModel, Number> call(TableColumn<JavaFxModel, Number> param) {

View File

@ -0,0 +1,17 @@
package ctbrec.ui.tasks;
import ctbrec.recorder.Recorder;
public class ForcePriorityTask extends AbstractModelTask {
public ForcePriorityTask(Recorder recorder) {
super(recorder, model -> {
try {
model.setForcePriority(true);
recorder.forcePriorityRecording(model);
} catch (Exception e) {
throw new TaskExecutionException(e);
}
});
}
}

View File

@ -0,0 +1,17 @@
package ctbrec.ui.tasks;
import ctbrec.recorder.Recorder;
public class ResumePriorityTask extends AbstractModelTask {
public ResumePriorityTask(Recorder recorder) {
super(recorder, model -> {
try {
model.setForcePriority(false);
recorder.resumePriorityRecording(model);
} catch (Exception e) {
throw new TaskExecutionException(e);
}
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -30,6 +30,7 @@ public abstract class AbstractModel implements Model {
private int streamUrlIndex = -1;
private int priority = new Settings().defaultPriority;
private boolean suspended = false;
private boolean forcePriority = false;
private boolean markedForLaterRecording = false;
protected transient Site site;
protected State onlineState = State.UNKNOWN;
@ -145,6 +146,12 @@ public abstract class AbstractModel implements Model {
this.suspended = suspended;
}
@Override
public boolean isForcePriority() { return forcePriority; }
@Override
public void setForcePriority(boolean forcePriority) { this.forcePriority = forcePriority; }
@Override
public void delay() {
this.delayUntil = Instant.now().plusSeconds(120);

View File

@ -123,6 +123,10 @@ public interface Model extends Comparable<Model>, Serializable {
void setSuspended(boolean suspended);
boolean isForcePriority();
void setForcePriority(boolean forcePriority);
void delay();
boolean isDelayed();

View File

@ -216,4 +216,6 @@ public class Settings {
public boolean checkForUpdates = true;
public int thumbCacheSize = 16;
public boolean dreamcamVR = false;
public String filterBlacklist = "";
public String filterWhitelist = "";
}

View File

@ -24,6 +24,7 @@ public class ModelDto {
private int streamUrlIndex = -1;
private boolean suspended = false;
private boolean bookmarked = false;
private boolean forcePriority = false;
@JsonSerialize(converter = InstantToMillisConverter.class)
@JsonDeserialize(converter = MillisToInstantConverter.class)
private Instant lastSeen;

View File

@ -67,6 +67,14 @@ public interface Recorder {
boolean isSuspended(Model model);
/**
* Returns true, if a model is in the list of models to ignore priorities and immediately record.
*/
public boolean isForcePriority(Model model);
public void forcePriorityRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
public void resumePriorityRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
boolean isMarkedForLaterRecording(Model model);
void markForLaterRecording(Model model, boolean mark) throws InvalidKeyException, NoSuchAlgorithmException, IOException;

View File

@ -98,7 +98,7 @@ public class RecordingPreconditions {
lastPreconditionMessage = now;
}
// check, if we can stop a recording for a model with lower priority
Optional<Recording> lowerPrioRecordingProcess = recordingProcessWithLowerPrio(model.getPriority());
Optional<Recording> lowerPrioRecordingProcess = recordingProcessWithLowerPrio(model.getPriority(), model.isForcePriority());
if (lowerPrioRecordingProcess.isPresent()) {
RecordingProcess download = lowerPrioRecordingProcess.get().getRecordingProcess();
Model lowerPrioModel = download.getModel();
@ -110,17 +110,17 @@ public class RecordingPreconditions {
}
}
private Optional<Recording> recordingProcessWithLowerPrio(int priority) {
private Optional<Recording> recordingProcessWithLowerPrio(int priority, boolean isForced) {
Recording lowest = null;
int lowestPrio = Integer.MAX_VALUE;
for (Recording rec : recorder.getRecordingProcesses()) {
Model m = rec.getModel();
if (m.getPriority() < lowestPrio) {
if (m.getPriority() < lowestPrio && !m.isForcePriority()) {
lowest = rec;
lowestPrio = m.getPriority();
}
}
if (lowestPrio < priority) {
if (isForced || (lowestPrio < priority)) {
return Optional.of(lowest);
} else {
return Optional.empty();

View File

@ -86,6 +86,7 @@ public class RemoteRecorder implements Recorder {
sendRequest("start", model);
findModel(model).ifPresent(cachedModel -> {
cachedModel.setSuspended(model.isSuspended());
cachedModel.setForcePriority(model.isForcePriority());
cachedModel.setMarkedForLaterRecording(model.isMarkedForLaterRecording());
cachedModel.setRecordUntil(model.getRecordUntil());
cachedModel.setRecordUntilSubsequentAction(model.getRecordUntilSubsequentAction());
@ -219,6 +220,11 @@ public class RemoteRecorder implements Recorder {
return findModel(model).map(Model::isSuspended).orElse(false);
}
@Override
public boolean isForcePriority(Model model) {
return findModel(model).map(Model::isForcePriority).orElse(false);
}
@Override
public boolean isMarkedForLaterRecording(Model model) {
return findModel(model).map(Model::isMarkedForLaterRecording).orElse(false);
@ -565,6 +571,30 @@ public class RemoteRecorder implements Recorder {
}
}
@Override
public void forcePriorityRecording(Model model) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
sendRequest("forcePriority", model);
model.setForcePriority(true);
// update cached model
int index = models.indexOf(model);
if (index >= 0) {
Model m = models.get(index);
m.setForcePriority(true);
}
}
@Override
public void resumePriorityRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
sendRequest("resumePriority", model);
model.setForcePriority(false);
// update cached model
int index = models.indexOf(model);
if (index >= 0) {
Model m = models.get(index);
m.setForcePriority(false);
}
}
@Override
public List<Model> getOnlineModels() {
return onlineModels;

View File

@ -345,6 +345,7 @@ public class SimplifiedLocalRecorder implements Recorder {
private void copyModelProperties(Model src, Model existing) {
existing.setSuspended(src.isSuspended());
existing.setForcePriority(src.isForcePriority());
existing.setMarkedForLaterRecording(src.isMarkedForLaterRecording());
existing.setPriority(src.getPriority());
existing.setRecordUntil(src.getRecordUntil());
@ -578,6 +579,49 @@ public class SimplifiedLocalRecorder implements Recorder {
}
}
@Override
public void forcePriorityRecording(Model model) throws IOException {
recorderLock.lock();
try {
if (models.contains(model)) {
int index = models.indexOf(model);
Model m = models.get(index);
m.setForcePriority(true);
m.setMarkedForLaterRecording(false);
model.setForcePriority(true);
model.setMarkedForLaterRecording(false);
saveConfig();
startRecordingProcess(m);
} else {
log.warn("Couldn't force ignore priority for model {}. Not found in list", model.getName());
}
} finally {
recorderLock.unlock();
}
}
@Override
public void resumePriorityRecording(Model model) {
recorderLock.lock();
try {
if (models.contains(model)) {
int index = models.indexOf(model);
models.get(index).setForcePriority(false);
model.setForcePriority(false);
saveConfig();
} else {
log.warn("Couldn't resume respecting priority for model {}. Not found in list", model.getName());
return;
}
getRecordingProcessForModel(model).ifPresent(this::stopRecordingProcess);
} catch (IOException e) {
errorSavingConfig(e);
} finally {
recorderLock.unlock();
}
}
@Override
public boolean isTracked(Model model) {
Optional<Model> m = findModel(model);
@ -863,6 +907,11 @@ public class SimplifiedLocalRecorder implements Recorder {
log.info("Resuming recorder");
running = true;
}
@Override
public boolean isForcePriority(Model model) {
return findModel(model).map(Model::isForcePriority).orElse(false);
}
@Override
public int getModelCount() {

View File

@ -25,6 +25,7 @@ class ModelMapperTest {
model.setLastSeen(Instant.now().minusSeconds(60));
model.setPriority(51);
model.setSuspended(true);
model.setForcePriority(false);
model.setMarkedForLaterRecording(true);
model.setRecordUntilSubsequentAction(SubsequentAction.REMOVE);
model.setDisplayName("whatever");
@ -45,6 +46,7 @@ class ModelMapperTest {
assertEquals(model.getPreview(), mapped.getPreview().toString());
assertEquals(model.isMarkedForLaterRecording(), mapped.isBookmarked());
assertEquals(model.isSuspended(), mapped.isSuspended());
assertEquals(model.isForcePriority(), mapped.isForcePriority());
}
@Test
@ -61,6 +63,7 @@ class ModelMapperTest {
dto.setLastSeen(Instant.now().minusSeconds(60));
dto.setPriority(51);
dto.setSuspended(true);
dto.setForcePriority(false);
dto.setBookmarked(true);
dto.setRecordUntilSubsequentAction(SubsequentAction.REMOVE);
dto.setDisplayName("whatever");
@ -81,5 +84,6 @@ class ModelMapperTest {
assertEquals(dto.getPreview().toString(), mapped.getPreview());
assertEquals(dto.isBookmarked(), mapped.isMarkedForLaterRecording());
assertEquals(dto.isSuspended(), mapped.isSuspended());
assertEquals(dto.isForcePriority(), mapped.isForcePriority());
}
}

View File

@ -87,6 +87,7 @@ public class RecorderServlet extends AbstractCtbrecServlet {
log.debug("Starting recording for model {} - {}", model.getName(), model.getUrl());
log.trace("Model marked: {}", model.isMarkedForLaterRecording());
log.trace("Model paused: {}", model.isSuspended());
log.trace("Model forced: {}", model.isForcePriority());
log.trace("Model until: {}", model.getRecordUntil().equals(Instant.ofEpochMilli(Model.RECORD_INDEFINITELY)) ? "no limit" : model.getRecordUntil());
log.trace("Model after: {}", model.getRecordUntilSubsequentAction());
recorder.addModel(model);
@ -227,6 +228,24 @@ public class RecorderServlet extends AbstractCtbrecServlet {
response = "{\"status\": \"success\"}";
responseWriter.write(response);
break;
case "forcePriority":
log.debug("Force ignore priority for model {} - {}", model.getName(), model.getUrl());
recorder.forcePriorityRecording(model);
response = "{\"status\": \"success\", \"msg\": \"Forcing ignore priority\"}";
responseWriter.write(response);
break;
case "resumePriority":
log.debug("Resume respecting priority for model {} - {}", model.getName(), model.getUrl());
GlobalThreadPool.submit(() -> {
try {
recorder.resumePriorityRecording(model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
log.error("Couldn't resume respecting priority for model {}", model, e);
}
});
response = "{\"status\": \"success\", \"msg\": \"Resuming respecting priority\"}";
responseWriter.write(response);
break;
case "saveModelGroup":
recorder.saveModelGroup(request.getModelGroup());
sendModelGroups(resp, recorder.getModelGroups());