From 321115b9ca416668c462cb8142f8cf2ebd13c3f5 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Sun, 17 Nov 2024 23:42:06 +0100 Subject: [PATCH 01/32] Rework app to use picocli --- pom.xml | 7 +- .../mkvaudiosubtitlechanger/Main.java | 21 +++- .../config/AttributeConfigConverter.java | 58 +++++++++ .../config/Config.java | 24 +++- .../config/ConfigLoader.java | 110 ------------------ .../config/ValidationResult.java | 1 + .../validator/AttributeConfigValidator.java | 1 + .../config/validator/BooleanValidator.java | 1 + .../validator/CoherentConfigValidator.java | 1 + .../config/validator/ConfigPathValidator.java | 1 + .../config/validator/ConfigValidator.java | 1 + .../config/validator/DateValidator.java | 1 + .../validator/MkvToolNixPathValidator.java | 1 + .../config/validator/PathValidator.java | 1 + .../config/validator/PatternValidator.java | 1 + .../config/validator/SetValidator.java | 1 + .../config/validator/ThreadValidator.java | 1 + .../impl/kernel/AttributeUpdaterKernel.java | 1 + .../util/LanguageValidatorUtil.java | 2 +- .../util/ProjectUtil.java | 8 +- .../config/ConfigLoaderTest.java | 10 +- 21 files changed, 128 insertions(+), 125 deletions(-) create mode 100644 src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigConverter.java delete mode 100644 src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java diff --git a/pom.xml b/pom.xml index 575e36e..09111eb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ at.pcgamingfreaks MKVAudioSubtitleChanger - 3.0.2 + 4.0.0 clean package @@ -127,6 +127,11 @@ 1.18.24 provided + + info.picocli + picocli + 4.7.6 + org.apache.logging.log4j diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index a746649..66dac88 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -1,21 +1,34 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger; import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; -import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigLoader; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CachedMkvFileProcessor; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import picocli.CommandLine; @Slf4j -public class Main { - public static void main(String[] args) { - ConfigLoader.initConfig(args); +@CommandLine.Command(mixinStandardHelpOptions = true, versionProvider = ProjectUtil.class) +public class Main implements Runnable { + + @Getter + @CommandLine.ArgGroup(exclusive = false) + private Config config = Config.getInstance(); + + @Override + public void run() { + Config.setInstance(config); AttributeUpdaterKernel kernel = Config.getInstance().getCoherent() != null ? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor()) : new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor()); kernel.execute(); } + + public static void main(String[] args) { + new CommandLine(Main.class).execute(args); + } } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigConverter.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigConverter.java new file mode 100644 index 0000000..754323f --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigConverter.java @@ -0,0 +1,58 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; +import picocli.CommandLine; + +import java.util.regex.Pattern; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isAudioLanguageValid; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid; + +public class AttributeConfigConverter implements CommandLine.ITypeConverter { + private static final String SEPARATOR = ":"; + private static final Pattern PATTERN = Pattern.compile("^.{3}:.{3}$"); + + /** + * Converts the input string into an AttributeConfig object. + * + * @param s The input string containing audio and subtitle language configuration in format "audioLang:subtitleLang" + * @return An AttributeConfig object representing the parsed configuration + * @throws CommandLine.TypeConversionException if the input string is invalid or contains invalid language codes + */ + @Override + public AttributeConfig convert(String s) throws Exception { + validateInput(s); + + String[] split = s.split(SEPARATOR); + AttributeConfig attr = new AttributeConfig(split[0], split[1]); + + validateResult(attr); + + return attr; + } + + /** + * Validates that the input string matches the expected pattern. + * + * @param s String to validate + * @throws CommandLine.TypeConversionException if the value doesn't match the expected pattern + */ + private static void validateInput(String s) { + if (!PATTERN.matcher(s).matches()) { + throw new CommandLine.TypeConversionException("Invalid Attribute config: " + s); + } + } + + /** + * Validates that both language codes in the AttributeConfig object are valid. + * + * @param attr AttributeConfig object to validate + * @throws CommandLine.TypeConversionException if either language code is invalid + */ + private static void validateResult(AttributeConfig attr) { + if (!isAudioLanguageValid(attr.getAudioLanguage())) + throw new CommandLine.TypeConversionException("Audio language invalid: " + attr.getAudioLanguage()); + if (!isLanguageValid(attr.getSubtitleLanguage())) + throw new CommandLine.TypeConversionException("Subtitle language invalid: " + attr.getSubtitleLanguage()); + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index dc8d6a5..758c0d9 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; +import picocli.CommandLine; import java.io.File; import java.util.*; @@ -18,7 +19,7 @@ import java.util.regex.Pattern; @Slf4j @Getter @Setter -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor public class Config { @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) @@ -27,25 +28,40 @@ public class Config { CommandLineParser parser = new DefaultParser(); @Getter(AccessLevel.NONE) HelpFormatter formatter = new HelpFormatter(); + private File configPath; + @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") private File libraryPath; @Getter(AccessLevel.NONE) + @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "C:\\Program Files\\MKVToolNix", description = "path to mkvtoolnix installation") private File mkvToolNix; + @CommandLine.Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: 2)") private int threads; + @CommandLine.Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")") private Pattern includePattern; + @CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)") private boolean safeMode; + @CommandLine.Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config") private Integer coherent; + @CommandLine.Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match") private boolean forceCoherent; + @CommandLine.Option(names = {"-n"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)") private boolean onlyNewFiles; + @CommandLine.Option(names = {"-d", "--filter-date"}, defaultValue = CommandLine.Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")") private Date filterDate; + @CommandLine.Option(names = {"-fk", "--force-keywords"}, description = "Additional keywords to identify forced tracks") private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs")); + @CommandLine.Option(names = {"-ck", "--commentary-keywords"}, description = "Additional keywords to identify commentary tracks") private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); + @CommandLine.Option(names = {"-e", "--excluded-directory"}, description = "Directories to be excluded, combines with config file") private Set excludedDirectories = new HashSet<>(); + @CommandLine.Option(names = {"-ps", "--preferred-subtiltes"}, description = "Additional keywords to prefer specific subtitle tracks") private Set preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); + @CommandLine.Option(names = {"-a"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class) private List attributeConfig; public static Config getInstance() { @@ -59,6 +75,10 @@ public class Config { return config; } + public static void setInstance(Config c) { + config = c; + } + /** * Get path to specific mkvtoolnix application. * @@ -66,7 +86,7 @@ public class Config { */ public String getPathFor(MkvToolNix application) { return mkvToolNix.getAbsolutePath().endsWith("/") ? mkvToolNix.getAbsolutePath() + application : - mkvToolNix.getAbsolutePath() + "/" + application; + mkvToolNix.getAbsolutePath() + "/" + application; } public String getNormalizedLibraryPath() { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java deleted file mode 100644 index 18d4daa..0000000 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java +++ /dev/null @@ -1,110 +0,0 @@ -package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; - -import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator.*; -import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; -import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil; -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.Comparator; -import java.util.List; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; - -public class ConfigLoader { - private static final List> VALIDATORS = Stream.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 BooleanValidator(ONLY_NEW_FILES, false), - new DateValidator(FILTER_DATE, false), - new PatternValidator(INCLUDE_PATTERN, false, Pattern.compile(".*")), - new SetValidator(FORCED_KEYWORDS, false, true), - new SetValidator(COMMENTARY_KEYWORDS, false, true), - new SetValidator(EXCLUDED_DIRECTORY, false, true), - new SetValidator(PREFERRED_SUBTITLES, false, true), - new AttributeConfigValidator(), - new CoherentConfigValidator(COHERENT, false), - new BooleanValidator(FORCE_COHERENT, false) - ).sorted(Comparator.comparing((ConfigValidator validator) -> validator.getWeight()).reversed()).collect(Collectors.toList()); - - 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 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) || results.contains(ValidationResult.MISSING)) 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(130, "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.prop())) { - formatter.printHelp(130, "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", ProjectUtil.getVersion()); - System.exit(0); - } - } -} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java index 5ac257e..0f17cfc 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java @@ -1,5 +1,6 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; +@Deprecated public enum ValidationResult { VALID, DEFAULT, diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java index 7342c9f..dd21ec8 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java @@ -13,6 +13,7 @@ import java.util.stream.Collectors; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isAudioLanguageValid; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid; +@Deprecated public class AttributeConfigValidator extends ConfigValidator> { private static final String SEPARATOR = ":"; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java index d192e25..6446722 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java @@ -12,6 +12,7 @@ import java.util.function.BiFunction; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.ARGUMENTS; +@Deprecated public class BooleanValidator extends ConfigValidator { public BooleanValidator(ConfigProperty property, boolean required) { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/CoherentConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/CoherentConfigValidator.java index 25edaf9..9f9bdee 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/CoherentConfigValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/CoherentConfigValidator.java @@ -3,6 +3,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import org.apache.commons.lang3.math.NumberUtils; +@Deprecated public class CoherentConfigValidator extends ConfigValidator { private static final Integer DISABLED = -1; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java index c051ca1..d9fa7dc 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java @@ -7,6 +7,7 @@ import java.io.File; import java.util.Optional; import java.util.function.BiFunction; +@Deprecated public class ConfigPathValidator extends PathValidator { public ConfigPathValidator(ConfigProperty property, boolean required) { super(property, required, null); diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java index 791ee77..cae426b 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java @@ -19,6 +19,7 @@ import java.util.function.Predicate; @Slf4j @RequiredArgsConstructor +@Deprecated public abstract class ConfigValidator { protected final ConfigProperty property; protected final boolean required; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/DateValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/DateValidator.java index f376af1..703f472 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/DateValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/DateValidator.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.util.Date; @Slf4j +@Deprecated public class DateValidator extends ConfigValidator { private static final Date INVALID_DATE = new Date(0); private static final Date DEFAULT_DATE = new Date(1000); diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java index 4095921..62fc682 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java @@ -8,6 +8,7 @@ import java.nio.file.Path; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_MERGER; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_PROP_EDIT; +@Deprecated public class MkvToolNixPathValidator extends PathValidator { private static final String EXE = ".exe"; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java index 3cc712d..688d8aa 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java @@ -5,6 +5,7 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import java.io.File; import java.nio.file.Path; +@Deprecated public class PathValidator extends ConfigValidator { public PathValidator(ConfigProperty property, boolean required, File defaultValue) { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java index d2c0f1e..9ee0468 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java @@ -5,6 +5,7 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +@Deprecated public class PatternValidator extends ConfigValidator { private static final Pattern EMPTY_PATTERN = Pattern.compile(""); diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java index 796513f..cddbb05 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java @@ -13,6 +13,7 @@ import java.util.*; import java.util.function.BiFunction; import java.util.stream.Collectors; +@Deprecated public class SetValidator extends ConfigValidator> { private final boolean append; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java index 8d3e5cb..85086a4 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java @@ -3,6 +3,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import org.apache.commons.lang3.math.NumberUtils; +@Deprecated public class ThreadValidator extends ConfigValidator{ public ThreadValidator(ConfigProperty property, boolean required, Integer defaultValue) { super(property, required, defaultValue); diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java index bb31a33..048e61c 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java @@ -19,6 +19,7 @@ import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; import net.harawata.appdirs.AppDirsFactory; +import picocli.CommandLine; import java.io.File; import java.io.IOException; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java index ed7bf6c..f3fb797 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java @@ -24,7 +24,7 @@ public class LanguageValidatorUtil { } public static boolean isAudioLanguageValid(String language) { - return !language.equals("OFF") && ISO3_LANGUAGES.contains(language); + return !language.equals("OFF") && isLanguageValid(language); } public static boolean isLanguageValid(String language) { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/ProjectUtil.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/ProjectUtil.java index 0e2c013..d86656c 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/ProjectUtil.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/ProjectUtil.java @@ -1,10 +1,12 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; +import picocli.CommandLine; + import java.io.IOException; import java.io.InputStream; import java.util.Properties; -public class ProjectUtil { +public class ProjectUtil implements CommandLine.IVersionProvider { private static final Properties PROJECT_PROPERTIES = new Properties(); static { @@ -15,8 +17,8 @@ public class ProjectUtil { } } - public static String getVersion() { - return PROJECT_PROPERTIES.getProperty("version"); + public String[] getVersion() { + return new String[] {getProjectName() + " " + PROJECT_PROPERTIES.getProperty("version")}; } public static String getProjectName() { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java index d78fab5..3849b97 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java @@ -2,6 +2,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import org.junit.jupiter.api.Test; +import picocli.CommandLine; import java.util.List; @@ -12,7 +13,7 @@ class ConfigLoaderTest { @Test void initConfig() { - String[] sut = new String[]{"-a", "ger:ger", "-l", TEST_FILE, + String[] sut = new String[]{"-a", "ger:ger", "eng:eng", "-l", TEST_FILE, "-s", "-cf", "-n", "-c", "2", "-t", "4", @@ -21,15 +22,16 @@ class ConfigLoaderTest { "-ck", "testCommentary", "-ps", "testPreferred" }; - ConfigLoader.initConfig(sut); + CommandLine.populateCommand(Config.getInstance(), sut); assertTrue(Config.getInstance().getLibraryPath().exists()); - assertEquals(List.of(new AttributeConfig("ger", "ger")), Config.getInstance().getAttributeConfig()); + assertEquals(List.of(new AttributeConfig("ger", "ger"), new AttributeConfig("eng", "eng")), + Config.getInstance().getAttributeConfig()); assertTrue(Config.getInstance().isSafeMode()); assertTrue(Config.getInstance().isForceCoherent()); assertTrue(Config.getInstance().isOnlyNewFiles()); - assertNotNull(Config.getInstance().getFilterDate()); + assertNull(Config.getInstance().getFilterDate()); assertEquals(2, Config.getInstance().getCoherent()); assertEquals(4, Config.getInstance().getThreads()); From 4714ef8db105c476ce123e84a34aed282e07a65c Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Mon, 18 Nov 2024 23:59:17 +0100 Subject: [PATCH 02/32] Update config tests --- pom.xml | 29 +++++++ .../mkvaudiosubtitlechanger/Main.java | 24 +++++- .../config/Config.java | 8 +- .../config/AttributeConfigTest.java | 83 ++++++++++++++++++ .../config/BooleanConfigParameterTest.java | 53 ++++++++++++ ...{ConfigLoaderTest.java => ConfigTest.java} | 2 +- .../config/IntegerConfigParameterTest.java | 59 +++++++++++++ .../AttributeConfigValidatorTest.java | 85 ------------------- .../validator/BooleanValidatorTest.java | 58 ------------- .../config/validator/ThreadValidatorTest.java | 61 ------------- .../util/TestUtil.java | 8 ++ 11 files changed, 263 insertions(+), 207 deletions(-) create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java rename src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/{ConfigLoaderTest.java => ConfigTest.java} (98%) create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java diff --git a/pom.xml b/pom.xml index 09111eb..0e2416b 100644 --- a/pom.xml +++ b/pom.xml @@ -132,6 +132,35 @@ picocli 4.7.6 + + + + org.hibernate.validator + hibernate-validator + 8.0.1.Final + + + + + org.glassfish + jakarta.el + 4.0.2 + + + + + jakarta.el + jakarta.el-api + 4.0.0 + + + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + org.apache.logging.log4j diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index 66dac88..581e305 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -7,20 +7,29 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUp import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import picocli.CommandLine; +import java.util.Set; + @Slf4j @CommandLine.Command(mixinStandardHelpOptions = true, versionProvider = ProjectUtil.class) public class Main implements Runnable { @Getter @CommandLine.ArgGroup(exclusive = false) - private Config config = Config.getInstance(); + private Config config; + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; @Override public void run() { + validate(); Config.setInstance(config); AttributeUpdaterKernel kernel = Config.getInstance().getCoherent() != null ? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor()) @@ -28,6 +37,19 @@ public class Main implements Runnable { kernel.execute(); } + private void validate() { + Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> violations = validator.validate(config); + + if (!violations.isEmpty()) { + StringBuilder errorMsg = new StringBuilder(); + for (ConstraintViolation violation : violations) { + errorMsg.append("ERROR: ").append(violation.getMessage()).append("\n"); + } + throw new CommandLine.ParameterException(spec.commandLine(), errorMsg.toString()); + } + } + public static void main(String[] args) { new CommandLine(Main.class).execute(args); } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index 758c0d9..65402ec 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -2,6 +2,11 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix; +import com.sun.jna.platform.win32.Netapi32Util; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.constraints.Min; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -36,7 +41,8 @@ public class Config { @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "C:\\Program Files\\MKVToolNix", description = "path to mkvtoolnix installation") private File mkvToolNix; - @CommandLine.Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: 2)") + @Min(value = 1) + @CommandLine.Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})") private int threads; @CommandLine.Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")") private Pattern includePattern; diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java new file mode 100644 index 0000000..22527ea --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java @@ -0,0 +1,83 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; +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.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import picocli.CommandLine; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static org.junit.jupiter.api.Assertions.*; + +class AttributeConfigTest { + 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(args("-a", "jpn:ger"), attrConf("jpn", "ger")), + Arguments.of(args("-a", "jpn:ger", "jpn:eng"), attrConf("jpn", "ger", "jpn", "eng")), + Arguments.of(args("-a", "jpn:ger", "jpn:OFF"), attrConf("jpn", "ger", "jpn", "OFF")) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, List expectedConfig) { + Main underTest = new Main(); + CommandLine.populateCommand(underTest, cmdArgs); + assertIterableEquals(expectedConfig, underTest.getConfig().getAttributeConfig()); + } + + @Test + void validate() { + Main sut = new Main(); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, new String[]{"-l", "/"})); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, new String[]{"-l", "/", "-a"})); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, new String[]{"-l", "/", "-a", "ger:"})); + assertThrows(CommandLine.ParameterException.class, + () -> CommandLine.populateCommand(sut, new String[]{"-l", "/", "-a", "ger:qwf"})); // Invalid language code + } + + private static String[] args(String... args) { + String[] staticArray = new String[]{"-l", "/"}; + String[] result = new String[staticArray.length + args.length]; + System.arraycopy(staticArray, 0, result, 0, staticArray.length); + System.arraycopy(args, 0, result, staticArray.length, args.length); + return result; + } + + private static List attrConf(String... languages) { + List conf = new ArrayList<>(); + for (int i = 0; i < languages.length; i += 2) { + conf.add(new AttributeConfig(languages[i], languages[i+1])); + } + return conf; + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java new file mode 100644 index 0000000..8a3619e --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java @@ -0,0 +1,53 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +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 picocli.CommandLine; + +import java.util.function.Function; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +class BooleanConfigParameterTest { + 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(args("-s"), true, (Function) Config::isSafeMode), + Arguments.of(args("--safemode"), true, (Function) Config::isSafeMode), + Arguments.of(args(), false, (Function) Config::isSafeMode), + Arguments.of(args("-cf"), true, (Function) Config::isForceCoherent), + Arguments.of(args("--force-coherent"), true, (Function) Config::isForceCoherent), + Arguments.of(args(), false, (Function) Config::isForceCoherent), + Arguments.of(args("-n"), true, (Function) Config::isOnlyNewFiles), + Arguments.of(args(), false, (Function) Config::isOnlyNewFiles) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, boolean expected, Function fieldUnderTest) { + Main sut = new Main(); + CommandLine.populateCommand(sut, cmdArgs); + assertEquals(expected, fieldUnderTest.apply(sut.getConfig())); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java similarity index 98% rename from src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java rename to src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java index 3849b97..10f0235 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoaderTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java @@ -9,7 +9,7 @@ import java.util.List; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE; import static org.junit.jupiter.api.Assertions.*; -class ConfigLoaderTest { +class ConfigTest { @Test void initConfig() { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java new file mode 100644 index 0000000..a8142b4 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java @@ -0,0 +1,59 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import picocli.CommandLine; + +import java.util.function.Function; +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.args; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.*; + +class IntegerConfigParameterTest { + + 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( + Arguments.of(args(), 2, (Function) Config::getThreads), + Arguments.of(args("-t", "5"), 5, (Function) Config::getThreads), + Arguments.of(args("--threads", "5"), 5, (Function) Config::getThreads) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, int expected, Function fieldUnderTest) { + Main sut = new Main(); + CommandLine.populateCommand(sut, cmdArgs); + assertEquals(expected, fieldUnderTest.apply(sut.getConfig())); + } + + @Test + void validate() { + Main sut = new Main(); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-t"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("--threads"))); + assertThrows(CommandLine.ParameterException.class, () -> Main.main(args("--threads", "0"))); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java deleted file mode 100644 index 8a1b143..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java +++ /dev/null @@ -1,85 +0,0 @@ -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("", 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 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 attrConf(String... languages) { - List conf = new ArrayList<>(); - for (int i = 0; i < languages.length; i += 2) { - conf.add(new AttributeConfig(languages[i], languages[i+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 deleted file mode 100644 index 15411c6..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java +++ /dev/null @@ -1,58 +0,0 @@ -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/ThreadValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java deleted file mode 100644 index d3d5dd3..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -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 index 0c08e15..458c4ba 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java @@ -43,4 +43,12 @@ public class TestUtil { fileInfoDto.setMatchedConfig(config); return fileInfoDto; } + + public static String[] args(String... args) { + String[] staticArray = new String[]{"-l", "/", "-a", "jpn:ger"}; + String[] result = new String[staticArray.length + args.length]; + System.arraycopy(staticArray, 0, result, 0, staticArray.length); + System.arraycopy(args, 0, result, staticArray.length, args.length); + return result; + } } From 939f6053dd5bf14c548d2aa8c87c2ce0aa8c3f7d Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Fri, 22 Nov 2024 00:21:13 +0100 Subject: [PATCH 03/32] Update collection config parameter config --- .../config/Config.java | 15 ++-- .../config/AttributeConfigTest.java | 14 ---- .../config/BooleanConfigParameterTest.java | 9 --- .../config/IntegerConfigParameterTest.java | 10 --- .../config/SetConfigParameterTest.java | 52 ++++++++++++++ .../config/validator/SetValidatorTest.java | 68 ------------------- 6 files changed, 63 insertions(+), 105 deletions(-) create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index 65402ec..951239a 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -58,13 +58,20 @@ public class Config { @CommandLine.Option(names = {"-d", "--filter-date"}, defaultValue = CommandLine.Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")") private Date filterDate; - @CommandLine.Option(names = {"-fk", "--force-keywords"}, description = "Additional keywords to identify forced tracks") + @CommandLine.Option(names = {"-fk", "--force-keywords"}, arity = "1..*", + description = "Additional keywords to identify forced tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs")); - @CommandLine.Option(names = {"-ck", "--commentary-keywords"}, description = "Additional keywords to identify commentary tracks") + + @CommandLine.Option(names = {"-ck", "--commentary-keywords"}, arity = "1..*", + description = "Additional keywords to identify commentary tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); - @CommandLine.Option(names = {"-e", "--excluded-directory"}, description = "Directories to be excluded, combines with config file") + + @CommandLine.Option(names = {"-e", "--excluded-directory"}, arity = "1..*", + description = "Directories to be excluded, combines with config file") private Set excludedDirectories = new HashSet<>(); - @CommandLine.Option(names = {"-ps", "--preferred-subtiltes"}, description = "Additional keywords to prefer specific subtitle tracks") + + @CommandLine.Option(names = {"-ps", "--preferred-subtiltes"}, arity = "1..*", + description = "Additional keywords to prefer specific subtitle tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") private Set preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); @CommandLine.Option(names = {"-a"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class) diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java index 22527ea..c9eacb6 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java @@ -24,20 +24,6 @@ import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsU import static org.junit.jupiter.api.Assertions.*; class AttributeConfigTest { - 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( diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java index 8a3619e..8b22f21 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java @@ -20,15 +20,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertIterableEquals; class BooleanConfigParameterTest { - 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( diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java index a8142b4..f5e1c19 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java @@ -23,16 +23,6 @@ import static org.junit.jupiter.api.Assertions.*; class IntegerConfigParameterTest { - 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( Arguments.of(args(), 2, (Function) Config::getThreads), diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java new file mode 100644 index 0000000..b12c0a0 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java @@ -0,0 +1,52 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import picocli.CommandLine; + +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class SetConfigParameterTest { + + private static Stream provideTestCases() { + return Stream.of( + Arguments.of(args("-ck", "test"), 1, (Function>) Config::getCommentaryKeywords), + Arguments.of(args("-ck", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getCommentaryKeywords), + Arguments.of(args(), 2, (Function>) Config::getCommentaryKeywords), + Arguments.of(args("-fk", "test"), 1, (Function>) Config::getForcedKeywords), + Arguments.of(args("-fk", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getForcedKeywords), + Arguments.of(args(), 3, (Function>) Config::getForcedKeywords), + Arguments.of(args("-ps", "test"), 1, (Function>) Config::getPreferredSubtitles), + Arguments.of(args("-ps", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getPreferredSubtitles), + Arguments.of(args(), 1, (Function>) Config::getPreferredSubtitles) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, int expectedSize, Function> fieldUnderTest) { + Main sut = new Main(); + CommandLine.populateCommand(sut, cmdArgs); + assertEquals(expectedSize, fieldUnderTest.apply(sut.getConfig()).size()); + } + + @Test + void validate() { + Main sut = new Main(); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-ck"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-fk"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-e"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-ps"))); + } +} \ 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 deleted file mode 100644 index 174a5b8..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java +++ /dev/null @@ -1,68 +0,0 @@ -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, true, false, COMMENTARY_KEYWORDS.prop() + ":\n - test\n - test2", new String[]{}, VALID, 2), - 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 From b638d93358c990826395f400af005fb28fbd0886 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Fri, 22 Nov 2024 00:44:02 +0100 Subject: [PATCH 04/32] Improve command description --- .../mkvaudiosubtitlechanger/Main.java | 11 +++++- .../config/Config.java | 37 ++++++++----------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index 581e305..ca5c34b 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -17,7 +17,16 @@ import picocli.CommandLine; import java.util.Set; @Slf4j -@CommandLine.Command(mixinStandardHelpOptions = true, versionProvider = ProjectUtil.class) +@CommandLine.Command( + name = "mkvasc", + usageHelpWidth = 120, + customSynopsis = { + "mkvasc -a ... -l [-s]", + "Example: mkvasc -a eng:eng eng:ger -l /mnt/media/ -s" + }, + mixinStandardHelpOptions = true, + versionProvider = ProjectUtil.class +) public class Main implements Runnable { @Getter diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index 951239a..83c6231 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -29,14 +29,17 @@ 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(); private File configPath; + + @CommandLine.Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class) + private List attributeConfig; @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") private File libraryPath; + + @CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)") + private boolean safeMode; + @Getter(AccessLevel.NONE) @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "C:\\Program Files\\MKVToolNix", description = "path to mkvtoolnix installation") private File mkvToolNix; @@ -44,38 +47,32 @@ public class Config { @Min(value = 1) @CommandLine.Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})") private int threads; - @CommandLine.Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")") - private Pattern includePattern; - @CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)") - private boolean safeMode; @CommandLine.Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config") private Integer coherent; @CommandLine.Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match") private boolean forceCoherent; + @CommandLine.Option(names = {"-n"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)") private boolean onlyNewFiles; @CommandLine.Option(names = {"-d", "--filter-date"}, defaultValue = CommandLine.Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")") private Date filterDate; - - @CommandLine.Option(names = {"-fk", "--force-keywords"}, arity = "1..*", - description = "Additional keywords to identify forced tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") - private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs")); - - @CommandLine.Option(names = {"-ck", "--commentary-keywords"}, arity = "1..*", - description = "Additional keywords to identify commentary tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") - private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); - + @CommandLine.Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")") + private Pattern includePattern; @CommandLine.Option(names = {"-e", "--excluded-directory"}, arity = "1..*", description = "Directories to be excluded, combines with config file") private Set excludedDirectories = new HashSet<>(); + @CommandLine.Option(names = {"-fk", "--force-keywords"}, arity = "1..*", + description = "Additional keywords to identify forced tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") + private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs")); + @CommandLine.Option(names = {"-ck", "--commentary-keywords"}, arity = "1..*", + description = "Additional keywords to identify commentary tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") + private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); @CommandLine.Option(names = {"-ps", "--preferred-subtiltes"}, arity = "1..*", description = "Additional keywords to prefer specific subtitle tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") private Set preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); - @CommandLine.Option(names = {"-a"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class) - private List attributeConfig; public static Config getInstance() { return getInstance(false); @@ -109,8 +106,6 @@ public class Config { @Override public String toString() { return new StringJoiner(", ", Config.class.getSimpleName() + "[", "]") - .add("parser=" + parser) - .add("formatter=" + formatter) .add("configPath=" + configPath) .add("libraryPath=" + libraryPath) .add("mkvToolNix=" + mkvToolNix) From 47b4cdc8964fb03963fdca7183a65e2ad6d2b904 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Sun, 24 Nov 2024 23:57:24 +0100 Subject: [PATCH 05/32] Update path & pattern tests --- .../config/Config.java | 12 +++- .../config/PathConfigParameterTest.java | 68 +++++++++++++++++++ .../config/PatternConfigParameterTest.java | 57 ++++++++++++++++ .../config/validator/PathValidatorTest.java | 65 ------------------ .../validator/PatternValidatorTest.java | 64 ----------------- 5 files changed, 136 insertions(+), 130 deletions(-) create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index 83c6231..7d85a52 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -32,9 +32,13 @@ public class Config { private File configPath; + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + @CommandLine.Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class) private List attributeConfig; - @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") + + @Setter(AccessLevel.NONE) private File libraryPath; @CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)") @@ -74,6 +78,12 @@ public class Config { private Set preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); + @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") + public void setLibraryPath(File libraryPath) { + this.libraryPath = libraryPath; + if (!libraryPath.exists()) throw new CommandLine.ParameterException(spec.commandLine(), "Path does not exist: " + libraryPath.getAbsolutePath()); + } + public static Config getInstance() { return getInstance(false); } diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java new file mode 100644 index 0000000..1cb778b --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java @@ -0,0 +1,68 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import picocli.CommandLine; + +import java.io.File; +import java.nio.file.Path; +import java.util.function.Function; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.LIBRARY; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_DIR; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class PathConfigParameterTest { + 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( + Arguments.of(args("-l", TEST_DIR), Path.of(TEST_DIR).toFile(), true, (Function) Config::getLibraryPath), + Arguments.of(args("-l", TEST_FILE), Path.of(TEST_FILE).toFile(), true, (Function) Config::getLibraryPath) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, File expected, boolean exists, Function fieldUnderTest) { + Main sut = new Main(); + CommandLine.populateCommand(sut, cmdArgs); + assertEquals(expected.getAbsolutePath(), fieldUnderTest.apply(sut.getConfig()).getAbsolutePath()); + assertEquals(exists, fieldUnderTest.apply(sut.getConfig()).exists()); + } + + @Test + void validate() { + Main sut = new Main(); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-l", "arst"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-l"))); + assertThrows(CommandLine.UnmatchedArgumentException.class, () -> CommandLine.populateCommand(sut, args(""))); + } + + private static String[] args(String... args) { + String[] staticArray = new String[]{"-a", "ger:ger"}; + String[] result = new String[staticArray.length + args.length]; + System.arraycopy(staticArray, 0, result, 0, staticArray.length); + System.arraycopy(args, 0, result, staticArray.length, args.length); + return result; + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java new file mode 100644 index 0000000..569de48 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java @@ -0,0 +1,57 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import picocli.CommandLine; + +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.INCLUDE_PATTERN; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.*; + +class PatternConfigParameterTest { + 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( + Arguments.of(args("-i", "[abd]?.*"), Pattern.compile("[abd]?.*"), (Function) Config::getIncludePattern), + Arguments.of(args("-i", ".*"), Pattern.compile(".*"), (Function) Config::getIncludePattern), + Arguments.of(args(), Pattern.compile(".*"), (Function) Config::getIncludePattern) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, Pattern expected, Function fieldUnderTest) { + Main sut = new Main(); + CommandLine.populateCommand(sut, cmdArgs); + assertEquals(expected.pattern(), fieldUnderTest.apply(sut.getConfig()).pattern()); + } + + @Test + void validate() { + Main sut = new Main(); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-i"))); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-i", "["))); + } +} \ 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 deleted file mode 100644 index b3e710a..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java +++ /dev/null @@ -1,65 +0,0 @@ -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.PathUtils.TEST_DIR; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; -import static org.junit.jupiter.api.Assertions.*; - -class PathValidatorTest { - 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-path: " + 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-path: " + 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 deleted file mode 100644 index cae1059..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java +++ /dev/null @@ -1,64 +0,0 @@ -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 From 7ea0ab17b00c4b158310b335d9f4f8011f6bf565 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 26 Nov 2024 23:42:16 +0100 Subject: [PATCH 06/32] Update mkvtoolnix path test --- .../config/Config.java | 18 ++++- .../MkvToolNixPathConfigParameterTest.java | 19 ++++++ .../config/PathConfigParameterTest.java | 15 ----- .../config/PatternConfigParameterTest.java | 9 --- .../MkvToolNixPathValidatorTest.java | 65 ------------------- 5 files changed, 35 insertions(+), 91 deletions(-) create mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java delete mode 100644 src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index 7d85a52..b8d75b3 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -18,6 +18,8 @@ import org.apache.commons.cli.HelpFormatter; import picocli.CommandLine; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; import java.util.regex.Pattern; @@ -45,7 +47,7 @@ public class Config { private boolean safeMode; @Getter(AccessLevel.NONE) - @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "C:\\Program Files\\MKVToolNix", description = "path to mkvtoolnix installation") + @Setter(AccessLevel.NONE) private File mkvToolNix; @Min(value = 1) @@ -80,8 +82,20 @@ public class Config { @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") public void setLibraryPath(File libraryPath) { - this.libraryPath = libraryPath; if (!libraryPath.exists()) throw new CommandLine.ParameterException(spec.commandLine(), "Path does not exist: " + libraryPath.getAbsolutePath()); + this.libraryPath = libraryPath; + } + + @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "C:\\Program Files\\MKVToolNix", description = "path to mkvtoolnix installation") + public void setMkvToolNix(File mkvToolNix) { + this.mkvToolNix = mkvToolNix; + if (!mkvToolNix.exists() + || !Path.of(getPathFor(MkvToolNix.MKV_MERGER)).toFile().exists() + || !Path.of(getPathFor(MkvToolNix.MKV_PROP_EDIT)).toFile().exists()) { + throw new CommandLine.ParameterException(spec.commandLine(), + "Invalid path to mkvtoolnix installation: " + mkvToolNix.getAbsolutePath()); + } + } public static Config getInstance() { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java new file mode 100644 index 0000000..519645d --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java @@ -0,0 +1,19 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.junit.jupiter.api.Test; +import picocli.CommandLine; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; +import static org.junit.jupiter.api.Assertions.*; + +class MkvToolNixPathConfigParameterTest { + + @Test + void validate() { + Main sut = new Main(); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m", "./"))); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m"))); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java index 1cb778b..d5aaaca 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PathConfigParameterTest.java @@ -1,10 +1,6 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -16,23 +12,12 @@ import java.nio.file.Path; import java.util.function.Function; import java.util.stream.Stream; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.LIBRARY; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_DIR; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; class PathConfigParameterTest { - 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( diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java index 569de48..ec010c1 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java @@ -22,15 +22,6 @@ import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsO import static org.junit.jupiter.api.Assertions.*; class PatternConfigParameterTest { - 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( diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java deleted file mode 100644 index fb66685..0000000 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java +++ /dev/null @@ -1,65 +0,0 @@ -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 From 1863432dc6e9558b774fe1a259efc413dcac24ee Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 27 Nov 2024 00:32:23 +0100 Subject: [PATCH 07/32] Make mkvtoolnix path default value of dependant --- .../config/Config.java | 32 +++++++-------- .../validator/MkvToolNixPathValidator.java | 6 +-- .../impl/MkvFileProcessor.java | 2 +- .../model/MkvToolNix.java | 2 +- .../MkvToolNixPathConfigParameterTest.java | 39 ++++++++++++++++++- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index b8d75b3..e7364cf 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -2,23 +2,16 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix; -import com.sun.jna.platform.win32.Netapi32Util; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.Validation; -import jakarta.validation.Validator; import jakarta.validation.constraints.Min; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.lang3.SystemUtils; import picocli.CommandLine; import java.io.File; -import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.regex.Pattern; @@ -46,7 +39,6 @@ public class Config { @CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)") private boolean safeMode; - @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private File mkvToolNix; @@ -79,23 +71,26 @@ public class Config { description = "Additional keywords to prefer specific subtitle tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") private Set preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); - @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") public void setLibraryPath(File libraryPath) { if (!libraryPath.exists()) throw new CommandLine.ParameterException(spec.commandLine(), "Path does not exist: " + libraryPath.getAbsolutePath()); this.libraryPath = libraryPath; } - @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "C:\\Program Files\\MKVToolNix", description = "path to mkvtoolnix installation") + static { + // Set default value into system properties to picocli can read the conditional value + System.setProperty("DEFAULT_MKV_TOOL_NIX", SystemUtils.IS_OS_WINDOWS ? "C:\\Program Files\\MKVToolNix" : "/usr/bin/"); + } + + @CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation") public void setMkvToolNix(File mkvToolNix) { this.mkvToolNix = mkvToolNix; if (!mkvToolNix.exists() - || !Path.of(getPathFor(MkvToolNix.MKV_MERGER)).toFile().exists() - || !Path.of(getPathFor(MkvToolNix.MKV_PROP_EDIT)).toFile().exists()) { + || !Path.of(getPathFor(MkvToolNix.MKV_MERGE, SystemUtils.IS_OS_WINDOWS)).toFile().exists() + || !Path.of(getPathFor(MkvToolNix.MKV_PROP_EDIT, SystemUtils.IS_OS_WINDOWS)).toFile().exists()) { throw new CommandLine.ParameterException(spec.commandLine(), "Invalid path to mkvtoolnix installation: " + mkvToolNix.getAbsolutePath()); } - } public static Config getInstance() { @@ -119,8 +114,13 @@ public class Config { * @return absolute path to desired application. */ public String getPathFor(MkvToolNix application) { - return mkvToolNix.getAbsolutePath().endsWith("/") ? mkvToolNix.getAbsolutePath() + application : - mkvToolNix.getAbsolutePath() + "/" + application; + return mkvToolNix.getAbsolutePath().endsWith("/") + ? mkvToolNix.getAbsolutePath() + application + : mkvToolNix.getAbsolutePath() + "/" + application; + } + + public String getPathFor(MkvToolNix application, boolean isWindows) { + return getPathFor(application) + (isWindows ? ".exe" : ""); } public String getNormalizedLibraryPath() { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java index 62fc682..c9ff163 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java @@ -5,7 +5,7 @@ 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_MERGE; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_PROP_EDIT; @Deprecated @@ -19,9 +19,9 @@ public class MkvToolNixPathValidator extends PathValidator { @Override protected boolean isValid(File result) { return result.isDirectory() - && (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER + EXE).toFile().isFile() + && (Path.of(result.getAbsolutePath() + "/" + MKV_MERGE + 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_MERGE).toFile().isFile() && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT).toFile().isFile()); } } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java index f57d66a..05dc487 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java @@ -39,7 +39,7 @@ public class MkvFileProcessor implements FileProcessor { Map jsonMap; List fileAttributes = new ArrayList<>(); try { - String command = format("\"%s\"", Config.getInstance().getPathFor(MkvToolNix.MKV_MERGER)); + String command = format("\"%s\"", Config.getInstance().getPathFor(MkvToolNix.MKV_MERGE)); String[] arguments = new String[]{ command, "--identify", diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java index 0e6e853..22d94f8 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; @AllArgsConstructor public enum MkvToolNix { - MKV_MERGER("mkvmerge"), + MKV_MERGE("mkvmerge"), MKV_PROP_EDIT("mkvpropedit"); private final String file; diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java index 519645d..b4b7a92 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/MkvToolNixPathConfigParameterTest.java @@ -1,19 +1,54 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; +import org.apache.commons.lang3.SystemUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import picocli.CommandLine; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import java.io.File; +import java.nio.file.Path; +import java.util.function.Function; +import java.util.stream.Stream; + import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; import static org.junit.jupiter.api.Assertions.*; class MkvToolNixPathConfigParameterTest { + private static final String TEST_INVALID_DIR = "src/test/resources/test-dir"; + private static final String TEST_MKVTOOLNIX_DIR = "src/test/resources/mkvtoolnix"; + private static final String TEST_MKVTOOLNIX_EXE_DIR = "src/test/resources/mkvtoolnix_exe"; + + private static Stream provideTestCases() { + if (SystemUtils.IS_OS_WINDOWS) { + return Stream.of( + Arguments.of(args("-m", TEST_MKVTOOLNIX_EXE_DIR), TEST_MKVTOOLNIX_EXE_DIR, (Function) Config::getMkvToolNix), + Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_EXE_DIR), TEST_MKVTOOLNIX_EXE_DIR, (Function) Config::getMkvToolNix) + ); + } + + return Stream.of( + Arguments.of(args("-m", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function) Config::getMkvToolNix), + Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function) Config::getMkvToolNix) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String[] cmdArgs, String expected, Function fieldUnderTest) { + Main sut = new Main(); + CommandLine.populateCommand(sut, cmdArgs); + assertEquals(Path.of(expected).toFile().getAbsolutePath(), fieldUnderTest.apply(sut.getConfig()).getAbsolutePath()); + } + @Test void validate() { Main sut = new Main(); - assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m", "./"))); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m", TEST_INVALID_DIR))); assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m"))); + assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args(""))); } } \ No newline at end of file From 547b5ad86c495e4f1e78b022ba423a67c55d96e9 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 27 Nov 2024 21:19:08 +0100 Subject: [PATCH 08/32] Update threads test --- .../mkvaudiosubtitlechanger/Main.java | 2 +- .../config/IntegerConfigParameterTest.java | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index ca5c34b..3ca455f 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -53,7 +53,7 @@ public class Main implements Runnable { if (!violations.isEmpty()) { StringBuilder errorMsg = new StringBuilder(); for (ConstraintViolation violation : violations) { - errorMsg.append("ERROR: ").append(violation.getMessage()).append("\n"); + errorMsg.append("ERROR: ").append(violation.getPropertyPath()).append(" ").append(violation.getMessage()).append("\n"); } throw new CommandLine.ParameterException(spec.commandLine(), errorMsg.toString()); } diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java index f5e1c19..67a71ad 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java @@ -11,6 +11,10 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import picocli.CommandLine; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.function.Function; import java.util.stream.Stream; @@ -44,6 +48,13 @@ class IntegerConfigParameterTest { Main sut = new Main(); assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-t"))); assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("--threads"))); - assertThrows(CommandLine.ParameterException.class, () -> Main.main(args("--threads", "0"))); + + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + CommandLine underTest = new CommandLine(sut); + underTest = underTest.setErr(printWriter); + underTest.execute(args("-t", "0")); + printWriter.flush(); + assertTrue(writer.toString().contains("ERROR: threads must be greater than or equal to 1")); } } \ No newline at end of file From 2710ea2602739690e8da168fdbf640b8b218a2ca Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 28 Jan 2025 23:45:06 +0100 Subject: [PATCH 09/32] Update graalvm and lombok config --- pom.xml | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 0e2416b..6e67c4f 100644 --- a/pom.xml +++ b/pom.xml @@ -8,6 +8,47 @@ MKVAudioSubtitleChanger 4.0.0 + + at.pcgamingfreaks.mkvaudiosubtitlechanger.Main + + 1.18.30 + + + + + native + + + + org.graalvm.buildtools + native-maven-plugin + 0.10.1 + true + + + build-native + + compile-no-fork + + package + + + test-native + + test + + test + + + + false + + + + + + + clean package src/main/java @@ -39,7 +80,7 @@ - at/pcgamingfreaks/mkvaudiosubtitlechanger/Main + ${mainClass} @@ -81,9 +122,25 @@ org.apache.maven.plugins maven-compiler-plugin + 3.13.0 - 11 - 11 + 21 + 21 + + -Aproject=${project.groupId}/${project.artifactId} + + + + org.projectlombok + lombok + ${lombok-version} + + + info.picocli + picocli-codegen + 4.7.6 + + @@ -101,6 +158,15 @@ maven/assembly.xml + + jar-with-dependencies + + + + true + ${mainClass} + + @@ -124,7 +190,7 @@ org.projectlombok lombok - 1.18.24 + ${lombok-version} provided From f3accd77d66888db9161d5b4bce52628380f6281 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Fri, 31 Jan 2025 19:35:50 +0100 Subject: [PATCH 10/32] Replace GraalVM with jpackage and wix --- pom.xml | 154 ++++++++++++++++++++++++++---------- src/main/resources/main.wxs | 144 +++++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+), 43 deletions(-) create mode 100644 src/main/resources/main.wxs diff --git a/pom.xml b/pom.xml index 6e67c4f..50803d3 100644 --- a/pom.xml +++ b/pom.xml @@ -16,33 +16,67 @@ - native + windows + + + windows + + - org.graalvm.buildtools - native-maven-plugin - 0.10.1 - true + org.panteleyev + jpackage-maven-plugin + 1.4.0 - build-native - - compile-no-fork - + windows + + ${project.basedir}/src/main/resources/ + EXE + true + false + false + package - - - test-native - test + jpackage + + + + + + + + + linux + + + linux + + + + + + org.panteleyev + jpackage-maven-plugin + 1.4.0 + + + linux-deb + + DEB + /usr/local/bin + false + mkvasc + your@email.com + + package + + jpackage - test - - false - @@ -62,6 +96,7 @@ language-codes project.properties + LICENSE true @@ -143,12 +178,37 @@ + + maven-resources-plugin + 3.3.1 + + + copy-jpackage-input + package + + copy-resources + + + ${project.build.directory}/jpackage-input + + + ${project.build.directory} + + ${project.artifactId}-${project.version}.jar + + + + + + + org.apache.maven.plugins maven-assembly-plugin 3.3.0 + archive package single @@ -158,19 +218,27 @@ maven/assembly.xml - - jar-with-dependencies - - - - true - ${mainClass} - - + + + org.panteleyev + jpackage-maven-plugin + 1.4.0 + + ${project.artifactId} + RatzzFatzz + ${project.version} + + target/installer + + target/jpackage-input + at.pcgamingfreaks.mkvaudiosubtitlechanger.Main + ${project.artifactId}-${project.version}.jar + + @@ -196,7 +264,7 @@ info.picocli picocli - 4.7.6 + 4.7.5 @@ -210,14 +278,14 @@ org.glassfish jakarta.el - 4.0.2 + 5.0.0-M1 jakarta.el jakarta.el-api - 4.0.0 + 5.0.1 @@ -231,69 +299,69 @@ org.apache.logging.log4j log4j-api - 2.18.0 + 2.22.0 org.apache.logging.log4j log4j-core - 2.18.0 + 2.22.0 org.apache.logging.log4j - log4j-slf4j18-impl - 2.18.0 + log4j-slf4j-impl + 2.22.0 com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.13.4 + 2.16.0 com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 commons-cli commons-cli - 1.5.0 + 1.6.0 org.apache.commons commons-lang3 - 3.12.0 + 3.13.0 me.tongfei progressbar - 0.9.5 + 0.10.0 org.junit.jupiter junit-jupiter-api - 5.9.0 + 5.10.1 test org.junit.jupiter junit-jupiter-engine - 5.9.0 + 5.10.1 test org.mockito mockito-all - 1.10.19 + 2.0.2-beta test org.junit.jupiter junit-jupiter-params - 5.9.0 + 5.10.1 test @@ -306,7 +374,7 @@ net.harawata appdirs - 1.2.1 + 1.2.2 diff --git a/src/main/resources/main.wxs b/src/main/resources/main.wxs new file mode 100644 index 0000000..389cbb6 --- /dev/null +++ b/src/main/resources/main.wxs @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Not Installed + Not Installed + Not Installed + + + Not Installed + + + Not Installed + + + Not Installed + + + + JP_UPGRADABLE_FOUND + + + JP_DOWNGRADABLE_FOUND + + + + + + + + + + + From 4fa5448e1c886cdde8f421df805152d392e5b9da Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Mon, 3 Feb 2025 01:13:15 +0100 Subject: [PATCH 11/32] Fix logging on installed app --- pom.xml | 173 +++++++++++++---------- src/main/resources/log4j2-dev.yaml | 8 +- src/main/resources/log4j2-installed.yaml | 31 ++++ src/main/resources/log4j2.yaml | 8 +- 4 files changed, 141 insertions(+), 79 deletions(-) create mode 100644 src/main/resources/log4j2-installed.yaml diff --git a/pom.xml b/pom.xml index 50803d3..a43200b 100644 --- a/pom.xml +++ b/pom.xml @@ -16,18 +16,61 @@ - windows - - - windows - - + portable + + + src/main/resources + + log4j2.yml + log4j2-debug.yml + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + archive + package + + single + + + false + + maven/assembly.xml + + + + + + + + + + windows + + + + src/main/resources + + log4j2-installed.yaml + + + + + + maven-resources-plugin + 3.3.1 + org.panteleyev jpackage-maven-plugin - 1.4.0 + 1.6.5 windows @@ -37,6 +80,9 @@ true false false + + -Dlog4j.configurationFile=log4j2-installed.yaml + package @@ -50,11 +96,6 @@ linux - - - linux - - @@ -88,9 +129,6 @@ src/main/java src/test/java - - src/main/resources - ./ @@ -178,68 +216,53 @@ - - maven-resources-plugin - 3.3.1 - - - copy-jpackage-input - package - - copy-resources - - - ${project.build.directory}/jpackage-input - - - ${project.build.directory} - - ${project.artifactId}-${project.version}.jar - - - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 3.3.0 - - - archive - package - - single - - - false - - maven/assembly.xml - - - - - - - org.panteleyev - jpackage-maven-plugin - 1.4.0 - - ${project.artifactId} - RatzzFatzz - ${project.version} - - target/installer - - target/jpackage-input - at.pcgamingfreaks.mkvaudiosubtitlechanger.Main - ${project.artifactId}-${project.version}.jar - - + + + + + maven-resources-plugin + 3.3.1 + + + copy-jpackage-input + package + + copy-resources + + + ${project.build.directory}/jpackage-input + + + ${project.build.directory} + + ${project.artifactId}-${project.version}.jar + + + + + + + + + org.panteleyev + jpackage-maven-plugin + 1.4.0 + + ${project.artifactId} + RatzzFatzz + ${project.version} + + target/installer + + target/jpackage-input + at.pcgamingfreaks.mkvaudiosubtitlechanger.Main + ${project.artifactId}-${project.version}.jar + + + + diff --git a/src/main/resources/log4j2-dev.yaml b/src/main/resources/log4j2-dev.yaml index bd94532..e2b4377 100644 --- a/src/main/resources/log4j2-dev.yaml +++ b/src/main/resources/log4j2-dev.yaml @@ -7,13 +7,17 @@ Configuration: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: level: debug - File: + RollingFile: name: FileAppender - fileName: default.log + fileName: logs/application.log + filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log PatternLayout: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: level: debug + Policies: + OnStartupTriggeringPolicy: + minSize: 0 Loggers: Root: level: debug diff --git a/src/main/resources/log4j2-installed.yaml b/src/main/resources/log4j2-installed.yaml new file mode 100644 index 0000000..17494b5 --- /dev/null +++ b/src/main/resources/log4j2-installed.yaml @@ -0,0 +1,31 @@ +Configuration: + name: DefaultLogger + Appenders: + File: + name: FileAppender + fileName: ${sys:user.home}/AppData/Roaming/MyApplication/MyApplication.log + PatternLayout: + Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" + ThresholdFilter: + level: info + RollingFile: + name: FileAppender + fileName: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/application.log + filePattern: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log + PatternLayout: + Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" + ThresholdFilter: + level: info + Policies: + OnStartupTriggeringPolicy: + minSize: 0 + Loggers: + Root: + level: info + AppenderRef: + - ref: FileAppender + Logger: + name: "com.zaxxer.hikari.HikariConfig" + level: info + AppenderRef: + - ref: FileAppender \ No newline at end of file diff --git a/src/main/resources/log4j2.yaml b/src/main/resources/log4j2.yaml index 371b601..7a1dc2d 100644 --- a/src/main/resources/log4j2.yaml +++ b/src/main/resources/log4j2.yaml @@ -1,13 +1,17 @@ Configuration: name: DefaultLogger Appenders: - File: + RollingFile: name: FileAppender - fileName: default.log + fileName: logs/application.log + filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log PatternLayout: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: level: info + Policies: + OnStartupTriggeringPolicy: + minSize: 0 Loggers: Root: level: info From 895597b91f96017444219e1ce2f5c6087b025eb0 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Mon, 3 Feb 2025 23:32:37 +0100 Subject: [PATCH 12/32] Fix github action --- .github/workflows/release.yml | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1746666..8aae7b3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,24 +6,24 @@ on: types: [created] jobs: - build: + portable-build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: distribution: temurin - java-version: 11 + java-version: 21 - name: Setup workspace run: mkdir artifacts - name: Build with Maven run: | - mvn clean package --file pom.xml + mvn clean package --file pom.xml -P portable cp target/M*.{zip,tar} artifacts/ - name: Upload artifacts @@ -33,3 +33,27 @@ jobs: with: args: 'artifacts/M*' + windows-installer-build: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up JDK 21 + uses: actions/setup-java@v2 + with: + distribution: temurin + java-version: 21 + + - name: Setup workspace + run: mkdir artifacts + + - name: Build with Maven + run: mvn clean package --file pom.xml -P windows + + - name: Upload artifacts + uses: skx/github-action-publish-binaries@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: 'target/installer/*' \ No newline at end of file From 76321bb9041eab71dfcfd799431b4700bfcd3152 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 00:03:56 +0100 Subject: [PATCH 13/32] Update dependencies --- pom.xml | 71 ++++++++++++------- .../config/AttributeConfigTest.java | 10 +-- .../config/BooleanConfigParameterTest.java | 7 -- .../config/IntegerConfigParameterTest.java | 10 --- .../config/PatternConfigParameterTest.java | 10 +-- .../config/SetConfigParameterTest.java | 2 - 6 files changed, 48 insertions(+), 62 deletions(-) diff --git a/pom.xml b/pom.xml index a43200b..c18c910 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ at.pcgamingfreaks.mkvaudiosubtitlechanger.Main - 1.18.30 + 1.18.36 @@ -273,45 +273,50 @@ + com.intellij forms_rt 7.0.3 + org.projectlombok lombok ${lombok-version} provided + info.picocli picocli - 4.7.5 + 4.7.6 + org.hibernate.validator hibernate-validator - 8.0.1.Final + 8.0.2.Final - - org.glassfish - jakarta.el - 5.0.0-M1 - - - + jakarta.el jakarta.el-api 5.0.1 + + org.glassfish + jakarta.el + 5.0.0-M1 + + + jakarta.validation jakarta.validation-api @@ -319,74 +324,88 @@ + org.apache.logging.log4j log4j-api - 2.22.0 + 2.24.3 + org.apache.logging.log4j log4j-core - 2.22.0 + 2.24.3 + org.apache.logging.log4j - log4j-slf4j-impl - 2.22.0 + log4j-slf4j2-impl + 2.24.3 + + com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.16.0 + 2.18.2 + + com.fasterxml.jackson.core jackson-databind - 2.16.0 + 2.18.2 + commons-cli commons-cli - 1.6.0 + 1.9.0 + org.apache.commons commons-lang3 - 3.13.0 + 3.17.0 + me.tongfei progressbar - 0.10.0 + 0.10.1 + org.junit.jupiter junit-jupiter-api - 5.10.1 + 5.11.4 test + org.junit.jupiter junit-jupiter-engine - 5.10.1 + 5.11.4 test - + org.mockito - mockito-all - 2.0.2-beta + mockito-core + 5.15.2 test + org.junit.jupiter junit-jupiter-params - 5.10.1 + 5.11.4 test + at.pcgamingfreaks @@ -397,7 +416,7 @@ net.harawata appdirs - 1.2.2 + 1.3.0 diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java index c9eacb6..5c31c2f 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/AttributeConfigTest.java @@ -2,13 +2,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; -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.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -19,8 +13,6 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; import static org.junit.jupiter.api.Assertions.*; class AttributeConfigTest { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java index 8b22f21..8bf61c9 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/BooleanConfigParameterTest.java @@ -1,10 +1,6 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -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; @@ -13,11 +9,8 @@ import picocli.CommandLine; import java.util.function.Function; import java.util.stream.Stream; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertIterableEquals; class BooleanConfigParameterTest { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java index 67a71ad..44b22eb 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/IntegerConfigParameterTest.java @@ -1,28 +1,18 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import picocli.CommandLine; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.function.Function; 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.args; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; import static org.junit.jupiter.api.Assertions.*; class IntegerConfigParameterTest { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java index ec010c1..739f4d6 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PatternConfigParameterTest.java @@ -1,10 +1,6 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -15,11 +11,9 @@ import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Stream; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.INCLUDE_PATTERN; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class PatternConfigParameterTest { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java index b12c0a0..62988f7 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java @@ -11,9 +11,7 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Stream; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; From 9f15b542bd21952a22d1d213a386fe12be33e1b1 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 00:31:07 +0100 Subject: [PATCH 14/32] Update github action --- .github/workflows/release.yml | 8 ++++---- pom.xml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8aae7b3..edda05a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up JDK 21 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4.7.0 with: distribution: temurin java-version: 21 @@ -37,10 +37,10 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up JDK 21 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4.7.0 with: distribution: temurin java-version: 21 diff --git a/pom.xml b/pom.xml index c18c910..c661bef 100644 --- a/pom.xml +++ b/pom.xml @@ -306,7 +306,7 @@ jakarta.el jakarta.el-api - 5.0.1 + 6.0.1 From c63fcd4f371c665b5e820d143a6872844c613a1c Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 00:34:40 +0100 Subject: [PATCH 15/32] Update maven plugins --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c661bef..55e19ba 100644 --- a/pom.xml +++ b/pom.xml @@ -149,7 +149,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.2 + 3.4.2 @@ -161,7 +161,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.4.1 + 3.6.0 package @@ -190,7 +190,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.22.2 + 3.5.2 org.apache.maven.plugins From bb4a686dfcfdd24926d4da286ad759844e315397 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 00:39:13 +0100 Subject: [PATCH 16/32] Update github action --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index edda05a..aacf5b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,9 @@ jobs: portable-build: runs-on: ubuntu-latest steps: + - name: Install mkvtoolnix + run: sudo apt-get install -y mkvtoolnix + - name: Checkout uses: actions/checkout@v4 @@ -36,6 +39,9 @@ jobs: windows-installer-build: runs-on: windows-latest steps: + - name: Install mkvtoolnix + run: winget install -y mkvtoolnix + - name: Checkout uses: actions/checkout@v4 From f6310c71ee69bcebb7d721ffb8d5490fe357b3ad Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 00:52:09 +0100 Subject: [PATCH 17/32] Update github action --- .github/workflows/release.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aacf5b1..41889b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Build and release on: release: - types: [created] + types: [ created ] jobs: portable-build: @@ -15,6 +15,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneLinux: "Europe/Berlin" + - name: Set up JDK 21 uses: actions/setup-java@v4.7.0 with: @@ -35,16 +40,23 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: args: 'artifacts/M*' - + windows-installer-build: runs-on: windows-latest steps: - name: Install mkvtoolnix - run: winget install -y mkvtoolnix + uses: crazy-max/ghaction-chocolatey@v3 + with: + args: choco install mkvtoolnix -y - name: Checkout uses: actions/checkout@v4 + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneWindows: "Berlin Standard Time" + - name: Set up JDK 21 uses: actions/setup-java@v4.7.0 with: From ecc5c56c8c5eff2d6347170a2199c414f974ca65 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 00:54:09 +0100 Subject: [PATCH 18/32] Update github action --- .github/workflows/release.yml | 2 +- .../mkvaudiosubtitlechanger/util/DateUtilsTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41889b0..169d149 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,7 +47,7 @@ jobs: - name: Install mkvtoolnix uses: crazy-max/ghaction-chocolatey@v3 with: - args: choco install mkvtoolnix -y + args: install mkvtoolnix -y - name: Checkout uses: actions/checkout@v4 diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtilsTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtilsTest.java index 3ff73c3..917a8ea 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtilsTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtilsTest.java @@ -1,11 +1,13 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.Date; import static org.junit.jupiter.api.Assertions.*; +@Disabled class DateUtilsTest { @Test From 36bd93bb501bcce57c6e930e9b2f0211d9e73ca4 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 12:33:19 +0100 Subject: [PATCH 19/32] Fix windows artifact upload --- .github/workflows/release.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 169d149..82c6896 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,8 +70,7 @@ jobs: run: mvn clean package --file pom.xml -P windows - name: Upload artifacts - uses: skx/github-action-publish-binaries@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: AButler/upload-release-assets@v3.0 with: - args: 'target/installer/*' \ No newline at end of file + files: 'target/installer/*' + repo-token: ${{ secrets.GITHUB_TOKEN }} From 44d2601d3ec014b454b1b9fbb3a47471198e1de6 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 13:49:19 +0100 Subject: [PATCH 20/32] Update config parameters and descriptions --- .../mkvaudiosubtitlechanger/Main.java | 7 +++--- .../config/Config.java | 23 ++++++++++--------- .../config/SetConfigParameterTest.java | 18 +++++++-------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index 3ca455f..89e5b6b 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -18,11 +18,12 @@ import java.util.Set; @Slf4j @CommandLine.Command( - name = "mkvasc", + name = "mkvaudiosubtitlechanger", usageHelpWidth = 120, customSynopsis = { - "mkvasc -a ... -l [-s]", - "Example: mkvasc -a eng:eng eng:ger -l /mnt/media/ -s" + "mkvaudiosubtitlechanger -a ... -l [-s]", + "Example: mkvaudiosubtitlechanger -a eng:eng eng:ger -l /mnt/media/ -s", + "" }, mixinStandardHelpOptions = true, versionProvider = ProjectUtil.class diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index e7364cf..02736c7 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -30,7 +30,8 @@ public class Config { @CommandLine.Spec CommandLine.Model.CommandSpec spec; - @CommandLine.Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class) + @CommandLine.Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class, + description = "List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger)") private List attributeConfig; @Setter(AccessLevel.NONE) @@ -51,7 +52,7 @@ public class Config { @CommandLine.Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match") private boolean forceCoherent; - @CommandLine.Option(names = {"-n"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)") + @CommandLine.Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)") private boolean onlyNewFiles; @CommandLine.Option(names = {"-d", "--filter-date"}, defaultValue = CommandLine.Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")") private Date filterDate; @@ -61,15 +62,15 @@ public class Config { description = "Directories to be excluded, combines with config file") private Set excludedDirectories = new HashSet<>(); - @CommandLine.Option(names = {"-fk", "--force-keywords"}, arity = "1..*", - description = "Additional keywords to identify forced tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") - private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs")); - @CommandLine.Option(names = {"-ck", "--commentary-keywords"}, arity = "1..*", - description = "Additional keywords to identify commentary tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") - private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); - @CommandLine.Option(names = {"-ps", "--preferred-subtiltes"}, arity = "1..*", - description = "Additional keywords to prefer specific subtitle tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}") - private Set preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); + @CommandLine.Option(names = {"--forced-keywords"}, arity = "1..*", defaultValue = "forced, signs, songs", split = ", ", + description = "Keywords to identify forced tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})") + private Set forcedKeywords; + @CommandLine.Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "commentary, director", split = ", ", + description = "Keywords to identify commentary tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})") + private Set commentaryKeywords; + @CommandLine.Option(names = {"--preferred-subtitles"}, arity = "1..*", defaultValue = "unstyled", split = ", ", + description = "Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})") + private Set preferredSubtitles; @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library") public void setLibraryPath(File libraryPath) { diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java index 62988f7..61b8a29 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/SetConfigParameterTest.java @@ -19,14 +19,14 @@ class SetConfigParameterTest { private static Stream provideTestCases() { return Stream.of( - Arguments.of(args("-ck", "test"), 1, (Function>) Config::getCommentaryKeywords), - Arguments.of(args("-ck", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getCommentaryKeywords), + Arguments.of(args("--commentary-keywords", "test"), 1, (Function>) Config::getCommentaryKeywords), + Arguments.of(args("--commentary-keywords", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getCommentaryKeywords), Arguments.of(args(), 2, (Function>) Config::getCommentaryKeywords), - Arguments.of(args("-fk", "test"), 1, (Function>) Config::getForcedKeywords), - Arguments.of(args("-fk", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getForcedKeywords), + Arguments.of(args("--forced-keywords", "test"), 1, (Function>) Config::getForcedKeywords), + Arguments.of(args("--forced-keywords", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getForcedKeywords), Arguments.of(args(), 3, (Function>) Config::getForcedKeywords), - Arguments.of(args("-ps", "test"), 1, (Function>) Config::getPreferredSubtitles), - Arguments.of(args("-ps", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getPreferredSubtitles), + Arguments.of(args("--preferred-subtitles", "test"), 1, (Function>) Config::getPreferredSubtitles), + Arguments.of(args("--preferred-subtitles", "test", "test1", "test2", "test3", "test4"), 5, (Function>) Config::getPreferredSubtitles), Arguments.of(args(), 1, (Function>) Config::getPreferredSubtitles) ); } @@ -42,9 +42,9 @@ class SetConfigParameterTest { @Test void validate() { Main sut = new Main(); - assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-ck"))); - assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-fk"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("--commentary-keywords"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("--forced-keywords"))); assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-e"))); - assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-ps"))); + assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("--preferred-subtitles"))); } } \ No newline at end of file From 0813744148a03b9883757b11a5820d5cee66b2c7 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 13:56:29 +0100 Subject: [PATCH 21/32] Update README.md --- README.md | 68 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index cc6925a..fb36f55 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,61 @@ ## Introduction -This program helps to change audio and subtitle tracks of mkv files without rewriting the file. Only track properties will be updated. +A streamlined solution for managing MKV files, this program leverages MKVToolNix to modify audio and subtitle track properties without the need for time-consuming file reencoding. Users can easily set their track preferences, and the application intelligently applies the best matching configuration. The tool focuses on metadata modification rather than full file rewriting, ensuring quick operations while maintaining the original file integrity. This makes it an ideal choice for managing multilingual media collections or batch processing multiple MKV files. ![](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/blob/master/example.gif) ## Requirements - - Java 11 or higher + - Java 21 or newer - mkvtoolnix installation ## Execution -**Minimal usage:** -`java -jar mkvaudiosubtitlechanger.jar --library "X:/Files" --attribute-config eng:ger eng:OFF` +### Minimal usage +Portable: `java -jar mkvaudiosubtitlechanger-.jar --library "X:/Files" --attribute-config eng:ger eng:OFF` -**Safe usage (best for testing before applying to whole library):** -`java -jar mkvaudiosubtitlechanger.jar --library "X:/Files" --attribute-config eng:ger eng:OFF --safe-mode` +Windows (installed): `mkvaudiosubtitlechanger.jar --library "X:/Files" --attribute-config eng:ger eng:OFF` -Attribute-config must be entered in pairs: `audio:subtitle`; Example: `jpn:eng`. More about this topic -[here](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Attribute-Config). +### Safe usage (best for testing before applying to whole library) +Portable: `java -jar mkvaudiosubtitlechanger-.jar --library "X:/Files" --attribute-config eng:ger eng:OFF --safe-mode` + +Windows (installed): `mkvaudiosubtitlechanger.jar --library "X:/Files" --attribute-config eng:ger eng:OFF --safe-mode` + +**Attribute-config must be entered in pairs: `audio:subtitle`; Example: `jpn:eng`. More about this topic +[here](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Attribute-Config).** ## Available parameters ``` - -l,--library-path Path to library - -a,--attribute-config Attribute config to decide which tracks to choose when - -p,--config-path Path to config file - -m,--mkvtoolnix Path to mkv tool nix installation - -s,--safe-mode Test run (no files will be changes) - -c,--coherent Try to match all files in dir of depth with the same config - -cf,--force-coherent Force coherent and don't update anything if config fits not whole config (default: false) - -n,--only-new-files Sets filter-date to last successful execution (Overwrites input of filter-date) - -d,--filter-date Only consider files created newer than entered date (format: "dd.MM.yyyy-HH:mm:ss") - -t,--threads Thread count (default: 2) - -i,--include-pattern Include files matching pattern (default: ".*") - -e,--excluded-directories Directories to be excluded, combines with config file - -fk,--forced-keywords Additional keywords to identify forced tracks - -ck,--commentary-keywords Additional keywords to identify commentary tracks - -ps,--preferred-subtitles Additional keywords to prefer specific subtitle tracks - -v,--version Display version - -h,--help "For help this is" - Yoda + -a, --attribute-config=... + List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger) + -c, --coherent= try to match all files in dir of depth with the same attribute config + -cf, --force-coherent changes are only applied if it's a coherent match + --commentary-keywords=[, ...]... + Keywords to identify commentary tracks (Defaults will be overwritten; Default: commentary, director) + -d, --filter-date= + only consider files created newer than entered date (format: "dd.MM.yyyy-HH:mm:ss") + -e, --excluded-directory=... + Directories to be excluded, combines with config file + --forced-keywords=[, ...]... + Keywords to identify forced tracks (Defaults will be overwritten; Default: forced, signs, songs) + -h, --help Show this help message and exit. + -i, --include-pattern= + include files matching pattern (default: ".*") + -l, --library= + path to library + -m, --mkvtoolnix= + path to mkvtoolnix installation + -n, --only-new-file sets filter-date to last successful execution (overwrites input of filter-date) + --preferred-subtitles=[, ...]... + Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: unstyled) + -s, --safemode test run (no files will be changes) + -t, --threads= thread count (default: 2) + -V, --version Print version information and exit. ``` -If you need more information about how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters). +If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters). All parameters can also be defined in a [config file](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/How-to-config-file). ## Build requirements -- JDK 11 or higher +- JDK 21 or newer - Maven 3 - Git @@ -51,5 +63,5 @@ All parameters can also be defined in a [config file](https://github.com/RatzzFa ```shell git clone https://github.com/RatzzFatzz/MKVAudioSubtitleChanger.git cd MKVAudioSubtitleChanger -mvn package +mvn clean package -Pportable ``` From ffac36ac27dcee0bb8a3deafca2f96a215bce753 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 14:45:57 +0100 Subject: [PATCH 22/32] Update example gif --- README.md | 5 +++-- example.gif | Bin 32849 -> 32026 bytes .../config/ConfigTest.java | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fb36f55..438b6d0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ## Introduction A streamlined solution for managing MKV files, this program leverages MKVToolNix to modify audio and subtitle track properties without the need for time-consuming file reencoding. Users can easily set their track preferences, and the application intelligently applies the best matching configuration. The tool focuses on metadata modification rather than full file rewriting, ensuring quick operations while maintaining the original file integrity. This makes it an ideal choice for managing multilingual media collections or batch processing multiple MKV files. + ![](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/blob/master/example.gif) ## Requirements @@ -24,7 +25,7 @@ Windows (installed): `mkvaudiosubtitlechanger.jar --library "X:/Files" --attribu ## Available parameters ``` - -a, --attribute-config=... + -a, --attribute-config=... List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger) -c, --coherent= try to match all files in dir of depth with the same attribute config -cf, --force-coherent changes are only applied if it's a coherent match @@ -50,7 +51,7 @@ Windows (installed): `mkvaudiosubtitlechanger.jar --library "X:/Files" --attribu -t, --threads= thread count (default: 2) -V, --version Print version information and exit. ``` -If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters). +If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters-v4). All parameters can also be defined in a [config file](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/How-to-config-file). diff --git a/example.gif b/example.gif index 56f56ff15941d9a10b609cf020d1d36811ac3549..34b95737bdfbedffce381167d350ec3165e7e972 100644 GIT binary patch literal 32026 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

78`hQcj(^u=))28)Y$Z+ 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

m5I@~i#}=w z0J9GrVbZdZppTMc3iXv^_9glp1%M9#S6|EGAzbE}h}vG;IPKHf`Ah2IIB@EVAxZ%B zD6BM8*d+)EE=bD05c5dTb8v5l)|f(@{P zB>lkadvV1u!mBU`F|^3Gt{Ag>9Be~LB{pUoD1LUQi#Dnm(jRpV;^UfvO325QZYy$w zgk9_3Ct%7IXC;#6jgv6tip$F&%bcW*QLPzrWSbm5qTLY?u3PST>9n1}_1Voe$IE%g z;!_{xZBc*&kiQTl0{$WSXwG{6f$@tPo&Z}@$r`Cfc>|y~WLE(1f~c2hH5Z-=G7Sk4 zU9`PemJGs+3y9)#frtvRA$Ztsi3|nI)|kPm ztrcFUo`x9(S>Gx^tLEydXhgv!scCYB<9I8Ll*u0Di2$uloD(@-KCJm(I^y|Kq!V{NcZp_5FDHm*4&4 Wi+;V!X2vs diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java index 10f0235..a81cbc8 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigTest.java @@ -18,9 +18,9 @@ class ConfigTest { "-c", "2", "-t", "4", "-i", ".*[abc].*", - "-fk", "testForced", - "-ck", "testCommentary", - "-ps", "testPreferred" + "--forced-keywords", "testForced", + "--commentary-keywords", "testCommentary", + "--preferred-subtitles", "testPreferred" }; CommandLine.populateCommand(Config.getInstance(), sut); From 21f244ff3fd00f5fac19df6effe8924c69712d46 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 17:48:45 +0100 Subject: [PATCH 23/32] Update logging config --- README.md | 2 +- src/main/resources/log4j2-dev.yaml | 12 +++++++++++- src/main/resources/log4j2-installed.yaml | 19 +++++++++++-------- src/main/resources/log4j2.yaml | 12 +++++++++++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 438b6d0..e56618f 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Windows (installed): `mkvaudiosubtitlechanger.jar --library "X:/Files" --attribu ``` If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters-v4). -All parameters can also be defined in a [config file](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/How-to-config-file). +All parameters can also be defined in a [config file](https://picocli.info/#_argument_files_for_long_command_lines). ## Build requirements - JDK 21 or newer diff --git a/src/main/resources/log4j2-dev.yaml b/src/main/resources/log4j2-dev.yaml index e2b4377..f3b739f 100644 --- a/src/main/resources/log4j2-dev.yaml +++ b/src/main/resources/log4j2-dev.yaml @@ -10,7 +10,7 @@ Configuration: RollingFile: name: FileAppender fileName: logs/application.log - filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log + filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz PatternLayout: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: @@ -18,6 +18,16 @@ Configuration: Policies: OnStartupTriggeringPolicy: minSize: 0 + DefaultRolloverStrategy: + max: 30 + Delete: + basePath: logs/archive + maxDepth: 1 + IfLastModified: + age: 30d + IfAccumulatedFileSize: + exceeds: 1GB + Loggers: Root: level: debug diff --git a/src/main/resources/log4j2-installed.yaml b/src/main/resources/log4j2-installed.yaml index 17494b5..804ec99 100644 --- a/src/main/resources/log4j2-installed.yaml +++ b/src/main/resources/log4j2-installed.yaml @@ -1,17 +1,10 @@ Configuration: name: DefaultLogger Appenders: - File: - name: FileAppender - fileName: ${sys:user.home}/AppData/Roaming/MyApplication/MyApplication.log - PatternLayout: - Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" - ThresholdFilter: - level: info RollingFile: name: FileAppender fileName: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/application.log - filePattern: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log + filePattern: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz PatternLayout: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: @@ -19,6 +12,16 @@ Configuration: Policies: OnStartupTriggeringPolicy: minSize: 0 + DefaultRolloverStrategy: + max: 30 + Delete: + basePath: logs/archive + maxDepth: 1 + IfLastModified: + age: 30d + IfAccumulatedFileSize: + exceeds: 1GB + Loggers: Root: level: info diff --git a/src/main/resources/log4j2.yaml b/src/main/resources/log4j2.yaml index 7a1dc2d..bfa5dca 100644 --- a/src/main/resources/log4j2.yaml +++ b/src/main/resources/log4j2.yaml @@ -4,7 +4,7 @@ Configuration: RollingFile: name: FileAppender fileName: logs/application.log - filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log + filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz PatternLayout: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: @@ -12,6 +12,16 @@ Configuration: Policies: OnStartupTriggeringPolicy: minSize: 0 + DefaultRolloverStrategy: + max: 30 + Delete: + basePath: logs/archive + maxDepth: 1 + IfLastModified: + age: 30d + IfAccumulatedFileSize: + exceeds: 1GB + Loggers: Root: level: info From d98c4cd49ea20660447b16e8533546648af53e94 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Tue, 4 Feb 2025 17:57:34 +0100 Subject: [PATCH 24/32] Handle empty input --- .../java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index 89e5b6b..48aa81a 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -61,6 +61,9 @@ public class Main implements Runnable { } public static void main(String[] args) { + if (args.length == 0) { + args = new String[] { "--help" }; + } new CommandLine(Main.class).execute(args); } } From 553c672e4d0874bda9c23d98c607070a8c9f20b0 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 5 Feb 2025 15:49:46 +0100 Subject: [PATCH 25/32] Implement debian package build --- pom.xml | 174 +++++++++++------- src/deb/bin/mkvaudiosubtitlechanger | 1 + src/deb/control/control | 8 + ...g4j2-installed.yaml => log4j2-debian.yaml} | 0 src/main/resources/log4j2-windows.yaml | 34 ++++ src/{main => wix}/resources/main.wxs | 0 6 files changed, 148 insertions(+), 69 deletions(-) create mode 100644 src/deb/bin/mkvaudiosubtitlechanger create mode 100644 src/deb/control/control rename src/main/resources/{log4j2-installed.yaml => log4j2-debian.yaml} (100%) create mode 100644 src/main/resources/log4j2-windows.yaml rename src/{main => wix}/resources/main.wxs (100%) diff --git a/pom.xml b/pom.xml index 55e19ba..b8a76fa 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,11 @@ at.pcgamingfreaks.mkvaudiosubtitlechanger.Main + RatzzFatzz + github.contact@ratzloeffel.de + Command-line utility for batch-managing default audio and subtitle tracks in MKV files. + + 21 1.18.36 @@ -66,24 +71,54 @@ maven-resources-plugin 3.3.1 + + + copy-jpackage-input + package + + copy-resources + + + ${project.build.directory}/jpackage-input + + + ${project.build.directory} + + ${project.artifactId}-${project.version}.jar + + + + + + org.panteleyev jpackage-maven-plugin 1.6.5 + + ${project.artifactId} + RatzzFatzz + ${project.version} + + target/installer + + target/jpackage-input + at.pcgamingfreaks.mkvaudiosubtitlechanger.Main + ${project.artifactId}-${project.version}.jar + + ${project.basedir}/src/wix/resources/ + EXE + true + false + false + + -Dlog4j.configurationFile=log4j2-windows.yaml + + windows - - ${project.basedir}/src/main/resources/ - EXE - true - false - false - - -Dlog4j.configurationFile=log4j2-installed.yaml - - package jpackage @@ -97,25 +132,71 @@ linux + + + src/main/resources + + log4j2-debian.yaml + + + - org.panteleyev - jpackage-maven-plugin - 1.4.0 + maven-resources-plugin + 3.3.1 - linux-deb - - DEB - /usr/local/bin - false - mkvasc - your@email.com - + filter-linux-package-info package - jpackage + copy-resources + + ${project.build.directory}/debian-package-info + + + ${project.basedir}/src/deb + true + + + + + + + + jdeb + org.vafer + 1.13 + + + package + + jdeb + + + + + + ${project.build.directory}/${project.build.finalName}.jar + file + + perm + /usr/lib/${project.artifactId} + + + + + ${project.build.directory}/debian-package-info/bin/mkvaudiosubtitlechanger + file + + perm + /usr/bin + 755 + + + + ${project.build.directory}/debian-package-info/control + @@ -197,8 +278,8 @@ maven-compiler-plugin 3.13.0 - 21 - 21 + ${java-version} + ${java-version} -Aproject=${project.groupId}/${project.artifactId} @@ -218,51 +299,6 @@ - - - - - maven-resources-plugin - 3.3.1 - - - copy-jpackage-input - package - - copy-resources - - - ${project.build.directory}/jpackage-input - - - ${project.build.directory} - - ${project.artifactId}-${project.version}.jar - - - - - - - - - org.panteleyev - jpackage-maven-plugin - 1.4.0 - - ${project.artifactId} - RatzzFatzz - ${project.version} - - target/installer - - target/jpackage-input - at.pcgamingfreaks.mkvaudiosubtitlechanger.Main - ${project.artifactId}-${project.version}.jar - - - - diff --git a/src/deb/bin/mkvaudiosubtitlechanger b/src/deb/bin/mkvaudiosubtitlechanger new file mode 100644 index 0000000..19ea12a --- /dev/null +++ b/src/deb/bin/mkvaudiosubtitlechanger @@ -0,0 +1 @@ +java -Dlog4j.configurationFile=log4j2-debian.yaml -jar /usr/lib/${project.artifactId}/${project.artifactId}-${project.version}.jar "$@" \ No newline at end of file diff --git a/src/deb/control/control b/src/deb/control/control new file mode 100644 index 0000000..1bcff12 --- /dev/null +++ b/src/deb/control/control @@ -0,0 +1,8 @@ +Package: ${project.artifactId} +Version: ${project.version} +Section: misc +Priority: optional +Architecture: all +Depends: java-runtime (>=21), mkvtoolnix +Maintainer: ${project.maintainer} <${project.maintainer.mail}> +Description: ${project.description} \ No newline at end of file diff --git a/src/main/resources/log4j2-installed.yaml b/src/main/resources/log4j2-debian.yaml similarity index 100% rename from src/main/resources/log4j2-installed.yaml rename to src/main/resources/log4j2-debian.yaml diff --git a/src/main/resources/log4j2-windows.yaml b/src/main/resources/log4j2-windows.yaml new file mode 100644 index 0000000..804ec99 --- /dev/null +++ b/src/main/resources/log4j2-windows.yaml @@ -0,0 +1,34 @@ +Configuration: + name: DefaultLogger + Appenders: + RollingFile: + name: FileAppender + fileName: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/application.log + filePattern: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz + PatternLayout: + Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" + ThresholdFilter: + level: info + Policies: + OnStartupTriggeringPolicy: + minSize: 0 + DefaultRolloverStrategy: + max: 30 + Delete: + basePath: logs/archive + maxDepth: 1 + IfLastModified: + age: 30d + IfAccumulatedFileSize: + exceeds: 1GB + + Loggers: + Root: + level: info + AppenderRef: + - ref: FileAppender + Logger: + name: "com.zaxxer.hikari.HikariConfig" + level: info + AppenderRef: + - ref: FileAppender \ No newline at end of file diff --git a/src/main/resources/main.wxs b/src/wix/resources/main.wxs similarity index 100% rename from src/main/resources/main.wxs rename to src/wix/resources/main.wxs From 7f8c14e3a99178369248a69d8e1430075f21fa74 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 5 Feb 2025 16:00:01 +0100 Subject: [PATCH 26/32] Use maven properties for wix installer vars --- pom.xml | 18 +++++++++++++++++- src/wix/resources/main.wxs | 10 +++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index b8a76fa..e7bfeef 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,22 @@ + + filter-windows-installer-info + package + + copy-resources + + + ${project.build.directory}/wix-resources + + + ${project.basedir}/src/wix/resources + true + + + + @@ -107,7 +123,7 @@ at.pcgamingfreaks.mkvaudiosubtitlechanger.Main ${project.artifactId}-${project.version}.jar - ${project.basedir}/src/wix/resources/ + ${project.build.directory}/wix-resources/ EXE true false diff --git a/src/wix/resources/main.wxs b/src/wix/resources/main.wxs index 389cbb6..bcd994e 100644 --- a/src/wix/resources/main.wxs +++ b/src/wix/resources/main.wxs @@ -24,12 +24,12 @@ - - - + + + - - + + Date: Wed, 5 Feb 2025 22:59:38 +0100 Subject: [PATCH 27/32] Fix logging for debian build --- pom.xml | 2 +- src/deb/control/control | 2 +- src/main/resources/log4j2-debian.yaml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index e7bfeef..8b278af 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ github.contact@ratzloeffel.de Command-line utility for batch-managing default audio and subtitle tracks in MKV files. - 21 + 17 1.18.36 diff --git a/src/deb/control/control b/src/deb/control/control index 1bcff12..2c892f9 100644 --- a/src/deb/control/control +++ b/src/deb/control/control @@ -3,6 +3,6 @@ Version: ${project.version} Section: misc Priority: optional Architecture: all -Depends: java-runtime (>=21), mkvtoolnix +Depends: java-runtime (>=${java-version}), mkvtoolnix Maintainer: ${project.maintainer} <${project.maintainer.mail}> Description: ${project.description} \ No newline at end of file diff --git a/src/main/resources/log4j2-debian.yaml b/src/main/resources/log4j2-debian.yaml index 804ec99..a57c2be 100644 --- a/src/main/resources/log4j2-debian.yaml +++ b/src/main/resources/log4j2-debian.yaml @@ -3,8 +3,8 @@ Configuration: Appenders: RollingFile: name: FileAppender - fileName: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/application.log - filePattern: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz + fileName: /var/log/MKVAudioSubtitleChanger/application.log + filePattern: /var/log/MKVAudioSubtitleChanger/archive/application-%d{yyyy-MM-dd}-%i.log.gz PatternLayout: Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" ThresholdFilter: @@ -15,7 +15,7 @@ Configuration: DefaultRolloverStrategy: max: 30 Delete: - basePath: logs/archive + basePath: archive maxDepth: 1 IfLastModified: age: 30d From c33777b0384a8c360ae4f6d0778e7808f5b9665c Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 5 Feb 2025 23:02:40 +0100 Subject: [PATCH 28/32] Add debian build to github action --- .github/workflows/release.yml | 43 +++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 82c6896..763741b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,11 +20,11 @@ jobs: with: timezoneLinux: "Europe/Berlin" - - name: Set up JDK 21 + - name: Set up JDK 17 uses: actions/setup-java@v4.7.0 with: distribution: temurin - java-version: 21 + java-version: 17 - name: Setup workspace run: mkdir artifacts @@ -41,6 +41,41 @@ jobs: with: args: 'artifacts/M*' + debian-build: + runs-on: ubuntu-latest + steps: + - name: Install mkvtoolnix + run: sudo apt-get install -y mkvtoolnix + + - name: Checkout + uses: actions/checkout@v4 + + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneLinux: "Europe/Berlin" + + - name: Set up JDK 17 + uses: actions/setup-java@v4.7.0 + with: + distribution: temurin + java-version: 17 + + - name: Setup workspace + run: mkdir artifacts + + - name: Build with Maven + run: | + mvn clean package --file pom.xml -P linux + cp target/M*.deb artifacts/ + + - name: Upload artifacts + uses: skx/github-action-publish-binaries@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: 'artifacts/M*' + windows-installer-build: runs-on: windows-latest steps: @@ -57,11 +92,11 @@ jobs: with: timezoneWindows: "Berlin Standard Time" - - name: Set up JDK 21 + - name: Set up JDK 17 uses: actions/setup-java@v4.7.0 with: distribution: temurin - java-version: 21 + java-version: 17 - name: Setup workspace run: mkdir artifacts From 9c8315aec77763424c3f19c22ab32e3b3c415bf1 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 5 Feb 2025 23:13:54 +0100 Subject: [PATCH 29/32] Remove config-template --- config-template.yaml | 34 ---------------------------------- maven/assembly.xml | 4 ---- 2 files changed, 38 deletions(-) delete mode 100644 config-template.yaml diff --git a/config-template.yaml b/config-template.yaml deleted file mode 100644 index df5b473..0000000 --- a/config-template.yaml +++ /dev/null @@ -1,34 +0,0 @@ -mkvtoolnix: C:\Program Files\MKVToolNix -library: X:/Files - -attribute-config: - 1: - audio: ger - subtitle: OFF - 2: - audio: eng - subtitle: ger - -# Recommendations for data stored on HDDs, increase when using SSDs -#threads: 2 - -#forced-keywords: ["forced", "signs"] -#commentary-keywords: ["commentary", "director"] -#preferred-subtitles: ["unstyled"] - -#exclude-directories: -# - "D:/Path/To/File.mkv" -# - "D:/Path/To/Directory" - -# If pattern is negated, can be used to exclude files -#include-pattern: "regex" - -# Only files newer than -#filter-date: 20.03.2021-10:11:12 - -safe-mode: -#coherent: -#force-coherent: -#only-new-files: - - diff --git a/maven/assembly.xml b/maven/assembly.xml index 5d51bfd..4e1a1ba 100644 --- a/maven/assembly.xml +++ b/maven/assembly.xml @@ -14,10 +14,6 @@ ${project.artifactId}.jar / - - ${project.basedir}/config-template.yaml - / - From 471255a09b59a2c0c8187f1a4ebdf38cfeee585f Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Wed, 5 Feb 2025 23:32:01 +0100 Subject: [PATCH 30/32] Fix windows installer build --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 763741b..ce84512 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,11 +92,11 @@ jobs: with: timezoneWindows: "Berlin Standard Time" - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4.7.0 with: distribution: temurin - java-version: 17 + java-version: 21 - name: Setup workspace run: mkdir artifacts From dc770c9325c050572afa38b215883c823804e389 Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Thu, 6 Feb 2025 00:00:28 +0100 Subject: [PATCH 31/32] Fix file count if no info was found --- .../impl/kernel/AttributeUpdaterKernel.java | 9 +++++++-- .../mkvaudiosubtitlechanger/model/FileInfoDto.java | 7 ++++--- .../mkvaudiosubtitlechanger/model/FileStatus.java | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java index 048e61c..54bc9f5 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/kernel/AttributeUpdaterKernel.java @@ -19,7 +19,6 @@ import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; import net.harawata.appdirs.AppDirsFactory; -import picocli.CommandLine; import java.io.File; import java.io.IOException; @@ -100,6 +99,12 @@ public abstract class AttributeUpdaterKernel { FileInfoDto fileInfo = new FileInfoDto(file); List attributes = processor.loadAttributes(file); + if (attributes == null || attributes.isEmpty()) { + statistic.total(); + statistic.failure(); + return; + } + List nonForcedTracks = processor.retrieveNonForcedTracks(attributes); List nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes); @@ -122,7 +127,7 @@ public abstract class AttributeUpdaterKernel { statistic.shouldChange(); commitChange(fileInfoDto); break; - case UNABLE_TO_APPLY: + case NO_SUITABLE_CONFIG: statistic.noSuitableConfigFound(); break; case ALREADY_SUITED: diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileInfoDto.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileInfoDto.java index 39264d9..439cc91 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileInfoDto.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileInfoDto.java @@ -40,8 +40,9 @@ public class FileInfoDto { } private boolean isSubtitleOFF() { - return desiredDefaultSubtitleLane == null && "OFF".equals(matchedConfig.getSubtitleLanguage()) && - (existingDefaultSubtitleLanes != null && !existingDefaultSubtitleLanes.isEmpty()); + return desiredDefaultSubtitleLane == null + && (matchedConfig != null && "OFF".equals(matchedConfig.getSubtitleLanguage())) + && (existingDefaultSubtitleLanes != null && !existingDefaultSubtitleLanes.isEmpty()); } public boolean areForcedTracksDifferent() { @@ -50,7 +51,7 @@ public class FileInfoDto { public FileStatus getStatus() { if (isChangeNecessary()) return FileStatus.CHANGE_NECESSARY; - if (isUnableToApplyConfig()) return FileStatus.UNABLE_TO_APPLY; + if (isUnableToApplyConfig()) return FileStatus.NO_SUITABLE_CONFIG; if (isAlreadySuitable()) return FileStatus.ALREADY_SUITED; return FileStatus.UNKNOWN; } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileStatus.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileStatus.java index 942faf9..891014a 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileStatus.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/FileStatus.java @@ -2,7 +2,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.model; public enum FileStatus { CHANGE_NECESSARY, - UNABLE_TO_APPLY, + NO_SUITABLE_CONFIG, ALREADY_SUITED, UNKNOWN; } From e81b06f6fa34aa85cbad4ed510623ce15db2728c Mon Sep 17 00:00:00 2001 From: RatzzFatzz Date: Thu, 6 Feb 2025 00:18:49 +0100 Subject: [PATCH 32/32] Improve logging --- .../mkvaudiosubtitlechanger/impl/MkvFileProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java index 05dc487..da0109a 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java @@ -184,7 +184,7 @@ public class MkvFileProcessor implements FileProcessor { } } - log.info(sb.toString()); + log.debug(sb.toString()); InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream(); String output = IOUtils.toString(new InputStreamReader(inputstream)); log.debug(output);