diff --git a/pom.xml b/pom.xml
index 092264f..4699ade 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
src/main/resources
- log4j2.yaml
+ log4j2.yml
@@ -64,7 +64,7 @@
src/main/resources
- log4j2-windows.yaml
+ log4j2-windows.yml
@@ -138,7 +138,7 @@
false
false
- -Dlog4j2.configurationFile=log4j2-windows.yaml
+ -Dlog4j2.configurationFile=log4j2-windows.yml
@@ -161,7 +161,7 @@
src/main/resources
- log4j2-debian.yaml
+ log4j2-debian.yml
@@ -396,18 +396,18 @@
2.25.3
-
+
- tools.jackson.dataformat
+ com.fasterxml.jackson.dataformat
jackson-dataformat-yaml
- 3.0.3
+ 2.20.0
-
+
- tools.jackson.core
+ com.fasterxml.jackson.core
jackson-databind
- 3.0.3
+ 2.20.0
@@ -421,6 +421,13 @@
commons-lang3
3.20.0
+
+
+ commons-io
+ commons-io
+ 2.21.0
+ compile
+
me.tongfei
diff --git a/src/deb/bin/mkvaudiosubtitlechanger b/src/deb/bin/mkvaudiosubtitlechanger
index dcc8207..c0bbcab 100644
--- a/src/deb/bin/mkvaudiosubtitlechanger
+++ b/src/deb/bin/mkvaudiosubtitlechanger
@@ -1 +1 @@
-java -Dlog4j2.configurationFile=log4j2-debian.yaml -jar /usr/lib/${project.artifactId}/${project.artifactId}-${project.version}.jar "$@"
\ No newline at end of file
+java -Dlog4j2.configurationFile=log4j2-debian.yml -jar /usr/lib/${project.artifactId}/${project.artifactId}-${project.version}.jar "$@"
\ No newline at end of file
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/CommandRunner.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/CommandRunner.java
index f818dad..fd65ff2 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/CommandRunner.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/CommandRunner.java
@@ -6,6 +6,10 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import picocli.CommandLine;
@@ -39,13 +43,31 @@ public class CommandRunner implements Runnable {
System.out.println("Safemode active. No files will be changed!");
}
- FileFilter fileFilter = new FileFilter(config.getExcluded(), config.getIncludePattern(), config.getFilterDate());
+ LastExecutionHandler lastExecutionHandler = config.isOnlyNewFiles() ? new LastExecutionHandler(getApplicationHome()) : null;
+ FileFilter fileFilter = new FileFilter(config.getExcluded(), config.getIncludePattern(), config.getFilterDate(), lastExecutionHandler);
FileProcessor fileProcessor = new CachedFileProcessor(new MkvFileProcessor(config.getMkvToolNix(), fileFilter));
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(config.getPreferredSubtitles().toArray(new String[0]), config.getForcedKeywords(), config.getCommentaryKeywords(), config.getHearingImpaired());
AttributeUpdater kernel = config.getCoherent() != null
- ? new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor)
- : new SingleFileAttributeUpdater(config, fileProcessor, attributeChangeProcessor);
+ ? new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler)
+ : new SingleFileAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler);
kernel.execute();
}
+
+ public String getApplicationHome() {
+ LoggerContext context = (LoggerContext) LogManager.getContext(false);
+ Configuration config = context.getConfiguration();
+
+ for (org.apache.logging.log4j.core.Appender appender : config.getAppenders().values()) {
+ if (appender instanceof RollingFileAppender rollingFileAppender) {
+ String fileName = rollingFileAppender.getFileName();
+ return new java.io.File(fileName).getParentFile().getParent();
+ }
+ }
+
+ log.error("Could not load log4j2 path info");
+ System.out.println("Could not load log4j2 path info");
+ System.exit(1);
+ return null;
+ }
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilter.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilter.java
index 8f78dc6..938283b 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilter.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilter.java
@@ -1,7 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
-import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -9,9 +8,8 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+import java.time.Instant;
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -20,7 +18,8 @@ import java.util.regex.Pattern;
public class FileFilter {
private final Set excluded;
private final Pattern includePattern;
- private final Date filterDate;
+ private final Instant filterDate;
+ private final LastExecutionHandler lastExecutionHandler;
private final String EXTENSION_GROUP = "extension";
private final Pattern extensionPattern = Pattern.compile(String.format(".*(?<%s>\\..*)", EXTENSION_GROUP));
@@ -33,8 +32,9 @@ public class FileFilter {
}
if (!hasMatchingPattern(pathName)
- || !isNewer(pathName)
- || isExcluded(pathName, new HashSet<>(excluded))) {
+ || isExcluded(pathName, new HashSet<>(excluded))
+ || lastExecutionHandler != null && !isNewer(pathName, lastExecutionHandler.get(pathName.getAbsolutePath()))
+ || !isNewer(pathName, filterDate)) {
log.debug("Excluded {}", pathName);
ResultStatistic.getInstance().excluded();
return false;
@@ -52,21 +52,18 @@ public class FileFilter {
return includePattern.matcher(pathName.getName()).matches();
}
- private boolean isNewer(File pathName) {
- if (filterDate == null) return true;
+ private boolean isNewer(File pathName, Instant date) {
+ if (date == null) return true;
try {
BasicFileAttributes attributes = Files.readAttributes(pathName.toPath(), BasicFileAttributes.class);
- return isNewer(DateUtils.convert(attributes.creationTime().toMillis()));
+ return attributes.creationTime().toInstant().isAfter(date)
+ || attributes.lastModifiedTime().toInstant().isAfter(date);
} catch (IOException e) {
log.warn("File attributes could not be read", e);
}
return true;
}
- private boolean isNewer(Date creationDate) {
- return creationDate.toInstant().isAfter(filterDate.toInstant());
- }
-
private boolean isExcluded(File pathName, Set excludedDirs) {
if (excludedDirs.contains(pathName.getPath())) return true;
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/LastExecutionHandler.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/LastExecutionHandler.java
new file mode 100644
index 0000000..16d4472
--- /dev/null
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/LastExecutionHandler.java
@@ -0,0 +1,56 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Properties;
+
+@Slf4j
+public class LastExecutionHandler {
+ private static final String FILE_NAME = "last-execution.properties";
+ private final File file;
+ private final Properties lastFileExecution;
+
+ public LastExecutionHandler(String path) {
+ file = new File(path + "/" + FILE_NAME);
+ lastFileExecution = loadLastFileExecution(file);
+ }
+
+ public Properties loadLastFileExecution(File file) {
+ Properties properties = new Properties();
+ try (FileInputStream in = new FileInputStream(file)) {
+ properties.load(in);
+ } catch (IOException e) {
+ log.info("Couldn't find or read {}", file.getPath(), e);
+ }
+ return properties;
+ }
+
+ public Instant get(String path) {
+ if (!lastFileExecution.containsKey(path)) return null;
+ return Instant.parse(lastFileExecution.getProperty(path));
+ }
+
+ public void update(String path) {
+ update(path, Instant.now());
+ }
+
+ public void update(String path, Instant execution) {
+ if (lastFileExecution == null) return;
+ lastFileExecution.put(path, execution.toString());
+ }
+
+ public void persist() {
+ try (FileOutputStream out = new FileOutputStream(file)) {
+ lastFileExecution.store(out, "MKVAudioSubtitleChanger - Last file execution");
+ } catch (IOException e) {
+ log.warn("Persisting last file execution dates failed", e);
+ }
+ }
+}
+
+
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java
index ba4e5e2..a8aae70 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java
@@ -37,10 +37,10 @@ public class AttributeConfigConverter implements CommandLine.ITypeConverter filterForPossibleDefaults(List tracks) {
+ /**
+ * Looks for default matches and applies them if found.
+ */
+ public void findAndApplyDefaultMatch(FileInfo fileInfo, AttributeConfig... configs) {
+ Map> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size());
+ Map> subsByLanguage = new HashMap<>(fileInfo.getTracks().size());
+ getPossibleDefaults(fileInfo.getTracks()).forEach(track -> {
+ if (TrackType.AUDIO.equals(track.type()))
+ audiosByLanguage.computeIfAbsent(track.language(), (k) -> new ArrayList<>()).add(track);
+ else if (TrackType.SUBTITLES.equals(track.type()))
+ subsByLanguage.computeIfAbsent(track.language(), (k) -> new ArrayList<>()).add(track);
+ });
+
+ for (AttributeConfig config : configs) {
+ if (("OFF".equals(config.getAudioLang()) || audiosByLanguage.containsKey(config.getAudioLang()))
+ && ("OFF".equals(config.getSubLang()) || subsByLanguage.containsKey(config.getSubLang()))) {
+ fileInfo.setMatchedConfig(config);
+ break;
+ }
+ }
+
+ if (fileInfo.getMatchedConfig() == null) return;
+
+ AttributeConfig match = fileInfo.getMatchedConfig();
+ removeExistingDefaults(fileInfo);
+ if (!"OFF".equals(match.getAudioLang())) applyNewDefault(fileInfo, audiosByLanguage.get(fileInfo.getMatchedConfig().getAudioLang()).get(0));
+ if (!"OFF".equals(match.getSubLang())) applyNewDefault(fileInfo, subsByLanguage.get(fileInfo.getMatchedConfig().getSubLang()).stream().max(subtitleTrackComparator).get());
+ }
+
+ /**
+ * If match with xxx:OFF was found forced track in audio language is applied as default.
+ * Forced track detection takes changes of {@link AttributeChangeProcessor#findAndApplyForcedTracks} into consideration.
+ */
+ public void applyForcedAsDefault(FileInfo fileInfo) {
+ AttributeConfig c = fileInfo.getMatchedConfig();
+ if (c == null) return;
+ if (!"OFF".equals(c.getAudioLang()) && "OFF".equals(c.getSubLang())) {
+ getForcedTracks(fileInfo)
+ .filter(track -> c.getAudioLang().equals(track.language()))
+ .findFirst()
+ .ifPresent(track -> applyNewDefault(fileInfo, track));
+ }
+ }
+
+ private Stream getPossibleDefaults(List tracks) {
Stream attributes = tracks.stream();
return attributes
@@ -34,55 +76,26 @@ public class AttributeChangeProcessor {
.filter(attr -> {
if (attr.trackName() == null) return true;
return forcedKeywords.stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0);
- })
- .toList();
+ });
}
- public void findDefaultMatchAndApplyChanges(FileInfo fileInfo, AttributeConfig... configs) {
- Map> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size());
- Map> subsByLanguage = new HashMap<>(fileInfo.getTracks().size());
- filterForPossibleDefaults(fileInfo.getTracks()).forEach(track -> {
- if (TrackType.AUDIO.equals(track.type()))
- audiosByLanguage.computeIfAbsent(track.language(), (k) -> new ArrayList<>()).add(track);
- else if (TrackType.SUBTITLES.equals(track.type()))
- subsByLanguage.computeIfAbsent(track.language(), (k) -> new ArrayList<>()).add(track);
- });
-
- for (AttributeConfig config : configs) {
- if (("OFF".equals(config.getAudioLanguage()) || audiosByLanguage.containsKey(config.getAudioLanguage()))
- && ("OFF".equals(config.getSubtitleLanguage()) || subsByLanguage.containsKey(config.getSubtitleLanguage()))) {
- fileInfo.setMatchedConfig(config);
- break;
- }
- // TODO: forced if OFF
- }
-
- if (fileInfo.getMatchedConfig() == null) return;
-
- applyDefaultChanges(fileInfo, FileInfo::getAudioTracks, fileInfo.getMatchedConfig().getAudioLanguage(),
- () -> audiosByLanguage.get(fileInfo.getMatchedConfig().getAudioLanguage()).get(0));
- applyDefaultChanges(fileInfo, FileInfo::getSubtitleTracks, fileInfo.getMatchedConfig().getSubtitleLanguage(),
- () -> subsByLanguage.get(fileInfo.getMatchedConfig().getSubtitleLanguage()).stream().max(subtitleTrackComparator).get());
- }
-
- private void applyDefaultChanges(FileInfo fileInfo, Function> tracks, String language, Supplier targetDefaultSupplier) {
- tracks.apply(fileInfo).stream()
+ private void removeExistingDefaults(FileInfo fileInfo) {
+ fileInfo.getTracks().stream()
.filter(TrackAttributes::defaultt)
.forEach(attr -> fileInfo.getChanges().getDefaultTrack().put(attr, false));
- if (!"OFF".equals(language)) {
- TrackAttributes targetDefault = targetDefaultSupplier.get();
- if (fileInfo.getChanges().getDefaultTrack().containsKey(targetDefault)) {
- fileInfo.getChanges().getDefaultTrack().remove(targetDefault);
- } else {
- fileInfo.getChanges().getDefaultTrack().put(targetDefault, true);
- }
+ }
+
+ private void applyNewDefault(FileInfo fileInfo, TrackAttributes targetDefault) {
+ Map changes = fileInfo.getChanges().getDefaultTrack();
+ if (changes.containsKey(targetDefault)) {
+ changes.remove(targetDefault);
+ } else {
+ changes.put(targetDefault, true);
}
}
- public void findForcedTracksAndApplyChanges(FileInfo fileInfo, boolean overwrite) {
- Stream forcedTracks = fileInfo.getTracks().stream()
- .filter(track -> track.trackName() != null)
- .filter(track -> forcedKeywords.stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT))));
+ public void findAndApplyForcedTracks(FileInfo fileInfo, boolean overwrite) {
+ Stream forcedTracks = getForcedTracks(fileInfo);
if (overwrite) {
fileInfo.getTracks().stream().filter(TrackAttributes::forced).forEach(attr -> {
@@ -97,7 +110,19 @@ public class AttributeChangeProcessor {
});
}
- public void findCommentaryTracksAndApplyChanges(FileInfo fileInfo) {
+ private Stream getForcedTracks(FileInfo fileInfo) {
+ return fileInfo.getTracks().stream()
+ .filter(track -> {
+ if (fileInfo.getChanges().getForcedTrack().containsKey(track)) return fileInfo.getChanges().getForcedTrack().get(track);
+ return matchesForcedKeywords(track) || track.forced();
+ });
+ }
+
+ private boolean matchesForcedKeywords(TrackAttributes track) {
+ return track.trackName() != null && forcedKeywords.stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT)));
+ }
+
+ public void findAndApplyCommentaryTracks(FileInfo fileInfo) {
fileInfo.getTracks().stream()
.filter(track -> !track.commentary())
.filter(track -> track.trackName() != null)
@@ -107,7 +132,7 @@ public class AttributeChangeProcessor {
});
}
- public void findHearingImpairedTracksAndApplyChanges(FileInfo fileInfo) {
+ public void findAndApplyHearingImpairedTracks(FileInfo fileInfo) {
fileInfo.getTracks().stream()
.filter(track -> !track.hearingImpaired())
.filter(track -> track.trackName() != null)
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdater.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdater.java
index 228bcfc..38caa1a 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdater.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdater.java
@@ -1,6 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
@@ -25,14 +26,16 @@ public abstract class AttributeUpdater {
protected final InputConfig config;
protected final FileProcessor fileProcessor;
protected final AttributeChangeProcessor attributeChangeProcessor;
+ protected final LastExecutionHandler lastExecutionHandler;
protected final ResultStatistic statistic = ResultStatistic.getInstance();
private final ExecutorService executor;
- public AttributeUpdater(InputConfig config, FileProcessor fileProcessor, AttributeChangeProcessor attributeChangeProcessor) {
+ public AttributeUpdater(InputConfig config, FileProcessor fileProcessor, AttributeChangeProcessor attributeChangeProcessor, LastExecutionHandler lastExecutionHandler) {
this.config = config;
this.fileProcessor = fileProcessor;
this.attributeChangeProcessor = attributeChangeProcessor;
+ this.lastExecutionHandler = lastExecutionHandler;
this.executor = Executors.newFixedThreadPool(config.getThreads());
}
@@ -62,7 +65,7 @@ public abstract class AttributeUpdater {
executor.awaitTermination(1, TimeUnit.DAYS);
}
-// writeLastExecutionDate();
+ if (lastExecutionHandler != null) lastExecutionHandler.persist();
statistic.stopTimer();
statistic.print();
@@ -84,6 +87,7 @@ public abstract class AttributeUpdater {
* @param fileInfo contains information about file and desired configuration.
*/
protected void checkStatusAndUpdate(FileInfo fileInfo) {
+ if (lastExecutionHandler != null) lastExecutionHandler.update(fileInfo.getFile().getAbsolutePath());
if (!fileInfo.getChanges().isEmpty()) {
statistic.changePlanned();
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java
index 24e356c..10cb59e 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java
@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
@@ -7,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBarBuilder;
import java.io.File;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -14,8 +16,8 @@ import java.util.Set;
@Slf4j
public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
- public CoherentAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor) {
- super(config, processor, attributeChangeProcessor);
+ public CoherentAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor, LastExecutionHandler lastExecutionHandler) {
+ super(config, processor, attributeChangeProcessor, lastExecutionHandler);
}
@Override
@@ -25,7 +27,9 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
}
protected List getFiles() {
- return fileProcessor.loadDirectory(config.getLibraryPath().getPath(), config.getCoherent());
+ return Arrays.stream(config.getLibraryPath())
+ .flatMap(path -> fileProcessor.loadDirectory(path.getPath(), config.getCoherent()).stream())
+ .toList();
}
@Override
@@ -49,16 +53,17 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
log.info("Found coherent match {} for {}", matchedConfig.toStringShort(), rootDir.getPath());
matchedFiles.forEach(fileInfo -> {
- attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, this.config.isOverwriteForced());
- attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
- attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
+ attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, this.config.isOverwriteForced());
+ attributeChangeProcessor.applyForcedAsDefault(fileInfo);
+ attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
+ attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
checkStatusAndUpdate(fileInfo);
});
return; // match was found and process must be stopped
}
- // Couldn't match any config at current level. Resetting changes and trying to one level deeper
+ // Couldn't match any config at current level. Resetting changes and trying one level deeper
matchedFiles.forEach(fileInfo -> {
fileInfo.resetChanges();
fileInfo.setMatchedConfig(null);
@@ -89,7 +94,7 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
break;
}
- attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config);
+ attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config);
if (matchedConfig == null) matchedConfig = fileInfo.getMatchedConfig();
if (matchedConfig == null || matchedConfig != fileInfo.getMatchedConfig()) {
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/MkvFileProcessor.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/MkvFileProcessor.java
index 2d3c113..5b207c4 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/MkvFileProcessor.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/MkvFileProcessor.java
@@ -3,10 +3,10 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileFilter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
+import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.logging.log4j.core.util.IOUtils;
-import tools.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.IOException;
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java
index 0d28a08..6e4bd4f 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java
@@ -1,18 +1,20 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBarBuilder;
import java.io.File;
+import java.util.Arrays;
import java.util.List;
@Slf4j
public class SingleFileAttributeUpdater extends AttributeUpdater {
- public SingleFileAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor) {
- super(config, processor, attributeChangeProcessor);
+ public SingleFileAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor, LastExecutionHandler lastExecutionHandler) {
+ super(config, processor, attributeChangeProcessor, lastExecutionHandler);
}
@Override
@@ -23,7 +25,9 @@ public class SingleFileAttributeUpdater extends AttributeUpdater {
@Override
protected List getFiles() {
- return fileProcessor.loadFiles(config.getLibraryPath().getPath());
+ return Arrays.stream(config.getLibraryPath())
+ .flatMap(path -> fileProcessor.loadFiles(path.getPath()).stream())
+ .toList();
}
@Override
@@ -36,10 +40,11 @@ public class SingleFileAttributeUpdater extends AttributeUpdater {
return;
}
- attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config.getAttributeConfig());
- attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, config.isOverwriteForced());
- attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
- attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
+ attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config.getAttributeConfig());
+ attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, config.isOverwriteForced());
+ attributeChangeProcessor.applyForcedAsDefault(fileInfo);
+ attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
+ attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
checkStatusAndUpdate(fileInfo);
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/validation/ValidFileValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/validation/ValidFileValidator.java
index b111865..d3bec0c 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/validation/ValidFileValidator.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/validation/ValidFileValidator.java
@@ -2,16 +2,26 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
+import lombok.extern.slf4j.Slf4j;
import java.io.File;
+import java.util.Arrays;
-public class ValidFileValidator implements ConstraintValidator {
+@Slf4j
+public class ValidFileValidator implements ConstraintValidator {
@Override
public void initialize(ValidFile constraintAnnotation) {
}
@Override
- public boolean isValid(File file, ConstraintValidatorContext context) {
- return file != null && file.exists();
+ public boolean isValid(File[] files, ConstraintValidatorContext context) {
+ if (files == null || files.length == 0) return false;
+ for (File file: files) {
+ if (!file.exists()) {
+ log.error("{} does not exist", file.getPath());
+ return false;
+ }
+ }
+ return true;
}
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java
index 45b278e..f9c30ab 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java
@@ -10,8 +10,8 @@ import java.util.Objects;
@Getter
@AllArgsConstructor
public class AttributeConfig {
- private final String audioLanguage;
- private final String subtitleLanguage;
+ private final String audioLang;
+ private final String subLang;
public static AttributeConfig of(String audioLanguage, String subtitleLanguage) {
return new AttributeConfig(audioLanguage, subtitleLanguage);
@@ -22,23 +22,23 @@ public class AttributeConfig {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AttributeConfig that = (AttributeConfig) o;
- return Objects.equals(audioLanguage, that.audioLanguage) && Objects.equals(subtitleLanguage, that.subtitleLanguage);
+ return Objects.equals(audioLang, that.audioLang) && Objects.equals(subLang, that.subLang);
}
@Override
public int hashCode() {
- return Objects.hash(audioLanguage, subtitleLanguage);
+ return Objects.hash(audioLang, subLang);
}
public String toStringShort() {
- return audioLanguage + ":" + subtitleLanguage;
+ return audioLang + ":" + subLang;
}
@Override
public String toString() {
return "AttributeConfig{"
- + "audioLanguage='" + audioLanguage + '\''
- + ", subtitleLanguage='" + subtitleLanguage + '\'' +
+ + "audioLanguage='" + audioLang + '\''
+ + ", subtitleLanguage='" + subLang + '\'' +
'}';
}
}
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/InputConfig.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/InputConfig.java
index bc9e69a..76a5dd9 100644
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/InputConfig.java
+++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/InputConfig.java
@@ -12,6 +12,7 @@ import org.apache.commons.lang3.SystemUtils;
import picocli.CommandLine;
import java.io.File;
+import java.time.Instant;
import java.util.*;
import java.util.regex.Pattern;
import picocli.CommandLine.Option;
@@ -29,8 +30,8 @@ public class InputConfig implements CommandLine.IVersionProvider {
CommandLine.Model.CommandSpec spec;
@ValidFile(message = "does not exist")
- @CommandLine.Parameters(description = "path to library")
- private File libraryPath;
+ @CommandLine.Parameters(description = "paths to library", arity = "1..*")
+ private File[] libraryPath;
@Option(names = {"-a", "--attribute-config"}, arity = "1..*", converter = AttributeConfigConverter.class,
description = "List of audio:subtitle pairs for matching defaults in order (e.g. jpn:eng jpn:ger)")
@@ -53,10 +54,10 @@ public class InputConfig implements CommandLine.IVersionProvider {
private boolean forceCoherent;
// TODO: implement usage
-// @Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)")
-// private boolean onlyNewFiles;
- @Option(names = {"-d", "--filter-date"}, defaultValue = Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")")
- private Date filterDate;
+ @Option(names = {"-n", "--only-new-files"}, description = "ignores all files unchanged and previously processed")
+ private boolean onlyNewFiles;
+ @Option(names = {"-d", "--filter-date"}, defaultValue = Option.NULL_VALUE, description = "only consider files created newer than entered date (following ISO-8601 yyyy-MM-ddTHH:mm:ss.sssZ)")
+ private Instant filterDate;
@Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern")
private Pattern includePattern;
@Option(names = {"-e", "--exclude"}, arity = "1..*",
diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtils.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtils.java
deleted file mode 100644
index 61eaa20..0000000
--- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/DateUtils.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class DateUtils {
- private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy-HH:mm:ss");
-
- public static Date convert(long millis) {
- return new Date(millis);
- }
-
- /**
- * Convert String to date.
- * @return parsed date, defaultDate if exception occurs
- */
- public static Date convert(String date, Date defaultDate) {
- try {
- return dateFormat.parse(date);
- } catch (ParseException e) {
- return defaultDate;
- }
- }
-
- public static String convert(Date date) {
- return dateFormat.format(date);
- }
-}
diff --git a/src/main/resources/log4j2-windows.yaml b/src/main/resources/log4j2-debian.yml
similarity index 63%
rename from src/main/resources/log4j2-windows.yaml
rename to src/main/resources/log4j2-debian.yml
index e39795f..109f2b2 100644
--- a/src/main/resources/log4j2-windows.yaml
+++ b/src/main/resources/log4j2-debian.yml
@@ -1,12 +1,20 @@
Configuration:
- name: DefaultLogger
+ name: MainConfig
+
+ Properties:
+ Property:
+ - name: logDir
+ value: ${sys:user.home}/.local/mkvaudiosubtitlechanger/logs
+ - name: logPattern
+ value: "%d{DEFAULT} | %-5level | %msg %n %throwable"
+
Appenders:
RollingFile:
name: FileAppender
- fileName: ${sys:user.home}/AppData/Local/MKVAudioSubtitleChanger/logs/application.log
- filePattern: ${sys:user.home}/AppData/Local/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz
+ fileName: ${logDir}/application.log
+ filePattern: ${logDir}/archive/application-%d{yyyy-MM-dd}-%i.log.gz
PatternLayout:
- Pattern: "%d{DEFAULT} | %-5level | %msg %n %throwable"
+ Pattern: logPattern
ThresholdFilter:
level: debug
Policies:
diff --git a/src/main/resources/log4j2-dev.yaml b/src/main/resources/log4j2-dev.yml
similarity index 69%
rename from src/main/resources/log4j2-dev.yaml
rename to src/main/resources/log4j2-dev.yml
index 71280f7..4949d72 100644
--- a/src/main/resources/log4j2-dev.yaml
+++ b/src/main/resources/log4j2-dev.yml
@@ -1,18 +1,25 @@
Configuration:
- name: DefaultLogger
+
+ Properties:
+ Property:
+ - name: logDir
+ value: "./logs"
+ - name: log_pattern
+ value: "%d{DEFAULT} | %-5level | %thread | %C{1} | %msg %n %throwable"
+
Appenders:
Console:
name: Console_Out
PatternLayout:
- Pattern: "%d{DEFAULT} | %-5level | %thread | %C{1} | %msg %n %throwable"
+ Pattern: ${log_pattern}
ThresholdFilter:
level: debug
RollingFile:
name: FileAppender
- fileName: logs/application.log
- filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz
+ fileName: ${logDir}/application.log
+ filePattern: ${logDir}/archive/application-%d{yyyy-MM-dd}-%i.log.gz
PatternLayout:
- Pattern: "%d{DEFAULT} | %-5level | %thread | %C{1} | %msg %n %throwable"
+ Pattern: logPattern
ThresholdFilter:
level: debug
Policies:
diff --git a/src/main/resources/log4j2-debian.yaml b/src/main/resources/log4j2-windows.yml
similarity index 59%
rename from src/main/resources/log4j2-debian.yaml
rename to src/main/resources/log4j2-windows.yml
index 1ad3cd5..8c24f4e 100644
--- a/src/main/resources/log4j2-debian.yaml
+++ b/src/main/resources/log4j2-windows.yml
@@ -1,12 +1,20 @@
Configuration:
- name: DefaultLogger
+ name: WindowsConfig
+
+ Properties:
+ Property:
+ - name: logDir
+ value: ${sys:user.home}/AppData/Local/MKVAudioSubtitleChanger/logs
+ - name: logPattern
+ value: "%d{DEFAULT} | %-5level | %msg %n %throwable"
+
Appenders:
RollingFile:
name: FileAppender
- fileName: ${sys:user.home}/.local/mkvaudiosubtitlechanger/logs/application.log
- filePattern: ${sys:user.home}/.local/mkvaudiosubtitlechanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz
+ fileName: ${logDir}/application.log
+ filePattern: ${logDir}/archive/application-%d{yyyy-MM-dd}-%i.log.gz
PatternLayout:
- Pattern: "%d{DEFAULT} | %-5level | %msg %n %throwable"
+ Pattern: logPattern
ThresholdFilter:
level: debug
Policies:
@@ -15,7 +23,7 @@ Configuration:
DefaultRolloverStrategy:
max: 30
Delete:
- basePath: archive
+ basePath: logs/archive
maxDepth: 1
IfLastModified:
age: 30d
diff --git a/src/main/resources/log4j2.yaml b/src/main/resources/log4j2.yml
similarity index 66%
rename from src/main/resources/log4j2.yaml
rename to src/main/resources/log4j2.yml
index b909c8d..3a01cc2 100644
--- a/src/main/resources/log4j2.yaml
+++ b/src/main/resources/log4j2.yml
@@ -1,12 +1,20 @@
Configuration:
- name: DefaultLogger
+ name: MainConfig
+
+ Properties:
+ Property:
+ - name: logDir
+ value: ./logs
+ - name: logPattern
+ value: "%d{DEFAULT} | %-5level | %msg %n %throwable"
+
Appenders:
RollingFile:
name: FileAppender
- fileName: logs/application.log
- filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz
+ fileName: ${logDir}/application.log
+ filePattern: ${logDir}/archive/application-%d{yyyy-MM-dd}-%i.log.gz
PatternLayout:
- Pattern: "%d{DEFAULT} | %-5level | %msg %n %throwable"
+ Pattern: logPattern
ThresholdFilter:
level: debug
Policies:
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PicoCliTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PicoCliTest.java
new file mode 100644
index 0000000..e0b30e8
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/PicoCliTest.java
@@ -0,0 +1,23 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
+
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CommandRunner;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidationExecutionStrategy;
+import org.junit.jupiter.api.Test;
+import picocli.CommandLine;
+
+import java.time.Instant;
+
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class PicoCliTest {
+
+ @Test
+ void loadFilterDate() {
+ CommandRunner underTest = new CommandRunner();
+ new CommandLine(underTest)
+ .setExecutionStrategy(new ValidationExecutionStrategy())
+ .parseArgs("-d", "2012-12-12T12:12:12.00Z", TEST_FILE);
+ assertEquals(Instant.parse("2012-12-12T12:12:12.00Z"), underTest.getConfig().getFilterDate());
+ }
+}
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilterTest.java
index 5fae36f..0ce5d1f 100644
--- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilterTest.java
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/FileFilterTest.java
@@ -1,8 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
-import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
-import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
@@ -14,11 +12,13 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.File;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Date;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@@ -71,12 +71,14 @@ class FileFilterTest {
when(file.toPath()).thenReturn(Path.of(TEST_FILE));
long currentTime = System.currentTimeMillis();
- FileFilter fileFilter = new FileFilter(excludedDirs, Pattern.compile(pattern), new Date(currentTime + filterDateOffset));
+ when(attributes.creationTime()).thenReturn(FileTime.fromMillis(currentTime));
+ when(attributes.lastModifiedTime()).thenReturn(FileTime.fromMillis(currentTime));
+ FileFilter fileFilter = new FileFilter(excludedDirs, Pattern.compile(pattern), Instant.ofEpochMilli(currentTime).plus(filterDateOffset, ChronoUnit.SECONDS), null);
- try (MockedStatic mockedFiles = Mockito.mockStatic(DateUtils.class)) {
+ try (MockedStatic mockedFiles = Mockito.mockStatic(Files.class)) {
mockedFiles
- .when(() -> DateUtils.convert(anyLong()))
- .thenReturn(new Date(currentTime));
+ .when(() -> Files.readAttributes(any(), eq(BasicFileAttributes.class)))
+ .thenReturn(attributes);
assertEquals(acceptanceExpected, fileFilter.accept(file, new HashSet<>(extensions)), "File is accepted");
assertEquals(excluded, ResultStatistic.getInstance().getExcluded() > 0, "Is counted in excluded statistic");
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/LastExecutionHandlerTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/LastExecutionHandlerTest.java
new file mode 100644
index 0000000..51e002c
--- /dev/null
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/LastExecutionHandlerTest.java
@@ -0,0 +1,74 @@
+package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.time.Instant;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class LastExecutionHandlerTest {
+ private static final String LAST_EXECUTION_PATH = ".";
+ private static final String LAST_EXECUTION_FILE = "./last-execution.properties";
+ private static final String TEST_MKV_FILE = "/arst/file.mkv";
+
+ @AfterEach
+ void destruct() {
+ File file = new File(LAST_EXECUTION_FILE);
+ if (file.exists()) file.delete();
+ }
+
+ @Test
+ void missingFile() throws IOException {
+ LastExecutionHandler underTest = new LastExecutionHandler(LAST_EXECUTION_PATH);
+ assertNull(underTest.get(TEST_MKV_FILE));
+ underTest.update(TEST_MKV_FILE);
+ assertNotNull(underTest.get(TEST_MKV_FILE));
+ underTest.persist();
+ File file = new File(LAST_EXECUTION_FILE);
+ assertTrue(file.exists());
+ assertTrue(Files.readString(file.toPath()).contains(TEST_MKV_FILE + "="));
+ }
+
+ @Test
+ void emptyFile() throws IOException {
+ File file = new File(LAST_EXECUTION_FILE);
+ file.createNewFile();
+ missingFile(); // does the checks needed for empty file case
+ }
+
+ @Test
+ void existingFileNoChanges() throws IOException {
+ File file = new File(LAST_EXECUTION_FILE);
+ file.createNewFile();
+ Files.writeString(file.toPath(), TEST_MKV_FILE + "=" + Instant.now());
+ String expected = Files.readString(file.toPath()).replace(":", "\\:");
+
+ LastExecutionHandler underTest = new LastExecutionHandler(LAST_EXECUTION_PATH);
+ assertNotNull(underTest.get(TEST_MKV_FILE));
+ underTest.persist();
+ File file1 = new File(LAST_EXECUTION_FILE);
+ assertTrue(file1.exists());
+ assertTrue(Files.readString(file.toPath()).contains(expected), "File contains expected value");
+ }
+
+ @Test
+ void existingFileWithChanges() throws IOException {
+ File file = new File(LAST_EXECUTION_FILE);
+ file.createNewFile();
+ Files.writeString(file.toPath(), TEST_MKV_FILE + "=" + Instant.now());
+ String expected = Files.readString(file.toPath());
+
+ LastExecutionHandler underTest = new LastExecutionHandler(LAST_EXECUTION_PATH);
+ assertNotNull(underTest.get(TEST_MKV_FILE));
+ underTest.update(TEST_MKV_FILE);
+ assertNotNull(underTest.get(TEST_MKV_FILE));
+ underTest.persist();
+ File file1 = new File(LAST_EXECUTION_FILE);
+ assertTrue(file1.exists());
+ assertNotEquals(expected, Files.readString(file.toPath()));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java
index 67b9f6e..6f65d39 100644
--- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java
@@ -12,13 +12,13 @@ import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Stream;
-import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileInfoTestUtil.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TrackAttributeUtil.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class AttributeChangeProcessorTest {
- private static Stream attributeConfigMatching() {
+ private static Stream findAndApplyDefaultMatch() {
return Stream.of(
Arguments.of(
List.of(withName(AUDIO_ENG, null), SUB_ENG),
@@ -99,13 +99,14 @@ class AttributeChangeProcessorTest {
}
@ParameterizedTest
- @MethodSource("attributeConfigMatching")
- void findDefaultMatchAndApplyChanges(List tracks, AttributeConfig[] config, String expectedConfig, Map changes) {
+ @MethodSource("findAndApplyDefaultMatch")
+ void findAndApplyDefaultMatch(List tracks, AttributeConfig[] config, String expectedConfig, Map changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH"));
-
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
- attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config);
+
+ attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config);
+
assertEquals(expectedConfig, fileInfo.getMatchedConfig() != null ? fileInfo.getMatchedConfig().toStringShort() : fileInfo.getMatchedConfig());
assertEquals(changes.size(), fileInfo.getChanges().getDefaultTrack().size());
changes.forEach((key, value) -> {
@@ -114,24 +115,54 @@ class AttributeChangeProcessorTest {
});
}
- private static AttributeConfig[] arr(AttributeConfig... configs) {
- return configs;
+ private static Stream applyForcedAsDefault() {
+ return Stream.of(
+ Arguments.of(
+ List.of(AUDIO_GER, SUB_GER_FORCED),
+ a("ger:OFF"),
+ Map.ofEntries(on(SUB_GER_FORCED))
+ ),
+ Arguments.of(
+ List.of(AUDIO_GER, SUB_GER_FORCED, SUB_GER),
+ a("ger:OFF"),
+ Map.ofEntries(on(SUB_GER_FORCED))
+ ),
+ Arguments.of(
+ List.of(AUDIO_GER, withName(SUB_GER, "forced")),
+ a("ger:OFF"),
+ Map.ofEntries(on(withName(SUB_GER, "forced")))
+ ),
+ Arguments.of(
+ List.of(AUDIO_GER, SUB_GER_FORCED, SUB_ENG),
+ a("ger:eng"),
+ Map.ofEntries()
+ ),
+ Arguments.of(
+ List.of(AUDIO_GER, SUB_GER_FORCED, SUB_ENG),
+ null,
+ Map.ofEntries()
+ )
+ );
}
- private static AttributeConfig a(String config) {
- String[] split = config.split(":");
- return new AttributeConfig(split[0], split[1]);
+ @ParameterizedTest
+ @MethodSource("applyForcedAsDefault")
+ void applyForcedAsDefault(List tracks, AttributeConfig config, Map changes) {
+ AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of(""), Set.of(""));
+ FileInfo fileInfo = new FileInfo(null);
+ fileInfo.addTracks(tracks);
+ fileInfo.setMatchedConfig(config);
+
+ attributeChangeProcessor.applyForcedAsDefault(fileInfo);
+
+ assertEquals(changes.size(), fileInfo.getChanges().getDefaultTrack().size());
+ changes.forEach((key, value) -> {
+ assertTrue(fileInfo.getChanges().getDefaultTrack().containsKey(key));
+ assertEquals(value, fileInfo.getChanges().getDefaultTrack().get(key));
+ });
}
- private static Map.Entry on(TrackAttributes track) {
- return Map.entry(track, true);
- }
-
- private static Map.Entry off(TrackAttributes track) {
- return Map.entry(track, false);
- }
-
- private static Stream filterForPossibleDefaults() {
+ private static Stream getPossibleDefaults() {
return Stream.of(
Arguments.of(List.of(AUDIO_GER, AUDIO_ENG, SUB_GER), Set.of(AUDIO_GER, AUDIO_ENG, SUB_GER)),
Arguments.of(List.of(AUDIO_GER, AUDIO_ENG, withName(AUDIO_GER, "forced"), SUB_GER), Set.of(AUDIO_GER, AUDIO_ENG, SUB_GER)),
@@ -145,24 +176,55 @@ class AttributeChangeProcessorTest {
}
@ParameterizedTest
- @MethodSource("filterForPossibleDefaults")
- void filterForPossibleDefaults(List tracks, Set expected) throws InvocationTargetException, IllegalAccessException {
+ @MethodSource("getPossibleDefaults")
+ void getPossibleDefaults(List tracks, Set expected) throws InvocationTargetException, IllegalAccessException {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH"));
Optional method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods())
- .filter(m -> m.getName().equals("filterForPossibleDefaults"))
+ .filter(m -> m.getName().equals("getPossibleDefaults"))
.findFirst();
assertTrue(method.isPresent());
Method underTest = method.get();
underTest.setAccessible(true);
- List result = (List) underTest.invoke(attributeChangeProcessor, tracks);
+ List result = ((Stream) underTest.invoke(attributeChangeProcessor, tracks)).toList();
assertEquals(expected.size(), result.size());
for (TrackAttributes track : result) {
assertTrue(expected.contains(track));
}
}
- private static Stream findForcedTracksAndApplyChanges() {
+ private static Stream getForcedTracks() {
+ return Stream.of(
+ Arguments.of(List.of(withName(SUB_GER, "forced")), Map.of(), Set.of(withName(SUB_GER, "forced"))),
+ Arguments.of(List.of(SUB_GER_FORCED), Map.of(), Set.of(SUB_GER_FORCED)),
+ Arguments.of(List.of(SUB_GER_FORCED, withName(SUB_GER, "forced")), Map.of(), Set.of(SUB_GER_FORCED, withName(SUB_GER, "forced"))),
+ Arguments.of(List.of(SUB_GER_FORCED, withName(SUB_GER, "forced")), Map.of(SUB_GER_FORCED, false), Set.of(withName(SUB_GER, "forced"))),
+ Arguments.of(List.of(SUB_GER, withName(SUB_GER, "forced")), Map.of(SUB_GER, true), Set.of(SUB_GER, withName(SUB_GER, "forced")))
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("getForcedTracks")
+ void getForcedTracks(List tracks, Map changes, Set expected) throws InvocationTargetException, IllegalAccessException {
+ AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of(), Set.of());
+ FileInfo fileInfo = new FileInfo(null);
+ fileInfo.addTracks(tracks);
+ changes.forEach((key, val) -> fileInfo.getChanges().getForcedTrack().put(key, val));
+ Optional method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods())
+ .filter(m -> m.getName().equals("getForcedTracks"))
+ .findFirst();
+
+ assertTrue(method.isPresent());
+ Method underTest = method.get();
+ underTest.setAccessible(true);
+ List result = ((Stream) underTest.invoke(attributeChangeProcessor, fileInfo)).toList();
+ assertEquals(expected.size(), result.size());
+ for (TrackAttributes track : result) {
+ assertTrue(expected.contains(track));
+ }
+ }
+
+ private static Stream findAndApplyForcedTracks() {
return Stream.of(
Arguments.of(List.of(),
Set.of("song & signs"), false,
@@ -196,13 +258,13 @@ class AttributeChangeProcessorTest {
}
@ParameterizedTest
- @MethodSource("findForcedTracksAndApplyChanges")
- void findForcedTracksAndApplyChanges(List tracks, Set keywords, boolean overwrite, Map changes) {
+ @MethodSource("findAndApplyForcedTracks")
+ void findAndApplyForcedTracks(List tracks, Set keywords, boolean overwrite, Map changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, keywords, Set.of(), Set.of());
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
- attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, overwrite);
+ attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, overwrite);
assertEquals(changes.size(), fileInfo.getChanges().getForcedTrack().size());
changes.forEach((key, value) -> {
@@ -211,7 +273,7 @@ class AttributeChangeProcessorTest {
});
}
- private static Stream findCommentaryTracksAndApplyChanges() {
+ private static Stream findAndApplyCommentaryTracks() {
return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "commentary"), withName(SUB_GER, null)),
Set.of("commentary"),
@@ -233,13 +295,13 @@ class AttributeChangeProcessorTest {
}
@ParameterizedTest
- @MethodSource("findCommentaryTracksAndApplyChanges")
- void findCommentaryTracksAndApplyChanges(List tracks, Set keywords, Map changes) {
+ @MethodSource("findAndApplyCommentaryTracks")
+ void findAndApplyCommentaryTracks(List tracks, Set keywords, Map changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), keywords, Set.of());
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
- attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
+ attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getCommentaryTrack().size());
changes.forEach((key, value) -> {
@@ -248,7 +310,7 @@ class AttributeChangeProcessorTest {
});
}
- private static Stream findHearingImpairedTracksAndApplyChanges() {
+ private static Stream findAndApplyHearingImpairedTracks() {
return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "SDH"), withName(SUB_GER, null)),
Set.of("SDH"),
@@ -270,13 +332,13 @@ class AttributeChangeProcessorTest {
}
@ParameterizedTest
- @MethodSource("findHearingImpairedTracksAndApplyChanges")
- void findHearingImpairedTracksAndApplyChanges(List tracks, Set keywords, Map changes) {
+ @MethodSource("findAndApplyHearingImpairedTracks")
+ void findAndApplyHearingImpairedTracks(List tracks, Set keywords, Map changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), Set.of(), keywords);
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
- attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
+ attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getHearingImpairedTrack().size());
changes.forEach((key, value) -> {
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdaterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdaterTest.java
index be5d7b2..a6a4140 100644
--- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdaterTest.java
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeUpdaterTest.java
@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
@@ -11,7 +12,7 @@ import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Stream;
-import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileInfoTestUtil.AUDIO_GER;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TrackAttributeUtil.AUDIO_GER;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE;
import static org.junit.jupiter.api.Assertions.*;
@@ -36,7 +37,7 @@ class AttributeUpdaterTest {
InputConfig config = new InputConfig();
config.setThreads(1);
config.setSafeMode(true);
- AttributeUpdater underTest = new AttributeUpdater(config, null, null) {
+ AttributeUpdater underTest = new AttributeUpdater(config, null, null, new LastExecutionHandler("")) {
@Override
protected List getFiles() {
return List.of();
diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdaterTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdaterTest.java
index afc05e8..c202f03 100644
--- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdaterTest.java
+++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdaterTest.java
@@ -1,12 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CommandRunner;
+import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import org.apache.commons.lang3.tuple.Pair;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -21,19 +21,17 @@ import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Stream;
-import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileInfoTestUtil.*;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_DIR;
+import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TrackAttributeUtil.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.when;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class CoherentAttributeUpdaterTest {
@Mock(lenient = true)
FileProcessor fileProcessor;
- @Test
- void process() {
- }
-
private static Stream findMatch() {
return Stream.of(
Arguments.of(AttributeConfig.of("ger", "ger"),
@@ -68,7 +66,8 @@ class CoherentAttributeUpdaterTest {
new CommandLine(commandRunner).parseArgs("-a", "ger:ger", "/arst");
InputConfig config = commandRunner.getConfig();
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(config.getPreferredSubtitles().toArray(new String[0]), config.getForcedKeywords(), config.getCommentaryKeywords(), config.getHearingImpaired());
- CoherentAttributeUpdater updater = new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor);
+ LastExecutionHandler lastExecutionHandler = new LastExecutionHandler("");
+ CoherentAttributeUpdater updater = new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler);
Set matchedFiles = new HashSet<>(fileInfoMock.size() * 2);
List files = new ArrayList<>();
@@ -91,4 +90,130 @@ class CoherentAttributeUpdaterTest {
fileInfo.addTracks(List.of(tracks));
return Pair.of(file, fileInfo);
}
+
+ private static Stream process() {
+ return Stream.of(
+ Arguments.of(
+ arr(a("ger:ger")), a("ger:ger"),
+ List.of(
+ List.of(AUDIO_GER, SUB_GER),
+ List.of(AUDIO_GER, SUB_GER)
+ ),
+ List.of(
+ Map.ofEntries(on(AUDIO_GER), on(SUB_GER)),
+ Map.ofEntries(on(AUDIO_GER), on(SUB_GER))
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ )
+ ),
+ Arguments.of(
+ arr(a("eng:eng"), a("ger:ger")), a("ger:ger"),
+ List.of(
+ List.of(SUB_ENG, AUDIO_GER, SUB_GER),
+ List.of(AUDIO_ENG, SUB_ENG, AUDIO_GER, SUB_GER)
+ ),
+ List.of(
+ Map.ofEntries(on(AUDIO_GER), on(SUB_GER)),
+ Map.ofEntries(on(AUDIO_GER), on(SUB_GER))
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ )
+ ),
+ Arguments.of(
+ arr(a("eng:eng"), a("ger:ger")), a("eng:eng"),
+ List.of(
+ List.of(AUDIO_ENG, withName(SUB_ENG, "SDH"), AUDIO_GER, SUB_GER),
+ List.of(AUDIO_ENG, SUB_ENG, AUDIO_GER, SUB_GER)
+ ),
+ List.of(
+ Map.ofEntries(on(AUDIO_ENG), on(withName(SUB_ENG, "SDH"))),
+ Map.ofEntries(on(AUDIO_ENG), on(SUB_ENG))
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ ),
+ List.of(
+ Map.ofEntries(),
+ Map.ofEntries()
+ ),
+ List.of(
+ Map.ofEntries(on(withName(SUB_ENG, "SDH"))),
+ Map.ofEntries()
+ )
+ )
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("process")
+ void process(AttributeConfig[] attributeConfigs, AttributeConfig expectedMatch,
+ List> tracks,
+ List