Add possibility to group models through a dialog
This commit is contained in:
parent
d52b728c1c
commit
0358a35a84
|
@ -3,7 +3,6 @@ package ctbrec.ui;
|
|||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
@ -14,7 +13,6 @@ import com.squareup.moshi.JsonReader;
|
|||
import com.squareup.moshi.JsonWriter;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroupEntry;
|
||||
import ctbrec.SubsequentAction;
|
||||
import ctbrec.recorder.download.Download;
|
||||
import ctbrec.recorder.download.HttpHeaderFactory;
|
||||
|
@ -331,16 +329,4 @@ public class JavaFxModel implements Model {
|
|||
public void setMarkedForLaterRecording(boolean marked) {
|
||||
delegate.setMarkedForLaterRecording(marked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModelGroup(ModelGroupEntry modelGroupEntry) {
|
||||
delegate.setModelGroup(modelGroupEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModelGroupEntry> getModelGroup() {
|
||||
return delegate.getModelGroup();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
package ctbrec.ui.action;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import ctbrec.ui.controls.autocomplete.ObservableListSuggester;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
public class AddToGroupAction {
|
||||
|
||||
private Node source;
|
||||
private Model model;
|
||||
private Recorder recorder;
|
||||
|
||||
public AddToGroupAction(Node source, Recorder recorder, Model model) {
|
||||
this.source = source;
|
||||
this.recorder = recorder;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
source.setCursor(Cursor.WAIT);
|
||||
try {
|
||||
var dialog = new ModelGroupDialog();
|
||||
boolean ok = Dialogs.showCustomInput(source.getScene(), "Add model to group", dialog.getMainPane());
|
||||
dialog.requestFocus();
|
||||
if (ok) {
|
||||
String text = dialog.getText();
|
||||
if (StringUtil.isBlank(text)) {
|
||||
return;
|
||||
}
|
||||
Set<ModelGroup> modelGroups = Config.getInstance().getSettings().modelGroups;
|
||||
Optional<ModelGroup> existingGroup = modelGroups.stream().filter(mg -> mg.getName().equalsIgnoreCase(text)).findFirst();
|
||||
if (existingGroup.isPresent()) {
|
||||
existingGroup.get().add(model);
|
||||
recorder.saveModelGroup(existingGroup.get());
|
||||
} else {
|
||||
var group = new ModelGroup();
|
||||
group.setId(UUID.randomUUID());
|
||||
group.setName(text);
|
||||
group.add(model);
|
||||
modelGroups.add(group);
|
||||
recorder.saveModelGroup(group);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Dialogs.showError(source.getScene(), "Add model to group", "Saving model group failed", e);
|
||||
} finally {
|
||||
source.setCursor(Cursor.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModelGroupDialog {
|
||||
private ComboBox<ModelGroupListItem> comboBox;
|
||||
private TextField editor;
|
||||
private ObservableListSuggester suggester;
|
||||
|
||||
public String getText() {
|
||||
return comboBox.getEditor().getText();
|
||||
}
|
||||
|
||||
public void requestFocus() {
|
||||
comboBox.requestFocus();
|
||||
editor.requestFocus();
|
||||
}
|
||||
|
||||
Region getMainPane() {
|
||||
var dialogPane = new GridPane();
|
||||
Set<ModelGroup> modelGroups = Config.getInstance().getSettings().modelGroups;
|
||||
List<ModelGroupListItem> comboBoxItems = modelGroups.stream().map(ModelGroupListItem::new).sorted().collect(Collectors.toList());
|
||||
ObservableList<ModelGroupListItem> comboBoxModel = FXCollections.observableArrayList(comboBoxItems);
|
||||
suggester = new ObservableListSuggester(comboBoxModel);
|
||||
comboBox = new ComboBox<>(comboBoxModel);
|
||||
comboBox.setEditable(true);
|
||||
editor = comboBox.getEditor();
|
||||
comboBox.getEditor().addEventHandler(KeyEvent.KEY_RELEASED, evt -> {
|
||||
if (evt.getCode().isLetterKey() || evt.getCode().isDigitKey()) {
|
||||
autocomplete(false);
|
||||
} else if (evt.getCode() == KeyCode.ENTER) {
|
||||
if (editor.getSelection().getLength() > 0) {
|
||||
editor.selectRange(0, 0);
|
||||
editor.insertText(editor.lengthProperty().get(), ":");
|
||||
editor.positionCaret(editor.lengthProperty().get());
|
||||
evt.consume();
|
||||
}
|
||||
} else if (evt.getCode() == KeyCode.SPACE && evt.isControlDown()) {
|
||||
autocomplete(true);
|
||||
}
|
||||
});
|
||||
comboBox.setPlaceholder(new Label(" type in a name to a add a new group "));
|
||||
dialogPane.add(new Label("Model group "), 0, 0);
|
||||
dialogPane.add(comboBox, 1, 0);
|
||||
return dialogPane;
|
||||
}
|
||||
|
||||
private void autocomplete(boolean fulltextSearch) {
|
||||
String oldtext = getOldText();
|
||||
if(oldtext.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<String> match;
|
||||
if (fulltextSearch) {
|
||||
match = suggester.fulltext(oldtext);
|
||||
} else {
|
||||
match = suggester.startsWith(oldtext);
|
||||
}
|
||||
|
||||
if (match.isPresent()) {
|
||||
editor.setText(match.get());
|
||||
int pos = oldtext.length();
|
||||
editor.positionCaret(pos);
|
||||
editor.selectRange(pos, match.get().length());
|
||||
}
|
||||
}
|
||||
|
||||
private String getOldText() {
|
||||
if(editor.getSelection().getLength() > 0) {
|
||||
return editor.getText().substring(0, editor.getSelection().getStart());
|
||||
} else {
|
||||
return editor.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModelGroupListItem implements Comparable<ModelGroupListItem> {
|
||||
private ModelGroup modelGroup;
|
||||
|
||||
public ModelGroupListItem(ModelGroup modelGroup) {
|
||||
this.modelGroup = modelGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.modelGroup.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash(modelGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ModelGroupListItem other = (ModelGroupListItem) obj;
|
||||
return java.util.Objects.equals(modelGroup, other.modelGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ModelGroupListItem o) {
|
||||
return this.modelGroup.getName().compareTo(o.modelGroup.getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,16 +4,26 @@ import static javafx.scene.control.ButtonType.*;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.ui.AutosizeAlert;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Dialog;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
@ -63,7 +73,7 @@ public class Dialogs {
|
|||
Dialog<String> dialog = new Dialog<>();
|
||||
dialog.setTitle(title);
|
||||
dialog.setHeaderText(header);
|
||||
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
||||
dialog.getDialogPane().getButtonTypes().addAll(OK, CANCEL);
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setResizable(true);
|
||||
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
|
||||
|
@ -86,7 +96,7 @@ public class Dialogs {
|
|||
Platform.runLater(notes::requestFocus);
|
||||
|
||||
dialog.setResultConverter(dialogButton -> {
|
||||
if (dialogButton == ButtonType.OK) {
|
||||
if (dialogButton == OK) {
|
||||
return notes.getText();
|
||||
}
|
||||
return null;
|
||||
|
@ -98,7 +108,7 @@ public class Dialogs {
|
|||
public static Boolean showCustomInput(Scene parent, String title, Region region) {
|
||||
Dialog<?> dialog = new Dialog<>();
|
||||
dialog.setTitle(title);
|
||||
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
||||
dialog.getDialogPane().getButtonTypes().addAll(OK, CANCEL);
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setResizable(true);
|
||||
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
|
||||
|
@ -109,7 +119,7 @@ public class Dialogs {
|
|||
}
|
||||
dialog.getDialogPane().setContent(region);
|
||||
dialog.showAndWait();
|
||||
return dialog.getResult() == ButtonType.OK;
|
||||
return dialog.getResult() == OK;
|
||||
}
|
||||
|
||||
public static boolean showConfirmDialog(String title, String message, String header, Scene parent) {
|
||||
|
@ -117,7 +127,7 @@ public class Dialogs {
|
|||
confirm.setTitle(title);
|
||||
confirm.setHeaderText(header);
|
||||
confirm.showAndWait();
|
||||
return confirm.getResult() == ButtonType.YES;
|
||||
return confirm.getResult() == YES;
|
||||
}
|
||||
|
||||
public static ButtonType showShutdownDialog(Scene parent) {
|
||||
|
@ -134,4 +144,36 @@ public class Dialogs {
|
|||
confirm.showAndWait();
|
||||
return confirm.getResult();
|
||||
}
|
||||
|
||||
public static Optional<ModelGroup> showModelGroupSelectionDialog(Scene parent, Model model) {
|
||||
GridPane dialogPane = new GridPane();
|
||||
Set<ModelGroup> modelGroups = Config.getInstance().getSettings().modelGroups;
|
||||
ObservableList<ModelGroup> comboBoxModel = FXCollections.observableArrayList(modelGroups);
|
||||
ComboBox<ModelGroup> comboBox = new ComboBox<>(comboBoxModel);
|
||||
comboBox.setEditable(true);
|
||||
comboBox.setPlaceholder(new Label(" type in a name to a add a new group "));
|
||||
dialogPane.add(new Label("Model group"), 0, 0);
|
||||
dialogPane.add(comboBox, 1, 0);
|
||||
boolean ok = showCustomInput(parent, "Add model to group", dialogPane);
|
||||
if (ok) {
|
||||
String text = comboBox.getEditor().getText();
|
||||
if (StringUtil.isBlank(text)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Optional<ModelGroup> existingGroup = modelGroups.stream().filter(mg -> mg.getName().equalsIgnoreCase(text)).findFirst();
|
||||
if (existingGroup.isPresent()) {
|
||||
existingGroup.get().add(model);
|
||||
return existingGroup;
|
||||
} else {
|
||||
ModelGroup group = new ModelGroup();
|
||||
group.setId(UUID.randomUUID());
|
||||
group.setName(text);
|
||||
group.add(model);
|
||||
modelGroups.add(group);
|
||||
return Optional.of(group);
|
||||
}
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
|
|||
import ctbrec.Config;
|
||||
import ctbrec.GlobalThreadPool;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.Site;
|
||||
|
@ -39,6 +40,7 @@ import ctbrec.ui.DesktopIntegration;
|
|||
import ctbrec.ui.SiteUiFactory;
|
||||
import ctbrec.ui.TipDialog;
|
||||
import ctbrec.ui.TokenLabel;
|
||||
import ctbrec.ui.action.AddToGroupAction;
|
||||
import ctbrec.ui.action.IgnoreModelsAction;
|
||||
import ctbrec.ui.action.OpenRecordingsDir;
|
||||
import ctbrec.ui.action.SetStopDateAction;
|
||||
|
@ -501,6 +503,11 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
MenuItem unfollow = new MenuItem("Unfollow");
|
||||
unfollow.setOnAction(e -> follow(getSelectedThumbCells(cell), false));
|
||||
|
||||
MenuItem addToGroup = new MenuItem("Add to group");
|
||||
addToGroup.setOnAction(e -> addToGroup(model));
|
||||
MenuItem editGroup = new MenuItem("Edit group");
|
||||
editGroup.setOnAction(e -> editGroup(model));
|
||||
|
||||
MenuItem ignore = new MenuItem("Ignore");
|
||||
ignore.setOnAction(e -> ignore(getSelectedThumbCells(cell)));
|
||||
|
||||
|
@ -535,6 +542,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
if (site.supportsTips()) {
|
||||
contextMenu.getItems().add(sendTip);
|
||||
}
|
||||
Optional<ModelGroup> modelGroup = Config.getInstance().getModelGroup(model);
|
||||
contextMenu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup);
|
||||
contextMenu.getItems().addAll(copyUrl, openInBrowser, ignore, refresh, openRecDir);
|
||||
if (model instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||
MenuItem debug = new MenuItem("debug");
|
||||
|
@ -545,6 +554,13 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
return contextMenu;
|
||||
}
|
||||
|
||||
private void editGroup(Model model) {
|
||||
}
|
||||
|
||||
private void addToGroup(Model model) {
|
||||
new AddToGroupAction(this.getContent(), recorder, model).execute();
|
||||
}
|
||||
|
||||
private void recordLater(List<ThumbCell> list, boolean recordLater) {
|
||||
for (ThumbCell cell : list) {
|
||||
cell.recordLater(recordLater);
|
||||
|
|
|
@ -41,7 +41,6 @@ public abstract class AbstractModel implements Model {
|
|||
private Instant lastRecorded;
|
||||
private Instant recordUntil;
|
||||
private SubsequentAction recordUntilSubsequentAction;
|
||||
private Optional<ModelGroupEntry> modelGroup = Optional.empty(); // NOSONAR
|
||||
|
||||
@Override
|
||||
public boolean isOnline() throws IOException, ExecutionException, InterruptedException {
|
||||
|
@ -310,14 +309,4 @@ public abstract class AbstractModel implements Model {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModelGroupEntry> getModelGroup() {
|
||||
return modelGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModelGroup(ModelGroupEntry modelGroup) {
|
||||
this.modelGroup = Optional.ofNullable(modelGroup);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ import java.util.List;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -185,11 +185,11 @@ public class Config {
|
|||
}
|
||||
// 3.11.0 make Cam4 model names lower case
|
||||
settings.models.stream()
|
||||
.filter(Cam4Model.class::isInstance)
|
||||
.forEach(m -> m.setName(m.getName().toLowerCase()));
|
||||
.filter(Cam4Model.class::isInstance)
|
||||
.forEach(m -> m.setName(m.getName().toLowerCase()));
|
||||
settings.modelsIgnored.stream()
|
||||
.filter(Cam4Model.class::isInstance)
|
||||
.forEach(m -> m.setName(m.getName().toLowerCase()));
|
||||
.filter(Cam4Model.class::isInstance)
|
||||
.forEach(m -> m.setName(m.getName().toLowerCase()));
|
||||
// 4.1.2 reduce models ignore to store only the URL
|
||||
if (settings.modelsIgnored != null && !settings.modelsIgnored.isEmpty()) {
|
||||
settings.ignoredModels = settings.modelsIgnored.stream()
|
||||
|
@ -230,9 +230,9 @@ public class Config {
|
|||
}
|
||||
|
||||
public synchronized void save() throws IOException {
|
||||
if (savingDisabled) {
|
||||
return;
|
||||
}
|
||||
if (savingDisabled) {
|
||||
return;
|
||||
}
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(Model.class, new ModelJsonAdapter())
|
||||
.add(PostProcessor.class, new PostProcessorJsonAdapter())
|
||||
|
@ -303,12 +303,18 @@ public class Config {
|
|||
public String getModelNotes(Model m) {
|
||||
return Config.getInstance().getSettings().modelNotes.getOrDefault(m.getUrl(), "");
|
||||
}
|
||||
|
||||
|
||||
public void disableSaving() {
|
||||
savingDisabled = true;
|
||||
savingDisabled = true;
|
||||
}
|
||||
|
||||
|
||||
public void enableSaving() {
|
||||
savingDisabled = false;
|
||||
savingDisabled = false;
|
||||
}
|
||||
|
||||
public Optional<ModelGroup> getModelGroup(Model model) {
|
||||
return getSettings().modelGroups.stream()
|
||||
.filter(mg -> mg.getModelUrls().contains(model.getUrl()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.io.IOException;
|
|||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
@ -149,7 +148,4 @@ public interface Model extends Comparable<Model>, Serializable {
|
|||
*/
|
||||
public boolean exists() throws IOException;
|
||||
|
||||
public void setModelGroup(ModelGroupEntry modelGroupEntry);
|
||||
public Optional<ModelGroupEntry> getModelGroup();
|
||||
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package ctbrec;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -12,7 +11,7 @@ public class ModelGroup implements Serializable {
|
|||
|
||||
private UUID id;
|
||||
private String name;
|
||||
private transient List<Model> models = new LinkedList<>();
|
||||
private List<String> modelUrls = new LinkedList<>();
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
|
@ -30,12 +29,12 @@ public class ModelGroup implements Serializable {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Model> getModels() {
|
||||
return models;
|
||||
public List<String> getModelUrls() {
|
||||
return modelUrls;
|
||||
}
|
||||
|
||||
public void setModels(List<Model> models) {
|
||||
this.models = models;
|
||||
public void setModelUrls(List<String> modelUrls) {
|
||||
this.modelUrls = modelUrls;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,15 +59,14 @@ public class ModelGroup implements Serializable {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModelGroup [id=" + id + ", name=" + name + ", models=" + models + "]";
|
||||
return "ModelGroup [id=" + id + ", name=" + name + ", models=" + modelUrls + "]";
|
||||
}
|
||||
|
||||
public void add(String modelUrl) {
|
||||
modelUrls.add(modelUrl);
|
||||
}
|
||||
|
||||
public void add(Model model) {
|
||||
models.add(model);
|
||||
Collections.sort(models, (m1, m2) -> {
|
||||
int index1 = m1.getModelGroup().map(ModelGroupEntry::getIndex).orElse(0);
|
||||
int index2 = m2.getModelGroup().map(ModelGroupEntry::getIndex).orElse(0);
|
||||
return index1 - index2;
|
||||
});
|
||||
modelUrls.add(model.getUrl());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package ctbrec;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ModelGroupEntry implements Serializable {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
private UUID id;
|
||||
private int index;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ModelGroupEntry other = (ModelGroupEntry) obj;
|
||||
return Objects.equals(id, other.id) && index == other.index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModelGroupEntry [id=" + id + ", index=" + index + "]";
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -16,7 +15,6 @@ import com.squareup.moshi.JsonReader.Token;
|
|||
import com.squareup.moshi.JsonWriter;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroupEntry;
|
||||
import ctbrec.SubsequentAction;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
||||
|
@ -71,18 +69,6 @@ public class ModelJsonAdapter extends JsonAdapter<Model> {
|
|||
model.setRecordUntil(Instant.ofEpochMilli(reader.nextLong()));
|
||||
} else if (key.equals("recordUntilSubsequentAction")) {
|
||||
model.setRecordUntilSubsequentAction(SubsequentAction.valueOf(reader.nextString()));
|
||||
} else if (key.equals("groupId")) {
|
||||
ModelGroupEntry entry = new ModelGroupEntry();
|
||||
entry.setId(UUID.fromString(reader.nextString()));
|
||||
model.setModelGroup(entry);
|
||||
} else if (key.equals("groupIndex")) {
|
||||
model.getModelGroup().ifPresent(mg -> {
|
||||
try {
|
||||
mg.setIndex(reader.nextInt());
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error while reading model group index", e);
|
||||
}
|
||||
});
|
||||
} else if (key.equals("siteSpecific")) {
|
||||
reader.beginObject();
|
||||
try {
|
||||
|
@ -128,8 +114,6 @@ public class ModelJsonAdapter extends JsonAdapter<Model> {
|
|||
writer.name("lastRecorded").value(model.getLastRecorded().toEpochMilli());
|
||||
writer.name("recordUntil").value(model.getRecordUntil().toEpochMilli());
|
||||
writer.name("recordUntilSubsequentAction").value(model.getRecordUntilSubsequentAction().name());
|
||||
writer.name("groupId").value(model.getModelGroup().map(ModelGroupEntry::getId).map(Object::toString).orElse(null));
|
||||
writer.name("groupIndex").value(model.getModelGroup().map(ModelGroupEntry::getIndex).orElse(0));
|
||||
writer.name("siteSpecific");
|
||||
writer.beginObject();
|
||||
model.writeSiteSpecificData(writer);
|
||||
|
|
|
@ -47,7 +47,6 @@ import com.google.common.eventbus.Subscribe;
|
|||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.ModelGroupEntry;
|
||||
import ctbrec.Recording;
|
||||
import ctbrec.Recording.State;
|
||||
import ctbrec.event.Event;
|
||||
|
@ -93,7 +92,6 @@ public class NextGenLocalRecorder implements Recorder {
|
|||
threadPoolScaler = new ThreadPoolScaler((ThreadPoolExecutor) downloadPool, 5);
|
||||
recordingManager = new RecordingManager(config, sites);
|
||||
loadModels();
|
||||
createModelGroups();
|
||||
int ppThreads = config.getSettings().postProcessingThreads;
|
||||
ppPool = new ThreadPoolExecutor(ppThreads, ppThreads, 5, TimeUnit.MINUTES, ppQueue, createThreadFactory("PP", MIN_PRIORITY));
|
||||
|
||||
|
@ -135,16 +133,6 @@ public class NextGenLocalRecorder implements Recorder {
|
|||
});
|
||||
}
|
||||
|
||||
private void createModelGroups() {
|
||||
for (Model model : models) {
|
||||
if(model.getModelGroup().isPresent()) {
|
||||
ModelGroupEntry groupEntry = model.getModelGroup().get(); // NOSONAR
|
||||
ModelGroup group = getModelGroup(groupEntry.getId());
|
||||
group.add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startCompletionHandler() {
|
||||
downloadCompletionPool.submit(() -> {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
|
@ -796,38 +784,26 @@ public class NextGenLocalRecorder implements Recorder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelGroup getModelGroup(UUID id) {
|
||||
public Optional<ModelGroup> getModelGroup(UUID id) {
|
||||
for (ModelGroup group : getModelGroups()) {
|
||||
if (Objects.equals(group.getId(), id)) {
|
||||
return group;
|
||||
return Optional.of(group);
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException("ModelGroup with id " + id + " not found");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelGroup createModelGroup(String name) {
|
||||
ModelGroup group = new ModelGroup();
|
||||
group.setName(name);
|
||||
config.getSettings().modelGroups.add(group);
|
||||
try {
|
||||
config.save();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Couldn't save new model group", e);
|
||||
}
|
||||
return group;
|
||||
public void saveModelGroup(ModelGroup group) throws IOException {
|
||||
Set<ModelGroup> modelGroups = config.getSettings().modelGroups;
|
||||
modelGroups.remove(group);
|
||||
modelGroups.add(group);
|
||||
config.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteModelGroup(ModelGroup group) {
|
||||
for (Model model : group.getModels()) {
|
||||
model.setModelGroup(null);
|
||||
}
|
||||
public void deleteModelGroup(ModelGroup group) throws IOException {
|
||||
config.getSettings().modelGroups.remove(group);
|
||||
try {
|
||||
config.save();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Couldn't delete model group", e);
|
||||
}
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -153,7 +154,16 @@ public interface Recorder {
|
|||
public int getModelCount();
|
||||
|
||||
public Set<ModelGroup> getModelGroups();
|
||||
public ModelGroup createModelGroup(String name);
|
||||
public ModelGroup getModelGroup(UUID uuid);
|
||||
public void deleteModelGroup(ModelGroup group);
|
||||
|
||||
/**
|
||||
* Saves a model group. If the group already exists, it will be overwritten. Otherwise it will
|
||||
* be saved as a new group.
|
||||
* @param group
|
||||
* @throws IOException
|
||||
*/
|
||||
public void saveModelGroup(ModelGroup group) throws IOException;
|
||||
|
||||
public Optional<ModelGroup> getModelGroup(UUID uuid);
|
||||
|
||||
public void deleteModelGroup(ModelGroup group) throws IOException;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@ package ctbrec.recorder;
|
|||
import static ctbrec.recorder.NextGenLocalRecorder.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -13,7 +16,6 @@ import org.slf4j.LoggerFactory;
|
|||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.ModelGroupEntry;
|
||||
import ctbrec.Recording;
|
||||
import ctbrec.recorder.download.Download;
|
||||
|
||||
|
@ -28,7 +30,7 @@ public class RecordingPreconditions {
|
|||
this.recorder = recorder;
|
||||
}
|
||||
|
||||
void check(Model model) throws IOException {
|
||||
void check(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||
ensureRecorderIsActive();
|
||||
ensureModelIsNotSuspended(model);
|
||||
ensureModelIsNotMarkedForLaterRecording(model);
|
||||
|
@ -134,20 +136,38 @@ public class RecordingPreconditions {
|
|||
return concurrentRecordings == 0 || concurrentRecordings > 0 && recorder.getRecordingProcesses().size() < concurrentRecordings;
|
||||
}
|
||||
|
||||
private void ensureNoOtherFromModelGroupIsRecording(Model model) {
|
||||
if (model.getModelGroup().isPresent()) {
|
||||
ModelGroupEntry modelGroupEntry = model.getModelGroup().get(); // NOSONAR
|
||||
ModelGroup modelGroup = recorder.getModelGroup(modelGroupEntry.getId());
|
||||
for (Model groupModel : modelGroup.getModels()) {
|
||||
if (groupModel.equals(model)) {
|
||||
return; // no other model with lower group index is online, start recording
|
||||
} else if (otherModelCanBeRecorded(groupModel)) {
|
||||
throw new PreconditionNotMetException(groupModel + " from the same group is already recorded");
|
||||
private void ensureNoOtherFromModelGroupIsRecording(Model model) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
|
||||
Optional<ModelGroup> modelGroup = Config.getInstance().getModelGroup(model);
|
||||
if (modelGroup.isPresent()) {
|
||||
for (String modelUrl : modelGroup.get().getModelUrls()) {
|
||||
if (modelUrl.equals(model.getUrl())) {
|
||||
// no other model with higher prio is online, start recording
|
||||
// but before that stop all recordings of models with lower prio
|
||||
stopModelsWithLowerPrio(modelGroup.get());
|
||||
return;
|
||||
} else {
|
||||
Optional<Model> otherModel = getModelForUrl(modelUrl);
|
||||
if (otherModel.isPresent() && otherModelCanBeRecorded(otherModel.get())) {
|
||||
throw new PreconditionNotMetException(otherModel.get() + " from the same group is already recorded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopModelsWithLowerPrio(ModelGroup modelGroup) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
|
||||
recorder.getCurrentlyRecording().stream()
|
||||
.filter(m -> modelGroup.getModelUrls().contains(m.getUrl()))
|
||||
.forEach(recorder::stopRecordingProcess);
|
||||
|
||||
}
|
||||
|
||||
private Optional<Model> getModelForUrl(String modelUrl) {
|
||||
return Config.getInstance().getSettings().models.stream()
|
||||
.filter(m -> Objects.equals(m.getUrl(), modelUrl))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private boolean otherModelCanBeRecorded(Model model) {
|
||||
try {
|
||||
ensureRecorderIsActive();
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
@ -616,9 +615,8 @@ public class RemoteRecorder implements Recorder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelGroup createModelGroup(String name) {
|
||||
public void saveModelGroup(ModelGroup group) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -627,12 +625,12 @@ public class RemoteRecorder implements Recorder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelGroup getModelGroup(UUID id) {
|
||||
public Optional<ModelGroup> getModelGroup(UUID id) {
|
||||
for (ModelGroup group : getModelGroups()) {
|
||||
if (Objects.equals(group.getId(), id)) {
|
||||
return group;
|
||||
return Optional.of(group);
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException("ModelGroup with id " + id + " not found");
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue