16 Commits
v5.0 ... dev

Author SHA1 Message Date
RatzzFatzz
6a965e4084 Fix logging 2026-01-24 19:11:03 +01:00
RatzzFatzz
e80331beef Fix log4j2 file link on windows 2026-01-15 21:16:10 +01:00
RatzzFatzz
a5fce22b95 Fix lastExecutionHandler NPE 2026-01-15 21:14:54 +01:00
RatzzFatzz
a97ed89d08 Parameterize log4j2 configs 2026-01-15 13:32:35 +01:00
RatzzFatzz
cce84f5c15 Make path of lastFileExecution platform dependent 2026-01-15 12:40:09 +01:00
RatzzFatzz
ff38457af1 Revert lib updates of jackson & log4j2 2026-01-15 12:19:48 +01:00
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
29 changed files with 758 additions and 241 deletions

27
pom.xml
View File

@@ -29,7 +29,7 @@
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j2.yaml</include>
<include>log4j2.yml</include>
</includes>
</resource>
</resources>
@@ -64,7 +64,7 @@
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j2-windows.yaml</include>
<include>log4j2-windows.yml</include>
</includes>
</resource>
</resources>
@@ -138,7 +138,7 @@
<winShortcut>false</winShortcut>
<winMenu>false</winMenu>
<javaOptions>
<javaOption>-Dlog4j2.configurationFile=log4j2-windows.yaml</javaOption>
<javaOption>-Dlog4j2.configurationFile=log4j2-windows.yml</javaOption>
</javaOptions>
</configuration>
<executions>
@@ -161,7 +161,7 @@
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j2-debian.yaml</include>
<include>log4j2-debian.yml</include>
</includes>
</resource>
</resources>
@@ -396,18 +396,18 @@
<version>2.25.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/tools.jackson.dataformat/jackson-dataformat-yaml -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
<dependency>
<groupId>tools.jackson.dataformat</groupId>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>3.0.3</version>
<version>2.20.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/tools.jackson.core/jackson-databind -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>tools.jackson.core</groupId>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>3.0.3</version>
<version>2.20.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency>
@@ -421,6 +421,13 @@
<artifactId>commons-lang3</artifactId>
<version>3.20.0</version>
</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 -->
<dependency>
<groupId>me.tongfei</groupId>

View File

@@ -1 +1 @@
java -Dlog4j2.configurationFile=log4j2-debian.yaml -jar /usr/lib/${project.artifactId}/${project.artifactId}-${project.version}.jar "$@"
java -Dlog4j2.configurationFile=log4j2-debian.yml -jar /usr/lib/${project.artifactId}/${project.artifactId}-${project.version}.jar "$@"

View File

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

View File

@@ -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<String> 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<String> excludedDirs) {
if (excludedDirs.contains(pathName.getPath())) return true;

View File

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

View File

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

View File

@@ -4,8 +4,6 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.SubtitleTrackComparator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class AttributeChangeProcessor {
@@ -21,7 +19,51 @@ public class AttributeChangeProcessor {
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();
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<String, List<TrackAttributes>> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size());
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()
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<TrackAttributes, Boolean> changes = fileInfo.getChanges().getDefaultTrack();
if (changes.containsKey(targetDefault)) {
changes.remove(targetDefault);
} else {
changes.put(targetDefault, true);
}
}
public void findForcedTracksAndApplyChanges(FileInfo fileInfo, boolean overwrite) {
Stream<TrackAttributes> 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<TrackAttributes> 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<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()
.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)

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<ValidFile, File> {
@Slf4j
public class ValidFileValidator implements ConstraintValidator<ValidFile, File[]> {
@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;
}
}

View File

@@ -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 + '\'' +
'}';
}
}

View File

@@ -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..*",

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

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

View File

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

View File

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

View File

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

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;
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<DateUtils> mockedFiles = Mockito.mockStatic(DateUtils.class)) {
try (MockedStatic<Files> 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");

View File

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

View File

@@ -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<Arguments> attributeConfigMatching() {
private static Stream<Arguments> 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<TrackAttributes> tracks, AttributeConfig[] config, String expectedConfig, Map<TrackAttributes, Boolean> changes) {
@MethodSource("findAndApplyDefaultMatch")
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"));
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<Arguments> 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<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) {
return Map.entry(track, true);
}
private static Map.Entry<TrackAttributes, Boolean> off(TrackAttributes track) {
return Map.entry(track, false);
}
private static Stream<Arguments> filterForPossibleDefaults() {
private static Stream<Arguments> 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<TrackAttributes> tracks, Set<TrackAttributes> expected) throws InvocationTargetException, IllegalAccessException {
@MethodSource("getPossibleDefaults")
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"));
Optional<Method> 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<TrackAttributes> result = (List<TrackAttributes>) underTest.invoke(attributeChangeProcessor, tracks);
List<TrackAttributes> result = ((Stream<TrackAttributes>) underTest.invoke(attributeChangeProcessor, tracks)).toList();
assertEquals(expected.size(), result.size());
for (TrackAttributes track : result) {
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(
Arguments.of(List.of(),
Set.of("song & signs"), false,
@@ -196,13 +258,13 @@ class AttributeChangeProcessorTest {
}
@ParameterizedTest
@MethodSource("findForcedTracksAndApplyChanges")
void findForcedTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, boolean overwrite, Map<TrackAttributes, Boolean> changes) {
@MethodSource("findAndApplyForcedTracks")
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());
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<Arguments> findCommentaryTracksAndApplyChanges() {
private static Stream<Arguments> 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<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) {
@MethodSource("findAndApplyCommentaryTracks")
void findAndApplyCommentaryTracks(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> 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<Arguments> findHearingImpairedTracksAndApplyChanges() {
private static Stream<Arguments> 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<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) {
@MethodSource("findAndApplyHearingImpairedTracks")
void findAndApplyHearingImpairedTracks(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> 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) -> {

View File

@@ -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<File> getFiles() {
return List.of();

View File

@@ -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<Arguments> 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<FileInfo> matchedFiles = new HashSet<>(fileInfoMock.size() * 2);
List<File> files = new ArrayList<>();
@@ -91,4 +90,130 @@ class CoherentAttributeUpdaterTest {
fileInfo.addTracks(List.of(tracks));
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 static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.*;
class ValidationExecutionStrategyTest {
@@ -24,7 +23,7 @@ class ValidationExecutionStrategyTest {
.setExecutionStrategy(new ValidationExecutionStrategy())
.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("\\", "/"));
}
@@ -32,6 +31,7 @@ class ValidationExecutionStrategyTest {
return Stream.of(
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[]{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", "jpn:ger"}, "libraryPath does not exist"),
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;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
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_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);
@@ -27,4 +30,22 @@ public class FileInfoTestUtil {
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());
}
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);
}
}