10 Commits

Author SHA1 Message Date
RatzzFatzz
906ec944eb Fix filter-date format & add test for filter-date 2026-01-13 15:50:38 +01:00
RatzzFatzz
41e107ef85 Migrate from date to instant 2026-01-13 15:35:16 +01:00
RatzzFatzz
3c57eb44ef Migrate last execution handler to properties 2026-01-12 19:02:06 +01:00
RatzzFatzz
8dbfb22ed8 Fix log4j2 and jackson.databind dependency 2026-01-12 19:01:10 +01:00
RatzzFatzz
a5aae0acf4 Add handler for only new files parameter 2026-01-08 22:03:06 +01:00
RatzzFatzz
1165dd8380 Add support for multiple library paths 2025-12-29 00:12:28 +01:00
RatzzFatzz
be004e6146 Add support for multiple library paths 2025-12-28 23:59:33 +01:00
RatzzFatzz
31b155d8a3 Add tests for coherent file attribute updater 2025-12-27 20:55:41 +01:00
RatzzFatzz
94365651ff Add tests for single file attribute updater 2025-12-25 14:28:18 +01:00
RatzzFatzz
f18fdbdda6 Apply forced track if sub lang is OFF 2025-12-24 16:22:17 +01:00
24 changed files with 677 additions and 214 deletions

13
pom.xml
View File

@@ -381,19 +381,19 @@
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId> <artifactId>log4j-api</artifactId>
<version>2.25.3</version> <version>3.0.0-beta2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-core</artifactId>
<version>2.25.3</version> <version>3.0.0-beta2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl --> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl -->
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId> <artifactId>log4j-slf4j2-impl</artifactId>
<version>2.25.3</version> <version>3.0.0-beta2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/tools.jackson.dataformat/jackson-dataformat-yaml --> <!-- https://mvnrepository.com/artifact/tools.jackson.dataformat/jackson-dataformat-yaml -->
@@ -421,6 +421,13 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.20.0</version> <version>3.20.0</version>
</dependency> </dependency>
<!-- Source: https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.21.0</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/me.tongfei/progressbar --> <!-- https://mvnrepository.com/artifact/me.tongfei/progressbar -->
<dependency> <dependency>
<groupId>me.tongfei</groupId> <groupId>me.tongfei</groupId>

View File

@@ -39,13 +39,14 @@ public class CommandRunner implements Runnable {
System.out.println("Safemode active. No files will be changed!"); 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("./last-executions.yml") : null;
FileFilter fileFilter = new FileFilter(config.getExcluded(), config.getIncludePattern(), config.getFilterDate(), lastExecutionHandler);
FileProcessor fileProcessor = new CachedFileProcessor(new MkvFileProcessor(config.getMkvToolNix(), fileFilter)); 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()); AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(config.getPreferredSubtitles().toArray(new String[0]), config.getForcedKeywords(), config.getCommentaryKeywords(), config.getHearingImpaired());
AttributeUpdater kernel = config.getCoherent() != null AttributeUpdater kernel = config.getCoherent() != null
? new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor) ? new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler)
: new SingleFileAttributeUpdater(config, fileProcessor, attributeChangeProcessor); : new SingleFileAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler);
kernel.execute(); kernel.execute();
} }
} }

View File

@@ -1,7 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -9,9 +8,8 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date; import java.time.Instant;
import java.util.HashSet; import java.util.*;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -20,7 +18,8 @@ import java.util.regex.Pattern;
public class FileFilter { public class FileFilter {
private final Set<String> excluded; private final Set<String> excluded;
private final Pattern includePattern; private final Pattern includePattern;
private final Date filterDate; private final Instant filterDate;
private final LastExecutionHandler lastExecutionHandler;
private final String EXTENSION_GROUP = "extension"; private final String EXTENSION_GROUP = "extension";
private final Pattern extensionPattern = Pattern.compile(String.format(".*(?<%s>\\..*)", EXTENSION_GROUP)); private final Pattern extensionPattern = Pattern.compile(String.format(".*(?<%s>\\..*)", EXTENSION_GROUP));
@@ -33,8 +32,9 @@ public class FileFilter {
} }
if (!hasMatchingPattern(pathName) 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); log.debug("Excluded {}", pathName);
ResultStatistic.getInstance().excluded(); ResultStatistic.getInstance().excluded();
return false; return false;
@@ -52,21 +52,18 @@ public class FileFilter {
return includePattern.matcher(pathName.getName()).matches(); return includePattern.matcher(pathName.getName()).matches();
} }
private boolean isNewer(File pathName) { private boolean isNewer(File pathName, Instant date) {
if (filterDate == null) return true; if (date == null) return true;
try { try {
BasicFileAttributes attributes = Files.readAttributes(pathName.toPath(), BasicFileAttributes.class); 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) { } catch (IOException e) {
log.warn("File attributes could not be read", e); log.warn("File attributes could not be read", e);
} }
return true; return true;
} }
private boolean isNewer(Date creationDate) {
return creationDate.toInstant().isAfter(filterDate.toInstant());
}
private boolean isExcluded(File pathName, Set<String> excludedDirs) { private boolean isExcluded(File pathName, Set<String> excludedDirs) {
if (excludedDirs.contains(pathName.getPath())) return true; if (excludedDirs.contains(pathName.getPath())) return true;

View File

@@ -0,0 +1,55 @@
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 final File file;
private final Properties lastFileExecution;
public LastExecutionHandler(String path) {
file = new File(path);
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.warn("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);
}
}
}

View File

@@ -37,10 +37,10 @@ public class AttributeConfigConverter implements CommandLine.ITypeConverter<Attr
* @return valid {@link AttributeConfig} * @return valid {@link AttributeConfig}
*/ */
private static AttributeConfig validateResult(AttributeConfig attr) { private static AttributeConfig validateResult(AttributeConfig attr) {
if (!isLanguageValid(attr.getAudioLanguage())) if (!isLanguageValid(attr.getAudioLang()))
throw new CommandLine.TypeConversionException("Audio language invalid: " + attr.getAudioLanguage()); throw new CommandLine.TypeConversionException("Audio language invalid: " + attr.getAudioLang());
if (!isLanguageValid(attr.getSubtitleLanguage())) if (!isLanguageValid(attr.getSubLang()))
throw new CommandLine.TypeConversionException("Subtitle language invalid: " + attr.getSubtitleLanguage()); throw new CommandLine.TypeConversionException("Subtitle language invalid: " + attr.getSubLang());
return attr; return attr;
} }

View File

@@ -4,8 +4,6 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.SubtitleTrackComparator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
public class AttributeChangeProcessor { public class AttributeChangeProcessor {
@@ -21,7 +19,51 @@ public class AttributeChangeProcessor {
this.forcedKeywords = forcedKeywords; this.forcedKeywords = forcedKeywords;
} }
private List<TrackAttributes> filterForPossibleDefaults(List<TrackAttributes> tracks) { /**
* Looks for default matches and applies them if found.
*/
public void findAndApplyDefaultMatch(FileInfo fileInfo, AttributeConfig... configs) {
Map<String, List<TrackAttributes>> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size());
Map<String, List<TrackAttributes>> 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<TrackAttributes> getPossibleDefaults(List<TrackAttributes> tracks) {
Stream<TrackAttributes> attributes = tracks.stream(); Stream<TrackAttributes> attributes = tracks.stream();
return attributes return attributes
@@ -34,55 +76,26 @@ public class AttributeChangeProcessor {
.filter(attr -> { .filter(attr -> {
if (attr.trackName() == null) return true; if (attr.trackName() == null) return true;
return forcedKeywords.stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0); return forcedKeywords.stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0);
}) });
.toList();
} }
public void findDefaultMatchAndApplyChanges(FileInfo fileInfo, AttributeConfig... configs) { private void removeExistingDefaults(FileInfo fileInfo) {
Map<String, List<TrackAttributes>> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size()); fileInfo.getTracks().stream()
Map<String, List<TrackAttributes>> 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<FileInfo, List<TrackAttributes>> tracks, String language, Supplier<TrackAttributes> targetDefaultSupplier) {
tracks.apply(fileInfo).stream()
.filter(TrackAttributes::defaultt) .filter(TrackAttributes::defaultt)
.forEach(attr -> fileInfo.getChanges().getDefaultTrack().put(attr, false)); .forEach(attr -> fileInfo.getChanges().getDefaultTrack().put(attr, false));
if (!"OFF".equals(language)) { }
TrackAttributes targetDefault = targetDefaultSupplier.get();
if (fileInfo.getChanges().getDefaultTrack().containsKey(targetDefault)) { private void applyNewDefault(FileInfo fileInfo, TrackAttributes targetDefault) {
fileInfo.getChanges().getDefaultTrack().remove(targetDefault); Map<TrackAttributes, Boolean> changes = fileInfo.getChanges().getDefaultTrack();
} else { if (changes.containsKey(targetDefault)) {
fileInfo.getChanges().getDefaultTrack().put(targetDefault, true); changes.remove(targetDefault);
} } else {
changes.put(targetDefault, true);
} }
} }
public void findForcedTracksAndApplyChanges(FileInfo fileInfo, boolean overwrite) { public void findAndApplyForcedTracks(FileInfo fileInfo, boolean overwrite) {
Stream<TrackAttributes> forcedTracks = fileInfo.getTracks().stream() Stream<TrackAttributes> forcedTracks = getForcedTracks(fileInfo);
.filter(track -> track.trackName() != null)
.filter(track -> forcedKeywords.stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT))));
if (overwrite) { if (overwrite) {
fileInfo.getTracks().stream().filter(TrackAttributes::forced).forEach(attr -> { fileInfo.getTracks().stream().filter(TrackAttributes::forced).forEach(attr -> {
@@ -97,7 +110,19 @@ public class AttributeChangeProcessor {
}); });
} }
public void findCommentaryTracksAndApplyChanges(FileInfo fileInfo) { private Stream<TrackAttributes> 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() fileInfo.getTracks().stream()
.filter(track -> !track.commentary()) .filter(track -> !track.commentary())
.filter(track -> track.trackName() != null) .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() fileInfo.getTracks().stream()
.filter(track -> !track.hearingImpaired()) .filter(track -> !track.hearingImpaired())
.filter(track -> track.trackName() != null) .filter(track -> track.trackName() != null)

View File

@@ -1,6 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException; import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
@@ -25,14 +26,16 @@ public abstract class AttributeUpdater {
protected final InputConfig config; protected final InputConfig config;
protected final FileProcessor fileProcessor; protected final FileProcessor fileProcessor;
protected final AttributeChangeProcessor attributeChangeProcessor; protected final AttributeChangeProcessor attributeChangeProcessor;
protected final LastExecutionHandler lastExecutionHandler;
protected final ResultStatistic statistic = ResultStatistic.getInstance(); protected final ResultStatistic statistic = ResultStatistic.getInstance();
private final ExecutorService executor; 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.config = config;
this.fileProcessor = fileProcessor; this.fileProcessor = fileProcessor;
this.attributeChangeProcessor = attributeChangeProcessor; this.attributeChangeProcessor = attributeChangeProcessor;
this.lastExecutionHandler = lastExecutionHandler;
this.executor = Executors.newFixedThreadPool(config.getThreads()); this.executor = Executors.newFixedThreadPool(config.getThreads());
} }
@@ -62,7 +65,7 @@ public abstract class AttributeUpdater {
executor.awaitTermination(1, TimeUnit.DAYS); executor.awaitTermination(1, TimeUnit.DAYS);
} }
// writeLastExecutionDate(); lastExecutionHandler.persist();
statistic.stopTimer(); statistic.stopTimer();
statistic.print(); statistic.print();
@@ -84,6 +87,7 @@ public abstract class AttributeUpdater {
* @param fileInfo contains information about file and desired configuration. * @param fileInfo contains information about file and desired configuration.
*/ */
protected void checkStatusAndUpdate(FileInfo fileInfo) { protected void checkStatusAndUpdate(FileInfo fileInfo) {
if (lastExecutionHandler != null) lastExecutionHandler.update(fileInfo.getFile().getAbsolutePath());
if (!fileInfo.getChanges().isEmpty()) { if (!fileInfo.getChanges().isEmpty()) {
statistic.changePlanned(); statistic.changePlanned();

View File

@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
@@ -7,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
import java.io.File; import java.io.File;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -14,8 +16,8 @@ import java.util.Set;
@Slf4j @Slf4j
public class CoherentAttributeUpdater extends SingleFileAttributeUpdater { public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
public CoherentAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor) { public CoherentAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor, LastExecutionHandler lastExecutionHandler) {
super(config, processor, attributeChangeProcessor); super(config, processor, attributeChangeProcessor, lastExecutionHandler);
} }
@Override @Override
@@ -25,7 +27,9 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
} }
protected List<File> getFiles() { protected List<File> 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 @Override
@@ -49,16 +53,17 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
log.info("Found coherent match {} for {}", matchedConfig.toStringShort(), rootDir.getPath()); log.info("Found coherent match {} for {}", matchedConfig.toStringShort(), rootDir.getPath());
matchedFiles.forEach(fileInfo -> { matchedFiles.forEach(fileInfo -> {
attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, this.config.isOverwriteForced()); attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, this.config.isOverwriteForced());
attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo); attributeChangeProcessor.applyForcedAsDefault(fileInfo);
attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo); attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
checkStatusAndUpdate(fileInfo); checkStatusAndUpdate(fileInfo);
}); });
return; // match was found and process must be stopped 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 -> { matchedFiles.forEach(fileInfo -> {
fileInfo.resetChanges(); fileInfo.resetChanges();
fileInfo.setMatchedConfig(null); fileInfo.setMatchedConfig(null);
@@ -89,7 +94,7 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
break; break;
} }
attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config); attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config);
if (matchedConfig == null) matchedConfig = fileInfo.getMatchedConfig(); if (matchedConfig == null) matchedConfig = fileInfo.getMatchedConfig();
if (matchedConfig == null || matchedConfig != fileInfo.getMatchedConfig()) { if (matchedConfig == null || matchedConfig != fileInfo.getMatchedConfig()) {

View File

@@ -5,7 +5,7 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileFilter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.core.util.IOUtils; import org.apache.commons.io.IOUtils;
import tools.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import java.io.File; import java.io.File;

View File

@@ -1,18 +1,20 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
import java.io.File; import java.io.File;
import java.util.Arrays;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
public class SingleFileAttributeUpdater extends AttributeUpdater { public class SingleFileAttributeUpdater extends AttributeUpdater {
public SingleFileAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor) { public SingleFileAttributeUpdater(InputConfig config, FileProcessor processor, AttributeChangeProcessor attributeChangeProcessor, LastExecutionHandler lastExecutionHandler) {
super(config, processor, attributeChangeProcessor); super(config, processor, attributeChangeProcessor, lastExecutionHandler);
} }
@Override @Override
@@ -23,7 +25,9 @@ public class SingleFileAttributeUpdater extends AttributeUpdater {
@Override @Override
protected List<File> getFiles() { protected List<File> getFiles() {
return fileProcessor.loadFiles(config.getLibraryPath().getPath()); return Arrays.stream(config.getLibraryPath())
.flatMap(path -> fileProcessor.loadFiles(path.getPath()).stream())
.toList();
} }
@Override @Override
@@ -36,10 +40,11 @@ public class SingleFileAttributeUpdater extends AttributeUpdater {
return; return;
} }
attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config.getAttributeConfig()); attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config.getAttributeConfig());
attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, config.isOverwriteForced()); attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, config.isOverwriteForced());
attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo); attributeChangeProcessor.applyForcedAsDefault(fileInfo);
attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo); attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
checkStatusAndUpdate(fileInfo); checkStatusAndUpdate(fileInfo);
} }

View File

@@ -2,16 +2,26 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext; import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;
import java.io.File; import java.io.File;
import java.util.Arrays;
public class ValidFileValidator implements ConstraintValidator<ValidFile, File> { @Slf4j
public class ValidFileValidator implements ConstraintValidator<ValidFile, File[]> {
@Override @Override
public void initialize(ValidFile constraintAnnotation) { public void initialize(ValidFile constraintAnnotation) {
} }
@Override @Override
public boolean isValid(File file, ConstraintValidatorContext context) { public boolean isValid(File[] files, ConstraintValidatorContext context) {
return file != null && file.exists(); 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;
} }
} }

View File

@@ -10,8 +10,8 @@ import java.util.Objects;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public class AttributeConfig { public class AttributeConfig {
private final String audioLanguage; private final String audioLang;
private final String subtitleLanguage; private final String subLang;
public static AttributeConfig of(String audioLanguage, String subtitleLanguage) { public static AttributeConfig of(String audioLanguage, String subtitleLanguage) {
return new AttributeConfig(audioLanguage, subtitleLanguage); return new AttributeConfig(audioLanguage, subtitleLanguage);
@@ -22,23 +22,23 @@ public class AttributeConfig {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
AttributeConfig that = (AttributeConfig) o; 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 @Override
public int hashCode() { public int hashCode() {
return Objects.hash(audioLanguage, subtitleLanguage); return Objects.hash(audioLang, subLang);
} }
public String toStringShort() { public String toStringShort() {
return audioLanguage + ":" + subtitleLanguage; return audioLang + ":" + subLang;
} }
@Override @Override
public String toString() { public String toString() {
return "AttributeConfig{" return "AttributeConfig{"
+ "audioLanguage='" + audioLanguage + '\'' + "audioLanguage='" + audioLang + '\''
+ ", subtitleLanguage='" + subtitleLanguage + '\'' + + ", subtitleLanguage='" + subLang + '\'' +
'}'; '}';
} }
} }

View File

@@ -12,6 +12,7 @@ import org.apache.commons.lang3.SystemUtils;
import picocli.CommandLine; import picocli.CommandLine;
import java.io.File; import java.io.File;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import picocli.CommandLine.Option; import picocli.CommandLine.Option;
@@ -29,8 +30,8 @@ public class InputConfig implements CommandLine.IVersionProvider {
CommandLine.Model.CommandSpec spec; CommandLine.Model.CommandSpec spec;
@ValidFile(message = "does not exist") @ValidFile(message = "does not exist")
@CommandLine.Parameters(description = "path to library") @CommandLine.Parameters(description = "paths to library", arity = "1..*")
private File libraryPath; private File[] libraryPath;
@Option(names = {"-a", "--attribute-config"}, arity = "1..*", converter = AttributeConfigConverter.class, @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)") 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; private boolean forceCoherent;
// TODO: implement usage // TODO: implement usage
// @Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)") @Option(names = {"-n", "--only-new-files"}, description = "ignores all files unchanged and previously processed")
// private boolean onlyNewFiles; 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\")") @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 Date filterDate; private Instant filterDate;
@Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern") @Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern")
private Pattern includePattern; private Pattern includePattern;
@Option(names = {"-e", "--exclude"}, arity = "1..*", @Option(names = {"-e", "--exclude"}, arity = "1..*",

View File

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

View File

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

View File

@@ -1,8 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@@ -14,11 +12,13 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import java.io.File; import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes; 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.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -71,12 +71,14 @@ class FileFilterTest {
when(file.toPath()).thenReturn(Path.of(TEST_FILE)); when(file.toPath()).thenReturn(Path.of(TEST_FILE));
long currentTime = System.currentTimeMillis(); 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<DateUtils> mockedFiles = Mockito.mockStatic(DateUtils.class)) { try (MockedStatic<Files> mockedFiles = Mockito.mockStatic(Files.class)) {
mockedFiles mockedFiles
.when(() -> DateUtils.convert(anyLong())) .when(() -> Files.readAttributes(any(), eq(BasicFileAttributes.class)))
.thenReturn(new Date(currentTime)); .thenReturn(attributes);
assertEquals(acceptanceExpected, fileFilter.accept(file, new HashSet<>(extensions)), "File is accepted"); assertEquals(acceptanceExpected, fileFilter.accept(file, new HashSet<>(extensions)), "File is accepted");
assertEquals(excluded, ResultStatistic.getInstance().getExcluded() > 0, "Is counted in excluded statistic"); assertEquals(excluded, ResultStatistic.getInstance().getExcluded() > 0, "Is counted in excluded statistic");

View File

@@ -0,0 +1,73 @@
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_YML = "./last-execution.properties";
private static final String TEST_MKV_FILE = "/arst/file.mkv";
@AfterEach
void destruct() {
File file = new File(LAST_EXECUTION_YML);
if (file.exists()) file.delete();
}
@Test
void missingFile() throws IOException {
LastExecutionHandler underTest = new LastExecutionHandler(LAST_EXECUTION_YML);
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_YML);
assertTrue(file.exists());
assertTrue(Files.readString(file.toPath()).contains(TEST_MKV_FILE + "="));
}
@Test
void emptyFile() throws IOException {
File file = new File(LAST_EXECUTION_YML);
file.createNewFile();
missingFile(); // does the checks needed for empty file case
}
@Test
void existingFileNoChanges() throws IOException {
File file = new File(LAST_EXECUTION_YML);
file.createNewFile();
Files.writeString(file.toPath(), TEST_MKV_FILE + "=" + Instant.now());
String expected = Files.readString(file.toPath()).replace(":", "\\:");
LastExecutionHandler underTest = new LastExecutionHandler(LAST_EXECUTION_YML);
assertNotNull(underTest.get(TEST_MKV_FILE));
underTest.persist();
File file1 = new File(LAST_EXECUTION_YML);
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_YML);
file.createNewFile();
Files.writeString(file.toPath(), TEST_MKV_FILE + "=" + Instant.now());
String expected = Files.readString(file.toPath());
LastExecutionHandler underTest = new LastExecutionHandler(LAST_EXECUTION_YML);
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_YML);
assertTrue(file1.exists());
assertNotEquals(expected, Files.readString(file.toPath()));
}
}

View File

@@ -12,13 +12,13 @@ import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.stream.Stream; 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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
class AttributeChangeProcessorTest { class AttributeChangeProcessorTest {
private static Stream<Arguments> attributeConfigMatching() { private static Stream<Arguments> findAndApplyDefaultMatch() {
return Stream.of( return Stream.of(
Arguments.of( Arguments.of(
List.of(withName(AUDIO_ENG, null), SUB_ENG), List.of(withName(AUDIO_ENG, null), SUB_ENG),
@@ -99,13 +99,14 @@ class AttributeChangeProcessorTest {
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("attributeConfigMatching") @MethodSource("findAndApplyDefaultMatch")
void findDefaultMatchAndApplyChanges(List<TrackAttributes> tracks, AttributeConfig[] config, String expectedConfig, Map<TrackAttributes, Boolean> changes) { void findAndApplyDefaultMatch(List<TrackAttributes> tracks, AttributeConfig[] config, String expectedConfig, Map<TrackAttributes, Boolean> changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH")); AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH"));
FileInfo fileInfo = new FileInfo(null); FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks); fileInfo.addTracks(tracks);
attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config);
attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config);
assertEquals(expectedConfig, fileInfo.getMatchedConfig() != null ? fileInfo.getMatchedConfig().toStringShort() : fileInfo.getMatchedConfig()); assertEquals(expectedConfig, fileInfo.getMatchedConfig() != null ? fileInfo.getMatchedConfig().toStringShort() : fileInfo.getMatchedConfig());
assertEquals(changes.size(), fileInfo.getChanges().getDefaultTrack().size()); assertEquals(changes.size(), fileInfo.getChanges().getDefaultTrack().size());
changes.forEach((key, value) -> { changes.forEach((key, value) -> {
@@ -114,24 +115,54 @@ class AttributeChangeProcessorTest {
}); });
} }
private static AttributeConfig[] arr(AttributeConfig... configs) { private static Stream<Arguments> applyForcedAsDefault() {
return configs; 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) { @ParameterizedTest
String[] split = config.split(":"); @MethodSource("applyForcedAsDefault")
return new AttributeConfig(split[0], split[1]); void applyForcedAsDefault(List<TrackAttributes> tracks, AttributeConfig config, Map<TrackAttributes, Boolean> 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<TrackAttributes, Boolean> on(TrackAttributes track) { private static Stream<Arguments> getPossibleDefaults() {
return Map.entry(track, true);
}
private static Map.Entry<TrackAttributes, Boolean> off(TrackAttributes track) {
return Map.entry(track, false);
}
private static Stream<Arguments> filterForPossibleDefaults() {
return Stream.of( 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, 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)), 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 @ParameterizedTest
@MethodSource("filterForPossibleDefaults") @MethodSource("getPossibleDefaults")
void filterForPossibleDefaults(List<TrackAttributes> tracks, Set<TrackAttributes> expected) throws InvocationTargetException, IllegalAccessException { void getPossibleDefaults(List<TrackAttributes> tracks, Set<TrackAttributes> expected) throws InvocationTargetException, IllegalAccessException {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH")); AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH"));
Optional<Method> method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods()) Optional<Method> method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods())
.filter(m -> m.getName().equals("filterForPossibleDefaults")) .filter(m -> m.getName().equals("getPossibleDefaults"))
.findFirst(); .findFirst();
assertTrue(method.isPresent()); assertTrue(method.isPresent());
Method underTest = method.get(); Method underTest = method.get();
underTest.setAccessible(true); underTest.setAccessible(true);
List<TrackAttributes> result = (List<TrackAttributes>) underTest.invoke(attributeChangeProcessor, tracks); List<TrackAttributes> result = ((Stream<TrackAttributes>) underTest.invoke(attributeChangeProcessor, tracks)).toList();
assertEquals(expected.size(), result.size()); assertEquals(expected.size(), result.size());
for (TrackAttributes track : result) { for (TrackAttributes track : result) {
assertTrue(expected.contains(track)); assertTrue(expected.contains(track));
} }
} }
private static Stream<Arguments> findForcedTracksAndApplyChanges() { private static Stream<Arguments> 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<TrackAttributes> tracks, Map<TrackAttributes, Boolean> changes, Set<TrackAttributes> 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> method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods())
.filter(m -> m.getName().equals("getForcedTracks"))
.findFirst();
assertTrue(method.isPresent());
Method underTest = method.get();
underTest.setAccessible(true);
List<TrackAttributes> result = ((Stream<TrackAttributes>) underTest.invoke(attributeChangeProcessor, fileInfo)).toList();
assertEquals(expected.size(), result.size());
for (TrackAttributes track : result) {
assertTrue(expected.contains(track));
}
}
private static Stream<Arguments> findAndApplyForcedTracks() {
return Stream.of( return Stream.of(
Arguments.of(List.of(), Arguments.of(List.of(),
Set.of("song & signs"), false, Set.of("song & signs"), false,
@@ -196,13 +258,13 @@ class AttributeChangeProcessorTest {
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("findForcedTracksAndApplyChanges") @MethodSource("findAndApplyForcedTracks")
void findForcedTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, boolean overwrite, Map<TrackAttributes, Boolean> changes) { void findAndApplyForcedTracks(List<TrackAttributes> tracks, Set<String> keywords, boolean overwrite, Map<TrackAttributes, Boolean> changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, keywords, Set.of(), Set.of()); AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, keywords, Set.of(), Set.of());
FileInfo fileInfo = new FileInfo(null); FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks); fileInfo.addTracks(tracks);
attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, overwrite); attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, overwrite);
assertEquals(changes.size(), fileInfo.getChanges().getForcedTrack().size()); assertEquals(changes.size(), fileInfo.getChanges().getForcedTrack().size());
changes.forEach((key, value) -> { changes.forEach((key, value) -> {
@@ -211,7 +273,7 @@ class AttributeChangeProcessorTest {
}); });
} }
private static Stream<Arguments> findCommentaryTracksAndApplyChanges() { private static Stream<Arguments> findAndApplyCommentaryTracks() {
return Stream.of( return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "commentary"), withName(SUB_GER, null)), Arguments.of(List.of(withName(SUB_GER, "commentary"), withName(SUB_GER, null)),
Set.of("commentary"), Set.of("commentary"),
@@ -233,13 +295,13 @@ class AttributeChangeProcessorTest {
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("findCommentaryTracksAndApplyChanges") @MethodSource("findAndApplyCommentaryTracks")
void findCommentaryTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) { void findAndApplyCommentaryTracks(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), keywords, Set.of()); AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), keywords, Set.of());
FileInfo fileInfo = new FileInfo(null); FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks); fileInfo.addTracks(tracks);
attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo); attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getCommentaryTrack().size()); assertEquals(changes.size(), fileInfo.getChanges().getCommentaryTrack().size());
changes.forEach((key, value) -> { changes.forEach((key, value) -> {
@@ -248,7 +310,7 @@ class AttributeChangeProcessorTest {
}); });
} }
private static Stream<Arguments> findHearingImpairedTracksAndApplyChanges() { private static Stream<Arguments> findAndApplyHearingImpairedTracks() {
return Stream.of( return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "SDH"), withName(SUB_GER, null)), Arguments.of(List.of(withName(SUB_GER, "SDH"), withName(SUB_GER, null)),
Set.of("SDH"), Set.of("SDH"),
@@ -270,13 +332,13 @@ class AttributeChangeProcessorTest {
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("findHearingImpairedTracksAndApplyChanges") @MethodSource("findAndApplyHearingImpairedTracks")
void findHearingImpairedTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) { void findAndApplyHearingImpairedTracks(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) {
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), Set.of(), keywords); AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), Set.of(), keywords);
FileInfo fileInfo = new FileInfo(null); FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks); fileInfo.addTracks(tracks);
attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo); attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getHearingImpairedTrack().size()); assertEquals(changes.size(), fileInfo.getChanges().getHearingImpairedTrack().size());
changes.forEach((key, value) -> { changes.forEach((key, value) -> {

View File

@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@@ -11,7 +12,7 @@ import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; 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 at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@@ -36,7 +37,7 @@ class AttributeUpdaterTest {
InputConfig config = new InputConfig(); InputConfig config = new InputConfig();
config.setThreads(1); config.setThreads(1);
config.setSafeMode(true); config.setSafeMode(true);
AttributeUpdater underTest = new AttributeUpdater(config, null, null) { AttributeUpdater underTest = new AttributeUpdater(config, null, null, new LastExecutionHandler("")) {
@Override @Override
protected List<File> getFiles() { protected List<File> getFiles() {
return List.of(); return List.of();

View File

@@ -1,12 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CommandRunner; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CommandRunner;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.LastExecutionHandler;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
@@ -21,19 +21,17 @@ import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.stream.Stream; 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.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) @ExtendWith(MockitoExtension.class)
class CoherentAttributeUpdaterTest { class CoherentAttributeUpdaterTest {
@Mock(lenient = true) @Mock(lenient = true)
FileProcessor fileProcessor; FileProcessor fileProcessor;
@Test
void process() {
}
private static Stream<Arguments> findMatch() { private static Stream<Arguments> findMatch() {
return Stream.of( return Stream.of(
Arguments.of(AttributeConfig.of("ger", "ger"), Arguments.of(AttributeConfig.of("ger", "ger"),
@@ -68,7 +66,8 @@ class CoherentAttributeUpdaterTest {
new CommandLine(commandRunner).parseArgs("-a", "ger:ger", "/arst"); new CommandLine(commandRunner).parseArgs("-a", "ger:ger", "/arst");
InputConfig config = commandRunner.getConfig(); InputConfig config = commandRunner.getConfig();
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(config.getPreferredSubtitles().toArray(new String[0]), config.getForcedKeywords(), config.getCommentaryKeywords(), config.getHearingImpaired()); 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<FileInfo> matchedFiles = new HashSet<>(fileInfoMock.size() * 2); Set<FileInfo> matchedFiles = new HashSet<>(fileInfoMock.size() * 2);
List<File> files = new ArrayList<>(); List<File> files = new ArrayList<>();
@@ -91,4 +90,130 @@ class CoherentAttributeUpdaterTest {
fileInfo.addTracks(List.of(tracks)); fileInfo.addTracks(List.of(tracks));
return Pair.of(file, fileInfo); return Pair.of(file, fileInfo);
} }
private static Stream<Arguments> 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<List<TrackAttributes>> tracks,
List<Map<TrackAttributes, Boolean>> defaultExp,
List<Map<TrackAttributes, Boolean>> forcedExp,
List<Map<TrackAttributes, Boolean>> commentaryExp,
List<Map<TrackAttributes, Boolean>> hearingImpairedExp) {
InputConfig config = new InputConfig();
config.setThreads(1);
config.setSafeMode(true);
config.setAttributeConfig(attributeConfigs);
FileProcessor fileProcessor = spy(FileProcessor.class);
List<File> testMkvFiles = new ArrayList<>();
List<FileInfo> testFileInfo = new ArrayList<>();
for (int i = 0; i < tracks.size(); i++) {
List<TrackAttributes> tracks1 = tracks.get(i);
File file = new File(TEST_DIR + i);
FileInfo fileInfo = new FileInfo(file);
fileInfo.addTracks(tracks1);
doReturn(fileInfo).when(fileProcessor).readAttributes(file);
testMkvFiles.add(file);
testFileInfo.add(fileInfo);
}
doReturn(testMkvFiles).when(fileProcessor).loadFiles(any());
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{"pref"}, Set.of("forced"), Set.of("commentary"), Set.of("SDH"));
LastExecutionHandler lastExecutionHandler = new LastExecutionHandler("");
CoherentAttributeUpdater underTest = new CoherentAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler);
underTest.process(new File(""));
for (int i = 0; i < testFileInfo.size(); i++) {
FileInfo fileInfo = testFileInfo.get(i);
assertEquals(expectedMatch, fileInfo.getMatchedConfig());
assertEquals(fileInfo.getChanges().getDefaultTrack().size(), defaultExp.get(i).size());
defaultExp.get(i).forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getDefaultTrack().get(key), "Default track flag"));
assertEquals(fileInfo.getChanges().getForcedTrack().size(), forcedExp.get(i).size());
forcedExp.get(i).forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getForcedTrack().get(key), "Forced track flag"));
assertEquals(fileInfo.getChanges().getCommentaryTrack().size(), commentaryExp.get(i).size());
commentaryExp.get(i).forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getCommentaryTrack().get(key), "Commentary track flag"));
assertEquals(fileInfo.getChanges().getHearingImpairedTrack().size(), hearingImpairedExp.get(i).size());
hearingImpairedExp.get(i).forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getHearingImpairedTrack().get(key), "Hearing Impaired track flag"));
}
}
} }

View File

@@ -0,0 +1,98 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
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.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.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_DIR;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TrackAttributeUtil.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
class SingleFileAttributeUpdaterTest {
private static Stream<Arguments> process() {
return Stream.of(
Arguments.of(
arr(a("ger:OFF")), a("ger:OFF"),
List.of(AUDIO_GER, SUB_GER_FORCED),
Map.ofEntries(on(AUDIO_GER), on(SUB_GER_FORCED)),
Map.ofEntries(),
Map.ofEntries(),
Map.ofEntries()
),
Arguments.of(
arr(a("ger:ger")), a("ger:ger"),
List.of(AUDIO_GER, SUB_GER, withName(AUDIO_GER, "SDH"), withName(AUDIO_GER, "commentary"), withName(SUB_GER, "Forced")),
Map.ofEntries(on(AUDIO_GER), on(SUB_GER)),
Map.ofEntries(on(withName(SUB_GER, "Forced"))),
Map.ofEntries(on(withName(AUDIO_GER, "commentary"))),
Map.ofEntries(on(withName(AUDIO_GER, "SDH")))
),
Arguments.of(
arr(a("ger:OFF")), a("ger:OFF"),
List.of(AUDIO_GER, SUB_GER, withName(AUDIO_GER, "SDH"), withName(AUDIO_GER, "commentary"), withName(SUB_GER, "Forced")),
Map.ofEntries(on(AUDIO_GER), on(withName(SUB_GER, "Forced"))),
Map.ofEntries(on(withName(SUB_GER, "Forced"))),
Map.ofEntries(on(withName(AUDIO_GER, "commentary"))),
Map.ofEntries(on(withName(AUDIO_GER, "SDH")))
),
Arguments.of(
arr(a("ger:eng")), null,
List.of(AUDIO_GER, SUB_GER, withName(AUDIO_GER, "SDH"), withName(AUDIO_GER, "commentary"), withName(SUB_GER, "Forced")),
Map.ofEntries(),
Map.ofEntries(on(withName(SUB_GER, "Forced"))),
Map.ofEntries(on(withName(AUDIO_GER, "commentary"))),
Map.ofEntries(on(withName(AUDIO_GER, "SDH")))
)
);
}
@ParameterizedTest
@MethodSource("process")
void process(AttributeConfig[] attributeConfigs, AttributeConfig expectedMatch,
List<TrackAttributes> tracks,
Map<TrackAttributes, Boolean> defaultExp,
Map<TrackAttributes, Boolean> forcedExp,
Map<TrackAttributes, Boolean> commentaryExp,
Map<TrackAttributes, Boolean> hearingImpairedExp) {
InputConfig config = new InputConfig();
config.setThreads(1);
config.setSafeMode(true);
config.setAttributeConfig(attributeConfigs);
FileInfo fileInfo = new FileInfo(new File(TEST_DIR));
fileInfo.addTracks(tracks);
FileProcessor fileProcessor = spy(FileProcessor.class);
doReturn(fileInfo).when(fileProcessor).readAttributes(any());
AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{"pref"}, Set.of("forced"), Set.of("commentary"), Set.of("SDH"));
LastExecutionHandler lastExecutionHandler = new LastExecutionHandler("");
SingleFileAttributeUpdater underTest = new SingleFileAttributeUpdater(config, fileProcessor, attributeChangeProcessor, lastExecutionHandler);
underTest.process(fileInfo.getFile());
assertEquals(expectedMatch, fileInfo.getMatchedConfig());
assertEquals(fileInfo.getChanges().getDefaultTrack().size(), defaultExp.size());
defaultExp.forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getDefaultTrack().get(key), "Default track flag"));
assertEquals(fileInfo.getChanges().getForcedTrack().size(), forcedExp.size());
forcedExp.forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getForcedTrack().get(key), "Forced track flag"));
assertEquals(fileInfo.getChanges().getCommentaryTrack().size(), commentaryExp.size());
commentaryExp.forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getCommentaryTrack().get(key), "Commentary track flag"));
assertEquals(fileInfo.getChanges().getHearingImpairedTrack().size(), hearingImpairedExp.size());
hearingImpairedExp.forEach((key, val) -> assertEquals(val, fileInfo.getChanges().getHearingImpairedTrack().get(key), "Hearing Impaired track flag"));
}
}

View File

@@ -12,7 +12,6 @@ import java.io.StringWriter;
import java.util.stream.Stream; import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.*; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class ValidationExecutionStrategyTest { class ValidationExecutionStrategyTest {
@@ -24,7 +23,7 @@ class ValidationExecutionStrategyTest {
.setExecutionStrategy(new ValidationExecutionStrategy()) .setExecutionStrategy(new ValidationExecutionStrategy())
.parseArgs("-a", "ger:ger", "-m", TEST_MKVTOOLNIX_DIR, TEST_FILE); .parseArgs("-a", "ger:ger", "-m", TEST_MKVTOOLNIX_DIR, TEST_FILE);
assertEquals(TEST_FILE, underTest.getConfig().getLibraryPath().getPath().replace("\\", "/")); assertEquals(TEST_FILE, underTest.getConfig().getLibraryPath()[0].getPath().replace("\\", "/"));
assertEquals(TEST_MKVTOOLNIX_DIR, underTest.getConfig().getMkvToolNix().getPath().replace("\\", "/")); assertEquals(TEST_MKVTOOLNIX_DIR, underTest.getConfig().getMkvToolNix().getPath().replace("\\", "/"));
} }
@@ -32,6 +31,7 @@ class ValidationExecutionStrategyTest {
return Stream.of( return Stream.of(
Arguments.of(new String[]{"-a", "jpn:ger"}, "Error: Missing required argument(s): <libraryPath>"), Arguments.of(new String[]{"-a", "jpn:ger"}, "Error: Missing required argument(s): <libraryPath>"),
Arguments.of(new String[]{"/arstarstarst"}, "libraryPath does not exist"), Arguments.of(new String[]{"/arstarstarst"}, "libraryPath does not exist"),
Arguments.of(new String[]{TEST_DIR, "/arstarstarst"}, "libraryPath does not exist"),
Arguments.of(new String[]{"/arstarstarst", "-a",}, "Missing required parameter for option '--attribute-config' at index 0 (<attributeConfig>)"), Arguments.of(new String[]{"/arstarstarst", "-a",}, "Missing required parameter for option '--attribute-config' at index 0 (<attributeConfig>)"),
Arguments.of(new String[]{"/arstarstarst", "-a", "jpn:ger"}, "libraryPath does not exist"), Arguments.of(new String[]{"/arstarstarst", "-a", "jpn:ger"}, "libraryPath does not exist"),
Arguments.of(new String[]{"/arstarstarst", "-m"}, "Missing required parameter for option '--mkvtoolnix' (<mkvToolNix>)"), Arguments.of(new String[]{"/arstarstarst", "-m"}, "Missing required parameter for option '--mkvtoolnix' (<mkvToolNix>)"),

View File

@@ -1,23 +0,0 @@
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
void convert() {
Date expectedDate = new Date(0);
String expectedString = "01.01.1970-01:00:00";
assertEquals(expectedDate, DateUtils.convert(0));
assertEquals(expectedDate, DateUtils.convert(expectedString, expectedDate));
assertEquals(expectedDate, DateUtils.convert("1234;15", expectedDate));
assertEquals(expectedString, DateUtils.convert(expectedDate));
}
}

View File

@@ -1,9 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType;
public class FileInfoTestUtil { import java.util.Map;
public class TrackAttributeUtil {
public static final TrackAttributes AUDIO_GER = new TrackAttributes(0, "ger", "", false, false, false, false, TrackType.AUDIO); public static final TrackAttributes AUDIO_GER = new TrackAttributes(0, "ger", "", false, false, false, false, TrackType.AUDIO);
public static final TrackAttributes AUDIO_ENG = new TrackAttributes(1, "eng", "", false, false, false, false, TrackType.AUDIO); public static final TrackAttributes AUDIO_ENG = new TrackAttributes(1, "eng", "", false, false, false, false, TrackType.AUDIO);
public static final TrackAttributes AUDIO_GER_DEFAULT = new TrackAttributes(0, "ger", "", true, false, false, false, TrackType.AUDIO); public static final TrackAttributes AUDIO_GER_DEFAULT = new TrackAttributes(0, "ger", "", true, false, false, false, TrackType.AUDIO);
@@ -27,4 +30,22 @@ public class FileInfoTestUtil {
public static TrackAttributes withName(TrackAttributes track, String trackName) { public static TrackAttributes withName(TrackAttributes track, String trackName) {
return new TrackAttributes(track.id(), track.language(), trackName, track.defaultt(), track.forced(), track.commentary(), track.hearingImpaired(), track.type()); return new TrackAttributes(track.id(), track.language(), trackName, track.defaultt(), track.forced(), track.commentary(), track.hearingImpaired(), track.type());
} }
public static AttributeConfig[] arr(AttributeConfig... configs) {
return configs;
}
public static AttributeConfig a(String config) {
String[] split = config.split(":");
return new AttributeConfig(split[0], split[1]);
}
public static Map.Entry<TrackAttributes, Boolean> on(TrackAttributes track) {
return Map.entry(track, true);
}
public static Map.Entry<TrackAttributes, Boolean> off(TrackAttributes track) {
return Map.entry(track, false);
}
} }