forked from j62/ctbrec
1
0
Fork 0

Improved grammar to allow multiple expressions in a function parameter

This commit is contained in:
0xb00bface 2023-03-11 13:59:27 +01:00
parent 699a99608e
commit 69ea8e0b92
17 changed files with 262 additions and 138 deletions

View File

@ -188,7 +188,7 @@ public class Player {
} }
private void expandPlaceHolders(String[] cmdline) { private void expandPlaceHolders(String[] cmdline) {
ModelVariableExpander expander = new ModelVariableExpander(model, Config.getInstance(), null); ModelVariableExpander expander = new ModelVariableExpander(model, Config.getInstance(), null, null);
for (int i = 0; i < cmdline.length; i++) { for (int i = 0; i < cmdline.length; i++) {
var param = cmdline[i]; var param = cmdline[i];
param = expander.expand(param); param = expander.expand(param);

View File

@ -1,43 +1,49 @@
package ctbrec.ui.action; package ctbrec.ui.action;
import java.io.File;
import java.time.Instant;
import ctbrec.Config; import ctbrec.Config;
import ctbrec.GlobalThreadPool; import ctbrec.GlobalThreadPool;
import ctbrec.Model; import ctbrec.Model;
import ctbrec.Settings.DirectoryStructure;
import ctbrec.ui.DesktopIntegration; import ctbrec.ui.DesktopIntegration;
import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.Dialogs;
import javafx.scene.Cursor; import javafx.scene.Cursor;
import javafx.scene.Node; import javafx.scene.Node;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.time.Instant;
@Slf4j
@RequiredArgsConstructor
public class OpenRecordingsDir { public class OpenRecordingsDir {
private Model selectedModel; private final Node source;
private Node source; private final Model selectedModel;
public OpenRecordingsDir(Node source, Model selectedModel) {
this.source = source;
this.selectedModel = selectedModel;
}
public void execute() { public void execute() {
source.setCursor(Cursor.WAIT); source.setCursor(Cursor.WAIT);
var fileForRecording = Config.getInstance().getFileForRecording(selectedModel, ".mp4", Instant.now()); var dir = Config.getInstance().getFileForRecording(selectedModel, ".mp4", Instant.now());
final File dir = getModelDirectory(fileForRecording); dir = findDeepestExistingDir(dir);
log.info("Directory for model is {}", dir.getAbsolutePath());
if (dir.exists()) { if (dir.exists()) {
GlobalThreadPool.submit(() -> DesktopIntegration.open(dir)); final File directory = dir;
GlobalThreadPool.submit(() -> DesktopIntegration.open(directory));
} else { } else {
Dialogs.showError(source.getScene(), "Directory does not exist", "There are no recordings for this model", null); Dialogs.showError(source.getScene(), "Directory does not exist", "There are no recordings for this model", null);
} }
source.setCursor(Cursor.DEFAULT); source.setCursor(Cursor.DEFAULT);
} }
private File getModelDirectory(File fileForRecording) { private File findDeepestExistingDir(File dir) {
var dir = fileForRecording.getParentFile(); while (!dir.exists()) {
if (Config.getInstance().getSettings().recordingsDirStructure == DirectoryStructure.ONE_PER_RECORDING) { if (dir.getParentFile() == null) {
return dir;
} else {
dir = dir.getParentFile(); dir = dir.getParentFile();
if (dir.exists()) {
break;
}
}
} }
return dir; return dir;
} }

View File

@ -123,6 +123,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
private LocalTimeProperty timeoutRecordingEndingAt; private LocalTimeProperty timeoutRecordingEndingAt;
private SimpleLongProperty recordUntilDefaultDurationInMinutes; private SimpleLongProperty recordUntilDefaultDurationInMinutes;
private SimpleStringProperty dateTimeFormat; private SimpleStringProperty dateTimeFormat;
private final VariablePlayGroundDialogFactory variablePlayGroundDialogFactory = new VariablePlayGroundDialogFactory();
public SettingsTab(List<Site> sites, Recorder recorder) { public SettingsTab(List<Site> sites, Recorder recorder) {
this.sites = sites; this.sites = sites;
@ -379,9 +380,9 @@ public class SettingsTab extends Tab implements TabSelectionListener {
} }
private Button createVariablePlayGroundButton() { private Button createVariablePlayGroundButton() {
var postProcessingHelpButton = new Button("Variable Playground"); var button = new Button("Variable Playground");
postProcessingHelpButton.setOnAction(e -> new VariablePlayGroundDialogFactory().openDialog(this.getTabPane().getScene(), config, recorder)); button.setOnAction(e -> variablePlayGroundDialogFactory.openDialog(this.getTabPane().getScene(), config, recorder));
return postProcessingHelpButton; return button;
} }
private void bindEnabledProperty(Setting s, BooleanExpression bindTo) { private void bindEnabledProperty(Setting s, BooleanExpression bindTo) {

View File

@ -5,42 +5,53 @@ import ctbrec.Recording;
import ctbrec.StringUtil; import ctbrec.StringUtil;
import ctbrec.UnknownModel; import ctbrec.UnknownModel;
import ctbrec.recorder.Recorder; import ctbrec.recorder.Recorder;
import ctbrec.recorder.postprocessing.PostProcessingContext;
import ctbrec.sites.chaturbate.Chaturbate; import ctbrec.sites.chaturbate.Chaturbate;
import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.tabs.DownloadPostprocessor; import ctbrec.variableexpansion.ConfigVariableExpander;
import ctbrec.variableexpansion.ModelVariableExpander;
import ctbrec.variableexpansion.RecordingVariableExpander;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter; import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Recognizer;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.time.Instant; import java.time.Instant;
@Slf4j
public class VariablePlayGroundDialogFactory { public class VariablePlayGroundDialogFactory {
private GridPane pane;
public void openDialog(Scene parent, Config config, Recorder recorder) { public void openDialog(Scene parent, Config config, Recorder recorder) {
if (pane == null) {
initGui(config, recorder);
}
Dialogs.showCustomInput(parent, "Playground", pane, (obs, oldV, newV) -> {
});
}
private void initGui(Config config, Recorder recorder) {
Chaturbate chaturbate = new Chaturbate(); Chaturbate chaturbate = new Chaturbate();
UnknownModel unknownModel = new UnknownModel(); UnknownModel unknownModel = new UnknownModel();
unknownModel.setName("Pussy_Galore"); unknownModel.setName("Pussy_Galore");
unknownModel.setDisplayName("Pussy Galore"); unknownModel.setDisplayName("Pussy Galore");
unknownModel.setSite(chaturbate); unknownModel.setSite(chaturbate);
unknownModel.setUrl("http://camsite.example/pussy_galore");
Recording recording = new Recording(); Recording recording = new Recording();
recording.setAbsoluteFile(Paths.get("ctbrec", "recs", "pussy_galore", "2023-02-26_14-05-56").toFile()); recording.setAbsoluteFile(Paths.get("ctbrec", "recs", "pussy_galore", "2023-02-26_14-05-56").toFile());
recording.setStartDate(Instant.now()); recording.setStartDate(Instant.now());
recording.setStatus(Recording.State.POST_PROCESSING); recording.setStatus(Recording.State.POST_PROCESSING);
recording.setNote("notes about the recording"); recording.setNote("notes about the recording");
recording.setModel(unknownModel); recording.setModel(unknownModel);
PostProcessingContext ctx = new PostProcessingContext();
ctx.setConfig(config);
ctx.setRecorder(recorder);
ctx.setRecording(recording);
DownloadPostprocessor postprocessor = new DownloadPostprocessor();
GridPane pane = new GridPane(); pane = new GridPane();
Label result = new Label(); Label result = new Label();
Label error = new Label(); Label error = new Label();
@ -49,18 +60,6 @@ public class VariablePlayGroundDialogFactory {
input.setMinWidth(600); input.setMinWidth(600);
pane.add(input, 1, 0); pane.add(input, 1, 0);
GridPane.setHgrow(input, Priority.ALWAYS); GridPane.setHgrow(input, Priority.ALWAYS);
input.setOnKeyTyped(evt -> {
String r = postprocessor.fillInPlaceHolders(input.getText(), ctx, new AntlrSyntacErrorAdapter() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int line, int pos, String s, RecognitionException e) {
error.setText(String.format("Syntax error at %d:%d %s", line, pos, s));
}
});
result.setText(r);
if (StringUtil.isNotBlank(r)) {
error.setText("");
}
});
pane.add(error, 0, 1); pane.add(error, 0, 1);
GridPane.setColumnSpan(error, 2); GridPane.setColumnSpan(error, 2);
@ -70,7 +69,31 @@ public class VariablePlayGroundDialogFactory {
pane.setHgap(5); pane.setHgap(5);
pane.vgapProperty().bind(pane.hgapProperty()); pane.vgapProperty().bind(pane.hgapProperty());
Dialogs.showCustomInput(parent, "Playground", pane, (obs, oldV, newV) -> {
AntlrSyntacErrorAdapter errorHandler = new AntlrSyntacErrorAdapter() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int line, int pos, String s, RecognitionException e) {
error.setText(String.format("Syntax error at %d:%d %s", line, pos, s));
}
};
ModelVariableExpander modelVariableExpander = new ModelVariableExpander(unknownModel, config, recorder, errorHandler);
RecordingVariableExpander recordingVariableExpander = new RecordingVariableExpander(recording, errorHandler);
ConfigVariableExpander configVariableExpander = new ConfigVariableExpander(config, errorHandler);
input.setOnKeyTyped(evt -> {
try {
String r = input.getText();
modelVariableExpander.getPlaceholderValueSuppliers().putAll(recordingVariableExpander.getPlaceholderValueSuppliers());
modelVariableExpander.getPlaceholderValueSuppliers().putAll(configVariableExpander.getPlaceholderValueSuppliers());
r = modelVariableExpander.expand(r);
result.setText(r);
if (StringUtil.isNotBlank(r)) {
error.setText("");
}
} catch (Exception e) {
log.error("Error", e);
}
}); });
} }
} }

View File

@ -2,11 +2,13 @@ grammar PostProcessing;
line: (text | variable | functionCall)* EOF; line: (text | variable | functionCall)* EOF;
functionCall: '$' identifier '(' (expression (',' expression)*)? ')'; functionCall: '$' identifier '(' (parameter (',' parameter)*)? ')';
text: CH+?; text: CH+?;
identifier: CH+?; identifier: CH+?;
parameter: expression*;
variable: '${' identifier '}'; variable: '${' identifier '}';
expression expression

View File

@ -183,9 +183,8 @@ public class Config {
} }
private void migrateOldSettings() { private void migrateOldSettings() {
// 4.7.18 // 5.0.0
convertChaturbateModelNamesToLowerCase(); convertChaturbateModelNamesToLowerCase();
} }
private void convertChaturbateModelNamesToLowerCase() { private void convertChaturbateModelNamesToLowerCase() {

View File

@ -2,29 +2,11 @@ package ctbrec.recorder.postprocessing;
import ctbrec.Config; import ctbrec.Config;
import ctbrec.Recording; import ctbrec.Recording;
import ctbrec.StringUtil; import ctbrec.variableexpansion.ConfigVariableExpander;
import ctbrec.variableexpansion.ModelVariableExpander; import ctbrec.variableexpansion.ModelVariableExpander;
import ctbrec.variableexpansion.ParserVisitor; import ctbrec.variableexpansion.RecordingVariableExpander;
import ctbrec.variableexpansion.VariableExpansionException;
import ctbrec.variableexpansion.antlr.PostProcessingLexer;
import ctbrec.variableexpansion.antlr.PostProcessingParser;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter; import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.IOException;
import java.io.StringReader;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static java.util.Optional.ofNullable;
@Slf4j @Slf4j
public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPostProcessor { public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPostProcessor {
@ -37,58 +19,11 @@ public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPost
Recording rec = ctx.getRecording(); Recording rec = ctx.getRecording();
Config config = ctx.getConfig(); Config config = ctx.getConfig();
ModelVariableExpander modelExpander = new ModelVariableExpander(rec.getModel(), config, ctx.getRecorder()); ModelVariableExpander modelExpander = new ModelVariableExpander(rec.getModel(), config, ctx.getRecorder(), errorListener);
Map<String, Optional<Object>> variables = new HashMap<>(modelExpander.getPlaceholderValueSuppliers()); RecordingVariableExpander recordingExpander = new RecordingVariableExpander(rec, errorListener);
variables.put("recordingNotes", getSanitizedRecordingNotes(rec)); ConfigVariableExpander configExpander = new ConfigVariableExpander(config, errorListener);
variables.put("fileSuffix", getFileSuffix(rec)); modelExpander.getPlaceholderValueSuppliers().putAll(recordingExpander.getPlaceholderValueSuppliers());
variables.put("recordingsDir", Optional.of(config.getSettings().recordingsDir)); modelExpander.getPlaceholderValueSuppliers().putAll(configExpander.getPlaceholderValueSuppliers());
variables.put("absolutePath", Optional.of(rec.getPostProcessedFile().getAbsolutePath())); return modelExpander.expand(input);
variables.put("absoluteParentPath", Optional.of(rec.getPostProcessedFile().getParentFile().getAbsolutePath()));
variables.put("epochSecond", ofNullable(rec.getStartDate()).map(Instant::getEpochSecond).map(l -> Long.toString(l))); // NOSONAR
variables.put("utcDateTime", getUtcDateTime(rec));
variables.put("localDateTime", getLocalDateTime(rec));
return fillInPlaceHolders(input, variables, errorListener);
}
private String fillInPlaceHolders(String input, Map<String, Optional<Object>> variables, AntlrSyntacErrorAdapter errorListener) {
try (StringReader reader = new StringReader(input)) {
CharStream s = CharStreams.fromReader(reader);
PostProcessingLexer lexer = new PostProcessingLexer(s);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PostProcessingParser parser = new PostProcessingParser(tokens);
Optional.ofNullable(errorListener).ifPresent(parser::addErrorListener);
ParseTree parseTree = parser.line();
ParserVisitor visitor = new ParserVisitor(variables);
return visitor.visit(parseTree);
} catch (IOException e) {
throw new VariableExpansionException("Couldn't replace placeholders", e);
}
}
protected Optional<Object> getUtcDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneOffset.UTC));
}
protected Optional<Object> getLocalDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneId.systemDefault()));
}
private Optional<Object> getFileSuffix(Recording rec) {
if (rec.isSingleFile()) {
String filename = rec.getPostProcessedFile().getName();
return Optional.of(filename.substring(filename.lastIndexOf('.') + 1));
} else {
return Optional.empty();
}
}
private Optional<Object> getSanitizedRecordingNotes(Recording rec) {
Optional<String> notes = ofNullable(rec.getNote());
return notes.map(StringUtil::sanitize);
} }
} }

View File

@ -4,8 +4,11 @@ import ctbrec.variableexpansion.antlr.PostProcessingLexer;
import ctbrec.variableexpansion.antlr.PostProcessingParser; import ctbrec.variableexpansion.antlr.PostProcessingParser;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter; import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.HashMap; import java.util.HashMap;
@ -17,18 +20,19 @@ abstract class AbstractVariableExpander {
protected Map<String, Optional<Object>> placeholderValueSuppliers = new HashMap<>(); protected Map<String, Optional<Object>> placeholderValueSuppliers = new HashMap<>();
protected AntlrSyntacErrorAdapter errorListener;
AbstractVariableExpander(@Nullable AntlrSyntacErrorAdapter errorListener) {
this.errorListener = errorListener;
}
protected String fillInPlaceHolders(String input, Map<String, Optional<Object>> variables) { protected String fillInPlaceHolders(String input, Map<String, Optional<Object>> variables) {
try (StringReader reader = new StringReader(input)) { try (StringReader reader = new StringReader(input)) {
CharStream s = CharStreams.fromReader(reader); CharStream s = CharStreams.fromReader(reader);
PostProcessingLexer lexer = new PostProcessingLexer(s); PostProcessingLexer lexer = new PostProcessingLexer(s);
CommonTokenStream tokens = new CommonTokenStream(lexer); CommonTokenStream tokens = new CommonTokenStream(lexer);
PostProcessingParser parser = new PostProcessingParser(tokens); PostProcessingParser parser = new PostProcessingParser(tokens);
parser.addErrorListener(new AntlrSyntacErrorAdapter() { Optional.ofNullable(errorListener).ifPresent(parser::addErrorListener);
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int line, int pos, String s, RecognitionException e) {
log.warn("Syntax error at {}:{} {}", line, pos, s);
}
});
PostProcessingParser.LineContext ctx = parser.line(); PostProcessingParser.LineContext ctx = parser.line();
ParserVisitor visitor = new ParserVisitor(variables); ParserVisitor visitor = new ParserVisitor(variables);
return visitor.visit(ctx); return visitor.visit(ctx);

View File

@ -0,0 +1,18 @@
package ctbrec.variableexpansion;
import ctbrec.Config;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import java.util.Optional;
public class ConfigVariableExpander extends AbstractVariableExpander {
public ConfigVariableExpander(Config config, AntlrSyntacErrorAdapter errorListener) {
super(errorListener);
placeholderValueSuppliers.put("recordingsDir", Optional.of(config.getSettings().recordingsDir));
}
public String expand(String input) {
return fillInPlaceHolders(input, placeholderValueSuppliers);
}
}

View File

@ -6,6 +6,7 @@ import ctbrec.ModelGroup;
import ctbrec.StringUtil; import ctbrec.StringUtil;
import ctbrec.recorder.Recorder; import ctbrec.recorder.Recorder;
import ctbrec.sites.Site; import ctbrec.sites.Site;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -14,7 +15,8 @@ import static java.util.Optional.ofNullable;
public class ModelVariableExpander extends AbstractVariableExpander { public class ModelVariableExpander extends AbstractVariableExpander {
public ModelVariableExpander(Model model, Config config, Recorder recorder) { public ModelVariableExpander(Model model, Config config, Recorder recorder, AntlrSyntacErrorAdapter errorListener) {
super(errorListener);
Optional<ModelGroup> modelGroup = Optional.ofNullable(recorder).flatMap(r -> r.getModelGroup(model)); Optional<ModelGroup> modelGroup = Optional.ofNullable(recorder).flatMap(r -> r.getModelGroup(model));
placeholderValueSuppliers.put("modelName", ofNullable(model.getName())); placeholderValueSuppliers.put("modelName", ofNullable(model.getName()));
placeholderValueSuppliers.put("modelDisplayName", ofNullable(model.getDisplayName())); placeholderValueSuppliers.put("modelDisplayName", ofNullable(model.getDisplayName()));

View File

@ -30,8 +30,8 @@ public class ParserVisitor extends PostProcessingBaseVisitor<String> {
String identifier = ctx.identifier().getText(); String identifier = ctx.identifier().getText();
VarArgsFunction<Object, String> function = functions.get(identifier); VarArgsFunction<Object, String> function = functions.get(identifier);
if (function != null) { if (function != null) {
List<PostProcessingParser.ExpressionContext> parameters = ctx.expression(); List<PostProcessingParser.ParameterContext> parameters = ctx.parameter();
List<String> params = parameters.stream().map(this::visitExpression).toList(); List<String> params = parameters.stream().map(this::visitParameter).toList();
return function.apply(params.toArray(new Object[0])); return function.apply(params.toArray(new Object[0]));
} else { } else {
return ctx.getText(); return ctx.getText();
@ -45,7 +45,7 @@ public class ParserVisitor extends PostProcessingBaseVisitor<String> {
if (value != null && value.isPresent()) { // NOSONAR if (value != null && value.isPresent()) { // NOSONAR
return value.get().toString(); return value.get().toString();
} else { } else {
return ""; return ctx.getText();
} }
} }

View File

@ -0,0 +1,58 @@
package ctbrec.variableexpansion;
import ctbrec.Recording;
import ctbrec.StringUtil;
import ctbrec.variableexpansion.functions.AntlrSyntacErrorAdapter;
import java.io.File;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Optional;
import static java.util.Optional.ofNullable;
public class RecordingVariableExpander extends AbstractVariableExpander {
public RecordingVariableExpander(Recording rec, AntlrSyntacErrorAdapter errorListener) {
super(errorListener);
placeholderValueSuppliers.put("recordingNotes", getSanitizedRecordingNotes(rec));
placeholderValueSuppliers.put("fileSuffix", getFileSuffix(rec));
placeholderValueSuppliers.put("absolutePath", Optional.of(rec).map(Recording::getPostProcessedFile).map(File::getAbsolutePath));
placeholderValueSuppliers.put("absoluteParentPath", Optional.of(rec).map(Recording::getPostProcessedFile).map(File::getParentFile).map(File::getAbsolutePath));
placeholderValueSuppliers.put("epochSecond", ofNullable(rec.getStartDate()).map(Instant::getEpochSecond).map(l -> Long.toString(l))); // NOSONAR
placeholderValueSuppliers.put("utcDateTime", getUtcDateTime(rec));
placeholderValueSuppliers.put("localDateTime", getLocalDateTime(rec));
}
public String expand(String input) {
return fillInPlaceHolders(input, placeholderValueSuppliers);
}
protected Optional<Object> getUtcDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneOffset.UTC));
}
protected Optional<Object> getLocalDateTime(Recording rec) {
return Optional.ofNullable(rec)
.map(Recording::getStartDate)
.map(i -> i.atZone(ZoneId.systemDefault()));
}
private Optional<Object> getFileSuffix(Recording rec) {
if (rec.isSingleFile()) {
String filename = rec.getPostProcessedFile().getName();
return Optional.of(filename.substring(filename.lastIndexOf('.') + 1));
} else {
return Optional.empty();
}
}
private Optional<Object> getSanitizedRecordingNotes(Recording rec) {
Optional<String> notes = ofNullable(rec.getNote());
return notes.map(StringUtil::sanitize);
}
}

View File

@ -4,8 +4,13 @@ import ctbrec.StringUtil;
import ctbrec.variableexpansion.VarArgsFunction; import ctbrec.variableexpansion.VarArgsFunction;
import java.util.Optional; import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OrElse implements VarArgsFunction<Object, String> { public class OrElse implements VarArgsFunction<Object, String> {
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{[^${}]+}");
@Override @Override
public String apply(Object... params) { public String apply(Object... params) {
if (params == null || params.length < 1) { if (params == null || params.length < 1) {
@ -18,7 +23,13 @@ public class OrElse implements VarArgsFunction<Object, String> {
Optional<String> result = Optional.ofNullable(params[0]).map(String::valueOf); Optional<String> result = Optional.ofNullable(params[0]).map(String::valueOf);
if (result.isPresent() && StringUtil.isNotBlank(result.get())) { if (result.isPresent() && StringUtil.isNotBlank(result.get())) {
String param = result.get();
Matcher m = VARIABLE_PATTERN.matcher(param);
if (m.find()) {
return fallback;
} else {
return result.get(); return result.get();
}
} else { } else {
return fallback; return fallback;
} }

View File

@ -49,9 +49,9 @@ class AbstractPlaceholderAwarePostProcessorTest extends AbstractPpTest {
@Test @Test
void testSiteNameReplacement() { void testSiteNameReplacement() {
String input = "asdf_${siteName}_asdf"; String input = "asdf_${siteName}_asdf";
assertEquals("asdf_Chaturbate_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config))); assertEquals("asdf_Stripchat_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
input = "asdf_$sanitize(${siteName})_asdf"; input = "asdf_$sanitize(${siteName})_asdf";
assertEquals("asdf_Chaturbate_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config))); assertEquals("asdf_Stripchat_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
} }
@Test @Test
@ -158,7 +158,7 @@ class AbstractPlaceholderAwarePostProcessorTest extends AbstractPpTest {
void testMissingValueForPlaceholder() { void testMissingValueForPlaceholder() {
String input = "asdf_${modelNotes}_asdf"; String input = "asdf_${modelNotes}_asdf";
when(config.getModelNotes(any())).thenReturn(null); when(config.getModelNotes(any())).thenReturn(null);
assertEquals("asdf__asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config))); assertEquals("asdf_${modelNotes}_asdf", placeHolderAwarePp.fillInPlaceHolders(input, createPostProcessingContext(rec, null, config)));
} }
@Test @Test

View File

@ -7,7 +7,7 @@ import ctbrec.Settings;
import ctbrec.recorder.Recorder; import ctbrec.recorder.Recorder;
import ctbrec.recorder.RecordingManager; import ctbrec.recorder.RecordingManager;
import ctbrec.sites.Site; import ctbrec.sites.Site;
import ctbrec.sites.chaturbate.Chaturbate; import ctbrec.sites.stripchat.Stripchat;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -71,7 +71,7 @@ public abstract class AbstractPpTest {
} }
Model mockModel() { Model mockModel() {
Site site = new Chaturbate(); Site site = new Stripchat();
Model model = site.createModel("Mockita Boobilicious"); Model model = site.createModel("Mockita Boobilicious");
model.setDisplayName("Mockita Boobilicious"); model.setDisplayName("Mockita Boobilicious");
return model; return model;

View File

@ -0,0 +1,65 @@
package ctbrec.variableexpansion;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.Settings;
import ctbrec.UnknownModel;
import ctbrec.recorder.Recorder;
import ctbrec.sites.chaturbate.Chaturbate;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
class ModelVariableExpanderTest {
Model model;
Config config;
MockedStatic<Config> configStatic;
@BeforeEach
void setup() {
UnknownModel unknownModel = new UnknownModel();
Chaturbate chaturbate = new Chaturbate();
unknownModel.setName("Pussy_Galore");
unknownModel.setDisplayName("Pussy Galore");
unknownModel.setSite(chaturbate);
this.model = unknownModel;
this.config = mockConfig();
}
@AfterEach
public void teardown() {
if (configStatic != null) {
configStatic.close();
configStatic = null;
}
}
@Test
void testMultipleVariablesAsParameter() {
Recorder recorder = mock(Recorder.class);
ModelVariableExpander modelVariableExpander = new ModelVariableExpander(model, config, recorder, null);
assertEquals("pussy_galore asdf pussy_galore", modelVariableExpander.expand("$lower(${modelName} ASDF ${modelName})"));
}
Config mockConfig() {
Config config = mock(Config.class);
Settings settings = mockSettings();
when(config.getSettings()).thenReturn(settings);
when(config.getModelNotes(any())).thenReturn("tag, foo, bar");
configStatic = mockStatic(Config.class);
configStatic.when(Config::getInstance).thenReturn(config);
return config;
}
Settings mockSettings() {
Settings settings = new Settings();
settings.recordingsDir = "/tmp/rec";
return settings;
}
}

View File

@ -24,6 +24,6 @@ class OrElseTest {
@Test @Test
void testFallback() { void testFallback() {
assertEquals("hello", orElse.apply("", "hello")); assertEquals("hello", orElse.apply("asdf ${variable} asdf", "hello"));
} }
} }