26 Commits

Author SHA1 Message Date
Michael
9f40d97d8a Merge pull request #34 from RatzzFatzz/dev
Add attribute config via cli
2023-02-20 23:50:05 +01:00
156e327943 Add attribute config via cli 2023-02-20 23:48:49 +01:00
Michael
5f72f4545f Merge pull request #28 from RatzzFatzz/dev-config-validators
Update parameter validation
2023-02-19 16:55:11 +01:00
Michael
1e341a0112 Merge branch 'master' into dev-config-validators 2023-02-19 16:53:24 +01:00
fe30d186df Fix CR comments & remove OS Validator 2023-02-19 16:52:27 +01:00
ce9a2fc805 Add linux compatibility & Finalize Config Loader 2023-02-19 15:51:50 +01:00
f69fbedee0 Add ConfigProperty Validation 2023-02-18 23:53:26 +01:00
d0c4b07f52 Add AttributeConfigValidatorTest 2023-02-16 22:43:38 +01:00
313abd311a Add ConfigPathValidatorTest 2023-02-15 23:06:12 +01:00
47f6d65eb2 Add PathValidatorTest 2023-02-14 20:05:37 +01:00
33276b7aa2 Fix PatternValidator & Add PatternValidatorTest 2023-02-13 23:12:08 +01:00
51b4885e65 Add config validator tests & Improve mkvtoolnix error logging & ConfigPathValidator 2023-02-12 21:34:38 +01:00
Michael
847a3f1f68 Merge pull request #29 from RatzzFatzz/dependabot/maven/com.fasterxml.jackson.core-jackson-databind-2.13.4.1
Bump jackson-databind from 2.13.2.1 to 2.13.4.1
2023-02-12 12:11:22 +01:00
dependabot[bot]
937c644b32 Bump jackson-databind from 2.13.2.1 to 2.13.4.1
Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.13.2.1 to 2.13.4.1.
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson.core:jackson-databind
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-19 05:39:05 +00:00
1d6098efc1 Add config validators & tests 2022-09-13 18:58:16 +02:00
b5030f9401 Add config validators 2022-09-03 21:14:07 +02:00
892bc59803 Fix build workflow 2022-06-16 13:22:42 +02:00
1bd136af6a Fix build workflow 2022-06-16 13:18:56 +02:00
d8f0dcdc87 Fix build workflow 2022-06-16 13:14:29 +02:00
10cfb07457 Fix build workflow 2022-06-16 13:11:15 +02:00
Michael
17158e3f15 Merge pull request #27 from RatzzFatzz/dev
Dev
2022-06-16 13:01:07 +02:00
5e27a72499 Fix build workflow 2022-06-16 12:56:40 +02:00
658849417a Add build workflow 2022-06-16 12:55:23 +02:00
8d63c02abd Add sponsor button & increase version number 2022-06-16 12:32:26 +02:00
bad2a39614 Ignore commentary tracks 2022-06-12 14:33:00 +02:00
Michael
2d861b0f1c Merge pull request #25 from RatzzFatzz/master
Update dev
2022-06-12 14:32:09 +02:00
43 changed files with 1439 additions and 263 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
github: [RatzzFatzz]
custom: "https://paypal.me/ratzmichael"

35
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
# This workflow will run every time a new release is created.
name: Build and release
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: 11
- name: Setup workspace
run: mkdir artifacts
- name: Build with Maven
run: |
mvn clean package --file pom.xml
cp target/M*.{zip,tar} artifacts/
- name: Upload artifacts
uses: skx/github-action-publish-binaries@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: 'artifacts/M*'

20
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>MKVAudioSubtileChanger</groupId>
<artifactId>MKVAudioSubtitleChanger</artifactId>
<version>2.0</version>
<version>3.0</version>
<build>
<defaultGoal>clean package</defaultGoal>
@@ -117,7 +117,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- region logging -->
@@ -155,12 +155,12 @@
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.1</version>
<version>2.13.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.1</version>
<version>2.13.4.1</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
@@ -182,20 +182,26 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.2</version>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.2</version>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<!-- endregion -->

View File

@@ -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<File> files = collector.loadFiles(Config.getInstance().getLibraryPath()).stream()
List<File> 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()) {

View File

@@ -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();
}

View File

@@ -2,222 +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<String> forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs"));
private final Set<String> excludedDirectories = new HashSet<>();
private Set<String> forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs"));
private Set<String> commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director"));
private Set<String> excludedDirectories = new HashSet<>();
private List<AttributeConfig> 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 <path_to_library>",
"\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 <path_to_library>",
"\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<AttributeConfig> loadAttributeConfig(YAML config, ConfigErrors errors) {
Function<String, String> audio = key -> config.getString(key + ".audio", null);
Function<String, String> subtitle = key -> config.getString(key + ".subtitle", null);
List<AttributeConfig> 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();
}
}

View File

@@ -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<String> 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));
}
}

View File

@@ -0,0 +1,102 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.VersionUtil;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.*;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
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<ConfigValidator<?>> VALIDATORS = List.of(
new ConfigPathValidator(CONFIG_PATH, false),
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();
formatter.setOptionComparator(null);
YAML yamlConfig = null;
Options options = initOptions();
CommandLine cmd = parseCommandLineArgs(formatter, options, args);
exitIfHelp(cmd, options, formatter);
exitIfVersion(cmd);
List<ValidationResult> results = new ArrayList<>();
for (ConfigValidator<?> validator: VALIDATORS) {
results.add(validator.validate(yamlConfig, cmd));
if (yamlConfig == 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();
Arrays.stream(ConfigProperty.values())
.filter(prop -> prop.abrv() != null)
.map(prop -> optionOf(prop, prop.abrv(), prop.args()))
.forEach(options::addOption);
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 <path_to_library>",
"\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 <path_to_library>",
"\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);
}
}
}

View File

@@ -1,7 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
public class InvalidConfigException extends RuntimeException{
public InvalidConfigException(ConfigErrors errors) {
super("Errors in config: " + errors);
}
}

View File

@@ -0,0 +1,9 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
public enum ValidationResult {
VALID,
DEFAULT,
NOT_PRESENT,
MISSING,
INVALID;
}

View File

@@ -0,0 +1,87 @@
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<List<AttributeConfig>> {
private static final String SEPARATOR = ":";
public AttributeConfigValidator() {
super(ConfigProperty.ATTRIBUTE_CONFIG, true, null);
}
/**
* {@inheritDoc}
*/
public ValidationResult validate(YAML yaml, CommandLine cmd) {
System.out.printf("%s: ", property.prop());
List<AttributeConfig> result;
if (cmd.hasOption(property.prop())) {
List<String> values = List.of(cmd.getOptionValues(property.prop()));
result = values.stream().anyMatch(pair -> !pair.contains(SEPARATOR))
? List.of()
: values.stream().map(pair -> pair.split(SEPARATOR))
.map(split -> new AttributeConfig(split[0], split[1]))
.collect(Collectors.toList());
} else if(yaml.getKeysFiltered(property.prop() + ".*").size() > 0) {
Function<String, String> audio = key -> yaml.getString(key + ".audio", null);
Function<String, String> subtitle = key -> yaml.getString(key + ".subtitle", null);
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<AttributeConfig> parse(String value) {
return null;
}
/**
* {@inheritDoc}
*/
@Override
boolean isValid(List<AttributeConfig> result) {
if (result.isEmpty()) {
return false;
}
boolean isValid;
for (AttributeConfig attributeConfig : result) {
isValid = isLanguageValid(attributeConfig.getAudioLanguage())
&& isLanguageValid(attributeConfig.getSubtitleLanguage());
if (!isValid) return false;
}
return true;
}
}

View File

@@ -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<Boolean> {
public BooleanValidator(ConfigProperty property, boolean required) {
super(property, required, null);
}
/**
* {@inheritDoc}
*/
protected BiFunction<YAML, ConfigProperty, Optional<Boolean>> 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<CommandLine, ConfigProperty, Optional<Boolean>> 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
}
}

View File

@@ -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) {
super(property, required, null);
}
/**
* {@inheritDoc}
*/
@Override
protected BiFunction<YAML, ConfigProperty, Optional<File>> 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"));
}
}

View File

@@ -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<FieldType> {
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<FieldType> cmdResult = provideDataCmd().apply(cmd, property);
Optional<FieldType> 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<YAML, ConfigProperty, Optional<FieldType>> 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<CommandLine, ConfigProperty, Optional<FieldType>> 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<Method> 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<Method> containsSetterOf(ConfigProperty property) {
return method -> StringUtils.containsIgnoreCase(method.getName(), "set")
&& StringUtils.containsIgnoreCase(method.getName(), property.prop().replace("-", ""));
}
protected Predicate<Method> containsGetterOf(ConfigProperty property) {
return method -> StringUtils.containsIgnoreCase(method.getName(), "get")
&& StringUtils.containsIgnoreCase(method.getName(), property.prop().replace("-", ""));
}
}

View File

@@ -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());
}
}

View File

@@ -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<File> {
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();
}
}

View File

@@ -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<Pattern> {
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);
}
}

View File

@@ -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<Set<String>> {
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<String> 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<String> result = parse(resultList);
if (!isValid(result) || !setValue(result)) {
System.out.println("invalid");
return ValidationResult.INVALID;
}
System.out.println("ok");
return ValidationResult.VALID;
}
protected BiFunction<YAML, ConfigProperty, Optional<Set<String>>> 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<CommandLine, ConfigProperty, Optional<Set<String>>> provideDataCmd() {
return (cmd, property) -> {
if (cmd.hasOption(property.prop())) {
return Optional.of(parse(List.of(cmd.getOptionValues(property.prop()))));
}
return Optional.empty();
};
}
@Override
Set<String> parse(String value) {
throw new RuntimeException("This should not be called");
}
protected Set<String> parse(List<String> value) {
return new HashSet<>(value);
}
@Override
boolean isValid(Set<String> result) {
return true;
}
@SuppressWarnings("unchecked")
protected boolean setValue(Set<String> result) {
List<Method> 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<String>) 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;
}
}

View File

@@ -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<Integer>{
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;
}
}

View File

@@ -2,6 +2,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.SetUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
@@ -21,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<FileAttribute> loadAttributes(File file) {
Map<String, Object> jsonMap;
@@ -73,17 +74,23 @@ public class MkvFileProcessor implements FileProcessor {
public FileInfoDto filterAttributes(List<FileAttribute> attributes) {
FileInfoDto info = new FileInfoDto();
List<FileAttribute> nonForcedTracks = attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(), forcedKeywords))
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(),
Config.getInstance().getForcedKeywords().toArray(new CharSequence[0])))
.filter(elem -> !elem.isForcedTrack())
.collect(Collectors.toList());
List<FileAttribute> nonCommentaryTracks = attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(),
Config.getInstance().getCommentaryKeywords().toArray(new CharSequence[0])))
.collect(Collectors.toList());
detectDefaultTracks(attributes, info, nonForcedTracks);
detectDesiredTracks(info, nonForcedTracks);
detectDefaultTracks(info, attributes, nonForcedTracks);
detectDesiredTracks(info, nonForcedTracks, nonCommentaryTracks);
log.debug(info);
return info;
}
private void detectDefaultTracks(List<FileAttribute> attributes, FileInfoDto info, List<FileAttribute> nonForcedTracks) {
protected void detectDefaultTracks(FileInfoDto info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks) {
Set<FileAttribute> detectedForcedSubtitleLanes = new HashSet<>();
for (FileAttribute attribute : attributes) {
if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType()))
@@ -101,11 +108,11 @@ public class MkvFileProcessor implements FileProcessor {
);
}
private void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks) {
protected void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks) {
for (AttributeConfig config : Config.getInstance().getAttributeConfig()) {
FileAttribute desiredAudio = null;
FileAttribute desiredSubtitle = null;
for (FileAttribute attribute : nonForcedTracks) {
for (FileAttribute attribute : SetUtils.retainOf(nonForcedTracks, nonCommentaryTracks)) {
if (attribute.getLanguage().equals(config.getAudioLanguage())
&& AUDIO.equals(attribute.getType())) desiredAudio = attribute;
if (attribute.getLanguage().equals(config.getSubtitleLanguage())
@@ -120,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()));
@@ -147,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);
}
}

View File

@@ -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{"

View File

@@ -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");
LIBRARY("library", "Path to library", "l", 1),
ATTRIBUTE_CONFIG("attribute-config", "Attribute config to decide which tracks to choose when", "a", Option.UNLIMITED_VALUES),
CONFIG_PATH("config-path", "Path to config file", "p", 1),
MKV_TOOL_NIX("mkvtoolnix", "Path to mkv tool nix installation", "m", 1),
SAFE_MODE("safe-mode", "Test run (no files will be changes)", "s", 0),
COHERENT("coherent", "Try to match whole series with same config", "c", 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 (default: \".*\")", "i", 1),
EXCLUDE_DIRECTORY("exclude-directories", "Directories to be excluded, combines with config file", "e", 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),
ARGUMENTS("arguments", "List of arguments", null, 0),
VERSION("version", "Display version", "v", 0),
HELP("help", "\"For help this is\" - Yoda", "h", 0);
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<String> 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);
}
}
}
}

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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) {

View File

@@ -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));
}
}
}

View File

@@ -0,0 +1,13 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SetUtils {
public static <T> Set<T> retainOf(List<T> list1, List<T> list2) {
Set<T> set = new HashSet<>(list1);
set.retainAll(list2);
return set;
}
}

View File

@@ -0,0 +1,85 @@
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<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(attrConfYaml("jpn", "ger"), new String[]{}, VALID, attrConf("jpn", "ger")),
Arguments.of("", new String[]{"-a", "jpn:ger"}, VALID, attrConf("jpn", "ger")),
Arguments.of(attrConfYaml("jpn", "ger", "jpn", "eng"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "eng")),
Arguments.of("", new String[]{"-a", "jpn:ger", "jpn:eng"}, VALID, attrConf("jpn", "ger", "jpn", "eng")),
Arguments.of(attrConfYaml("jpn", "ger", "jpn", "OFF"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "OFF")),
Arguments.of("", new String[]{"-a", "jpn:ger", "jpn:OFF"}, 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<AttributeConfig> 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[i], languages[i+1]));
}
return yaml.toString();
}
private static List<AttributeConfig> attrConf(String... languages) {
List<AttributeConfig> conf = new ArrayList<>();
for (int i = 0; i < languages.length; i += 2) {
conf.add(new AttributeConfig(languages[i], languages[i+1]));
}
return conf;
}
}

View File

@@ -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<Arguments> 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);
}
}

View File

@@ -0,0 +1,57 @@
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.config.ValidationResult.INVALID;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.CONFIG_PATH;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
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.yaml";
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<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(CONFIG_PATH, true, "", new String[]{"-p", TEST_CONFIG}, VALID),
Arguments.of(CONFIG_PATH, true, "config-path: " + TEST_CONFIG, new String[]{}, MISSING),
Arguments.of(CONFIG_PATH, false, "config-path: " + TEST_CONFIG, new String[]{}, NOT_PRESENT),
Arguments.of(CONFIG_PATH, true, "", new String[]{"-p", TEST_FILE}, INVALID)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
ConfigPathValidator underTest = new ConfigPathValidator(property, required);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
}
}

View File

@@ -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<Arguments> 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);
}
}

View File

@@ -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<Arguments> 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);
}
}

View File

@@ -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<Arguments> 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);
}
}

View File

@@ -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<Arguments> 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());
}
}

View File

@@ -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<Arguments> 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);
}
}

View File

@@ -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 <T> 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);
}
}