Settings for Flaresolverr

This commit is contained in:
reusedname 2024-12-04 16:56:46 +05:00
parent 2572268600
commit ae1d5c7af8
5 changed files with 115 additions and 66 deletions

View File

@ -1,6 +1,7 @@
package ctbrec.ui.settings;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
@ -25,6 +26,7 @@ import ctbrec.ui.settings.api.Setting;
import ctbrec.ui.settings.api.SimpleDirectoryProperty;
import ctbrec.ui.settings.api.SimpleFileProperty;
import ctbrec.ui.settings.api.SimpleRangeProperty;
import ctbrec.io.BoundField;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ListProperty;
@ -115,13 +117,13 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
optionB.setSelected(!optionA.isSelected());
optionB.setToggleGroup(toggleGroup);
optionA.selectedProperty().bindBidirectional(prop);
prop.addListener((obs, oldV, newV) -> saveValue(() -> {
var field = Settings.class.getField(setting.getKey());
field.set(settings, newV); // NOSONAR
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV)) {
runRestartRequiredCallback();
prop.addListener((obs, oldV, newV) -> saveValue(() -> {
if (setIfChanged(setting.getKey(), newV)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
config.save();
}
config.save();
}));
var row = new HBox();
row.getChildren().addAll(optionA, optionB);
@ -155,15 +157,15 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
resolutionRange.setHigh(highValue >= 0 ? highValue : values.get(values.size() - 1));
resolutionRange.getLow().addListener((obs, o, n) -> saveValue(() -> {
int newV = labels.get(n.intValue());
var field = Settings.class.getField(rangeProperty.getLowKey());
field.set(settings, newV); // NOSONAR
config.save();
if (setIfChanged(rangeProperty.getLowKey(), newV)) {
config.save();
}
}));
resolutionRange.getHigh().addListener((obs, o, n) -> saveValue(() -> {
int newV = labels.get(n.intValue());
var field = Settings.class.getField(rangeProperty.getHighKey());
field.set(settings, newV); // NOSONAR
config.save();
if (setIfChanged(rangeProperty.getHighKey(), newV)) {
config.save();
}
}));
return resolutionRange;
}
@ -181,11 +183,7 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
private Node createFileSelector(Setting setting) {
var programSelector = new ProgramSelectionBox("");
programSelector.fileProperty().addListener((obs, o, n) -> saveValue(() -> {
String path = n;
var field = Settings.class.getField(setting.getKey());
String oldValue = (String) field.get(settings);
if (!Objects.equals(path, oldValue)) {
field.set(settings, path); // NOSONAR
if (setIfChanged(setting.getKey(), n)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
@ -201,11 +199,7 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
var directorySelector = new DirectorySelectionBox("");
directorySelector.prefWidth(400);
directorySelector.fileProperty().addListener((obs, o, n) -> saveValue(() -> {
String path = n;
var field = Settings.class.getField(setting.getKey());
String oldValue = (String) field.get(settings);
if (!Objects.equals(path, oldValue)) {
field.set(settings, path); // NOSONAR
if (setIfChanged(setting.getKey(), n)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
@ -221,10 +215,7 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
LocalTime time = (LocalTime) setting.getProperty().getValue();
var timePicker = new TimePicker(time);
timePicker.valueProperty().addListener((obs, o, n) -> saveValue(() -> {
var field = Settings.class.getField(setting.getKey());
LocalTime oldValue = (LocalTime) field.get(settings);
if (!Objects.equals(n, oldValue)) {
field.set(settings, n); // NOSONAR
if (setIfChanged(setting.getKey(), n)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
@ -237,12 +228,12 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
private Node createStringProperty(Setting setting) {
var ctrl = new TextField();
ctrl.textProperty().addListener((obs, oldV, newV) -> saveValue(() -> {
var field = Settings.class.getField(setting.getKey());
field.set(settings, newV); // NOSONAR
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV)) {
runRestartRequiredCallback();
if (setIfChanged(setting.getKey(), newV)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
config.save();
}
config.save();
}));
StringProperty prop = (StringProperty) setting.getProperty();
ctrl.textProperty().bindBidirectional(prop);
@ -256,10 +247,8 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
if (!newV.matches("\\d*")) {
ctrl.setText(newV.replaceAll(PATTERN_NOT_A_DIGIT, ""));
}
if (!ctrl.getText().isEmpty()) {
var field = Settings.class.getField(setting.getKey());
field.set(settings, Integer.parseInt(ctrl.getText())); // NOSONAR
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV) && prefs != null) {
if (!ctrl.getText().isEmpty() && setIfChanged(setting.getKey(), Integer.parseInt(ctrl.getText()))) {
if (setting.doesNeedRestart() && prefs != null) {
runRestartRequiredCallback();
}
config.save();
@ -282,12 +271,12 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
if (setting.getConverter() != null) {
value = (long) setting.getConverter().convertFrom(value);
}
var field = Settings.class.getField(setting.getKey());
field.set(settings, value); // NOSONAR
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV)) {
runRestartRequiredCallback();
if (setIfChanged(setting.getKey(), value)) {
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV)) {
runRestartRequiredCallback();
}
config.save();
}
config.save();
}
}));
Property<Number> prop = setting.getProperty();
@ -298,12 +287,12 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
private Node createBooleanProperty(Setting setting) {
var ctrl = new CheckBox();
ctrl.selectedProperty().addListener((obs, oldV, newV) -> saveValue(() -> {
var field = Settings.class.getField(setting.getKey());
field.set(settings, newV); // NOSONAR
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV)) {
runRestartRequiredCallback();
if (setIfChanged(setting.getKey(), newV)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
config.save();
}
config.save();
}));
BooleanProperty prop = (BooleanProperty) setting.getProperty();
ctrl.selectedProperty().bindBidirectional(prop);
@ -311,11 +300,10 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Node createComboBox(Setting setting) throws NoSuchFieldException, IllegalAccessException {
private Node createComboBox(Setting setting) throws IllegalAccessException, NoSuchFieldException {
ListProperty<?> listProp = (ListProperty<?>) setting.getProperty();
ComboBox<Object> comboBox = new ComboBox(listProp);
var field = Settings.class.getField(setting.getKey());
Object value = field.get(settings);
Object value = BoundField.of(settings, setting.getKey()).get();
if (StringUtil.isNotBlank(value.toString())) {
if (setting.getConverter() != null) {
comboBox.getSelectionModel().select(setting.getConverter().convertTo(value));
@ -325,21 +313,29 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
}
comboBox.valueProperty().addListener((obs, oldV, newV) -> saveValue(() -> {
LOG.debug("Saving setting {}", setting.getKey());
if (setting.getConverter() != null) {
field.set(settings, setting.getConverter().convertFrom(newV)); // NOSONAR
} else {
field.set(settings, newV); // NOSONAR
if (setIfChanged(setting.getKey(), setting.getConverter() != null ? setting.getConverter().convertFrom(newV) : newV)) {
if (setting.doesNeedRestart()) {
runRestartRequiredCallback();
}
config.save();
}
if (setting.doesNeedRestart() && !Objects.equals(oldV, newV)) {
runRestartRequiredCallback();
}
config.save();
}));
if (setting.getChangeListener() != null) {
comboBox.valueProperty().addListener((ChangeListener<? super Object>) setting.getChangeListener());
}
return comboBox;
}
private boolean setIfChanged(String key, Object n) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException {
var field = BoundField.of(settings, key);
var o = field.get();
if (!Objects.equals(n, o)) {
field.set(n); // NOSONAR
return true;
}
return false;
}
private void saveValue(Exec exe) {
try {
@ -351,6 +347,6 @@ public class CtbrecPreferencesStorage implements PreferencesStorage {
@FunctionalInterface
private interface Exec {
public void run() throws IllegalAccessException, IOException, NoSuchFieldException;
public void run() throws IllegalAccessException, IOException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException;
}
}

View File

@ -60,6 +60,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
private final Settings settings;
private boolean initialized = false;
private SimpleStringProperty flaresolverrApiUrl;
private SimpleIntegerProperty flaresolverrTimeoutInMillis;
private SimpleStringProperty httpUserAgent;
private SimpleStringProperty httpUserAgentMobile;
private SimpleIntegerProperty overviewUpdateIntervalInSecs;
@ -144,6 +146,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
}
private void initializeProperties() {
flaresolverrApiUrl = new SimpleStringProperty(null, "flaresolverr.apiUrl", settings.flaresolverr.apiUrl);
flaresolverrTimeoutInMillis = new SimpleIntegerProperty(null, "flaresolverr.timeoutInMillis", settings.flaresolverr.timeoutInMillis);
httpUserAgent = new SimpleStringProperty(null, "httpUserAgent", settings.httpUserAgent);
httpUserAgentMobile = new SimpleStringProperty(null, "httpUserAgentMobile", settings.httpUserAgentMobile);
overviewUpdateIntervalInSecs = new SimpleIntegerProperty(null, "overviewUpdateIntervalInSecs", settings.overviewUpdateIntervalInSecs);
@ -258,7 +262,11 @@ public class SettingsTab extends Tab implements TabSelectionListener {
Group.of("Browser",
Setting.of("Browser", browserOverride),
Setting.of("Start parameters", browserParams),
Setting.of("Force use (ignore default browser)", forceBrowserOverride, "Default behaviour will fallback to OS default if the above browser fails"))),
Setting.of("Force use (ignore default browser)", forceBrowserOverride, "Default behaviour will fallback to OS default if the above browser fails")),
Group.of("Flaresolverr",
Setting.of("API URL", flaresolverrApiUrl),
Setting.of("Request timeout", flaresolverrTimeoutInMillis))),
Category.of("Look & Feel",
Group.of("Look & Feel",
Setting.of("Colors (Base / Accent)", new ColorSettingsPane(Config.getInstance())).needsRestart(),
@ -354,6 +362,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
setContent(stackPane);
prefs.expandTree();
prefs.getSetting("flaresolverr.apiUrl").ifPresent(s -> bindEnabledProperty(s, recordLocal.not()));
prefs.getSetting("flaresolverr.timeoutInMillis").ifPresent(s -> bindEnabledProperty(s, recordLocal.not()));
prefs.getSetting("httpServer").ifPresent(s -> bindEnabledProperty(s, recordLocal));
prefs.getSetting("httpPort").ifPresent(s -> bindEnabledProperty(s, recordLocal));
prefs.getSetting("servletContext").ifPresent(s -> bindEnabledProperty(s, recordLocal));

View File

@ -7,11 +7,7 @@ import ctbrec.ui.settings.SettingsTab;
import ctbrec.ui.sites.AbstractConfigUI;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
@ -103,6 +99,18 @@ public class ChaturbateConfigUi extends AbstractConfigUI {
GridPane.setHgrow(requestThrottle, Priority.ALWAYS);
GridPane.setColumnSpan(requestThrottle, 2);
layout.add(requestThrottle, 1, row++);
var label = new Label("Use Flaresolverr");
label.setTooltip(new Tooltip("Use Flaresolverr for solving the Cloudflare challenge. This also overrides the User Agent used for HTTP requests (only for the site)"));
layout.add(label, 0, row);
var flaresolverrToggle = new CheckBox();
flaresolverrToggle.setSelected(settings.chaturbateUseFlaresolverr);
flaresolverrToggle.setOnAction(e -> {
settings.chaturbateUseFlaresolverr = flaresolverrToggle.isSelected();
save();
});
GridPane.setMargin(flaresolverrToggle, new Insets(0, 0, SettingsTab.CHECKBOX_MARGIN, SettingsTab.CHECKBOX_MARGIN));
layout.add(flaresolverrToggle, 1, row++);
var createAccount = new Button("Create new Account");
createAccount.setOnAction(e -> DesktopIntegration.open(Chaturbate.REGISTRATION_LINK));

View File

@ -0,0 +1,32 @@
package ctbrec.io;
import java.lang.reflect.*;
public class BoundField {
public Object object = null;
public Field field = null;
public BoundField(Object o, Field f) {
object = o;
field = f;
}
public Object get() throws IllegalAccessException {
return field.get(object);
}
public void set(Object value) throws IllegalAccessException {
field.set(object, value);
}
// by-path field resolver (i.e: "a.b.c")
public static BoundField of(Object root, String path) throws NoSuchFieldException, IllegalAccessException {
var keys = path.split("\\.");
var result = new BoundField(root, root.getClass().getField(keys[0]));
for (int i = 1; i<keys.length; i++) {
result.object = result.field.get(result.object);
result.field = result.object.getClass().getField(keys[i]);
}
return result;
}
}

View File

@ -3,7 +3,6 @@ package ctbrec.recorder.server;
import static javax.servlet.http.HttpServletResponse.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalTime;
@ -21,6 +20,7 @@ import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.Settings;
import ctbrec.Settings.SplitStrategy;
import ctbrec.io.BoundField;
public class ConfigServlet extends AbstractCtbrecServlet {
@ -76,6 +76,9 @@ public class ConfigServlet extends AbstractCtbrecServlet {
addParameter("webinterfacePassword", "Web-Interface Password", DataType.STRING, settings.webinterfacePassword, json);
addParameter("servletContext", "Servlet Context", DataType.STRING, settings.servletContext, json);
addParameter("logFFmpegOutput", "Log FFmpeg Output", DataType.BOOLEAN, settings.logFFmpegOutput, json);
addParameter("flaresolverr.apiUrl", "Flaresolverr API URL", DataType.STRING, settings.flaresolverr.apiUrl, json);
addParameter("flaresolverr.timeoutInMillis", "Flaresolverr request timeout (ms)", DataType.INTEGER, settings.flaresolverr.timeoutInMillis, json);
addParameter("chaturbateUseFlaresolverr", "Chaturbate: use Flaresolverr", DataType.BOOLEAN, settings.chaturbateUseFlaresolverr, json);
resp.setStatus(SC_OK);
resp.setContentType("application/json");
@ -135,8 +138,8 @@ public class ConfigServlet extends AbstractCtbrecServlet {
Object typeCorrectedValue = correctType(type, value);
LOG.debug("{}: {}", key, value);
Field field = Settings.class.getField(key);
field.set(settings, typeCorrectedValue);
var field = BoundField.of(settings, key);
field.set(typeCorrectedValue);
}
config.save();
} catch (Exception e) {