Improve input validation

This commit is contained in:
RatzzFatzz
2025-12-04 22:09:24 +01:00
parent 0f6bc271b1
commit 9ab417f71d
21 changed files with 239 additions and 177 deletions

View File

@@ -1,23 +1,18 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CachedMkvFileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import picocli.CommandLine;
import java.util.Set;
@Slf4j
@CommandLine.Command(
name = "mkvaudiosubtitlechanger",
@@ -34,36 +29,7 @@ public class Main implements Runnable {
@Getter
@CommandLine.ArgGroup(exclusive = false)
private Config config;
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@Override
public void run() {
if (config.isDebug()) {
Configurator.setRootLevel(Level.DEBUG);
}
validate();
Config.setInstance(config);
AttributeUpdaterKernel kernel = Config.getInstance().getCoherent() != null
? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor())
: new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor());
kernel.execute();
}
private void validate() {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Config>> violations = validator.validate(config);
if (!violations.isEmpty()) {
StringBuilder errorMsg = new StringBuilder();
for (ConstraintViolation<Config> violation : violations) {
errorMsg.append("ERROR: ").append(violation.getPropertyPath()).append(" ").append(violation.getMessage()).append("\n");
}
throw new CommandLine.ParameterException(spec.commandLine(), errorMsg.toString());
}
}
private InputConfig config;
public static void main(String[] args) {
if (args.length == 0) {
@@ -71,4 +37,17 @@ public class Main implements Runnable {
}
new CommandLine(Main.class).execute(args);
}
@Override
public void run() {
if (config.isDebug()) {
Configurator.setRootLevel(Level.DEBUG);
}
InputConfig.setInstance(config);
AttributeUpdaterKernel kernel = InputConfig.getInstance().getCoherent() != null
? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor())
: new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor());
kernel.execute();
}
}

View File

@@ -1,7 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidFile;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidMkvToolNix;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ValidationUtil;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import jakarta.validation.constraints.Min;
import lombok.AccessLevel;
import lombok.Getter;
@@ -12,109 +17,115 @@ import org.apache.commons.lang3.SystemUtils;
import picocli.CommandLine;
import java.io.File;
import java.nio.file.Path;
import java.util.*;
import java.util.regex.Pattern;
import picocli.CommandLine.Option;
@Slf4j
@Getter
@Setter
@NoArgsConstructor
public class Config implements CommandLine.IVersionProvider {
@CommandLine.Command
public class InputConfig {
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private static Config config = null;
private static InputConfig config = null;
private File configPath;
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@CommandLine.Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class,
@Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class,
description = "List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger)")
private List<AttributeConfig> attributeConfig;
@Setter(AccessLevel.NONE)
@ValidFile(message = "does not exist")
@Option(names = {"-l", "--library"}, required = true, description = "path to library")
private File libraryPath;
@CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
@Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
private boolean safeMode;
@Setter(AccessLevel.NONE)
@ValidMkvToolNix(message = "does not exist")
@Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation")
private File mkvToolNix;
@Min(value = 1)
@CommandLine.Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})")
@Min(1)
@Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})")
private int threads;
@CommandLine.Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config")
@Min(0)
@Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config")
private Integer coherent;
@CommandLine.Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match")
@Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match")
private boolean forceCoherent;
@CommandLine.Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)")
@Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)")
private boolean onlyNewFiles;
@CommandLine.Option(names = {"-d", "--filter-date"}, defaultValue = CommandLine.Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")")
@Option(names = {"-d", "--filter-date"}, defaultValue = Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")")
private Date filterDate;
@CommandLine.Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")")
@Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")")
private Pattern includePattern;
@CommandLine.Option(names = {"-e", "--excluded-directory"}, arity = "1..*",
@Option(names = {"-e", "--excluded-directory"}, arity = "1..*",
description = "Directories to be excluded, combines with config file")
private Set<String> excludedDirectories = new HashSet<>();
@CommandLine.Option(names = {"--forced-keywords"}, arity = "1..*", defaultValue = "forced, signs, songs", split = ", ",
@Option(names = {"--forced-keywords"}, arity = "1..*", defaultValue = "forced, signs, songs", split = ", ",
description = "Keywords to identify forced tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
private Set<String> forcedKeywords;
@CommandLine.Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "commentary, director", split = ", ",
@Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "commentary, director", split = ", ",
description = "Keywords to identify commentary tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
private Set<String> commentaryKeywords;
@CommandLine.Option(names = {"--preferred-subtitles"}, arity = "1..*", defaultValue = "unstyled", split = ", ",
@Option(names = {"--preferred-subtitles"}, arity = "1..*", defaultValue = "unstyled", split = ", ",
description = "Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
private Set<String> preferredSubtitles;
@CommandLine.Option(names = {"--debug"}, description = "Enable debug logging")
@Option(names = {"--debug"}, description = "Enable debug logging")
private boolean debug;
@CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library")
public void setLibraryPath(File libraryPath) {
if (!libraryPath.exists()) throw new CommandLine.ParameterException(spec.commandLine(), "Path does not exist: " + libraryPath.getAbsolutePath());
this.libraryPath = libraryPath;
}
static {
// Set default value into system properties to picocli can read the conditional value
System.setProperty("DEFAULT_MKV_TOOL_NIX", SystemUtils.IS_OS_WINDOWS ? "C:\\Program Files\\MKVToolNix" : "/usr/bin/");
}
@CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation")
public void setMkvToolNix(File mkvToolNix) {
this.mkvToolNix = mkvToolNix;
if (!mkvToolNix.exists()
|| !Path.of(getPathFor(MkvToolNix.MKV_MERGE, SystemUtils.IS_OS_WINDOWS)).toFile().exists()
|| !Path.of(getPathFor(MkvToolNix.MKV_PROP_EDIT, SystemUtils.IS_OS_WINDOWS)).toFile().exists()) {
throw new CommandLine.ParameterException(spec.commandLine(),
"Invalid path to mkvtoolnix installation: " + mkvToolNix.getAbsolutePath());
}
}
public static Config getInstance() {
public static InputConfig getInstance() {
return getInstance(false);
}
public static Config getInstance(boolean reset) {
public static InputConfig getInstance(boolean reset) {
if (config == null || reset) {
config = new Config();
config = new InputConfig();
}
return config;
}
public static void setInstance(Config c) {
public static void setInstance(InputConfig c) {
config = c;
validate();
}
private static void validate() {
Validator validator = ValidationUtil.getValidator();
Set<ConstraintViolation<InputConfig>> violations = validator.validate(config);
if (!violations.isEmpty()) {
StringBuilder errors = new StringBuilder();
for (ConstraintViolation<InputConfig> violation : violations) {
errors.append(violation.getPropertyPath()).append(" ").append(violation.getMessage()).append("\n");
}
throw new CommandLine.ParameterException(config.getSpec().commandLine(), errors.toString());
}
}
/**
* Get path to specific mkvtoolnix application.
*
* @return absolute path to desired application.
*/
public String getPathFor(MkvToolNix application) {
@@ -133,7 +144,7 @@ public class Config implements CommandLine.IVersionProvider {
@Override
public String toString() {
return new StringJoiner(", ", Config.class.getSimpleName() + "[", "]")
return new StringJoiner(", ", InputConfig.class.getSimpleName() + "[", "]")
.add("configPath=" + configPath)
.add("libraryPath=" + libraryPath)
.add("mkvToolNix=" + mkvToolNix)
@@ -151,10 +162,5 @@ public class Config implements CommandLine.IVersionProvider {
.add("attributeConfig=" + attributeConfig)
.toString();
}
@Override
public String[] getVersion() throws Exception {
return new String[0];
}
}

View File

@@ -0,0 +1,16 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = ValidFileValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidFile {
String message() default "File does not exist";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,17 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.io.File;
public class ValidFileValidator implements ConstraintValidator<ValidFile, File> {
@Override
public void initialize(ValidFile constraintAnnotation) {
}
@Override
public boolean isValid(File file, ConstraintValidatorContext context) {
return file != null && file.exists();
}
}

View File

@@ -0,0 +1,16 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = ValidMkvToolNixValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidMkvToolNix {
String message() default "MkvToolNix does not exist";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,24 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.apache.commons.lang3.SystemUtils;
import java.io.File;
import java.nio.file.Path;
public class ValidMkvToolNixValidator implements ConstraintValidator<ValidMkvToolNix, File> {
@Override
public void initialize(ValidMkvToolNix constraintAnnotation) {
}
@Override
public boolean isValid(File file, ConstraintValidatorContext context) {
return file != null && file.exists()
&& Path.of(InputConfig.getInstance().getPathFor(MkvToolNix.MKV_MERGE, SystemUtils.IS_OS_WINDOWS)).toFile().exists()
&& Path.of(InputConfig.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT, SystemUtils.IS_OS_WINDOWS)).toFile().exists();
}
}

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
@@ -31,11 +31,11 @@ public class FileFilter {
}
private static boolean hasMatchingPattern(File pathName) {
return Config.getInstance().getIncludePattern().matcher(pathName.getName()).matches();
return InputConfig.getInstance().getIncludePattern().matcher(pathName.getName()).matches();
}
private static boolean isNewer(File pathName) {
Config config = Config.getInstance();
InputConfig config = InputConfig.getInstance();
if (config.getFilterDate() == null) return true;
try {
BasicFileAttributes attributes = Files.readAttributes(pathName.toPath(), BasicFileAttributes.class);
@@ -47,6 +47,6 @@ public class FileFilter {
}
private static boolean isNewer(Date creationDate) {
return creationDate.toInstant().isAfter(Config.getInstance().getFilterDate().toInstant());
return creationDate.toInstant().isAfter(InputConfig.getInstance().getFilterDate().toInstant());
}
}

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.SetUtils;
@@ -26,7 +26,7 @@ public class MkvFileProcessor implements FileProcessor {
private final ObjectMapper mapper = new ObjectMapper();
private static final SubtitleTrackComparator subtitleTrackComparator =
new SubtitleTrackComparator(Config.getInstance().getPreferredSubtitles().toArray(new String[0]));
new SubtitleTrackComparator(InputConfig.getInstance().getPreferredSubtitles().toArray(new String[0]));
private static final String DISABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=0";
private static final String ENABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=1";
@@ -40,7 +40,7 @@ public class MkvFileProcessor implements FileProcessor {
List<FileAttribute> fileAttributes = new ArrayList<>();
try {
String[] command = new String[]{
Config.getInstance().getPathFor(MkvToolNix.MKV_MERGE),
InputConfig.getInstance().getPathFor(MkvToolNix.MKV_MERGE),
"--identify",
"--identification-format",
"json",
@@ -132,7 +132,7 @@ public class MkvFileProcessor implements FileProcessor {
public List<FileAttribute> retrieveNonForcedTracks(List<FileAttribute> attributes) {
return attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.trackName(),
Config.getInstance().getForcedKeywords().toArray(new CharSequence[0])))
InputConfig.getInstance().getForcedKeywords().toArray(new CharSequence[0])))
.filter(elem -> !elem.forcedTrack())
.collect(Collectors.toList());
}
@@ -141,7 +141,7 @@ public class MkvFileProcessor implements FileProcessor {
public List<FileAttribute> retrieveNonCommentaryTracks(List<FileAttribute> attributes) {
return attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.trackName(),
Config.getInstance().getCommentaryKeywords().toArray(new CharSequence[0])))
InputConfig.getInstance().getCommentaryKeywords().toArray(new CharSequence[0])))
.collect(Collectors.toList());
}
@@ -151,7 +151,7 @@ public class MkvFileProcessor implements FileProcessor {
@Override
public void update(File file, FileInfo fileInfo) throws IOException, MkvToolNixException {
List<String> command = new ArrayList<>();
command.add(Config.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT));
command.add(InputConfig.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT));
command.add(String.format(file.getAbsolutePath()));
if (fileInfo.isAudioDifferent()) {

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
@@ -38,7 +38,7 @@ public abstract class AttributeUpdaterKernel {
protected final FileCollector collector;
protected final FileProcessor processor;
protected final ResultStatistic statistic = ResultStatistic.getInstance();
private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreads());
private final ExecutorService executor = Executors.newFixedThreadPool(InputConfig.getInstance().getThreads());
protected ProgressBarBuilder pbBuilder() {
return new ProgressBarBuilder()
@@ -52,7 +52,7 @@ public abstract class AttributeUpdaterKernel {
statistic.startTimer();
try (ProgressBar progressBar = pbBuilder().build()) {
List<File> files = loadFiles(Config.getInstance().getLibraryPath().getAbsolutePath());
List<File> files = loadFiles(InputConfig.getInstance().getLibraryPath().getAbsolutePath());
progressBar.maxHint(files.size());
files.forEach(file -> executor.submit(() -> {
@@ -71,7 +71,7 @@ public abstract class AttributeUpdaterKernel {
}
protected List<File> loadExcludedFiles() {
List<File> excludedFiles = Config.getInstance().getExcludedDirectories().stream()
List<File> excludedFiles = InputConfig.getInstance().getExcludedDirectories().stream()
.map(collector::loadFiles)
.flatMap(Collection::stream)
.collect(Collectors.toList());
@@ -111,7 +111,7 @@ public abstract class AttributeUpdaterKernel {
processor.detectDefaultTracks(fileInfo, attributes, nonForcedTracks);
processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks,
Config.getInstance().getAttributeConfig().toArray(new AttributeConfig[]{}));
InputConfig.getInstance().getAttributeConfig().toArray(new AttributeConfig[]{}));
updateFile(fileInfo);
}
@@ -142,7 +142,7 @@ public abstract class AttributeUpdaterKernel {
}
private void commitChange(FileInfo fileInfo) {
if (Config.getInstance().isSafeMode()) {
if (InputConfig.getInstance().isSafeMode()) {
return;
}
@@ -157,7 +157,7 @@ public abstract class AttributeUpdaterKernel {
}
protected void endProcess() {
if (Config.getInstance().isSafeMode()) {
if (InputConfig.getInstance().isSafeMode()) {
return;
}
@@ -171,7 +171,7 @@ public abstract class AttributeUpdaterKernel {
if (!lastExecutionFile.exists()) lastExecutionFile.createNewFile();
YAML yaml = new YAML(lastExecutionFile);
yaml.set(Config.getInstance().getNormalizedLibraryPath(), DateUtils.convert(new Date()));
yaml.set(InputConfig.getInstance().getNormalizedLibraryPath(), DateUtils.convert(new Date()));
yaml.save(lastExecutionFile);
} catch (IOException | YamlInvalidContentException e) {
log.error("last-execution.yml could not be created or read.", e);

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
@@ -32,7 +32,7 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
*/
@Override
List<File> loadFiles(String path) {
return loadFiles(path, Config.getInstance().getCoherent());
return loadFiles(path, InputConfig.getInstance().getCoherent());
}
List<File> loadFiles(String path, int depth) {
@@ -53,7 +53,7 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
/**
* Update files in directory, if possible, with the same {@link AttributeConfig}.
* If {@link Config#isForceCoherent()} then there will be no changes to the file if they don't match the same config.
* If {@link InputConfig#isForceCoherent()} then there will be no changes to the file if they don't match the same config.
* Otherwise, the default behaviour is executed.
* This method is called by the executor and is run in parallel.
*
@@ -61,7 +61,7 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
*/
@Override
void process(File file) {
process(file, Config.getInstance().getCoherent());
process(file, InputConfig.getInstance().getCoherent());
}
void process(File file, int depth) {
@@ -71,7 +71,7 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
.map(FileInfo::new)
.collect(Collectors.toList());
for (AttributeConfig config : Config.getInstance().getAttributeConfig()) {
for (AttributeConfig config : InputConfig.getInstance().getAttributeConfig()) {
for (FileInfo fileInfo : fileInfos) {
List<FileAttribute> attributes = processor.loadAttributes(fileInfo.getFile());
@@ -99,7 +99,7 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
log.info("No coherent match found for {}", file.getAbsoluteFile());
for (FileInfo fileInfo : fileInfos) {
if (!Config.getInstance().isForceCoherent()) {
if (!InputConfig.getInstance().isForceCoherent()) {
super.process(fileInfo.getFile());
} else {
statistic.excluded();

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import lombok.extern.slf4j.Slf4j;
@@ -29,7 +29,7 @@ public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel {
@Override
List<File> loadFiles(String path) {
List<File> excludedFiles = loadExcludedFiles();
return collector.loadFiles(Config.getInstance().getLibraryPath().getAbsolutePath()).stream()
return collector.loadFiles(InputConfig.getInstance().getLibraryPath().getAbsolutePath()).stream()
.filter(file -> !excludedFiles.contains(file))
.collect(Collectors.toList());
}

View File

@@ -0,0 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import lombok.Getter;
public class ValidationUtil {
private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
@Getter
private static final Validator validator = factory.getValidator();
}

View File

@@ -16,20 +16,20 @@ class BooleanConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-s"), true, (Function<Config, Boolean>) Config::isSafeMode),
Arguments.of(args("--safemode"), true, (Function<Config, Boolean>) Config::isSafeMode),
Arguments.of(args(), false, (Function<Config, Boolean>) Config::isSafeMode),
Arguments.of(args("-cf"), true, (Function<Config, Boolean>) Config::isForceCoherent),
Arguments.of(args("--force-coherent"), true, (Function<Config, Boolean>) Config::isForceCoherent),
Arguments.of(args(), false, (Function<Config, Boolean>) Config::isForceCoherent),
Arguments.of(args("-n"), true, (Function<Config, Boolean>) Config::isOnlyNewFiles),
Arguments.of(args(), false, (Function<Config, Boolean>) Config::isOnlyNewFiles)
Arguments.of(args("-s"), true, (Function<InputConfig, Boolean>) InputConfig::isSafeMode),
Arguments.of(args("--safemode"), true, (Function<InputConfig, Boolean>) InputConfig::isSafeMode),
Arguments.of(args(), false, (Function<InputConfig, Boolean>) InputConfig::isSafeMode),
Arguments.of(args("-cf"), true, (Function<InputConfig, Boolean>) InputConfig::isForceCoherent),
Arguments.of(args("--force-coherent"), true, (Function<InputConfig, Boolean>) InputConfig::isForceCoherent),
Arguments.of(args(), false, (Function<InputConfig, Boolean>) InputConfig::isForceCoherent),
Arguments.of(args("-n"), true, (Function<InputConfig, Boolean>) InputConfig::isOnlyNewFiles),
Arguments.of(args(), false, (Function<InputConfig, Boolean>) InputConfig::isOnlyNewFiles)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, boolean expected, Function<Config, Boolean> fieldUnderTest) {
void validate(String[] cmdArgs, boolean expected, Function<InputConfig, Boolean> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected, fieldUnderTest.apply(sut.getConfig()));

View File

@@ -22,24 +22,24 @@ class ConfigTest {
"--commentary-keywords", "testCommentary",
"--preferred-subtitles", "testPreferred"
};
CommandLine.populateCommand(Config.getInstance(true), sut);
CommandLine.populateCommand(InputConfig.getInstance(true), sut);
assertTrue(Config.getInstance().getLibraryPath().exists());
assertTrue(InputConfig.getInstance().getLibraryPath().exists());
assertEquals(List.of(new AttributeConfig("ger", "ger"), new AttributeConfig("eng", "eng")),
Config.getInstance().getAttributeConfig());
InputConfig.getInstance().getAttributeConfig());
assertTrue(Config.getInstance().isSafeMode());
assertTrue(Config.getInstance().isForceCoherent());
assertTrue(Config.getInstance().isOnlyNewFiles());
assertNull(Config.getInstance().getFilterDate());
assertTrue(InputConfig.getInstance().isSafeMode());
assertTrue(InputConfig.getInstance().isForceCoherent());
assertTrue(InputConfig.getInstance().isOnlyNewFiles());
assertNull(InputConfig.getInstance().getFilterDate());
assertEquals(2, Config.getInstance().getCoherent());
assertEquals(4, Config.getInstance().getThreads());
assertEquals(".*[abc].*", Config.getInstance().getIncludePattern().pattern());
assertTrue(Config.getInstance().getForcedKeywords().contains("testForced"));
assertTrue(Config.getInstance().getCommentaryKeywords().contains("testCommentary"));
assertTrue(Config.getInstance().getPreferredSubtitles().contains("testPreferred"));
assertEquals(2, InputConfig.getInstance().getCoherent());
assertEquals(4, InputConfig.getInstance().getThreads());
assertEquals(".*[abc].*", InputConfig.getInstance().getIncludePattern().pattern());
assertTrue(InputConfig.getInstance().getForcedKeywords().contains("testForced"));
assertTrue(InputConfig.getInstance().getCommentaryKeywords().contains("testCommentary"));
assertTrue(InputConfig.getInstance().getPreferredSubtitles().contains("testPreferred"));
assertNull(Config.getInstance().getConfigPath());
assertNull(InputConfig.getInstance().getConfigPath());
}
}

View File

@@ -19,15 +19,15 @@ class IntegerConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args(), 2, (Function<Config, Integer>) Config::getThreads),
Arguments.of(args("-t", "5"), 5, (Function<Config, Integer>) Config::getThreads),
Arguments.of(args("--threads", "5"), 5, (Function<Config, Integer>) Config::getThreads)
Arguments.of(args(), 2, (Function<InputConfig, Integer>) InputConfig::getThreads),
Arguments.of(args("-t", "5"), 5, (Function<InputConfig, Integer>) InputConfig::getThreads),
Arguments.of(args("--threads", "5"), 5, (Function<InputConfig, Integer>) InputConfig::getThreads)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, int expected, Function<Config, Integer> fieldUnderTest) {
void validate(String[] cmdArgs, int expected, Function<InputConfig, Integer> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected, fieldUnderTest.apply(sut.getConfig()));
@@ -45,6 +45,6 @@ class IntegerConfigParameterTest {
underTest = underTest.setErr(printWriter);
underTest.execute(args("-t", "0"));
printWriter.flush();
assertTrue(writer.toString().contains("ERROR: threads must be greater than or equal to 1"));
assertTrue(writer.toString().contains("threads must be greater than or equal to 1"));
}
}

View File

@@ -19,26 +19,18 @@ import static org.junit.jupiter.api.Assertions.*;
class MkvToolNixPathConfigParameterTest {
private static final String TEST_INVALID_DIR = "src/test/resources/test-dir";
private static final String TEST_MKVTOOLNIX_DIR = "src/test/resources/mkvtoolnix";
private static final String TEST_MKVTOOLNIX_EXE_DIR = "src/test/resources/mkvtoolnix_exe";
private static final String TEST_MKVTOOLNIX_DIR = SystemUtils.IS_OS_WINDOWS ? "src/test/resources/mkvtoolnix_exe" : "src/test/resources/mkvtoolnix";
private static Stream<Arguments> provideTestCases() {
if (SystemUtils.IS_OS_WINDOWS) {
return Stream.of(
Arguments.of(args("-m", TEST_MKVTOOLNIX_EXE_DIR), TEST_MKVTOOLNIX_EXE_DIR, (Function<Config, File>) Config::getMkvToolNix),
Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_EXE_DIR), TEST_MKVTOOLNIX_EXE_DIR, (Function<Config, File>) Config::getMkvToolNix)
);
}
return Stream.of(
Arguments.of(args("-m", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function<Config, File>) Config::getMkvToolNix),
Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function<Config, File>) Config::getMkvToolNix)
Arguments.of(args("-m", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function<InputConfig, File>) InputConfig::getMkvToolNix),
Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function<InputConfig, File>) InputConfig::getMkvToolNix)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, String expected, Function<Config, File> fieldUnderTest) {
void validate(String[] cmdArgs, String expected, Function<InputConfig, File> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(Path.of(expected).toFile().getAbsolutePath(), fieldUnderTest.apply(sut.getConfig()).getAbsolutePath());
@@ -47,7 +39,7 @@ class MkvToolNixPathConfigParameterTest {
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m", TEST_INVALID_DIR)));
// assertThrows(CommandLine.ParameterException.class, () -> new CommandLine(sut).execute(args("-m", TEST_INVALID_DIR)));
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m")));
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("")));
}

View File

@@ -21,14 +21,14 @@ class PathConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-l", TEST_DIR), Path.of(TEST_DIR).toFile(), true, (Function<Config, File>) Config::getLibraryPath),
Arguments.of(args("-l", TEST_FILE), Path.of(TEST_FILE).toFile(), true, (Function<Config, File>) Config::getLibraryPath)
Arguments.of(args("-l", TEST_DIR), Path.of(TEST_DIR).toFile(), true, (Function<InputConfig, File>) InputConfig::getLibraryPath),
Arguments.of(args("-l", TEST_FILE), Path.of(TEST_FILE).toFile(), true, (Function<InputConfig, File>) InputConfig::getLibraryPath)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, File expected, boolean exists, Function<Config, File> fieldUnderTest) {
void validate(String[] cmdArgs, File expected, boolean exists, Function<InputConfig, File> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected.getAbsolutePath(), fieldUnderTest.apply(sut.getConfig()).getAbsolutePath());
@@ -38,7 +38,7 @@ class PathConfigParameterTest {
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-l", "arst")));
// assertThrows(CommandLine.ParameterException.class, () -> new CommandLine(sut).execute(args("-l", "arst")));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-l")));
assertThrows(CommandLine.UnmatchedArgumentException.class, () -> CommandLine.populateCommand(sut, args("")));
}

View File

@@ -19,15 +19,15 @@ class PatternConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-i", "[abd]?.*"), Pattern.compile("[abd]?.*"), (Function<Config, Pattern>) Config::getIncludePattern),
Arguments.of(args("-i", ".*"), Pattern.compile(".*"), (Function<Config, Pattern>) Config::getIncludePattern),
Arguments.of(args(), Pattern.compile(".*"), (Function<Config, Pattern>) Config::getIncludePattern)
Arguments.of(args("-i", "[abd]?.*"), Pattern.compile("[abd]?.*"), (Function<InputConfig, Pattern>) InputConfig::getIncludePattern),
Arguments.of(args("-i", ".*"), Pattern.compile(".*"), (Function<InputConfig, Pattern>) InputConfig::getIncludePattern),
Arguments.of(args(), Pattern.compile(".*"), (Function<InputConfig, Pattern>) InputConfig::getIncludePattern)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, Pattern expected, Function<Config, Pattern> fieldUnderTest) {
void validate(String[] cmdArgs, Pattern expected, Function<InputConfig, Pattern> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected.pattern(), fieldUnderTest.apply(sut.getConfig()).pattern());

View File

@@ -19,21 +19,21 @@ class SetConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("--commentary-keywords", "test"), 1, (Function<Config, Set<String>>) Config::getCommentaryKeywords),
Arguments.of(args("--commentary-keywords", "test", "test1", "test2", "test3", "test4"), 5, (Function<Config, Set<String>>) Config::getCommentaryKeywords),
Arguments.of(args(), 2, (Function<Config, Set<String>>) Config::getCommentaryKeywords),
Arguments.of(args("--forced-keywords", "test"), 1, (Function<Config, Set<String>>) Config::getForcedKeywords),
Arguments.of(args("--forced-keywords", "test", "test1", "test2", "test3", "test4"), 5, (Function<Config, Set<String>>) Config::getForcedKeywords),
Arguments.of(args(), 3, (Function<Config, Set<String>>) Config::getForcedKeywords),
Arguments.of(args("--preferred-subtitles", "test"), 1, (Function<Config, Set<String>>) Config::getPreferredSubtitles),
Arguments.of(args("--preferred-subtitles", "test", "test1", "test2", "test3", "test4"), 5, (Function<Config, Set<String>>) Config::getPreferredSubtitles),
Arguments.of(args(), 1, (Function<Config, Set<String>>) Config::getPreferredSubtitles)
Arguments.of(args("--commentary-keywords", "test"), 1, (Function<InputConfig, Set<String>>) InputConfig::getCommentaryKeywords),
Arguments.of(args("--commentary-keywords", "test", "test1", "test2", "test3", "test4"), 5, (Function<InputConfig, Set<String>>) InputConfig::getCommentaryKeywords),
Arguments.of(args(), 2, (Function<InputConfig, Set<String>>) InputConfig::getCommentaryKeywords),
Arguments.of(args("--forced-keywords", "test"), 1, (Function<InputConfig, Set<String>>) InputConfig::getForcedKeywords),
Arguments.of(args("--forced-keywords", "test", "test1", "test2", "test3", "test4"), 5, (Function<InputConfig, Set<String>>) InputConfig::getForcedKeywords),
Arguments.of(args(), 3, (Function<InputConfig, Set<String>>) InputConfig::getForcedKeywords),
Arguments.of(args("--preferred-subtitles", "test"), 1, (Function<InputConfig, Set<String>>) InputConfig::getPreferredSubtitles),
Arguments.of(args("--preferred-subtitles", "test", "test1", "test2", "test3", "test4"), 5, (Function<InputConfig, Set<String>>) InputConfig::getPreferredSubtitles),
Arguments.of(args(), 1, (Function<InputConfig, Set<String>>) InputConfig::getPreferredSubtitles)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, int expectedSize, Function<Config, Set<String>> fieldUnderTest) {
void validate(String[] cmdArgs, int expectedSize, Function<InputConfig, Set<String>> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expectedSize, fieldUnderTest.apply(sut.getConfig()).size());

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -57,8 +57,8 @@ class FileFilterTest {
when(file.getName()).thenReturn(List.of(path.split("/")).get(1));
when(file.toPath()).thenReturn(Path.of(TEST_FILE));
Config.getInstance(true).setIncludePattern(Pattern.compile(pattern));
if (filterDate != null) Config.getInstance().setFilterDate(filterDate);
InputConfig.getInstance(true).setIncludePattern(Pattern.compile(pattern));
if (filterDate != null) InputConfig.getInstance().setFilterDate(filterDate);
try (MockedStatic<DateUtils> mockedFiles = Mockito.mockStatic(DateUtils.class)) {
mockedFiles

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
@@ -30,7 +30,7 @@ class MkvFileProcessorTest {
@ParameterizedTest
@MethodSource
void detectDesiredTracks(AttributeConfig expectedMatch, List<FileAttribute> tracks, AttributeConfig... configs) {
Config.getInstance().setPreferredSubtitles(Set.of());
InputConfig.getInstance().setPreferredSubtitles(Set.of());
FileInfo info = new FileInfo(null);
MkvFileProcessor processor = new MkvFileProcessor();
processor.detectDesiredTracks(info, tracks, tracks, configs);
@@ -52,8 +52,8 @@ class MkvFileProcessorTest {
@ParameterizedTest
@MethodSource
void retrieveNonForcedTracks(List<FileAttribute> attributes, List<FileAttribute> expected) {
Config.getInstance().setPreferredSubtitles(Set.of());
Config.getInstance().setForcedKeywords(Set.of("forced"));
InputConfig.getInstance().setPreferredSubtitles(Set.of());
InputConfig.getInstance().setForcedKeywords(Set.of("forced"));
MkvFileProcessor processor = new MkvFileProcessor();
List<FileAttribute> actual = processor.retrieveNonForcedTracks(attributes);
@@ -77,8 +77,8 @@ class MkvFileProcessorTest {
@ParameterizedTest
@MethodSource
void retrieveNonCommentaryTracks(List<FileAttribute> attributes, List<FileAttribute> expected) {
Config.getInstance().setPreferredSubtitles(Set.of());
Config.getInstance().setCommentaryKeywords(Set.of("commentary"));
InputConfig.getInstance().setPreferredSubtitles(Set.of());
InputConfig.getInstance().setCommentaryKeywords(Set.of("commentary"));
MkvFileProcessor processor = new MkvFileProcessor();
List<FileAttribute> actual = processor.retrieveNonCommentaryTracks(attributes);