diff --git a/pom.xml b/pom.xml
index f739365..4038330 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
MKVAudioSubtileChanger
MKVAudioSubtitleChanger
- 2.1
+ 3.0
clean package
@@ -117,7 +117,7 @@
org.projectlombok
lombok
- 1.18.8
+ 1.18.24
provided
@@ -155,7 +155,7 @@
com.fasterxml.jackson.dataformat
jackson-dataformat-yaml
- 2.13.1
+ 2.13.4
com.fasterxml.jackson.core
@@ -182,20 +182,26 @@
org.junit.jupiter
junit-jupiter-api
- 5.4.2
+ 5.9.0
test
org.junit.jupiter
junit-jupiter-engine
- 5.4.2
+ 5.9.0
test
org.mockito
mockito-all
- 1.9.5
+ 1.10.19
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.9.0
test
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java
index 99a7681..c009087 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java
@@ -24,7 +24,7 @@ import java.util.stream.Collectors;
@Log4j2
public class AttributeUpdaterKernel {
- private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreadCount());
+ private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreads());
private final FileCollector collector;
private final FileProcessor processor;
private final ResultStatistic statistic = new ResultStatistic();
@@ -43,7 +43,7 @@ public class AttributeUpdaterKernel {
.map(collector::loadFiles)
.flatMap(Collection::stream)
.collect(Collectors.toList());
- List files = collector.loadFiles(Config.getInstance().getLibraryPath()).stream()
+ List files = collector.loadFiles(Config.getInstance().getLibraryPath().getAbsolutePath()).stream()
.filter(file -> !excludedFiles.contains(file))
.collect(Collectors.toList());
progressBar.maxHint(files.size());
@@ -68,9 +68,9 @@ public class AttributeUpdaterKernel {
processor.update(file, fileInfo);
statistic.success();
log.info("Updated {}", file.getAbsolutePath());
- } catch (IOException e) {
+ } catch (IOException | RuntimeException e) {
statistic.failedChanging();
- log.warn("File couldn't be updated: {}", file.getAbsoluteFile());
+ log.warn("File couldn't be updated: '{}', Error: {}", file.getAbsoluteFile(), e.getMessage().replaceAll("\\r|\\n", " "));
}
}
} else if (fileInfo.isUnableToApplyConfig()) {
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java
index 6e26216..efd6077 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java
@@ -1,6 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigLoader;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileProcessor;
import lombok.extern.log4j.Log4j2;
@@ -8,7 +9,7 @@ import lombok.extern.log4j.Log4j2;
@Log4j2
public class Main {
public static void main(String[] args) {
- Config.getInstance().initConfig(args);
+ ConfigLoader.initConfig(args);
AttributeUpdaterKernel kernel = new AttributeUpdaterKernel(new MkvFileCollector(), new MkvFileProcessor());
kernel.execute();
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java
index 5e66832..536830c 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java
@@ -2,223 +2,83 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
-import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.VersionUtil;
-import at.pcgamingfreaks.yaml.YAML;
-import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import lombok.AccessLevel;
import lombok.Getter;
-import lombok.SneakyThrows;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
import lombok.extern.log4j.Log4j2;
-import org.apache.commons.cli.*;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
+import java.util.*;
import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import java.util.stream.Collectors;
-
-import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
-import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
-import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid;
@Log4j2
@Getter
+@Setter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Config {
+ @Getter(AccessLevel.NONE)
+ @Setter(AccessLevel.NONE)
+ private static Config config = null;
@Getter(AccessLevel.NONE)
CommandLineParser parser = new DefaultParser();
@Getter(AccessLevel.NONE)
HelpFormatter formatter = new HelpFormatter();
-
- @Getter(AccessLevel.NONE)
- private static Config config = null;
-
private File configPath;
- private String libraryPath;
- private boolean isSafeMode;
-
- private int threadCount;
- private Pattern includePattern;
+ private File libraryPath;
@Getter(AccessLevel.NONE)
- private String mkvToolNixPath;
+ private File mkvToolNix;
- private boolean isWindows;
+ private int threads;
+ private Pattern includePattern;
+ private boolean safeMode;
- private final Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs"));
- private final Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director"));
- private final Set excludedDirectories = new HashSet<>();
+ private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs"));
+ private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director"));
+ private Set excludedDirectories = new HashSet<>();
private List attributeConfig;
public static Config getInstance() {
- if (config == null) {
+ return getInstance(false);
+ }
+
+ public static Config getInstance(boolean reset) {
+ if (config == null || reset) {
config = new Config();
}
return config;
}
- public void initConfig(String[] args) throws InvalidConfigException {
- ConfigErrors errors = new ConfigErrors();
- CommandLine cmd = null;
- Options options = initOptions();
-
- try {
- cmd = parser.parse(options, args);
- if (cmd == null) throw new NullPointerException();
- } catch (ParseException | NullPointerException e) {
- formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ",
- "\nParameters:", options,
- "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues");
- System.exit(1);
- }
-
- exitIfHelp(cmd, options);
- exitIfVersion(cmd);
-
- configPath = loadConfigPath(cmd, errors);
- libraryPath = loadLibraryPath(cmd, errors);
- isSafeMode = cmd.hasOption(SAFE_MODE.prop());
-
- try (YAML config = new YAML(configPath)) {
- threadCount = loadThreadCount(cmd, config);
- includePattern = loadIncludePattern(cmd, config, errors);
- mkvToolNixPath = loadMkvToolNixPath(cmd, config, errors);
-
- isWindows = loadOperatingSystem();
-
- loadForcedKeywords(cmd, config);
- loadExcludedDirectories(cmd, config);
-
- attributeConfig = loadAttributeConfig(config, errors);
- } catch (IOException | YamlInvalidContentException ignored) {}
-
- if (errors.hasErrors()) {
- throw new InvalidConfigException(errors);
- }
+ /**
+ * Get path to specific mkvtoolnix application.
+ *
+ * @return absolute path to desired application.
+ */
+ public String getPathFor(MkvToolNix application) {
+ return mkvToolNix.getAbsolutePath().endsWith("/") ? mkvToolNix.getAbsolutePath() + application :
+ mkvToolNix.getAbsolutePath() + "/" + application;
}
- private static Options initOptions() {
- Options options = new Options();
- options.addOption(optionOf(HELP, "h", false));
- options.addOption(optionOf(VERSION, "v", false));
- options.addOption(optionOf(LIBRARY, "l", true));
- options.addOption(optionOf(MKV_TOOL_NIX, "m", true));
- options.addOption(optionOf(CONFIG_PATH, "c", true));
- options.addOption(optionOf(THREADS, "t", true));
- options.addOption(optionOf(SAFE_MODE, "s", false));
- options.addOption(optionOf(FORCED_KEYWORDS, "k", Option.UNLIMITED_VALUES, false));
- options.addOption(optionOf(EXCLUDE_DIRECTORY, "e", Option.UNLIMITED_VALUES, false));
- options.addOption(optionOf(INCLUDE_PATTERN, "i", true));
- return options;
- }
-
- private void exitIfHelp(CommandLine cmd, Options options) {
- if (cmd.hasOption("help")) {
- formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ",
- "\nParameters:", options,
- "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues");
- System.exit(0);
- }
- }
-
- private void exitIfVersion(CommandLine cmd) {
- if (cmd.hasOption(VERSION.prop())) {
- System.out.printf("MKV Audio Subtitle Changer Version %s%n", VersionUtil.getVersion());
- System.exit(0);
- }
- }
-
- private File loadConfigPath(CommandLine cmd, ConfigErrors errors) {
- File configPath = new File(cmd.getOptionValue(CONFIG_PATH.prop(), "config.yaml"));
- if (configPath.isFile()) return configPath;
-
- errors.add("invalid config path");
- return null;
- }
-
- private String loadLibraryPath(CommandLine cmd, ConfigErrors errors) {
- if (cmd.hasOption(LIBRARY.prop())) {
- File libraryPath = new File(cmd.getOptionValue(LIBRARY.prop()));
- if (libraryPath.isFile() || libraryPath.isDirectory()) {
- return libraryPath.getAbsolutePath();
- } else {
- errors.add("invalid library path");
- }
- } else {
- errors.add("missing library path");
- }
- return null;
- }
-
- private int loadThreadCount(CommandLine cmd, YAML config) {
- return cmd.hasOption(THREADS.prop())
- ? Integer.parseInt(cmd.getOptionValue(THREADS.prop()))
- : config.getInt(THREADS.prop(), 2);
- }
-
- private Pattern loadIncludePattern(CommandLine cmd, YAML config, ConfigErrors errors) {
- try {
- return Pattern.compile(cmd.hasOption(INCLUDE_PATTERN.prop())
- ? cmd.getOptionValue(INCLUDE_PATTERN.prop())
- : config.getString(INCLUDE_PATTERN.prop(), ".*"));
- } catch (PatternSyntaxException e) {
- errors.add("invalid regex pattern");
- }
- return null;
- }
-
- @SneakyThrows
- private String loadMkvToolNixPath(CommandLine cmd, YAML config, ConfigErrors errors){
- if (cmd.hasOption(MKV_TOOL_NIX.prop())) return cmd.getOptionValue(MKV_TOOL_NIX.prop());
- if (config.isSet(MKV_TOOL_NIX.prop())) return config.getString(MKV_TOOL_NIX.prop());
- errors.add("path to mkv tool nix installation missing");
- return null;
- }
-
- private boolean loadOperatingSystem() {
- return System.getProperty("os.name").toLowerCase().contains("windows");
- }
-
- @SneakyThrows
- private void loadForcedKeywords(CommandLine cmd, YAML config) {
- if (cmd.hasOption(FORCED_KEYWORDS.prop())) forcedKeywords.addAll(List.of(cmd.getOptionValues(FORCED_KEYWORDS.prop())));
- if (config.isSet(FORCED_KEYWORDS.prop())) forcedKeywords.addAll(config.getStringList(FORCED_KEYWORDS.prop()));
- }
-
- @SneakyThrows
- private void loadExcludedDirectories(CommandLine cmd, YAML config) {
- if (cmd.hasOption(EXCLUDE_DIRECTORY.prop())) excludedDirectories.addAll(List.of(cmd.getOptionValues(EXCLUDE_DIRECTORY.prop())));
- if (config.isSet(EXCLUDE_DIRECTORY.prop())) excludedDirectories.addAll(config.getStringList(EXCLUDE_DIRECTORY.prop()));
- }
-
- private List loadAttributeConfig(YAML config, ConfigErrors errors) {
- Function audio = key -> config.getString(key + ".audio", null);
- Function subtitle = key -> config.getString(key + ".subtitle", null);
-
- List attributeConfigs = config.getKeysFiltered(".*audio.*").stream()
- .sorted()
- .map(key -> key.replace(".audio", ""))
- .map(key -> new AttributeConfig(audio.apply(key), subtitle.apply(key)))
- .collect(Collectors.toList());
-
- if (attributeConfigs.isEmpty()) {
- errors.add("no language configuration");
- } else {
- for (AttributeConfig attributeConfig : attributeConfigs) {
- isLanguageValid(attributeConfig.getAudioLanguage(), errors);
- isLanguageValid(attributeConfig.getSubtitleLanguage(), errors);
- }
- }
-
- return attributeConfigs;
- }
-
- public String getPathFor(MkvToolNix exe) {
- return mkvToolNixPath.endsWith("/") ? mkvToolNixPath + exe : mkvToolNixPath + "/" + exe;
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", Config.class.getSimpleName() + "[", "]")
+ .add("parser=" + parser).add("\n")
+ .add("formatter=" + formatter).add("\n")
+ .add("configPath=" + configPath).add("\n")
+ .add("libraryPath=" + libraryPath).add("\n")
+ .add("isSafeMode=" + safeMode).add("\n")
+ .add("forcedKeywords=" + forcedKeywords).add("\n")
+ .add("commentaryKeywords=" + commentaryKeywords).add("\n")
+ .add("excludedDirectories=" + excludedDirectories).add("\n")
+ .add("threadCount=" + threads).add("\n")
+ .add("includePattern=" + includePattern).add("\n")
+ .add("mkvToolNixPath='" + mkvToolNix + "'").add("\n")
+ .add("attributeConfig=" + attributeConfig)
+ .toString();
}
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigErrors.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigErrors.java
deleted file mode 100644
index 50cecae..0000000
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigErrors.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ConfigErrors {
- private final List errors = new ArrayList<>();
-
- public void add(String errorMessage) {
- errors.add(errorMessage);
- }
-
- public boolean hasErrors() {
- return !errors.isEmpty();
- }
-
- public String toString() {
- return StringUtils.capitalize(String.join(", ", errors));
- }
-}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java
new file mode 100644
index 0000000..df22e31
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java
@@ -0,0 +1,106 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator.*;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.VersionUtil;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+
+public class ConfigLoader {
+ private static final List> VALIDATORS = List.of(
+ new ConfigPathValidator(CONFIG_PATH, true, Path.of("./config.yaml").toFile()),
+ new PathValidator(LIBRARY, true, null),
+ new ThreadValidator(THREADS, false, 2),
+ new MkvToolNixPathValidator(MKV_TOOL_NIX, true, Path.of("C:\\Program Files\\MKVToolNix").toFile()),
+ new BooleanValidator(SAFE_MODE, false),
+ new PatternValidator(INCLUDE_PATTERN, false, Pattern.compile(".*")),
+ new SetValidator(FORCED_KEYWORDS, false, true),
+ new SetValidator(COMMENTARY_KEYWORDS, false, true),
+ new SetValidator(EXCLUDE_DIRECTORY, false, true),
+ new AttributeConfigValidator()
+ );
+
+ public static void initConfig(String[] args) {
+ HelpFormatter formatter = new HelpFormatter();
+ YAML yamlConfig = null;
+
+ Options options = initOptions();
+ CommandLine cmd = parseCommandLineArgs(formatter, options, args);
+
+ exitIfHelp(cmd, options, formatter);
+ exitIfVersion(cmd);
+
+ List results = new ArrayList<>();
+
+ for (ConfigValidator> validator: VALIDATORS) {
+ results.add(validator.validate(yamlConfig, cmd));
+ if (yamlConfig == null && Config.getInstance().getConfigPath() != null) {
+ try {
+ yamlConfig = Config.getInstance().getConfigPath() != null
+ ? new YAML(Config.getInstance().getConfigPath())
+ : new YAML("");
+ } catch (IOException | YamlInvalidContentException ignored) {}
+ }
+ }
+
+ if (results.contains(ValidationResult.INVALID)) System.exit(1);
+ System.out.println();
+ }
+
+ private static Options initOptions() {
+ Options options = new Options();
+ options.addOption(optionOf(HELP, HELP.abrv(), HELP.args()));
+ options.addOption(optionOf(VERSION, VERSION.abrv(), VERSION.args()));
+ options.addOption(optionOf(LIBRARY, LIBRARY.abrv(), LIBRARY.args() ));
+ options.addOption(optionOf(MKV_TOOL_NIX, MKV_TOOL_NIX.abrv(), MKV_TOOL_NIX.args() ));
+ options.addOption(optionOf(CONFIG_PATH, CONFIG_PATH.abrv(), CONFIG_PATH.args() ));
+ options.addOption(optionOf(THREADS, THREADS.abrv(), THREADS.args()));
+ options.addOption(optionOf(SAFE_MODE, SAFE_MODE.abrv(), SAFE_MODE.args() ));
+ options.addOption(optionOf(FORCED_KEYWORDS, FORCED_KEYWORDS.abrv(), FORCED_KEYWORDS.args()));
+ options.addOption(optionOf(EXCLUDE_DIRECTORY, FORCED_KEYWORDS.abrv(), FORCED_KEYWORDS.args()));
+ options.addOption(optionOf(INCLUDE_PATTERN, INCLUDE_PATTERN.abrv(), INCLUDE_PATTERN.args()));
+ return options;
+ }
+
+ private static CommandLine parseCommandLineArgs(HelpFormatter formatter, Options options, String[] args) {
+ CommandLineParser parser = new DefaultParser();
+
+ try {
+ CommandLine cmd = parser.parse(options, args);
+ if (cmd == null) throw new NullPointerException();
+ return cmd;
+ } catch (ParseException | NullPointerException e) {
+ formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ",
+ "\nParameters:", options,
+ "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues");
+ System.exit(1);
+ }
+ return null; // can't be reached
+ }
+
+ private static void exitIfHelp(CommandLine cmd, Options options, HelpFormatter formatter) {
+ if (cmd.hasOption("help")) {
+ formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ",
+ "\nParameters:", options,
+ "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues");
+ System.exit(0);
+ }
+ }
+
+ private static void exitIfVersion(CommandLine cmd) {
+ if (cmd.hasOption(VERSION.prop())) {
+ System.out.printf("MKV Audio Subtitle Changer Version %s%n", VersionUtil.getVersion());
+ System.exit(0);
+ }
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/InvalidConfigException.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/InvalidConfigException.java
deleted file mode 100644
index 9a42eb9..0000000
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/InvalidConfigException.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
-
-public class InvalidConfigException extends RuntimeException{
- public InvalidConfigException(ConfigErrors errors) {
- super("Errors in config: " + errors);
- }
-}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java
new file mode 100644
index 0000000..5ac257e
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java
@@ -0,0 +1,9 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
+
+public enum ValidationResult {
+ VALID,
+ DEFAULT,
+ NOT_PRESENT,
+ MISSING,
+ INVALID;
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java
new file mode 100644
index 0000000..2166a18
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java
@@ -0,0 +1,78 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import org.apache.commons.cli.CommandLine;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid;
+
+public class AttributeConfigValidator extends ConfigValidator> {
+
+ public AttributeConfigValidator() {
+ super(ConfigProperty.ATTRIBUTE_CONFIG, true, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ValidationResult validate(YAML yaml, CommandLine cmd) {
+ System.out.printf("%s: ", property.prop());
+ List result;
+
+ Function audio = key -> yaml.getString(key + ".audio", null);
+ Function subtitle = key -> yaml.getString(key + ".subtitle", null);
+
+ if (yaml.getKeysFiltered(property.prop() + ".*").size() > 0) {
+ result = yaml.getKeysFiltered(".*audio.*").stream()
+ .sorted()
+ .map(key -> key.replace(".audio", ""))
+ .map(key -> new AttributeConfig(audio.apply(key), subtitle.apply(key)))
+ .collect(Collectors.toList());
+ } else if (required) {
+ System.out.println("missing");
+ return ValidationResult.MISSING;
+ } else {
+ System.out.println("ok");
+ return ValidationResult.NOT_PRESENT;
+ }
+
+ if (!isValid(result) || !setValue(result)) {
+ System.out.println("invalid");
+ return ValidationResult.INVALID;
+ }
+
+ System.out.println("ok");
+ return ValidationResult.VALID;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ List parse(String value) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ boolean isValid(List result) {
+ if (result.isEmpty()) {
+ return false;
+ }
+ boolean isValid = true;
+ for (AttributeConfig attributeConfig : result) {
+ isValid = isLanguageValid(attributeConfig.getAudioLanguage())
+ && isLanguageValid(attributeConfig.getSubtitleLanguage());
+ if (!isValid) return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java
new file mode 100644
index 0000000..d192e25
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java
@@ -0,0 +1,63 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlKeyNotFoundException;
+import org.apache.commons.cli.CommandLine;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.BiFunction;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.ARGUMENTS;
+
+public class BooleanValidator extends ConfigValidator {
+
+ public BooleanValidator(ConfigProperty property, boolean required) {
+ super(property, required, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected BiFunction> provideDataYaml() {
+ return (yaml, property) -> {
+ if (yaml.isSet(ARGUMENTS.prop())
+ && yaml.getStringList(ARGUMENTS.prop(), List.of()).contains(property.prop())) {
+ return Optional.of(true);
+ }
+ return Optional.empty();
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected BiFunction> provideDataCmd() {
+ return (cmd, property) -> {
+ if (cmd.hasOption(property.prop())) {
+ return Optional.of(true);
+ }
+ return Optional.empty();
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ * This should not be used.
+ */
+ @Override
+ Boolean parse(String value) {
+ throw new RuntimeException("This should not be called");
+ }
+
+ /**
+ * {@inheritDoc}
+ * Validation is skipped.
+ */
+ @Override
+ boolean isValid(Boolean result) {
+ return true; // skip
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java
new file mode 100644
index 0000000..54422f3
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java
@@ -0,0 +1,30 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+
+import java.io.File;
+import java.util.Optional;
+import java.util.function.BiFunction;
+
+public class ConfigPathValidator extends PathValidator {
+ public ConfigPathValidator(ConfigProperty property, boolean required, File defaultValue) {
+ super(property, required, defaultValue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected BiFunction> provideDataYaml() {
+ return (yaml, property) -> Optional.empty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean isValid(File result) {
+ return super.isValid(result) && (result.getAbsolutePath().endsWith(".yml") || result.getAbsolutePath().endsWith(".yaml"));
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java
new file mode 100644
index 0000000..0aa4fc3
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java
@@ -0,0 +1,149 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlKeyNotFoundException;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+@RequiredArgsConstructor
+public abstract class ConfigValidator {
+ protected final ConfigProperty property;
+ protected final boolean required;
+ protected final FieldType defaultValue;
+
+ /**
+ * Validate the user input. Parameters of cmd are prioritised.
+ *
+ * @param yaml config file
+ * @param cmd command line parameters
+ * @return {@link ValidationResult} containing validity of input.
+ */
+ public ValidationResult validate(YAML yaml, CommandLine cmd) {
+ System.out.printf("%s: ", property.prop());
+ FieldType result;
+
+ Optional cmdResult = provideDataCmd().apply(cmd, property);
+ Optional yamlResult = provideDataYaml().apply(yaml, property);
+
+ if (cmdResult.isPresent()) {
+ result = cmdResult.get();
+ } else if (yamlResult.isPresent()) {
+ result = yamlResult.get();
+ } else {
+ if (defaultValue != null) {
+ if (setValue(defaultValue)) {
+ System.out.println("default");
+ return ValidationResult.DEFAULT;
+ } else {
+ System.out.println("invalid");
+ return ValidationResult.INVALID;
+ }
+ }
+ if (required) {
+ System.out.println("missing");
+ return ValidationResult.MISSING;
+ } else {
+ System.out.println("ok");
+ return ValidationResult.NOT_PRESENT;
+ }
+ }
+
+ if (!isValid(result) || !setValue(result)) {
+ System.out.println("invalid");
+ return ValidationResult.INVALID;
+ }
+
+ System.out.println("ok");
+ return ValidationResult.VALID;
+ }
+
+ /**
+ * @return parsed input of yaml config for property
+ */
+ protected BiFunction> provideDataYaml() {
+ return (yaml, property) -> {
+ if (yaml.isSet(property.prop())) {
+ try {
+ return Optional.of(parse(yaml.getString(property.prop())));
+ } catch (YamlKeyNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return Optional.empty();
+ };
+ }
+
+ /**
+ * @return parsed input of command line parameters config for property
+ */
+ protected BiFunction> provideDataCmd() {
+ return (cmd, property) -> {
+ if (cmd.hasOption(property.prop())) {
+ return Optional.of(parse(cmd.getOptionValue(property.prop())));
+ }
+ return Optional.empty();
+ };
+ }
+
+ /**
+ * Parse input parameter to desired format.
+ *
+ * @param value input parameter
+ * @return parsed property
+ */
+ abstract FieldType parse(String value);
+
+ /**
+ * Validate if the data has the desired and allowed format.
+ *
+ * @param result parsed property
+ * @return true if data is in desired format.
+ */
+ abstract boolean isValid(FieldType result);
+
+ /**
+ * Sets valid properties to {@link Config} via reflections.
+ *
+ * @param result parsed property
+ * @return false if method invocation failed
+ */
+ protected boolean setValue(FieldType result) {
+ List methods = Arrays.stream(Config.getInstance().getClass().getDeclaredMethods())
+ .filter(containsSetterOf(property))
+ .collect(Collectors.toList());
+ if (methods.size() != 1) {
+ return false;
+ }
+ try {
+ methods.get(0).invoke(Config.getInstance(), result);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+
+ protected Predicate containsSetterOf(ConfigProperty property) {
+ return method -> StringUtils.containsIgnoreCase(method.getName(), "set")
+ && StringUtils.containsIgnoreCase(method.getName(), property.prop().replace("-", ""));
+ }
+
+ protected Predicate containsGetterOf(ConfigProperty property) {
+ return method -> StringUtils.containsIgnoreCase(method.getName(), "get")
+ && StringUtils.containsIgnoreCase(method.getName(), property.prop().replace("-", ""));
+ }
+
+
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java
new file mode 100644
index 0000000..4095921
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java
@@ -0,0 +1,26 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+
+import java.io.File;
+import java.nio.file.Path;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_MERGER;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_PROP_EDIT;
+
+public class MkvToolNixPathValidator extends PathValidator {
+ private static final String EXE = ".exe";
+
+ public MkvToolNixPathValidator(ConfigProperty property, boolean required, File defaultValue) {
+ super(property, required, defaultValue);
+ }
+
+ @Override
+ protected boolean isValid(File result) {
+ return result.isDirectory()
+ && (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER + EXE).toFile().isFile()
+ && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT + EXE).toFile().isFile())
+ || (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER).toFile().isFile()
+ && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT).toFile().isFile());
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java
new file mode 100644
index 0000000..3cc712d
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java
@@ -0,0 +1,30 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+
+import java.io.File;
+import java.nio.file.Path;
+
+public class PathValidator extends ConfigValidator {
+
+ public PathValidator(ConfigProperty property, boolean required, File defaultValue) {
+ super(property, required, defaultValue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected File parse(String value) {
+ return Path.of(value).toFile();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean isValid(File result) {
+ return result.isDirectory() || result.isFile();
+ }
+
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java
new file mode 100644
index 0000000..d2c0f1e
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java
@@ -0,0 +1,34 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class PatternValidator extends ConfigValidator {
+ private static final Pattern EMPTY_PATTERN = Pattern.compile("");
+
+ public PatternValidator(ConfigProperty property, boolean required, Pattern defaultValue) {
+ super(property, required, defaultValue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ Pattern parse(String value) {
+ try {
+ return Pattern.compile(value);
+ } catch (PatternSyntaxException e) {
+ return EMPTY_PATTERN;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ boolean isValid(Pattern result) {
+ return !result.equals(EMPTY_PATTERN);
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java
new file mode 100644
index 0000000..796513f
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java
@@ -0,0 +1,111 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlKeyNotFoundException;
+import org.apache.commons.cli.CommandLine;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+
+public class SetValidator extends ConfigValidator> {
+ private final boolean append;
+
+ public SetValidator(ConfigProperty property, boolean required, boolean append) {
+ super(property, required, null);
+ this.append = append;
+ }
+
+ public ValidationResult validate(YAML yaml, CommandLine cmd) {
+ System.out.printf("%s: ", property.prop());
+ List resultList = null;
+
+ if (cmd.hasOption(property.prop())) {
+ resultList = List.of(cmd.getOptionValues(property.prop()));
+ } else if (yaml.isSet(property.prop())) {
+ try {
+ resultList = yaml.getStringList(property.prop());
+ } catch (YamlKeyNotFoundException ignored) {}
+ } else if (required) {
+ System.out.println("missing");
+ return ValidationResult.MISSING;
+ } else {
+ System.out.println("ok");
+ return ValidationResult.NOT_PRESENT;
+ }
+
+ Set result = parse(resultList);
+
+ if (!isValid(result) || !setValue(result)) {
+ System.out.println("invalid");
+ return ValidationResult.INVALID;
+ }
+
+ System.out.println("ok");
+ return ValidationResult.VALID;
+ }
+
+ protected BiFunction>> provideDataYaml() {
+ return (yaml, property) -> {
+ if (yaml.isSet(property.prop())) {
+ try {
+ return Optional.of(parse(yaml.getStringList(property.prop())));
+ } catch (YamlKeyNotFoundException ignored) {
+ }
+ }
+ return Optional.empty();
+ };
+ }
+
+ protected BiFunction>> provideDataCmd() {
+ return (cmd, property) -> {
+ if (cmd.hasOption(property.prop())) {
+ return Optional.of(parse(List.of(cmd.getOptionValues(property.prop()))));
+ }
+ return Optional.empty();
+ };
+ }
+
+ @Override
+ Set parse(String value) {
+ throw new RuntimeException("This should not be called");
+ }
+
+ protected Set parse(List value) {
+ return new HashSet<>(value);
+ }
+
+ @Override
+ boolean isValid(Set result) {
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected boolean setValue(Set result) {
+ List methods = append
+ ? Arrays.stream(Config.getInstance().getClass().getDeclaredMethods())
+ .filter(containsGetterOf(property))
+ .collect(Collectors.toList())
+ : Arrays.stream(Config.getInstance().getClass().getDeclaredMethods())
+ .filter(containsSetterOf(property))
+ .collect(Collectors.toList());
+ if (methods.size() != 1) {
+ return false;
+ }
+ try {
+ if (append) {
+ ((Set) methods.get(0).invoke(Config.getInstance())).addAll(result);
+ } else {
+ methods.get(0).invoke(Config.getInstance(), result);
+ }
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java
new file mode 100644
index 0000000..8d3e5cb
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java
@@ -0,0 +1,26 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import org.apache.commons.lang3.math.NumberUtils;
+
+public class ThreadValidator extends ConfigValidator{
+ public ThreadValidator(ConfigProperty property, boolean required, Integer defaultValue) {
+ super(property, required, defaultValue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ Integer parse(String value) {
+ return NumberUtils.isParsable(value) ? Integer.parseInt(value) : defaultValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ boolean isValid(Integer result) {
+ return result > 0;
+ }
+}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java
index 65bc848..0457d38 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java
@@ -22,12 +22,12 @@ import static java.lang.String.format;
@Log4j2
public class MkvFileProcessor implements FileProcessor {
private final ObjectMapper mapper = new ObjectMapper();
- private final String[] forcedKeywords = new String[]{"forced", "signs"};
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 ";
private static final String ENABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=1 ";
+ @SuppressWarnings("unchecked")
@Override
public List loadAttributes(File file) {
Map jsonMap;
@@ -90,7 +90,7 @@ public class MkvFileProcessor implements FileProcessor {
return info;
}
- private void detectDefaultTracks(FileInfoDto info, List attributes, List nonForcedTracks) {
+ protected void detectDefaultTracks(FileInfoDto info, List attributes, List nonForcedTracks) {
Set detectedForcedSubtitleLanes = new HashSet<>();
for (FileAttribute attribute : attributes) {
if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType()))
@@ -108,7 +108,7 @@ public class MkvFileProcessor implements FileProcessor {
);
}
- private void detectDesiredTracks(FileInfoDto info, List nonForcedTracks, List nonCommentaryTracks) {
+ protected void detectDesiredTracks(FileInfoDto info, List nonForcedTracks, List nonCommentaryTracks) {
for (AttributeConfig config : Config.getInstance().getAttributeConfig()) {
FileAttribute desiredAudio = null;
FileAttribute desiredSubtitle = null;
@@ -127,7 +127,7 @@ public class MkvFileProcessor implements FileProcessor {
}
@Override
- public void update(File file, FileInfoDto fileInfo) throws IOException {
+ public void update(File file, FileInfoDto fileInfo) throws IOException, RuntimeException {
StringBuilder sb = new StringBuilder();
sb.append(format("\"%s\" ", Config.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT)));
sb.append(format("\"%s\" ", file.getAbsolutePath()));
@@ -154,6 +154,8 @@ public class MkvFileProcessor implements FileProcessor {
}
InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream();
- log.debug(IOUtils.toString(new InputStreamReader(inputstream)));
+ String output = IOUtils.toString(new InputStreamReader(inputstream));
+ log.debug(output);
+ if (output.contains("Error")) throw new RuntimeException(output);
}
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java
index 3208cc6..53dd213 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java
@@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
+import java.util.Objects;
+
@Log4j2
@Getter
@AllArgsConstructor
@@ -11,6 +13,19 @@ public class AttributeConfig {
private final String audioLanguage;
private final String subtitleLanguage;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AttributeConfig that = (AttributeConfig) o;
+ return Objects.equals(audioLanguage, that.audioLanguage) && Objects.equals(subtitleLanguage, that.subtitleLanguage);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(audioLanguage, subtitleLanguage);
+ }
+
@Override
public String toString() {
return "AttributeConfig{"
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java
index 203b4b2..475f591 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java
@@ -1,28 +1,64 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import lombok.AllArgsConstructor;
+import org.apache.commons.cli.Option;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
@AllArgsConstructor
public enum ConfigProperty {
- CONFIG_PATH("config", "Path to config file"),
- LIBRARY("library", "Path to library"),
- SAFE_MODE("safe-mode", "Test run (no files will be changes)"),
- THREADS("threads", "thread count (default: 2)"),
- INCLUDE_PATTERN("include-pattern", "Include files matching pattern"),
- MKV_TOOL_NIX("mkvtoolnix", "Path to mkv tool nix installation"),
- FORCED_KEYWORDS("forcedKeywords", "Additional keywords to identify forced tracks, combines with config file"),
- EXCLUDE_DIRECTORY("exclude-directories", "Directories to be excluded, combines with config file"),
- HELP("help", "\"for help this is\" - Yoda"),
- VERSION("version", "Display version");
+ CONFIG_PATH("config-path", "Path to config file", "p", 1),
+ LIBRARY("library", "Path to library", "l", 1),
+ SAFE_MODE("safe-mode", "Test run (no files will be changes)", "s", 0),
+ WINDOWS("windows", "Is operating system windows", null, 0),
+ THREADS("threads", "thread count (default: 2)", "t", 1),
+ INCLUDE_PATTERN("include-pattern", "Include files matching pattern", "i", 1),
+ MKV_TOOL_NIX("mkvtoolnix", "Path to mkv tool nix installation", "m", 1),
+ FORCED_KEYWORDS("forcedKeywords", "Additional keywords to identify forced tracks", "fk", Option.UNLIMITED_VALUES),
+ COMMENTARY_KEYWORDS("commentary-keywords", "Additional keywords to identify commentary tracks", "ck", Option.UNLIMITED_VALUES),
+ EXCLUDE_DIRECTORY("exclude-directories", "Directories to be excluded, combines with config file", "e", 1),
+ COHERENT("coherent", "Try to match whole series with same config", "c", 0),
+ HELP("help", "\"for help this is\" - Yoda", "h", 0),
+ VERSION("version", "Display version", "v", 0),
+ ARGUMENTS("arguments", "List of arguments", null, 0),
+ ATTRIBUTE_CONFIG("attribute-config", "Attribute config to decide which tracks to choose when", "a", 1);
private final String property;
private final String description;
+ private final String shortParameter;
+ private final int args;
+
+ public String prop() {
+ return property;
+ }
public String desc() {
return description;
}
- public String prop() {
- return property;
+ public String abrv() {
+ return shortParameter;
+ }
+
+ public int args() {
+ return args;
+ }
+
+ /*
+ * Verify at startup that there are no duplicated shortParameters.
+ */
+ static {
+ Set shortParameters = new HashSet<>();
+ for (String param: Arrays.stream(ConfigProperty.values()).map(ConfigProperty::abrv).collect(Collectors.toList())) {
+ if (shortParameters.contains(param)) {
+ throw new IllegalStateException("It is not allowed to have multiple properties with the same abbreviation!");
+ }
+ if (param != null) {
+ shortParameters.add(param);
+ }
+ }
}
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java
index 5bf698b..0e6e853 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java
@@ -4,8 +4,8 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum MkvToolNix {
- MKV_MERGER("mkvmerge.exe"),
- MKV_PROP_EDIT("mkvpropedit.exe");
+ MKV_MERGER("mkvmerge"),
+ MKV_PROP_EDIT("mkvpropedit");
private final String file;
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java
index 49a1974..99acefd 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java
@@ -12,7 +12,7 @@ public class ResultStatistic {
"├─ No suitable config found: %s%n" +
"├─ Already fit config: %s%n" +
"└─ Failed: %s%n" +
- "Runtime: %ss";
+ "Runtime: %s";
private int filesTotal = 0;
@@ -64,9 +64,26 @@ public class ResultStatistic {
runtime = System.currentTimeMillis() - startTime;
}
+ private String formatTimer() {
+ int seconds = (int) (runtime / 1000);
+ int minutes = seconds / 60;
+ int hours = minutes / 60;
+ int days = hours / 24;
+
+ if (days >= 1) {
+ return String.format("%sd %sh %sm %ss", days, hours % 24, minutes % 60, seconds % 60);
+ } else if (hours >= 1) {
+ return String.format("%sh %sm %ss", hours, minutes % 60, seconds % 60);
+ } else if (minutes >= 1) {
+ return String.format("%sm %ss", minutes , seconds % 60);
+ } else {
+ return String.format("%ss", seconds % 60);
+ }
+ }
+
@Override
public String toString() {
return String.format(result, filesTotal, shouldChange, failedChanging, successfullyChanged,
- noSuitableConfigFound, alreadyFits, failed, runtime / 1000);
+ noSuitableConfigFound, alreadyFits, failed, formatTimer());
}
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java
index 95607ac..3b887a8 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java
@@ -4,8 +4,8 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import org.apache.commons.cli.Option;
public class CommandLineOptionsUtil {
- public static Option optionOf(ConfigProperty property, String opt, boolean hasArg) {
- return optionOf(property, opt, hasArg ? 1 : 0, false);
+ public static Option optionOf(ConfigProperty property, String opt, int args) {
+ return optionOf(property, opt, args, false);
}
public static Option optionOf(ConfigProperty property, String opt, boolean hasArg, boolean required) {
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java
index 1ba46b4..7613eea 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java
@@ -1,7 +1,5 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
-import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigErrors;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -28,10 +26,4 @@ public class LanguageValidatorUtil {
public static boolean isLanguageValid(String language) {
return ISO3_LANGUAGES.contains(language);
}
-
- public static void isLanguageValid(String language, ConfigErrors errors) {
- if (!isLanguageValid(language)) {
- errors.add(String.format("%s is not a valid language", language));
- }
- }
}
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java
new file mode 100644
index 0000000..9427272
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java
@@ -0,0 +1,82 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static org.junit.jupiter.api.Assertions.*;
+
+class AttributeConfigValidatorTest {
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(ATTRIBUTE_CONFIG, ATTRIBUTE_CONFIG.abrv(), ATTRIBUTE_CONFIG.args()));
+ }
+
+ @BeforeEach
+ void beforeEach() {
+ Config.getInstance(true);
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ Arguments.of(attrConfYaml("jpn", "ger"), new String[]{}, VALID, attrConf("jpn", "ger")),
+ Arguments.of(attrConfYaml("jpn", "ger", "jpn", "eng"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "eng")),
+ Arguments.of(attrConfYaml("jpn", "ger", "jpn", "OFF"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "OFF")),
+ Arguments.of(attrConfYaml("jpn", "invalid"), new String[]{}, INVALID, null),
+ Arguments.of("", new String[]{}, MISSING, null)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(String yamlArgs, String[] cmdArgs, ValidationResult expectedResult, List expectedConfig)
+ throws ParseException, YamlInvalidContentException {
+ AttributeConfigValidator underTest = new AttributeConfigValidator();
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ assertIterableEquals(expectedConfig, Config.getInstance().getAttributeConfig());
+ }
+
+ private static String attrConfYaml(String... languages) {
+ StringBuilder yaml = new StringBuilder("attribute-config: ");
+ int counter = 0;
+ for (int i = 0; i < languages.length; i += 2) {
+ counter++;
+ yaml.append(String.format("\n %s:\n audio: %s\n subtitle: %s", counter, languages[0], languages[1]));
+ }
+ return yaml.toString();
+ }
+
+ private static List attrConf(String... languages) {
+ List conf = new ArrayList<>();
+ for (int i = 0; i < languages.length; i += 2) {
+ conf.add(new AttributeConfig(languages[0], languages[1]));
+ }
+ return conf;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java
new file mode 100644
index 0000000..15411c6
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java
@@ -0,0 +1,58 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.yamlList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class BooleanValidatorTest {
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(SAFE_MODE, SAFE_MODE.abrv(), SAFE_MODE.args()));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ Arguments.of(SAFE_MODE, false, "", new String[]{"-safe-mode"}, VALID),
+ Arguments.of(SAFE_MODE, true, "", new String[]{"-safe-mode"}, VALID),
+ Arguments.of(SAFE_MODE, false, "", new String[]{""}, NOT_PRESENT),
+ Arguments.of(SAFE_MODE, true, "", new String[]{""}, MISSING),
+ Arguments.of(SAFE_MODE, false, yamlList(ARGUMENTS, SAFE_MODE), new String[]{""}, VALID),
+ Arguments.of(SAFE_MODE, true, yamlList(ARGUMENTS, SAFE_MODE), new String[]{""}, VALID),
+ Arguments.of(SAFE_MODE, false, yamlList(ARGUMENTS, WINDOWS), new String[]{""}, NOT_PRESENT),
+ Arguments.of(SAFE_MODE, true, yamlList(ARGUMENTS, WINDOWS), new String[]{""}, MISSING)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
+ BooleanValidator underTest = new BooleanValidator(property, required);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidatorTest.java
new file mode 100644
index 0000000..5cbaa41
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidatorTest.java
@@ -0,0 +1,61 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.CONFIG_PATH;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
+import static org.junit.jupiter.api.Assertions.*;
+
+class ConfigPathValidatorTest {
+ private static final String TEST_FILE = "src/test/resources/test-dir/test-file.mkv";
+ private static final String TEST_CONFIG = "src/test/resources/test-dir/test-config.yml";
+
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(CONFIG_PATH, CONFIG_PATH.abrv(), CONFIG_PATH.args()));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ argumentsOf(CONFIG_PATH, true, null, "", new String[]{"-p", TEST_CONFIG}, VALID),
+ argumentsOf(CONFIG_PATH, true, null, "config-path: " + TEST_CONFIG, new String[]{}, MISSING),
+ argumentsOf(CONFIG_PATH, false, null, "config-path: " + TEST_CONFIG, new String[]{}, NOT_PRESENT),
+ argumentsOf(CONFIG_PATH, false, Path.of(TEST_CONFIG).toFile(), "", new String[]{}, DEFAULT),
+ argumentsOf(CONFIG_PATH, true, null, "", new String[]{"-p", TEST_FILE}, INVALID)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
+ ConfigPathValidator underTest = new ConfigPathValidator(property, required, defaultValue);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java
new file mode 100644
index 0000000..fb66685
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java
@@ -0,0 +1,65 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.MISSING;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static org.junit.jupiter.api.Assertions.*;
+
+class MkvToolNixPathValidatorTest {
+ 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 CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(MKV_TOOL_NIX, MKV_TOOL_NIX.abrv(), MKV_TOOL_NIX.args()));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ Arguments.of(MKV_TOOL_NIX, false, null, "", new String[]{"-m", TEST_MKVTOOLNIX_DIR}, VALID),
+ Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{"-m", TEST_MKVTOOLNIX_EXE_DIR}, VALID),
+ Arguments.of(MKV_TOOL_NIX, false, null, "mkvtoolnix: " + TEST_MKVTOOLNIX_EXE_DIR, new String[]{}, VALID),
+ Arguments.of(MKV_TOOL_NIX, true, null, "mkvtoolnix: " + TEST_MKVTOOLNIX_DIR, new String[]{}, VALID),
+ Arguments.of(MKV_TOOL_NIX, false, Path.of(TEST_MKVTOOLNIX_EXE_DIR).toFile(), "", new String[]{}, DEFAULT),
+ Arguments.of(MKV_TOOL_NIX, false, null, "", new String[]{}, NOT_PRESENT),
+ Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{}, MISSING),
+ Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{"-m", TEST_INVALID_DIR}, INVALID)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
+ MkvToolNixPathValidator underTest = new MkvToolNixPathValidator(property, required, defaultValue);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java
new file mode 100644
index 0000000..4e91a56
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java
@@ -0,0 +1,66 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.File;
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.LIBRARY;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
+import static org.junit.jupiter.api.Assertions.*;
+
+class PathValidatorTest {
+ private static final String TEST_DIR = "src/test/resources/test-dir";
+ private static final String TEST_FILE = "src/test/resources/test-dir/test-file.mkv";
+
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(LIBRARY, LIBRARY.abrv(), LIBRARY.args()));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ argumentsOf(LIBRARY, false, null, "library: " + TEST_DIR, new String[]{}, VALID),
+ argumentsOf(LIBRARY, true, null, "", new String[]{"-l", TEST_FILE}, VALID),
+
+ argumentsOf(LIBRARY, false, TEST_DIR, "", new String[]{}, DEFAULT),
+ argumentsOf(LIBRARY, true, TEST_FILE, "", new String[]{}, DEFAULT),
+ argumentsOf(LIBRARY, true, null, "", new String[]{}, MISSING),
+ argumentsOf(LIBRARY, false, null, "", new String[]{}, NOT_PRESENT),
+
+ argumentsOf(LIBRARY, true, null, "", new String[]{"-l", TEST_DIR + "/invalid"}, INVALID),
+ argumentsOf(LIBRARY, false, null, "library: " + TEST_DIR + "/invalid", new String[]{}, INVALID),
+ argumentsOf(LIBRARY, true, TEST_DIR, "", new String[]{"-l", TEST_DIR + "/invalid"}, INVALID)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
+ PathValidator underTest = new PathValidator(property, required, defaultValue);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java
new file mode 100644
index 0000000..cae1059
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java
@@ -0,0 +1,64 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.INCLUDE_PATTERN;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
+import static org.junit.jupiter.api.Assertions.*;
+
+class PatternValidatorTest {
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(INCLUDE_PATTERN, INCLUDE_PATTERN.abrv(), INCLUDE_PATTERN.args()));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ argumentsOf(INCLUDE_PATTERN, false, null, "include-pattern: \"[abd]?.*\"", new String[]{}, VALID),
+ argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{"-i", "[abd]?.*"}, VALID),
+
+ argumentsOf(INCLUDE_PATTERN, false, Pattern.compile(".*"), "", new String[]{}, DEFAULT),
+ argumentsOf(INCLUDE_PATTERN, true, Pattern.compile(".*"), "", new String[]{}, DEFAULT),
+
+ argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{}, MISSING),
+ argumentsOf(INCLUDE_PATTERN, false, null, "", new String[]{}, NOT_PRESENT),
+
+ argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{"-i", "?."}, INVALID),
+ argumentsOf(INCLUDE_PATTERN, false, null, "include-pattern: \"[arst*\"", new String[]{}, INVALID),
+ argumentsOf(INCLUDE_PATTERN, true, Pattern.compile(".?"), "", new String[]{"-i", "?."}, INVALID)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, Pattern defaultValue, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
+ PatternValidator underTest = new PatternValidator(property, required, defaultValue);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java
new file mode 100644
index 0000000..0a82951
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java
@@ -0,0 +1,67 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.COMMENTARY_KEYWORDS;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class SetValidatorTest {
+
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(COMMENTARY_KEYWORDS, COMMENTARY_KEYWORDS.abrv(), COMMENTARY_KEYWORDS.args()));
+ }
+
+ @BeforeEach
+ void beforeEach() {
+ Config.getInstance(true);
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ argumentsOf(COMMENTARY_KEYWORDS, true, true, "", new String[]{"-ck", "test"}, VALID, 3),
+ argumentsOf(COMMENTARY_KEYWORDS, true, false, COMMENTARY_KEYWORDS.prop() + ": [test]", new String[]{}, VALID, 1),
+ argumentsOf(COMMENTARY_KEYWORDS, false, true, COMMENTARY_KEYWORDS.prop() + ": [test]", new String[]{}, VALID, 3),
+ argumentsOf(COMMENTARY_KEYWORDS, false, false, "", new String[]{"-ck", "test"}, VALID, 1),
+ argumentsOf(COMMENTARY_KEYWORDS, true, true, COMMENTARY_KEYWORDS.prop() + ": [commentary]", new String[]{}, VALID, 2),
+
+ argumentsOf(COMMENTARY_KEYWORDS, true, true, "", new String[]{}, MISSING, 2),
+ argumentsOf(COMMENTARY_KEYWORDS, false, true, "", new String[]{}, NOT_PRESENT, 2)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, boolean append, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult, int expectedSize) throws ParseException, YamlInvalidContentException {
+ SetValidator underTest = new SetValidator(property, required, append);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ assertEquals(expectedSize, Config.getInstance().getCommentaryKeywords().size());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java
new file mode 100644
index 0000000..d3d5dd3
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java
@@ -0,0 +1,61 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import at.pcgamingfreaks.yaml.YAML;
+import at.pcgamingfreaks.yaml.YamlInvalidContentException;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.THREADS;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ThreadValidatorTest {
+
+ private static CommandLineParser parser;
+ private static Options options;
+
+ @BeforeAll
+ static void before() {
+ parser = new DefaultParser();
+ options = new Options();
+ options.addOption(optionOf(THREADS, "t", THREADS.args()));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ argumentsOf(THREADS, false, null, "", new String[]{"-t", "10"}, VALID),
+ argumentsOf(THREADS, true, null, "", new String[]{"-t", "10"}, VALID),
+ argumentsOf(THREADS, false, null, "threads: 10", new String[]{}, VALID),
+ argumentsOf(THREADS, true, null, "threads: 10", new String[]{}, VALID),
+ argumentsOf(THREADS, false, 2, "", new String[]{}, DEFAULT),
+ argumentsOf(THREADS, true, null, "", new String[]{}, MISSING),
+ argumentsOf(THREADS, false, null, "", new String[]{}, NOT_PRESENT),
+ argumentsOf(THREADS, true, null, "", new String[]{"-t", "-1"}, INVALID),
+ argumentsOf(THREADS, true, null, "threads: 0", new String[]{}, INVALID),
+ argumentsOf(THREADS, true, 2, "", new String[]{"-t", "0"}, INVALID)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void validate(ConfigProperty property, boolean required, Integer defaultValue, String yamlArgs, String[] cmdArgs,
+ ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
+ ThreadValidator underTest = new ThreadValidator(property, required, defaultValue);
+
+ ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
+
+ assertEquals(expectedResult, result);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java
new file mode 100644
index 0000000..ffd452a
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java
@@ -0,0 +1,28 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
+import org.junit.jupiter.params.provider.Arguments;
+
+import java.util.Arrays;
+
+import static java.util.stream.Collectors.joining;
+
+public class TestUtil {
+ public static String yamlList(ConfigProperty main, ConfigProperty... child) {
+ return main.prop() + ":\n" + Arrays.stream(child)
+ .map(ConfigProperty::prop)
+ .collect(joining("\n", " - ", ""));
+ }
+
+ public static Arguments argumentsOf(ConfigProperty property, boolean required, T defaultValue, String yaml, String[] cmd,
+ ValidationResult result) {
+ return Arguments.of(property, required, defaultValue, yaml, cmd, result);
+ }
+
+ public static Arguments argumentsOf(ConfigProperty property, boolean required, boolean append, String yaml, String[] cmd,
+ ValidationResult result, int expectedSize) {
+ return Arguments.of(property, required, append, yaml, cmd, result, expectedSize);
+ }
+
+}
diff --git a/src/test/resources/mkvmerge.exe b/src/test/resources/mkvtoolnix/mkvmerge
similarity index 100%
rename from src/test/resources/mkvmerge.exe
rename to src/test/resources/mkvtoolnix/mkvmerge
diff --git a/src/test/resources/mkvpropedit.exe b/src/test/resources/mkvtoolnix/mkvpropedit
similarity index 100%
rename from src/test/resources/mkvpropedit.exe
rename to src/test/resources/mkvtoolnix/mkvpropedit
diff --git a/src/test/resources/mkvtoolnix_exe/mkvmerge.exe b/src/test/resources/mkvtoolnix_exe/mkvmerge.exe
new file mode 100644
index 0000000..e69de29
diff --git a/src/test/resources/mkvtoolnix_exe/mkvpropedit.exe b/src/test/resources/mkvtoolnix_exe/mkvpropedit.exe
new file mode 100644
index 0000000..e69de29
diff --git a/src/test/resources/test-dir/test-config.yml b/src/test/resources/test-dir/test-config.yml
new file mode 100644
index 0000000..e69de29
diff --git a/src/test/resources/test-dir/test-file.mkv b/src/test/resources/test-dir/test-file.mkv
new file mode 100644
index 0000000..e69de29