Patching in ForcePriority changes, needs test case
Patching in the first set which is ForcePriority context menu feature, allows instantly bumping a model to top of priority list no matter what their priority value is. # TODO - Needs a test case, I made an attempt but unfortunately I do not know enough to get this working so I have removed it. Doesn't help I had to do some mangling to get the current path joining to work properly with Windows-based paths and pass the current tests. - The basic test case it needs is 2 Models, Model with lower priority does not record, forcepriority to true on lower priority Model, Model with lower priority should now record, set back to false on lower priority Model, Model with lower priority should no longer record.
This commit is contained in:
parent
2f1ef7854a
commit
fe21f8d6a9
|
@ -258,6 +258,17 @@ public class JavaFxModel implements Model {
|
|||
return delegate.getPriority();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isForcePriority() {
|
||||
return delegate.isForcePriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForcePriority(boolean forcePriority) {
|
||||
delegate.setForcePriority(forcePriority);
|
||||
}
|
||||
|
||||
public SimpleObjectProperty<Instant> lastSeenProperty() {
|
||||
return lastSeenProperty;
|
||||
}
|
||||
|
|
|
@ -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:");
|
||||
}
|
||||
}
|
|
@ -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:");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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("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("Resume Priority");
|
||||
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");
|
||||
|
|
|
@ -285,6 +285,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 +384,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) {
|
||||
|
@ -389,6 +413,10 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
|
|||
prio = Math.min(Math.max(0, prio), Model.MAX_PRIO);
|
||||
m.setPriority(prio);
|
||||
updatePriority(m, prio);
|
||||
if (m.isForcePriority()) {
|
||||
tableCell.setStyle("-fx-font-weight: bold;");
|
||||
tableCell.setStyle("-fx-background-color: red;");
|
||||
}
|
||||
}
|
||||
});
|
||||
tableCell.setStyle("-fx-alignment: CENTER-LEFT;");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,7 +110,7 @@ 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()) {
|
||||
|
@ -120,7 +120,7 @@ public class RecordingPreconditions {
|
|||
lowestPrio = m.getPriority();
|
||||
}
|
||||
}
|
||||
if (lowestPrio < priority) {
|
||||
if (isForced || (lowestPrio < priority)) {
|
||||
return Optional.of(lowest);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
|
|
|
@ -219,6 +219,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);
|
||||
|
@ -558,6 +563,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;
|
||||
|
|
|
@ -578,6 +578,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 +906,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() {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,6 +227,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());
|
||||
|
|
Loading…
Reference in New Issue